今晚一口气看完了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;
}