关于扫雷,大概老司机们都有影响,都曾今玩过把。
早年时候虫虫就曾玩过,当时用的不知道怎么玩,都一个一个点出来慢慢玩,所以基本上没怎么赢过,当时借用北大化学实验室做课题,偷偷用一台高级设备带的数据处理电脑玩,被大老板发现了,痛批了一顿(影响深刻)。当时都不知道这款游戏的工作原理,直到最近发现了这个方向,其游戏数据老司机都或多或少通过工具做过,比如金山游侠给仙剑偷道具,用变速齿轮减速然后过关,但是具体底层自己写程序可能没做过,所以小编就找来这个主题和大家一起学习下。。
在Windows XP中,你可以从%systemroot%\system32\winmine.exe中找到扫雷游戏的二进制执行文件。如果你没有Windows XP,也没关系,你可以从网上下载下载地址为(http://www.minesweeper.info/downloads/WinmineXP.html)。下载后再win10下也是可以玩的,小编就是下载的这个版本在win10下玩了一把截的图。
静态分析
首先,让我们看看二进制文件是否启用ASLR。DLL特征的值为0x8000,即’IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE’。
确认这个PE未经ASLR保护编译的。如果你熟悉是精于此道的老司机,可以轻松地对地址进行硬编码。
通过查看IAT,我们可以通过查看从’gdi32.dll’导入的函数来确定程序使用了Microsoft Windows图形设备接口(GDI)。显而易见的,因为这是一个游戏,我们还可以从’advapi32.dll’中看到使用的注册表API,这意味着我们可以通过注册表篡改应用程序。
篡改分数
扫雷分数存储在注册表中,并从注册表读取值。如果你检查所有导入并找到对’RegQueryValueExW’API的引用并找到一个中断点,则可以找到注册表的位置。另一个简单的方法是使用沟子API。
点击断点后,你可以看到堆栈中的参数,在注册表中的位置为:
HKEY_CURRENT_USER\software\Microsoft\winmine
在此可以修改名称,分数,还有颜色,难度,高度,宽度等其他选项。“Name1”的值与十六进制中的“Time1”的分数值相对应。
破解扫雷区域
在’BeginPaint’ API中点击断点
进入该函数
01001C4C |. E8 720E0000 CALL Winmine_.01002AC3
同样的步骤进入函数
01002AE6 |. 56 PUSH ESI ; /Arg1
01002AE7 |. E8 BBFBFFFF CALL Winmine_.010026A7 ;\Winmine_.010026A7
你会看到’BitBlt’ api被用来逐个绘制雷区块。
如果我们检查寄存器,EBX包含地址字段0x010056360,ESI寄存器用于递增字节。
如果我们导出EBX寄存器,我们可以从0x01005340确定起始点。
它向EBX添加0x20,我们可以确定每个字段的结尾。
0100271D |. 83C3 20 |ADDEBX,20Coding实现
首先,要打开游戏的进程,我们用FindWindow获取窗口的句柄,然后将它传递给’GetWindowThreadProcessId’,一旦我们获得’dwProcessId’,我们就可以将该值传递给’OpenProcess’ API。也可以使用使用’CreateToolhelp32Snapshot’技术。
HWNDwindow = FindWindow(NULL, L”Minesweeper”);
if (window== NULL)
return wprintf(L”[-] Failed to find Minesweeper process”);
GetWindowThreadProcessId(window,&dwProcessId);
HANDLEprocess = OpenProcess(PROCESS_VM_READ, FALSE, dwProcessId);
接下来,我们将分配一个缓冲来存储我们的雷区的数据。
LPBYTEbuffer = (LPBYTE)malloc(size);
if(buffer == NULL)
return wprintf(L”[-] Failed to allocated memory”);
最后,写一个无限循环来,用’ReadProcessMemory’ API从内存的起始地址读取内存,这样每次我们单击一个字段时,字段就会被更新。我们可以使用0x20作为字段中每行的结尾。
while (true) {
BOOL ret = ReadProcessMemory(process, (LPVOID)start,buffer, size,&dwRead);
if (ret == NULL) return wprintf(L”[-] Failed toread memory”);
for (size_t i = 0, j = 0; i < size; i++, j++) {
if (j == 0x20) {
puts(“”);
j = 0;
}
printf(“%c”, buffer[i]);
}
Sleep(1500);
system(“cls”);
}
我们只是使用’ReadProcessMemory’ API从内存中导出雷区数据。
最后完整的源代码:
#include “stdafx.h”
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#define start 0x1005340
#define end 0x10056A0
int _tmain(int argc, _TCHAR* argv[]) {
DWORD dwProcessId = 0;
DWORD dwRead = 0;
HWND window = FindWindow(NULL, L”Minesweeper”);
if (window == NULL)
return wprintf(L”[-] Failed to find Minesweeper process”);
GetWindowThreadProcessId(window, &dwProcessId);
HANDLE process = OpenProcess(PROCESS_VM_READ, FALSE, dwProcessId);
DWORD size = end – start;
LPBYTE buffer = (LPBYTE)malloc(size);
if (buffer == NULL)
return wprintf(L”[-] Failed to allocated memory”);
while (true) {
wprintf(L”[+] Minesweeper hack\n”);
BOOL ret = ReadProcessMemory(process, (LPVOID)start, buffer, size,
&dwRead);
if (ret == NULL) return wprintf(L”[-] Failed to read memory”);
BYTE field = NULL;
for (size_t i = 0, j = 0; i < size; i++, j++) {
if (j == 0x20) {
puts(“”);
j = 0;
}
printf(“%c”, buffer[i]);
}
Sleep(1500);
system(“cls”);
}
return 0;
}
来源:freebuf.com 2018-04-13 09:21:04 by: ijzmesec
请登录后发表评论
注册