BUUCTF
刮开有奖
这是一道相对复杂的题,打开题目看到WinMain函数
查看DiaogFunc函数,里面是程序的加密过程,需要仔细分析
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
| INT_PTR __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4) { const char *v4; const char *v5; int v7[2]; int v8; int v9; int v10; int v11; int v12; int v13; int v14; int v15; int v16; CHAR String[65536]; char v18[65536];
if ( a2 == 272 ) return 1; if ( a2 != 273 ) return 0; if ( (_WORD)a3 == 1001 ) { memset(String, 0, 0xFFFFu); GetDlgItemTextA(hDlg, 1000, String, 0xFFFF); if ( strlen(String) == 8 ) { v7[0] = 90; v7[1] = 74; v8 = 83; v9 = 69; v10 = 67; v11 = 97; v12 = 78; v13 = 72; v14 = 51; v15 = 110; v16 = 103; sub_4010F0(v7, 0, 10); memset(v18, 0, 0xFFFFu); v18[0] = String[5]; v18[2] = String[7]; v18[1] = String[6]; v4 = (const char *)sub_401000(v18, strlen(v18)); memset(v18, 0, 0xFFFFu); v18[1] = String[3]; v18[0] = String[2]; v18[2] = String[4]; v5 = (const char *)sub_401000(v18, strlen(v18)); if ( String[0] == v7[0] + 34 && String[1] == v10 && 4 * String[2] - 141 == 3 * v8 && String[3] / 4 == 2 * (v13 / 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; }
|
经过分析我们先要理清思路
- flag为8位
- 算出经过sub_4010F0函数处理后的v7字符串是多少
- 将v4和v5逆运算得出结果,即可知道flag后六位是多少
- 将flag前两位组合及获得最后flag
先从简单的入手,直接看sub_401000函数
查看这个byte_407830里有啥
很明显是一个base64的加密,直接对v4,v5进行解密
v4 = ‘jMp’ v5 = ‘WP1’
重新排序string[2,3,4,5,6] = ‘WP1jMp’
接着分析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; }
|
emmmm,直接换成C语言跑一遍。将所有的*(_DWORD *)删去,并把汇编代码的基本地址+偏移都改成寻址(具体也是在网上看的师傅们的wp,TAT还是太菜)还是决定自己尝试分析下,代码如下
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
| #include <stdio.h> #include <string.h>
int 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; }
int main(void) { char str[]="ZJSECaNH3ng"; sub_4010F0(str,0,10); printf("%s",str); return 0; }
|
得到结果v7[ ] = ‘3CEHJNSZagn’
String[0] == v7[0] + 34 第一位就是51+34=85 ‘U’
String[1] == v10 ( v7[4] ) ‘J’
最后flag{UJWP1jMp}
Day4 - 多段加密要分开分析,常用函数敏感性,要有耐心TAT