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