测试文件:https://static2.ichunqiu.com/icq/resources/fileupload/CTF/BSRC/BSRC-11-3/CrackMe01_97D2BF0DBD2EC13065E7104F24CAAED9.zip
1.准备
获取信息
- 32位文件
2.IDA打开
熟悉Windows API的话,一般组成的就是MessageBox,ShowWindow...这里测试错误答案时,没有窗口提示,也就排除了MessageBox,而且要处理消息事件的话,直接查找默认消息处理DefWindowProc。
在import里面搜索DefWindowProc
点击进入之后,Ctrl+X查找用到的地方
一个一个进入,F5分析就行。(实际上就是第一个)
找到这么一段代码
1 LRESULT __stdcall sub_4027F0(int a1, UINT Msg, WPARAM wParam, LPARAM lParam) 2 { 3 UINT v4; // eax 4 LPARAM v5; // edx 5 __int16 v6; // bx 6 void *v7; // edi 7 HDC v9; // esi 8 unsigned int v10; // ecx 9 __int16 v11; // ax 10 unsigned int v12; // eax 11 int v13; // edi 12 int v14; // eax 13 struct tagRECT v15; // [esp+18h] [ebp-68h] 14 struct tagRECT Rect; // [esp+28h] [ebp-58h] 15 struct tagPAINTSTRUCT Paint; // [esp+38h] [ebp-48h] 16 17 v4 = Msg; 18 v5 = lParam; 19 v6 = 0; 20 v7 = (void *)wParam; 21 if ( Msg > 0xF ) 22 { 23 if ( Msg != 4097 ) 24 return DefWindowProcW((HWND)a1, v4, (WPARAM)v7, v5); 25 v10 = 0; 26 do 27 { 28 v11 = *(_WORD *)(wParam + 2 * v10++); 29 v6 += v11; 30 } 31 while ( v10 <= lParam ); 32 v12 = 0; 33 do 34 { 35 *(const WCHAR *)((char *)&chText + v12) ^= v6; 36 v12 += 2; 37 } 38 while ( v12 < 0x2C ); 39 GetWindowRect((HWND)a1, &v15); 40 v13 = (v15.left - v15.right + GetSystemMetrics(16)) / 2; 41 v14 = GetSystemMetrics(17); 42 SetWindowPos((HWND)a1, HWND_MESSAGE|0x2, v13, (v15.top - v15.bottom + v14) / 2, -1, -1, 5u); 43 SetWindowPos((HWND)a1, (HWND)0xFFFFFFFE, 0, 0, 0, 0, 3u); 44 if ( (v6 & 0xF00) == 0x400 && (v6 & 0xF0) == 0xB0u && (v6 & 6) == 6 ) 45 { 46 ShowWindow((HWND)a1, 5); 47 UpdateWindow((HWND)a1); 48 } 49 v7 = (void *)wParam; 50 LABEL_18: 51 if ( v7 ) 52 free(v7); 53 v5 = lParam; 54 v4 = Msg; 55 return DefWindowProcW((HWND)a1, v4, (WPARAM)v7, v5); 56 } 57 switch ( Msg ) 58 { 59 case 0xFu: 60 v9 = BeginPaint((HWND)a1, &Paint); 61 GetClientRect((HWND)a1, &Rect); 62 DrawTextW(v9, &chText, -1, &Rect, 0x25u); 63 EndPaint((HWND)a1, &Paint); 64 goto LABEL_18; 65 case 1u: 66 return 0; 67 case 2u: 68 PostQuitMessage(0); 69 return 0; 70 } 71 return DefWindowProcW((HWND)a1, v4, (WPARAM)v7, v5); 72 }
3.代码分析
去除掉代码中对窗口消息,创建,我们需要的代码就是
do { *(const WCHAR *)((char *)&chText + v12) ^= v6; v12 += 2; } while ( v12 < 0x2C );
这里实际上就是对chText的前0x2c个进行了异或处理,代码中两个字节为一组,总共22组。
chText
F0 04 DA 04 D7 04 D1 04 8C 04 FF 04 F5 04 FE 04 E3 04 F8 04 E7 04 FF 04 E3 04 E9 04 F0 04 F3 04 85 04 80 04 84 04 F2 04 F4 04 F3 04
因此chText为
chText[]={0x4F0, 0x4DA, 0x4D7, 0x4D1, 0x48C, 0x4FF, 0x4F5, 0x4FE, 0x4E3, 0x4F8, 0x4E7, 0x4FF, 0x4E3, 0x4E9, 0x4F0, 0x4F3, 0x485, 0x480, 0x484, 0x4F2, 0x4F4, 0x4F3}
v6的值我们可以通过第44行代码
if ( (v6 & 0xF00) == 0x400 && (v6 & 0xF0) == 0xB0u && (v6 & 6) == 6 ) { ShowWindow((HWND)a1, 5); UpdateWindow((HWND)a1); }
得到v6=0x4b6
4.脚本获取
chText = [0x4F0, 0x4DA, 0x4D7, 0x4D1, 0x48C, 0x4FF, 0x4F5, 0x4FE, 0x4E3, 0x4F8, 0x4E7, 0x4FF, 0x4E3, 0x4E9, 0x4F0, 0x4F3, 0x485, 0x480, 0x484, 0x4F2, 0x4F4, 0x4F3] flag = '' for i in range(22): chText[i] ^= 0x4b6 flag += chr(chText[i]) print(flag)
5.get flag!
Flag:ICHUNQIU_FE362DBE