10.1国庆宅在家里,没事干就调戏了扫雷。
这是在Windows 7下的32位扫雷程序,有空在看看64位。
首先理清逆向思路:
1.载入OD,下消息断点201 (后来发现此路不通....)
2.后来枚举所有函数,发现了Rand这个有趣的东东,然后OD中 bp rand
3.最后游戏结束的时候发现对话框,可以直接给 DialogBoxParamW下断
上面是我自己的开始的思路,当然有大神提供思路的,请留言,十分感谢。
第一步,当然是载入OD,bp rand

接着程序会断这里

之后OD会不停的断在这,我们在堆栈窗口找到上层CALL的调用地址,再搜索哪些地方调用了当前的CALL,每个调用的地方都F2
就会得出有8个地方调用了,把那个一直调用rand的断点的去掉,还有把bp rand那个断也去掉

去掉之后再点击格子,此时回到OD如当前图片的断点,去这个CALL的头部从上往下分析。

经过分析,得知当前CALL是一个"布雷函数"
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | mov edi``,``edi ;布雷函数 push ebp mov ebp``,``esp push ecx push ecx push ebx push esi push edi mov esi``,``ecx call MineSweeper.0034D816 ``;全局变量到EAX push dword ptr ds``:[``esi``+0x2C] ``;push 5BB9B276 == push eax mov dword ptr ss``:[``ebp``-0x08],``eax ;mov ecx, eax call MineSweeper.0034D821 ``;这个参数也就是eax 即为随机序列种子 push 0x00000010 call MineSweeper.0034DCA7 ``;申请4个DWORD大小的空间(malloc) pop ecx ;变相的平衡堆栈 ecx = eax = 0x5BB9B276 test eax``,``eax je MineSweeper.003400F1 push 0x00000010 ``;初始化函数第一个参数0x10 mov ecx``,``eax ;ecx = 01FD6948 即为第一次申请的空间首地址 call MineSweeper.0033F959 ``;上面四个参数初始化为:0x0 0x0 0x10 0x0 mov dword ptr ss``:[``ebp``-0x04],``eax ;ecx = eax 即为01FD6948 jmp MineSweeper.003400F5 and dword ptr ss``:[``ebp``-0x04],0x00000 mov eax``,``dword ptr ds``:[``esi``+0x08] ``;获取扫雷的行 rows imul eax``,``dword ptr ds``:[``esi``+0x0C] ``;获取扫雷的列 eax = rows * columns -> 9+9 = 0x51 xor edi``,``edi ;i=0 edi置零 test eax``,``eax jle MineSweeper.0034014B mov ecx``,``dword ptr ds``:[``esi``+0x0C] ``;ecx = columns.....[esi]=3DC248 mov eax``,``edi ;eax = i cdq ``idiv ecx ;此时ecx为columns i/dwColumn=eax行号....edx列号 xor ecx``,``ecx ;ecx置零 sub edx``,``dword ptr ss``:[``ebp``+0x08] ``;sub 0,0 鼠标点击的列号 sub eax``,``dword ptr ss``:[``ebp``+0x0C] ``;sub 0,0 鼠标点击的行号 test edx``,``edx ;列号!!! setnl cl ;根据列号是否正负,取绝对值 lea ecx``,``dword ptr ds``:[``ecx``+``ecx``-0x01] imul ecx``,``edx cmp ecx``,0x01 jnle MineSweeper.00340136 ``;第一个差值绝对值<=1,判断第二个差值 xor ecx``,``ecx ;ecx置零 test eax``,``eax ;行号!!! setnl cl ;根据行号是否正负,取绝对值 lea ecx``,``dword ptr ds``:[``ecx``+``ecx``-0x01] imul ecx``,``eax cmp ecx``,0x01 jle MineSweeper.0034013F ``;第二个差值绝对值>=1 mov ecx``,``dword ptr ss``:[``ebp``-0x04] push edi call MineSweeper.00355A51 mov eax``,``dword ptr ds``:[``esi``+0x08] ``;行数 imul eax``,``dword ptr ds``:[``esi``+0x0C] ``;列数 -> 行数 * 列数 = 0x51 inc edi ;i++ cmp edi``,``eax ;判断是否布满81个格子 jl MineSweeper.00340102 ``;没有布满就继续 push 0x00000010 call MineSweeper.0034DCA7 ``;第二次4个DWORD大小的申请空间 pop ecx ;变相平衡堆栈 ecx = 0x10 test eax``,``eax je MineSweeper.00340165 ``;可能是申请失败时的操作 push dword ptr ds``:[``esi``+0x04] ``;雷数入栈 mov ecx``,``eax ;ecx为第二次申请的首地址 call MineSweeper.0033F959 ``;第二次申请空间初始化 0x0,0x0,0xA,0x0 ``mov edi``,``eax ;edi 为第二次申请的首地址 jmp MineSweeper.00340196 ``;无条件跳 xor edi``,``edi jmp MineSweeper.00340196 mov eax``,``dword ptr ss``:[``ebp``-0x04] ``;eax = 第一次申请的首地址 mov eax``,``dword ptr ds``:[``eax``] ``;eax = 0x4D = 77 test eax``,``eax jbe MineSweeper.0034019D ``;判断雷是否布完了 dec eax push eax ;循环从0x4D 开始减一 入栈 push 0x00000000 call MineSweeper.0034D7F3 ``;rand函数 随机数是:0-0x4C之间 即0-76之间 mov ebx``,``eax ;ebx = 雷的随机数 mov eax``,``dword ptr ss``:[``ebp``-0x04] ``;第一个申请的首地址 mov eax``,``dword ptr ds``:[``eax``+0x0C] ``;eax = 0436F980 push dword ptr ds``:[``eax``+``ebx``*4] ``;找到随机布局中放雷的位置 mov ecx``,``edi ;ecx = 第二个申请的首地址 call MineSweeper.00355A51 ``;将数据保存到第二个申请空间里 mov ecx``,``dword ptr ss``:[``ebp``-0x04] ``;ecx第一个申请的首地址 push ebx call MineSweeper.0034EC9E mov eax``,``dword ptr ds``:[``edi``] ``;eax的值是存放布雷数 cmp eax``,``dword ptr ds``:[``esi``+0x04] ``;判断雷数 jne MineSweeper.00340169 ``;雷数=第二次申请空间的第一个属性值 xor ecx``,``ecx cmp dword ptr ds``:[``edi``],``ecx jbe MineSweeper.003401C4 mov eax``,``dword ptr ds``:[``edi``+0x0C] ``;获取存雷数组的地址 mov eax``,``dword ptr ds``:[``eax``+``ecx``*4] ``;取第i(ecx)个雷的位置数 mov ebx``,``dword ptr ds``:[``esi``+0x0C] ``;扫雷初始化数据中第四个属性是列数 cdq idiv ebx ;雷的位置数 / 列数 = 真实布雷的地址(EAX行号,EDX列号) mov ebx``,``dword ptr ds``:[``esi``+0x44] ``;[esi+0x44]地址表 mov ebx``,``dword ptr ds``:[``ebx``+0x0C] ``;[[esi+0x44]+0xc] 第二层地址表 inc ecx ;i++ mov edx``,``dword ptr ds``:[``ebx``+``edx``*4] mov edx``,``dword ptr ds``:[``edx``+0x0C] ``;根据雷所在列号取第edx(列号)个地址 mov byte ptr ds``:[``eax``+``edx``],0x01 ``;为雷时,填充0x1 cmp ecx``,``dword ptr ds``:[``edi``] ``;判断是否布完了 jc MineSweeper.003401A3 ``;布雷完毕 push 0x00000001 mov ecx``,``edi call MineSweeper.0033FC96 ``;free mov ecx``,``dword ptr ss``:[``ebp``-0x04] pop edi pop esi pop ebx test ecx``,``ecx je MineSweeper.003401DE push 0x00000001 call MineSweeper.0033FC96 ``;free push dword ptr ss``:[``ebp``-0x08] call MineSweeper.0034D821 leave retn 0x0008 |
这还没完,在堆栈窗口找到向上2层的CALL那个才是左键点击的CALL
|-------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | mov edi``,``edi ;左键单击函数 push ebp mov ebp``,``esp mov eax``,``dword ptr ds``:[MineSweeper.003A68B4] ``;这玩意就是基址 push ebx push esi mov esi``,``dword ptr ss``:[``ebp``+0x08] push edi mov byte ptr ds``:[``eax``+0x000000C5],0x01 push dword ptr ds``:[``esi``+0x1C] ``;这个是y 坐标 mov edi``,``ecx push dword ptr ds``:[``esi``+0x18] ``;这个是x 坐标 mov ecx``,``dword ptr ds``:[MineSweeper.003A68B4] ``;this 指针 xor bl``,``bl call MineSweeper.00341418 ``;判断单击的是不是雷,传X,Y坐标 test eax``,``eax ;比较返回值 jnle MineSweeper.00346FF1 mov dword ptr ds``:[``edi``+0x0000009C],``esi inc bl jmp MineSweeper.00346FF9 push eax mov ecx``,``edi call MineSweeper.00346BCD ``;后续CALL mov byte ptr ds``:[``edi``+0x000000AC],0x01 pop edi pop esi mov al``,``bl pop ebx pop ebp etn 0x0004 |
再分析一下这个CALL里面"主要"做了什么:call MineSweeper.00341418 --> 判断单击的是不是雷,传X,Y坐标
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 01 02 03 04 05 06 07 08 09 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 | mov edi``,``edi push ebp mov ebp``,``esp ecx``,``dword ptr ds``:[``ecx``+0x10] ``;this指针偏移+0x10(第5个属性地址) pop ebp jmp MineSweeper.00340C50 ``;无条件跳 mov edi``,``edi push ebp mov ebp``,``esp push ecx ;this->第5个属性地址 push ebx mov ebx``,``dword ptr ss``:[``ebp``+0x08] ``;x坐标 push esi ;[esi+0x1C] = 存放x,y坐标的地址 mov esi``,``ecx ;此时esi=ecx=this指针->第5个属性地址 mov eax``,``dword ptr ds``:[``esi``+0x40] ``;this->某个对象 mov eax``,``dword ptr ds``:[``eax``+0x0C] ``;某个对象->属性 mov eax``,``dword ptr ds``:[``eax``+``ebx``*4] ``;ebx = x坐标 mov eax``,``dword ptr ds``:[``eax``+0x0C] ``;这个eax指向的地址就是存储[color=#666]所有列状态的地址表[/color] push edi mov edi``,``dword ptr ss``:[``ebp``+0x0C] ``;y 坐标 mov eax``,``dword ptr ds``:[``eax``+``edi``*4] ``;edi = y坐标 xor ecx``,``ecx mov dword ptr ss``:[``ebp``-0x04],``ecx cmp eax``,0x09 ``;未点击 je MineSweeper.00340C95 cmp eax``,0x0B ``;问号 je MineSweeper.00340C95 mov eax``,``dword ptr ds``:[MineSweeper.003A68B4] cmp byte ptr ds``:[``eax``+0x18],``cl je MineSweeper.00340CE5 push ecx push ecx push ecx call MineSweeper.003505E9 xor ecx``,``ecx jmp MineSweeper.00340CE5 cmp dword ptr ds``:[``esi``+0x18],``ecx ;this->第七属性 jne MineSweeper.00340CBA ``;判断是否第一次鼠标点击 push edi push ebx mov ecx``,``esi call MineSweeper.003400BB ``;布雷CALL push 0x00000000 push edi push ebx push 0x00000000 push edi push ebx mov ecx``,``esi call MineSweeper.00340A42 mov dword ptr ds``:[``esi``+0x24],``ebx mov dword ptr ds``:[``esi``+0x28],``edi jmp MineSweeper.00340CDD mov eax``,``dword ptr ds``:[``esi``+0x44] mov eax``,``dword ptr ds``:[``eax``+0x0C] mov eax``,``dword ptr ds``:[``eax``+``ebx``*4] ``;这个ecx里面就是存储[color=#666]所有列有雷的地址表 [/color] mov eax``,``dword ptr ds``:[``eax``+0x0C] cmp byte ptr ds``:[``edi``+``eax``],``cl ;判断是否为雷 [edi+eax]->edi=行 eax=地址偏移 cl=0(cl值不变) je MineSweeper.00340CD0 ``;不为雷跳转 |
最后分析得出:
真实基址 = 扫雷起始地址 + 0x868B4(RVA)
格子数据 = [[[[[[[真实基址] + 0x10] + 0x40] + 0x0C] + 4 * X坐标] + 0x0C]+ 4 * Y坐标]
取值范围:1~8数字 9未开 10旗 11问号 12空
雷数据 = [[[[[[[真实基址] + 0x10] + 0x44] + 0x0C] + 4 * X坐标] + 0x0C] + Y坐标]
esi = [[真实基址] + 0x10]
esi + 0x04\] = 雷数 \[esi + 0x08\] = 行数 \[esi + 0x0C\] = 列数 \[esi + 0x18\] = 鼠标左键单机次数 第一次单机时: 列号:\[esi + 0x24
行号:[esi + 0x28]
这就是鼠标左键CALL分析了,至于右键CALL提供思路:在第一块数据方格中下硬件写入断点
然后回溯跟踪 直到返回2次后,就是我们要找的CALL
OK...............................分析到这就结束了。
具体实现核心代码:
cpp
DWORD CheckMineSweeperRun(HANDLE* hProcess, DWORD* dwMineBaseAddr)
{
DWORD dwPid;
HWND hWnd = FindWindow(NULL, L"扫雷");
if (!hWnd)
{
MessageBox(NULL, L"扫雷未运行!", L"提示", 0);
return 0;
}
// 获取进程PID
GetWindowThreadProcessId(hWnd, &dwPid);
HMODULE hMine = GetProcessBase(L"MineSweeper.exe", dwPid);
if (NULL == hMine)
{
MessageBox(NULL, L"无法找到模块MineSweeper!", L"提示", 0);
return 0;
}
// 模块句柄就是基址
*dwMineBaseAddr = (DWORD)hMine;
*hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (!hProcess)
{
MessageBox(NULL, L"打开扫雷进程失败!", L"提示", 0);
return 0;
}
return 1;
}
VOID ClickMouseLeft(DWORD dwMineBaseAddr, DWORD row, DWORD column, DWORD secondskill)
{
// 后续CALL
DWORD vaCallLeft1 = dwMineBaseAddr + 0x26bcd;
// 检查CALL 判断左键是否为雷 第一次点击布雷
DWORD vaCallLeft0 = dwMineBaseAddr + 0x21418;
__asm
{
push eax
push ecx
push ebx
mov eax, dwMineBaseAddr
mov eax, [eax + 0x868b4]
mov[eax + 0xC5], 1
mov ecx, eax
// 传过来的secondskill不为0时,即暴力秒杀
cmp secondskill, 0x0
je keepOn
// START 关键代码
push esi
xor esi, esi
mov eax, [eax + 0x10]
mov [eax + 0x04], esi
pop esi
// END 关键代码
keepOn :
push row
push column
xor bl, bl
mov eax, vaCallLeft0
call eax
test eax, eax
jg sHome
jmp endHome
sHome :
push eax
mov eax, vaCallLeft1
call eax
endHome :
pop ebx
pop ecx
pop eax
}
}
int main()
{
HookGameProc HookProc = 0;
HMODULE hDll = LoadLibrary(L"MineSweeperDll.dll");
if (hDll)
{
HookProc = (HookGameProc)GetProcAddress(hDll, "HookMine");
if (!HookProc)
{
MessageBox(NULL, L"加载注入函数失败!", L"Error", MB_OK);
return 0;
}
}
else
{
MessageBox(NULL, L"加载Dll失败!", L"Error", MB_OK);
return 0;
}
HHOOK hkGame = HookProc();
if (hkGame)
MessageBox(NULL, L"安装FZ成功!", L"Success", MB_OK);
else
printf("安装FZ失败!");
return 0;
}
附上超级难度下秒杀图:

下载完成后把后缀名改一下,另外我用的是VS2015写的。