逆向扫雷(2)
緊接著 掃雷(1)博客,我們接著說,接下來我們需要找到存放寬和高的內存地址,一般肯定也是立即數地址,這種小游戲不會存在那種太難的偏移。
第一步:拿到游戲的窗口句柄:
HWND hwnd = ::FindWindowA("掃雷", "掃雷");//獲取游戲的窗口句柄第二步:通過窗口句柄拿到進程ID:
GetWindowThreadProcessId(hwnd, &pid);這個pid是上面提前定義好的DWORD類型
第三步:通過進程ID拿到進程句柄:
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid)第四步:隨便找個基地址讀取一下,觀察進程是否存在(打開):
這里的0x1005361是通過CE觀察出來的,大家可以自行嘗試
if (!ReadProcessMemory(hProcess, (LPCVOID)0x1005361, &gamedata, 32 * 24, &pid)){::MessageBoxA(NULL, "掃雷游戲未打開", "錯誤", MB_OK);return 0;}第五步(綜合講解所需要的一些值計算):把每格的大小,以及坐標利用VS自帶的SPY++計算一下:
a.這里我算出來是(20,60);
short gamex = 20; short gamey = 60;每格大小的話,利用兩個點計算一下就好,這里用圖表示一下:
這是點擊了雷區的左上角
這是點擊了雷區的右上角
然后兩個相減,最后再來除以格子數量,就可以得到長度了,既可以找到鼠標點擊的位置坐標。
b.至于雷區的寬度和高度利用CE立即數搜索就可以搜索到它們的立即數地址,即不變的地址,就可以找到
c.通過觀察,高度最大可以24,長度最大可為32,如何判斷終止的地方呢?
通過觀察,遇到0x10后它就停止了一行的有效區,這就是掃雷模式的改變,雷區所放的地方是不變的,它只需要改變一下一行結尾。每行的起始位置是不變的,它只改變終止位置。這就改變了掃雷模式的寬度和高度。所以一行的長度是不變的,如何控制呢?我們只需要找到0x10地點,高度呢?高度只需要讀取一下CE里面找出來的立即數不就行嘍,思路就是這樣
根據上述我們即可 初始化一個雷區數組unsigned char gamedata[24][32] = { 0 };
第六步:遍歷之后判斷并用鼠標點擊:
unsigned short xypos[2] = { 0 };for (int i = 0; i < dwHight;++i) {for (int j = 0; j < 32;++j) {if (0x10 == gamedata[i][j])break;xypos[0] = gamex + j * 16;xypos[1] = gamey + i * 16;if (0x8F != gamedata[i][j]) {::PostMessage(hwnd, WM_LBUTTONDOWN,MK_LBUTTON,*(int *)xypos);::PostMessage(hwnd, WM_LBUTTONUP,0, *(int*)xypos);}}}完整代碼如下
閱讀下面的c++代碼需要一點點的windows核心編程基礎,掃雷程序的話可以參照模仿一下就行
#include<iostream> #include<windows.h> using namespace std; int main() {DWORD pid;HWND hwnd = ::FindWindowA("掃雷", "掃雷");//獲取游戲的窗口句柄if (NULL == hwnd){MessageBoxA(NULL, "掃雷游戲未打開", "錯誤", MB_OK);return 0;}GetWindowThreadProcessId(hwnd, &pid);//通過窗口句柄拿到進程IDHANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);//通過進程ID拿到進程句柄if (NULL == hProcess) {::MessageBoxA(NULL, "掃雷游戲未打開","錯誤", MB_OK);return 0;}//掃雷基址:0x1005361 炸彈:0x8F //掃雷的高 0x01005338 //掃雷的寬 0x01005334unsigned char gamedata[24][32] = { 0 };if (!ReadProcessMemory(hProcess, (LPCVOID)0x1005361, &gamedata, 32 * 24, &pid)){::MessageBoxA(NULL, "掃雷游戲未打開", "錯誤", MB_OK);return 0;}DWORD dwHight = 0;if (!ReadProcessMemory(hProcess, (LPCVOID)0x01005338, &dwHight, sizeof(dwHight), &pid)){::MessageBoxA(NULL, "讀取掃雷進程未打開", "錯誤", MB_OK);return 0;}short gamex = 20;short gamey = 60;unsigned short xypos[2] = { 0 };for (int i = 0; i < dwHight;++i) {for (int j = 0; j < 32;++j) {if (0x10 == gamedata[i][j])break;xypos[0] = gamex + j * 16;xypos[1] = gamey + i * 16;if (0x8F != gamedata[i][j]) {::PostMessage(hwnd, WM_LBUTTONDOWN,MK_LBUTTON,*(int *)xypos);::PostMessage(hwnd, WM_LBUTTONUP,0, *(int*)xypos);}}}cout << "彪哥出品,必為廢品";CloseHandle(hProcess); }運行結果圖:
前三步總結也就是
通過窗口的標題拿到窗口的句柄,FindWindowA
然后通過窗口的句柄拿到進程的ID,GetWindowThreadProcessId
最后通過進程的ID拿到進程的句柄OpenProcess
插入一個提示(vs如何打開MSDN幫助文檔)
比如要查看float的特征。
在vs中輸入float,然后按F1鍵,會在默認瀏覽器上打開幫助文檔。
總結
- 上一篇: 2020年度总结(只有做好自己不喜欢的事
- 下一篇: ARM多寄存器加载/存储指令