逆向实战 | win7扫雷逆向&辅助实现
win7扫雷逆向&辅助实现
做这个事情是因为软件工程上机课太无聊了,就开始玩扫雷,但是觉得原版界面有点太丑了,就想自己改一改。
参考的资料还挺多的,这个讲xp扫雷的讲的比较好(https://www.cnblogs.com/iBinary/p/7533292.html),但是不太适用于win7版本的扫雷。
首先在win10上运行win7的扫雷需要patch一下程序最开头对信息的校验。
然后使用ida分析的时候可以下载网络上的pdb进行分析。
分析雷在内存中的存储
首先通过的是Game::Load()这样一个函数来定位到对宽高雷数量的判定:
然后继续往下翻,发现Board::Board这样一个构造函数,应该是对扫雷的板子进行初始化了:
直接跟进去,在里面找到了对扫雷的板子的具体初始化函数:
最后定位到是一个二重循环对Array<UITile>类型的游戏板子进行了初始化!
注:推测UITile继承了NodeBase。
之后的分析就采用动静结合的方式,有一个文章写得比较好:https://www.itdaan.com/blog/2017/05/06/d8daff1e0db2e3334cefc7aec9c0e351.html
总的来说就是对创建雷的部分进行下断点然后往上层函数进行分析。
关键部分:
上面这个部分为我们提供了关键判断,方便我们通过v3(this指针)去找到雷的位置。
之后就写了一个测试脚本去提出雷(上面省略了用ce继续查基址的部分(很简单的))
直接丢代码了:
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <string.h>
int main(){
// 获取pid
HWND hWnd = FindWindow(NULL, "扫雷");
DWORD pid = NULL;
GetWindowThreadProcessId(hWnd, &pid);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
printf("hProcess: %p \n", hProcess);
// 获取模块地址
DWORD modaddr = NULL;
MODULEENTRY32 modentry;
memset(&modentry, 0, sizeof(modentry));
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,pid);
modentry.dwSize = sizeof(MODULEENTRY32);
Module32First(hSnapshot, &modentry);
do{
if (strcmp(modentry.szModule, "MineSweeper.exe") == 0)
{
modaddr = (DWORD)modentry.hModule;
CloseHandle(hSnapshot);
break;
}
}while(Module32Next(hSnapshot, &modentry));
printf("modaddr: %p \n", modaddr);
int a[16][16] = {0};
int x = 0;
int y = 0;
//[[[[[ecx+17*4]+12]+列index]+12]+行index]
//ecx = [[MineSweeper.exe+868B4]+0x10]
DWORD pObj = modaddr;
ReadProcessMemory(hProcess, (LPCVOID)(pObj+0x868B4), &pObj, 4, 0);
ReadProcessMemory(hProcess, (LPCVOID)(pObj+0x10), &pObj, 4, 0);
printf("ecx: %p \n", pObj);
ReadProcessMemory(hProcess, (LPCVOID)(pObj+17*4), &pObj, 4, 0);
ReadProcessMemory(hProcess, (LPCVOID)(pObj+12), &pObj, 4, 0);// 此时pObj指向列array
DWORD lie; // 一列一列处理
BYTE tmp = 0;
for (y = 0; y < 16; y ++){
ReadProcessMemory(hProcess, (LPCVOID)(pObj+y*4), &lie, 4, 0);
ReadProcessMemory(hProcess, (LPCVOID)(lie+12), &lie, 4, 0);
for (x = 0; x < 16; x ++)
{
ReadProcessMemory(hProcess, (LPCVOID)(lie+x), &tmp, 1, 0);
//printf("%d ", tmp);
a[x][y] = tmp;
}
}
printf("下面是雷区:\n");
// 输出雷区
for(x = 0; x < 16; x ++){
for (y = 0; y < 16; y ++){
printf("%d ", a[x][y]);
}
printf("\n");
}
CloseHandle(hProcess);
return 0;
}
效果图:
接着就是实现一个外挂dll了(注入的部分就省略了反正怎么注入都一样):
// apparent.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include <stdio.h>
extern "C" __declspec(dllexport) VOID __stdcall haha(){
MessageBox(0,"hahaha",0,0);
}
DWORD WINAPI ThreadProc(LPVOID lpParameter){
char buf[1000] = {0}; // 输出缓冲区
//MessageBox(0,"Mz1dll注入成功,enjoy it!", "Welcome",0);
DWORD pid = GetCurrentProcessId();
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);// 获取当前句柄
HMODULE hModule = GetModuleHandle(NULL);
//sprintf(buf, "hModule: %p", hModule);
//MessageBox(0, buf, 0, 0);
//sprintf(buf, "pid: %p\r\n句柄: %p", pid, hProcess);
//MessageBox(0,buf,"提示", 0);
while(1){
Sleep(2000);
int a[16][16] = {0};
int x = 0;
int y = 0;
//[[[[[ecx+17*4]+12]+列index]+12]+行index]
//ecx = [[MineSweeper.exe+868B4]+0x10]
DWORD pObj = (DWORD)hModule;
ReadProcessMemory(hProcess, (LPCVOID)(pObj+0x868B4), &pObj, 4, 0);
ReadProcessMemory(hProcess, (LPCVOID)(pObj+0x10), &pObj, 4, 0);
printf("ecx: %p \n", pObj);
ReadProcessMemory(hProcess, (LPCVOID)(pObj+17*4), &pObj, 4, 0);
ReadProcessMemory(hProcess, (LPCVOID)(pObj+12), &pObj, 4, 0);// 此时pObj指向列array
DWORD lie; // 一列一列处理
BYTE tmp = 0;
for (y = 0; y < 16; y ++){
ReadProcessMemory(hProcess, (LPCVOID)(pObj+y*4), &lie, 4, 0);
ReadProcessMemory(hProcess, (LPCVOID)(lie+12), &lie, 4, 0);
for (x = 0; x < 16; x ++)
{
ReadProcessMemory(hProcess, (LPCVOID)(lie+x), &tmp, 1, 0);
//printf("%d ", tmp);
a[x][y] = tmp;
}
}
// 展现图形化提示
int index = 0;
char tip[] = "下面是雷区提示:\r\n";
sprintf(buf, tip);
index += sizeof(tip);
index -= 1;
for (x = 0; x < 16; x ++){
for (y = 0; y < 16; y ++){
//buf[index] = a[x][y]+'0';
sprintf(buf+index, "%d ", a[x][y]);
index += 2;
}
buf[index] = '\r';
index ++;
buf[index] = '\n';
index ++;
}
MessageBox(0, buf, "tip", 0);
}
return 0;
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch ( ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// 执行需要的代码
CreateThread(NULL,0,
(LPTHREAD_START_ROUTINE)ThreadProc,
NULL, 0,NULL);//创建新线程执行代码
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
这个dll会弹框显示雷区内存。
做的比较粗糙,但是原理基本上就是这个亚子。
演示:
差不多就这样~
本文来自博客园,作者:Mz1,转载请注明原文链接:https://www.cnblogs.com/Mz1-rc/p/15396115.html
如果有问题可以在下方评论或者email:mzi_mzi@163.com