[BUUCTF-刮开有奖] 1. 丢进exeinfo查看信息,没加壳,需要用ida32位。
2. 发现是winmain函数,也许是因为这是个窗口程序。
属实有点懵。那就再跟进这个函数DialogFunc
。
3. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 BOOL __stdcall DialogFunc (HWND hDlg, UINT a2, WPARAM a3, LPARAM a4) { const char *v4; const char *v5; int v7; int v8; int v9; int v10; int v11; int v12; int v13; int v14; int v15; int v16; int v17; CHAR String; char v19; char v20; char v21; char v22; char v23; char v24; char v25; char v26; char v27; char v28; if ( a2 == 272 ) return 1 ; if ( a2 != 273 ) return 0 ; if ( (_WORD)a3 == 1001 ) { memset (&String, 0 , 0xFFFF u); GetDlgItemTextA(hDlg, 1000 , &String, 0xFFFF ); if ( strlen (&String) == 8 ) { v7 = 'Z' ; v8 = 'J' ; v9 = 'S' ; v10 = 'E' ; v11 = 'C' ; v12 = 'a' ; v13 = 'N' ; v14 = 'H' ; v15 = '3' ; v16 = 'n' ; v17 = 'g' ; sub_4010F0(&v7, 0 , 10 ); memset (&v26, 0 , 0xFFFF u); v26 = v23; v28 = v25; v27 = v24; v4 = (const char *)sub_401000(&v26, strlen (&v26)); memset (&v26, 0 , 0xFFFF u); v27 = v21; v26 = v20; v28 = v22; v5 = (const char *)sub_401000(&v26, strlen (&v26)); if ( String == v7 + 34 && v19 == v11 && 4 * v20 - 141 == 3 * v9 && v21 / 4 == 2 * (v14 / 9 ) && !strcmp (v4, "ak1w" ) && !strcmp (v5, "V1Ax" ) ) { MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0 ); } } return 0 ; } if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 ) return 0 ; EndDialog(hDlg, (unsigned __int16)a3); return 1 ; }
一个重要问题就是,sub_4010F0
这个函数做了什么事情。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 int __cdecl sub_4010F0 (int a1, int a2, int a3) { int result; int i; int v5; int v6; result = a3; for ( i = a2; i <= a3; a2 = i ) { v5 = 4 * i; v6 = *(_DWORD *)(4 * i + a1); if ( a2 < result && i < result ) { do { if ( v6 > *(_DWORD *)(a1 + 4 * result) ) { if ( i >= result ) break ; ++i; *(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result); if ( i >= result ) break ; while ( *(_DWORD *)(a1 + 4 * i) <= v6 ) { if ( ++i >= result ) goto LABEL_13; } if ( i >= result ) break ; v5 = 4 * i; *(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1); } --result; } while ( i < result ); } LABEL_13: *(_DWORD *)(a1 + 4 * result) = v6; sub_4010F0(a1, a2, i - 1 ); result = a3; ++i; } return result; }
实际上我们并不需要分析这个代码,因为我们只要它的结果。
所以将他稍微修改为C语言,跑一遍就明白了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #include <iostream> #include <stdlib.h> #include <stdio.h> using namespace std ;int __cdecl sub_4010F0 (char *a1, int a2, int a3) { int result; int i; int v5; int v6; 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 ; }
得出结果 其实就是按acsii码升序(大致能理解代码,但写不出来,果然还是得先再学习一遍C语言啊)
而后还有sub_401000
函数
跟进会发现其中的byte_407830
是这样的
那么大概率就是base64加密
于是把结果”ak1w”,”V1Ax”拿去base64解密便可得出v4,v5。
v4,v5解密后为”jMp”,”PW1”
首先v9组清零,v9被string组赋值。v4是v9经过base64加密赋值的,v9组清零后对v5进行同样的操作。
所以他们base64解密后,就是对应v9组的值。
然后通过v9位的值,我们能知道对应string位的值。
我的IDA识别不出这些组,其他人的wp明明都能识别出来的,怪事。也许是大佬后期加的?
整理下便是,v7组是v7v17,v9组是v26v28,string组是v18~v25.
结合我上面的注释,得出
string = “UJWP1jMp” 即flag值。搞定!
思考:
(借此机会懂了蛮多伪代码,到看书的时候再整理写一篇)
(突然发现,看不懂伪代码的一大原因是我不知道许多函数。)