BUUCTF--刮开有奖
准备
获取信息
- 32位文件
IDA打开
进入主函数WinMain
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { DialogBoxParamA(hInstance, (LPCSTR)0x67, 0, DialogFunc, 0); return 0; }
找到关键的函数DialogFunc,并反编译为C代码
1 BOOL __userpurge DialogFunc@<eax>(int a1@<edi>, int a2@<esi>, HWND hDlg, UINT a4, WPARAM a5, LPARAM a6) 2 { 3 const char *v6; // esi 4 const char *v7; // edi 5 int v9; // [esp+4h] [ebp-20030h] 6 int v10; // [esp+8h] [ebp-2002Ch] 7 int v11; // [esp+Ch] [ebp-20028h] 8 int v12; // [esp+10h] [ebp-20024h] 9 int v13; // [esp+14h] [ebp-20020h] 10 int v14; // [esp+18h] [ebp-2001Ch] 11 int v15; // [esp+1Ch] [ebp-20018h] 12 int v16; // [esp+20h] [ebp-20014h] 13 int v17; // [esp+24h] [ebp-20010h] 14 int v18; // [esp+28h] [ebp-2000Ch] 15 int v19; // [esp+2Ch] [ebp-20008h] 16 CHAR String; // [esp+30h] [ebp-20004h] 17 char v21; // [esp+31h] [ebp-20003h] 18 char v22; // [esp+32h] [ebp-20002h] 19 char v23; // [esp+33h] [ebp-20001h] 20 char v24; // [esp+34h] [ebp-20000h] 21 char v25; // [esp+10030h] [ebp-10004h] 22 char v26; // [esp+10031h] [ebp-10003h] 23 char v27; // [esp+10032h] [ebp-10002h] 24 int v28; // [esp+20028h] [ebp-Ch] 25 int v29; // [esp+2002Ch] [ebp-8h] 26 27 __alloca_probe(); 28 if ( a4 == 272 ) 29 return 1; 30 v29 = a2; 31 v28 = a1; 32 if ( a4 != 273 ) 33 return 0; 34 if ( (_WORD)a5 == 1001 ) 35 { 36 memset(&String, 0, 0xFFFFu); 37 GetDlgItemTextA(hDlg, 1000, &String, 0xFFFF); 38 if ( strlen(&String) == 8 ) 39 { 40 v9 = 90; 41 v10 = 74; 42 v11 = 83; 43 v12 = 69; 44 v13 = 67; 45 v14 = 97; 46 v15 = 78; 47 v16 = 72; 48 v17 = 51; 49 v18 = 110; 50 v19 = 103; 51 sub_4010F0(&v9, 0, 10); 52 memset(&v25, 0, 0xFFFFu); 53 v6 = (const char *)sub_401000(&v25, strlen(&v25)); 54 memset(&v25, 0, 0xFFFFu); 55 v26 = v23; 56 v25 = v22; 57 v27 = v24; 58 v7 = (const char *)sub_401000(&v25, strlen(&v25)); 59 if ( String == v9 + 34 60 && v21 == v13 61 && 4 * v22 - 141 == 3 * v11 62 && v23 / 4 == 2 * (v16 / 9) 63 && !strcmp(v6, "ak1w") 64 && !strcmp(v7, "V1Ax") ) 65 { 66 MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0); 67 } 68 } 69 return 0; 70 } 71 if ( (_WORD)a5 != 1 && (_WORD)a5 != 2 ) 72 return 0; 73 EndDialog(hDlg, (unsigned __int16)a5); 74 return 1; 75 }
代码分析
字符串解析
通过第37行代码GetDlgItemTextA,我们知道了String是我们输入的flag。
通过第38行代码我们知道flag的长度应该是8
第51行函数sub_4010F0在对v9~v19进行某种操作,进入sub_4010F0函数,将函数转换为C语言代码,再将v9~v19代入
#include <iostream> #include <stdlib.h> #include <stdio.h> using namespace std; int __cdecl sub_4010F0(char *a1, int a2, int a3) { int result; // eax int i; // esi int v5; // ecx int v6; // edx result = a3; for (i = a2; i <= a3; a2 = i) { v5 = i; v6 = a1[i]; if (a2 < result && i < result) { do { if (v6 >a1[result]) { if (i >= result) break; ++i; a1[v5] = a1[result]; if (i >= result) break; while (a1[i] <= v6) { if (++i >= result) goto LABEL_13; } if (i >= result) break; v5 = i; a1[result] = a1[i]; } --result; } while (i < result); } LABEL_13: a1[result] = v6; sub_4010F0(a1, a2, i - 1); result = a3; ++i; } return result; } char str[20] = { 90,74,83,69,67,97,78,72,51,110,103 }; int main() { cout << str << endl; sub_4010F0(str, 0, 10); for (int i = 0; i < 11; ++i) { cout << str[i]; } return 0; }
输出
字符串加密
分析第52行代码~58行代码。我们转到汇编代码处
.text:004012B0 push 0FFFFh ; size_t .text:004012B5 lea edx, [ebp+var_10004] .text:004012BB push 0 ; int .text:004012BD push edx ; void * .text:004012BE call _memset .text:004012C3 mov al, [ebp+var_1FFFF] .text:004012C9 mov dl, [ebp+var_1FFFD] .text:004012CF mov cl, [ebp+var_1FFFE] .text:004012D5 mov [ebp+var_10004], al .text:004012DB lea eax, [ebp+var_10004] .text:004012E1 mov [ebp+var_10002], dl .text:004012E7 add esp, 18h .text:004012EA mov [ebp+var_10003], cl .text:004012F0 lea edx, [eax+1] .text:004012F3 .text:004012F3 loc_4012F3: ; CODE XREF: DialogFunc+158↓j .text:004012F3 mov cl, [eax] .text:004012F5 inc eax .text:004012F6 test cl, cl .text:004012F8 jnz short loc_4012F3 .text:004012FA sub eax, edx .text:004012FC push eax .text:004012FD lea eax, [ebp+var_10004] .text:00401303 push eax .text:00401304 call sub_401000 .text:00401309 push 0FFFFh ; size_t .text:0040130E lea ecx, [ebp+var_10004] .text:00401314 push 0 ; int .text:00401316 push ecx ; void * .text:00401317 mov esi, eax .text:00401319 call _memset .text:0040131E mov al, [ebp+var_20001] .text:00401324 mov dl, [ebp+var_20002] .text:0040132A mov cl, [ebp+var_20000] .text:00401330 mov [ebp+var_10003], al .text:00401336 lea eax, [ebp+var_10004] .text:0040133C mov [ebp+var_10004], dl .text:00401342 add esp, 14h .text:00401345 mov [ebp+var_10002], cl .text:0040134B lea edx, [eax+1] .text:0040134E mov edi, edi
看加粗加红处(下面是对应字符串的信息)
-00020004 String db ? -00020003 var_20003 db ? -00020002 var_20002 db ? -00020001 var_20001 db ? -00020000 var_20000 db ? -0001FFFF var_1FFFF db ? -0001FFFE var_1FFFE db ? -0001FFFD var_1FFFD db ?
我们可以知道,v6使用sub_4010F0函数后的字符串的6,7,8位,调用sub_401000函数,v7使用sub_4010F0函数后的字符串的3,4,5位,调用sub_401000函数。
加密方式
进入sub_401000
1 _BYTE *__cdecl sub_401000(int a1, int a2) 2 { 3 int v2; // eax 4 int v3; // esi 5 size_t v4; // ebx 6 _BYTE *v5; // eax 7 _BYTE *v6; // edi 8 int v7; // eax 9 _BYTE *v8; // ebx 10 int v9; // edi 11 signed int v10; // edx 12 int v11; // edi 13 signed int v12; // eax 14 signed int v13; // esi 15 _BYTE *result; // eax 16 _BYTE *v15; // [esp+Ch] [ebp-10h] 17 _BYTE *v16; // [esp+10h] [ebp-Ch] 18 int v17; // [esp+14h] [ebp-8h] 19 int v18; // [esp+18h] [ebp-4h] 20 21 v2 = a2 / 3; 22 v3 = 0; 23 if ( a2 % 3 > 0 ) 24 ++v2; 25 v4 = 4 * v2 + 1; 26 v5 = malloc(v4); 27 v6 = v5; 28 v15 = v5; 29 if ( !v5 ) 30 exit(0); 31 memset(v5, 0, v4); 32 v7 = a2; 33 v8 = v6; 34 v16 = v6; 35 if ( a2 > 0 ) 36 { 37 while ( 1 ) 38 { 39 v9 = 0; 40 v10 = 0; 41 v18 = 0; 42 do 43 { 44 if ( v3 >= v7 ) 45 break; 46 ++v10; 47 v9 = *(unsigned __int8 *)(v3++ + a1) | (v9 << 8); 48 } 49 while ( v10 < 3 ); 50 v11 = v9 << 8 * (3 - v10); 51 v12 = 0; 52 v17 = v3; 53 v13 = 18; 54 do 55 { 56 if ( v10 >= v12 ) 57 { 58 *((_BYTE *)&v18 + v12) = (v11 >> v13) & 0x3F; 59 v8 = v16; 60 } 61 else 62 { 63 *((_BYTE *)&v18 + v12) = 64; 64 } 65 *v8++ = byte_407830[*((char *)&v18 + v12)]; 66 v13 -= 6; 67 ++v12; 68 v16 = v8; 69 } 70 while ( v13 > -6 ); 71 v3 = v17; 72 if ( v17 >= a2 ) 73 break; 74 v7 = a2; 75 } 76 v6 = v15; 77 } 78 result = v6; 79 *v8 = 0; 80 return result; 81 }
进入第65行byte_407830
.rdata:00407830 ; char byte_407830[] .rdata:00407830 byte_407830 db 41h ; DATA XREF: sub_401000+C0↑r .rdata:00407831 aBcdefghijklmno db 'BCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',0
我们可以猜测这个函数应该是base64加密。
flag分析
if ( String == v9 + 34 // sub_4010F0函数后的第一位等于51+34=85-->'U' && v21 == v13 // 第2位,等于v13,即sub_4010F0函数返回值的第5位值-->'J' && 4 * v22 - 141 == 3 * v11 && v23 / 4 == 2 * (v16 / 9) && !strcmp(v6, "ak1w") // 第6,7,8行代码base64之后,需要等于"ak1w" && !strcmp( // 第3,4,5行代码,加密之后等于V1Ax v7, "V1Ax") ) { MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0); }
将v6,v7解密之后得到WP1jMp,再结合第1,2位得到flag
get flag!
flag{UJWP1jMp}