今晚一口气看完了M的BLOG,鸭梨山大啊,看来我还要好好努力。。先转一篇
一大早起来我家的小猫又出问题了。。哎这也用了好多年了。。现在觉得三天两头给我坏一次。。Link灯一直不亮。。打电话给电信局的。人家说他在休假不管这事。。这尼玛坑爹的。大过年的让我上不了网啊。。看会书。。但是上不了网查资料也查不了。。。老爸也很郁闷。。上不了网他就打不了斗地主了。。在卧室里一个人玩蜘蛛纸牌呢。但是技术不够。。让我过去帮他一起看。。正好来分析一下。。帮老爸做个外挂。。。
OD加载之。对RegisterClass下断,一共中断四次后程序就运行了。。看参数WNDCLASS的lpfnWndProc字段。。只有一次在当前模块内。。。看栈里的数据
0006FB08 010071DD /CALL 到 RegisterClassW 来自 spider.010071D7 0006FB0C 0006FB1C \pWndClass = 0006FB1C
这里0006FB1C就是WNDCLASS结构。lpfnWndProc位于第二个四字。
0006FB1C 00002003 0006FB20 010070AB spider.010070AB
可以确定这里就是主窗体过程了。。。。
在游戏刚开始的时候会弹出一个对话框让你选择难度。这里再对DialogBoxParam下断。中断后栈里的数据如下
0006F744 0100671E /CALL 到 DialogBoxParamW 来自 spider.01006718 0006F748 01000000 |hInst = 01000000 0006F74C 00000077 |pTemplate = 77 0006F750 000704E6 |hOwner = 000704E6 ('蜘蛛',class='蜘蛛') 0006F754 01007B06 |DlgProc = spider.01007B06 0006F758 01012008 \lParam = spider.01012008
很显然对话框窗体过程为01007B06。在这里对WM_COMMAND消息下断。按“确定”。看代码
01007B39 |> \56 push esi ; Case 1 of switch 01007B1C 01007B3A |. 8B35 68120001 mov esi, dword ptr [<&USER32.IsDlgButtonChecked>] ; USER32.IsDlgButtonChecked 01007B40 |. 68 F0030000 push 3F0 ; /ButtonID = 3F0 (1008.) 01007B45 |. FF75 08 push dword ptr [ebp+8] ; |hWnd 01007B48 |. FFD6 call esi ; \IsDlgButtonChecked 01007B4A |. 85C0 test eax, eax 01007B4C |. 74 10 je short 01007B5E 01007B4E |. A1 44300101 mov eax, dword ptr [1013044] 01007B53 |. 8B40 04 mov eax, dword ptr [eax+4] 01007B56 |. C700 01000000 mov dword ptr [eax], 1 01007B5C |. EB 24 jmp short 01007B82 01007B5E |> 68 F1030000 push 3F1 01007B63 |. FF75 08 push dword ptr [ebp+8] 01007B66 |. FFD6 call esi 01007B68 |. 85C0 test eax, eax 01007B6A |. A1 44300101 mov eax, dword ptr [1013044] 01007B6F |. 8B40 04 mov eax, dword ptr [eax+4] 01007B72 |. 74 08 je short 01007B7C 01007B74 |. C700 02000000 mov dword ptr [eax], 2 01007B7A |. EB 06 jmp short 01007B82 01007B7C |> C700 04000000 mov dword ptr [eax], 4 01007B82 |> 6A 01 push 1 ; /Result = 1 01007B84 |. FF75 08 push dword ptr [ebp+8] ; |hWnd 01007B87 |. FF15 98110001 call dword ptr [<&USER32.EndDialog>] ; \EndDialog
这里调用IsDlgButtonChecked函数来获取单选按钮的选择情况来设置游戏难度。注意这几句
01007B4E |. A1 44300101 mov eax, dword ptr [1013044] 01007B53 |. 8B40 04 mov eax, dword ptr [eax+4] 01007B56 |. C700 01000000 mov dword ptr [eax], 1 。。。 01007B74 |. C700 02000000 mov dword ptr [eax], 2 。。。 01007B7C |> C700 04000000 mov dword ptr [eax], 4
把结果储存在[[[1013044] + 4]]中。1为初级。2中级。4高级。。。。这里储存的地址为004C0728。。对这里设置硬件访问断点。。。中断在了这里
01007502 |> \8338 01 |||cmp dword ptr [eax], 1
看这附近的代码
.text:0100746E sub_100746E proc near ; CODE XREF: sub_100454D+BCp .text:0100746E ; sub_1005AFB+2Ap .text:0100746E .text:0100746E Buffer_length = dword ptr -0Ch .text:0100746E buffer = dword ptr -8 .text:0100746E var_4 = dword ptr -4 .text:0100746E random = dword ptr 8 .text:0100746E .text:0100746E mov edi, edi .text:01007470 push ebp .text:01007471 mov ebp, esp .text:01007473 sub esp, 0Ch .text:01007476 push esi .text:01007477 mov esi, ecx .text:01007479 push edi .text:0100747A mov edi, [esi+8] .text:0100747D mov eax, edi .text:0100747F shl eax, 2 .text:01007482 push eax ; wint_t .text:01007483 mov [ebp+Buffer_length], edi .text:01007486 call AllocateHeap ; 申请缓冲区 .text:0100748B test eax, eax .text:0100748D pop ecx .text:0100748E mov [ebp+buffer], eax .text:01007491 jz loc_100753A .text:01007497 push [ebp+random] .text:0100749A call InitRandom ; 初始化随机数种子。把随机数写到10110A0中 .text:0100749F test edi, edi .text:010074A1 pop ecx .text:010074A2 jle short loc_10074AD .text:010074A4 mov ecx, edi ; 取缓冲区长度1A0 .text:010074A6 mov edi, [ebp+buffer] ; 取缓冲区地址 .text:010074A9 xor eax, eax ; eax清零 .text:010074AB rep stosd ; 这里初始化缓冲区 .text:010074AD .text:010074AD loc_10074AD: ; CODE XREF: sub_100746E+34j .text:010074AD and [ebp+var_4], 0 .text:010074B1 cmp dword ptr [esi+4], 0 .text:010074B5 jle short loc_100752D .text:010074B7 .text:010074B7 loc_10074B7: ; CODE XREF: sub_100746E+BDj .text:010074B7 xor edi, edi .text:010074B9 .text:010074B9 loc_10074B9: ; CODE XREF: sub_100746E+B2j .text:010074B9 and [ebp+random], 0 .text:010074BD .text:010074BD loc_10074BD: ; CODE XREF: sub_100746E+61j .text:010074BD ; sub_100746E+ACj .text:010074BD call _rand .text:010074C2 cdq .text:010074C3 idiv [ebp+Buffer_length] ; rand() % 68 .text:010074C6 mov eax, [ebp+buffer] ; 取缓冲区 .text:010074C9 lea eax, [eax+edx*4] ; 使用随机数得到一个随机地址 .text:010074CC cmp dword ptr [eax], 0 ; 该处为零? .text:010074CF jnz short loc_10074BD ; 为零则说明该位已经设置过。不为零则重新生成一个随机数 .text:010074D1 mov dword ptr [eax], 1 ; 置1说明该位已经设置过 .text:010074D7 mov ecx, [esi+0Ch] ; 取储存棋盘的缓冲区 .text:010074DA lea eax, [edx+edx*2] .text:010074DD lea eax, [ecx+eax*4] ; 这两句为ecx+edx*0C .text:010074DD ; 每一张牌由3个dword组成,第一个dword为花色,第二个为大小,第三个为是不翻开的状态 .text:010074E0 mov [eax], edi ; edi为花色。这里设置花色 .text:010074E2 mov ecx, [esi] ; 获取当前级别 .text:010074E4 cmp ecx, 1 ; 初级? .text:010074E7 jnz short loc_10074F1 .text:010074E9 mov dword ptr [eax], 3 ; 初级则花色都为3。即黑桃 .text:010074EF jmp short loc_1007509 .text:010074F1 ; --------------------------------------------------------------------------- .text:010074F1 .text:010074F1 loc_10074F1: ; CODE XREF: sub_100746E+79j .text:010074F1 push 2 .text:010074F3 pop edx .text:010074F4 cmp ecx, edx .text:010074F6 jnz short loc_1007509 .text:010074F8 test edi, edi .text:010074FA jnz short loc_1007502 .text:010074FC mov dword ptr [eax], 3 .text:01007502 .text:01007502 loc_1007502: ; CODE XREF: sub_100746E+8Cj .text:01007502 cmp dword ptr [eax], 1 .text:01007505 jnz short loc_1007509 .text:01007507 mov [eax], edx .text:01007509 .text:01007509 loc_1007509: ; CODE XREF: sub_100746E+81j .text:01007509 ; sub_100746E+88j ... .text:01007509 mov ecx, [ebp+random] .text:0100750C and dword ptr [eax+8], 0 .text:01007510 inc [ebp+random] ; 大小加1,0到C代表A到K .text:01007513 cmp [ebp+random], 0Ch ; 和K比较,大于K的时候推出该循环 .text:01007517 mov [eax+4], ecx .text:0100751A jle short loc_10074BD .text:0100751C inc edi ; 下一种花色 .text:0100751D cmp edi, 3 ; 0到3。四种花色 .text:01007520 jle short loc_10074B9 .text:01007522 inc [ebp+var_4] .text:01007525 mov eax, [ebp+var_4] .text:01007528 cmp eax, [esi+4] .text:0100752B jl short loc_10074B7 .text:0100752D .text:0100752D loc_100752D: ; CODE XREF: sub_100746E+47j .text:0100752D push [ebp+buffer] .text:01007530 call FreeHeap .text:01007535 and dword ptr [esi+10h], 0 .text:01007539 pop ecx .text:0100753A .text:0100753A loc_100753A: ; CODE XREF: sub_100746E+23j .text:0100753A pop edi .text:0100753B pop esi .text:0100753C leave .text:0100753D retn 4 .text:0100753D sub_100746E endp
这里的代码用来布局棋盘。这里这个过程有一个参数。即ebp+8。这个参数是通过调用GetSystemTimeAsFileTime函数获得的一个随机数。。。这里通过这个获取到的时间来布局棋盘。。。其它代码按注释也是很好理解的。。。逆过来如下
struct pai { int huase; int daxiao; BOOL fankai; }; .......... pai Buffer[0x68]; p = AllocateHeap(10xA0); ZeroMemory(p, 0x1A0); for (int j = 0;j <= 3;j++) { for (int i = 0;i <= 0x0C;i++) { int r; do { r = rand() % l; } while (Buffer[r].huase != 0); Buffer[r].huase = j; if (dengji == 1) { Buffer[r].huase = 3; } if (dengji == 2) { if ((j != 0)&&(j != 1)) { Buffer[r].huase = 0; } else { Buffer[r].huase = 3; } } Buffer[r].daxiao = i; Buffer[r].fankai = FALSE; } }
这样只要读出这里的数据就可以知道对应的地方是什么牌了。。。也可以把这里的翻开状态都改为1.。。这样所有的牌就都处于可见状态了
时间紧。。随便写几句代码演示一下效果好了。
#include <Windows.h> int _tmain(int argc, _TCHAR* argv[]) { HWND hwnd = FindWindow(NULL, TEXT("蜘蛛")); DWORD pid; GetWindowThreadProcessId(hwnd, &pid); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); DWORD p; ReadProcessMemory(hProcess, (LPCVOID)0x01013044, &p, sizeof(p), NULL); ReadProcessMemory(hProcess, (LPCVOID)(p + 4), &p, sizeof(p), NULL); ReadProcessMemory(hProcess, (LPCVOID)(p + 0x0C), &p, sizeof(p), NULL); //取缓冲区地址 for (int i = 0;i < 44;i++) { int x = 1; WriteProcessMemory(hProcess, (LPVOID)(p + i * 0x0C + 8), &x, sizeof(x), NULL); //讲翻开状态置TRUE ReadProcessMemory(hProcess, (LPCVOID)(p + i * 0x0C), &x, sizeof(x), NULL); //取花色 switch (x) { case 0: printf("梅"); break; case 1: printf("方"); break; case 2: printf("红"); break; case 3: printf("黑"); } ReadProcessMemory(hProcess, (LPCVOID)(p + i * 0x0C + 4), &x, sizeof(x), NULL); if (x == 0) { printf("A"); } else if (x == 0x0A) { printf("J"); } else if (x == 0x0B) { printf("Q"); } else if (x == 0x0C) { printf("K"); } else { printf("%d", x + 1); } printf("\t"); if ((i + 1) % 10 == 0) { printf("\n"); } } return 0; }