本题难点
1.这道题要给线程下断点,
2.而且还要跳过一个IsDebuggerPresent的反调试,
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
| int Main_func() { sub_41141A(); return sub_412A90(); }
int Key_func() { CreateThread(0, 0, (LPTHREAD_START_ROUTINE)StartAddress, 0, 0, 0); hHandle = (HANDLE)sub_41127B(); CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sub_411316, 0, 0, 0); }
__int64 __stdcall sub_411B80(int a1) { int v1; __int64 v2; char v4; size_t Size; char Buf2; int v7_32; char flag; int savedregs;
sub_41137F((int)&unk_41D0F4); WaitForSingleObject(hObject, 0xFFFFFFFF); Check_Run_Error(&v4 == &v4); Print_str((int)"please input your flag:", v4); Input_str("%32s", (unsigned int)&flag); v7_32 = j_strlen(&flag); Enc_str(16, (int)&flag, v7_32, (int)&Buf2); Size = 32; if ( !j_memcmp(&unk_41B018, &Buf2, 32u) ) Print_str((int)"you win!", v4); else Print_str((int)"you lose!", v4); SetEvent(hObject); Check_Run_Error(&v4 == &v4); HIDWORD(v2) = v1; LODWORD(v2) = 1; sub_411217((int)&savedregs, (int)&dword_411C7C); return v2; }
|
猜测memcmp比较的:unk_41B018是程序的密文,Buf2存储根据输入生成的密文。
跟入前面的处理函数,
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
| unsigned __int64 __cdecl sub_411DA0(int a1_16, int flag, int a3_32, int cipher) { size_t v4; __int64 v5; char v6; unsigned __int8 v7; unsigned __int64 v8; char v10[264]; int v11; int v12; int v13; int v14; int v15; int v16; int j; int i; unsigned int v19; char v20; char v21; char v22; char v23[21]; int savedregs;
sub_41137F((int)&unk_41D0F4); v11 = 1; v12 = 0x55; v13 = 0x1C39; v14 = 0x95EED; v15 = 0x31C84B1; v19 = 0; for ( i = 0; ; i += 4 ) { v4 = j_strlen(Dest); if ( v19 >= v4 ) break; v16 = 0; for ( j = 0; j < 5; ++j ) { if ( Dest[j + v19] == 0x7A ) *(&v20 + j + i) = 0; else v16 += *(&v11 + 4 - j) * (Dest[j + v19] - 33); } v23[i] = v16; *(&v22 + i) = BYTE1(v16); *(&v21 + i) = BYTE2(v16); *(&v20 + i) = HIBYTE(v16); v19 += 5; } v5 = sub_411127((int)&v20, a1_16, (int)v10); v19 = 0; i = 0; for ( j = 0; j < a3_32; ++j ) { v19 = (signed int)(v19 + 1) % 256; i = (i + (unsigned __int8)v10[v19]) % 256; v6 = v10[v19]; v10[v19] = v10[i]; v10[i] = v6; v7 = v10[((unsigned __int8)v10[i] + (unsigned __int8)v10[v19]) % 256]; HIDWORD(v5) = v7; *(_BYTE *)(j + cipher) = v7 ^ *(_BYTE *)(j + flag); } v8 = __PAIR__(HIDWORD(v5), j); Check_Stack((int)&savedregs, (int)&dword_411FF8); return v8; }
|
可以看到前面根据一系列操作,生成了v7,然后用v7和flag异或得到了正确的cipher。
所以动态调试,
1.先搜索字符串,下好断点,一个是输入位置,一个是比较位置。
考点1
多线程下好断点。
考点2
2.一开始直接jmp F12E10
。
3.进入到F12A90。
F9运行,断到了线程函数执行前。
按几下F9,成功断到了关键函数处。
此时的线程状态:
考点3
跟入F11037,在F12860的跳转处,强制让其不跳转。
断在输入位置0x411BDE位置,
先随便输入32个1,根据对比函数里的栈地址,找到密文unk_41B018,
1 2
| 00F1B018 DE 1C 22 27 1D AE AD 65 AD EF 6E 41 4C 34 75 F1 ?"'enAL4u? 00F1B028 16 50 50 D4 48 69 6D 93 36 1C 86 3B BB D0 4C 91 PP訦im??恍L?
|
整理如下:
1
| DE1C22271DAEAD65ADEF6E414C3475F1165050D448696D93361C863BBBD04C91
|
再次运行程序,先断到长度函数处。
修改这里的输入值,将前面的密文输入进去。
再断到加密函数位置处:
经过异或处理后,此时memcmp的Buf2里, 就是flag值。
flag
Run跟踪
- 跟踪一个call运行了哪些代码,有递归所有call和只对一层call的方法,操作方式分别是CTRL+F11和CTRL+F12。
给线程下断的另一种方式