-
涉及相關(guān)API函數(shù)
SendMessage
PostMessage
FindWindow
GetWindowThreadProcessId
OpenProcess
ReadProcessMemory
-
涉及相關(guān)工具
CE
Spy++
VC++ 6.0
-
步驟
1.用CE分析棋盤基址及其寬、高铸本;
①基址: 通過CE以字節(jié)數(shù)值類型反復(fù)“未知初始化數(shù)值”骡显、“更改過的數(shù)值”和“未更改過的數(shù)值”掃描內(nèi)存,對掃描結(jié)果逐一進(jìn)行過濾矗蕊,查看濾后結(jié)果的內(nèi)存與實(shí)際游戲界面顯示情況是否對應(yīng)疙驾,由此進(jìn)行判定基址阀趴;
②寬昏翰、高:通過CE直接搜索對應(yīng)寬度苍匆、高度,然后調(diào)整掃雷級別(即雷面的大信锞铡)锉桑,再次用CE,通過“大于...”窍株、“小于...”對寬高進(jìn)行掃描民轴,從而判定寬、高在內(nèi)存中的地址球订;
2.用CE查看棋盤對應(yīng)內(nèi)存中數(shù)據(jù)的意義后裸;
- 狀態(tài):查看非雷、未翻開的雷(標(biāo)記冒滩、未標(biāo)記的雷)微驶、翻開的雷(失敗后游戲自動(dòng)翻開)等幾種狀態(tài)對應(yīng)內(nèi)存中的十六進(jìn)制數(shù)值;
狀態(tài) | 十六進(jìn)制數(shù)值 |
---|---|
未翻開的雷 | 0x8F |
翻開的雷 | 0x8A |
結(jié)束標(biāo)識(shí) | 0x10 |
- 棋盤坐標(biāo):通過Spy++ 監(jiān)控winmine.exe的鼠標(biāo)左鍵按下开睡、松開消息因苹,查看對應(yīng)棋盤左上角坐標(biāo)及每格的長、寬篇恒;
棋盤坐標(biāo) | 十進(jìn)制數(shù)值 |
---|---|
橫坐標(biāo)X | 10 |
縱坐標(biāo)Y | 53 |
PS:對于棋盤的左上角坐標(biāo)大致即可扶檐,使用時(shí),需要在此基礎(chǔ)上加上一個(gè)偏移胁艰,以使鼠標(biāo)模擬時(shí)能點(diǎn)擊到小格內(nèi)區(qū)域款筑;
每小格 | 十進(jìn)制數(shù)值 |
---|---|
長 | 16 |
寬 | 16 |
3.編制掃雷游戲輔助;
1.輔助源碼
2.主要部分SweeperDlg.cpp
unsigned char gameData[24][32]; //ReadProcessMemory
#define gamex 10 + 8
#define gamey 53 + 8
void CSweeperDlg::OnButtonReaddata()
{
// TODO: Add your control notification handler code here
// TODO: Add your control notification handler code here
HWND hwnd = ::FindWindow(NULL,"掃雷");
if (hwnd == 0)
{
::MessageBox(0,"游戲未打開",0,MB_OK);
return;
}
//1005194
DWORD pid;
GetWindowThreadProcessId(hwnd,&pid);
//GetWindowThreadProcessId
//OpenProcss
HANDLE hp=OpenProcess(PROCESS_ALL_ACCESS,false,pid);
//
if (hp==NULL)
{
::MessageBox(0,"打開進(jìn)程出錯(cuò)",0,MB_OK);
return;
}
ReadProcessMemory(hp,(LPCVOID)0x1005361,gameData,32*24,&pid);
int high = 0;
ReadProcessMemory(hp,(LPCVOID)0x1005338,&high,4,&pid);//字節(jié)大小可為1腾么,2等奈梳,若不為int大小,應(yīng)對high進(jìn)行初始化置0解虱;
m_gameData.Empty();
CString strGameData;
WORD yx[2] = {0,0};
for (int y = 0 ; y < high ; y++)
{
for (int x = 0 ; x <32 ; x++)
{
//對于后續(xù)無意義的字節(jié)直接略掉攘须;
if (gameData[y][x] == 0x10)
break;
//格式化
strGameData.Format("%x,",gameData[y][x]);
//統(tǒng)一占兩位顯示
if (strlen(strGameData) == 2)
strGameData = "0" + strGameData;
m_gameData += strGameData;
}
//一排結(jié)束換行
m_gameData += "\r\n";
}
UpdateData(false);
}
void CSweeperDlg::OnButtonSweeper()
{
// TODO: Add your control notification handler code here
HWND hwnd = ::FindWindow(NULL,"掃雷");
if (hwnd == 0)
{
::MessageBox(0,"游戲未打開",0,MB_OK);
return;
}
//1005194
DWORD pid;
GetWindowThreadProcessId(hwnd,&pid);
//GetWindowThreadProcessId
//OpenProcss
HANDLE hp=OpenProcess(PROCESS_ALL_ACCESS,false,pid);
//
if (hp==NULL)
{
::MessageBox(0,"打開進(jìn)程出錯(cuò)",0,MB_OK);
return;
}
ReadProcessMemory(hp,(LPCVOID)0x1005361,gameData,32*24,&pid);
int high = 0;
ReadProcessMemory(hp,(LPCVOID)0x1005338,&high,4,&pid);//字節(jié)大小可為1,2等殴泰,若不為int大小于宙,應(yīng)對high進(jìn)行初始化置0;
CString strGameData;
for (int y = 0 ; y < high ; y++)
{
for (int x = 0 ; x <32 ; x++)
{
//對于后續(xù)無意義的字節(jié)直接略掉艰匙;
if (gameData[y][x] == 0x10)
break;
//不是雷就挖開
/*
point[0] = 14+6;
point[1] = 56+6;
*/
if (gameData[y][x] != 0x8f)
{
WORD yx[2];
yx[0] = gamex + x*16;
yx[1] = gamey + y*16;
::PostMessage(hwnd,WM_LBUTTONDOWN,1,*(int*)yx);
::PostMessage(hwnd,WM_LBUTTONUP,0,*(int*)yx);
}
}
}
}
void CSweeperDlg::OnButtonClick()
{
// TODO: Add your control notification handler code here
WORD point[2];
HWND hwnd = ::FindWindowA("掃雷",NULL);
if (hwnd == 0)
{
return ;
}
point[0] = 14+6;
point[1] = 56+6;
::SendMessage(hwnd,WM_LBUTTONDOWN,1,*(int*)point);
::SendMessage(hwnd,WM_LBUTTONUP ,0,*(int*)point);
}