逆向實戰 | win7掃雷逆向&輔助實現


win7掃雷逆向&輔助實現

做這個事情是因為軟件工程上機課太無聊了,就開始玩掃雷,但是覺得原版界面有點太丑了,就想自己改一改。

參考的資料還挺多的,這個講xp掃雷的講的比較好(https://www.cnblogs.com/iBinary/p/7533292.html),但是不太適用於win7版本的掃雷。

首先在win10上運行win7的掃雷需要patch一下程序最開頭對信息的校驗。

然后使用ida分析的時候可以下載網絡上的pdb進行分析。

分析雷在內存中的存儲

首先通過的是Game::Load()這樣一個函數來定位到對寬高雷數量的判定:
image

然后繼續往下翻,發現Board::Board這樣一個構造函數,應該是對掃雷的板子進行初始化了:
image

直接跟進去,在里面找到了對掃雷的板子的具體初始化函數:
image

最后定位到是一個二重循環對Array<UITile>類型的游戲板子進行了初始化!
注:推測UITile繼承了NodeBase。
image

之后的分析就采用動靜結合的方式,有一個文章寫得比較好:https://www.itdaan.com/blog/2017/05/06/d8daff1e0db2e3334cefc7aec9c0e351.html
總的來說就是對創建雷的部分進行下斷點然后往上層函數進行分析。
關鍵部分:
image

上面這個部分為我們提供了關鍵判斷,方便我們通過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;
}

效果圖:
image

接着就是實現一個外掛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會彈框顯示雷區內存。
做的比較粗糙,但是原理基本上就是這個亞子。

演示:
image

差不多就這樣~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM