遊戲修改器製作教程四:用API讀寫記憶體
本教程面向有C\C++基礎的人,最好還要懂一些Windows程式設計知識
程式碼一律用Visual Studio 2013編譯,如果你還在用VC6請趁早丟掉它...
寫這個教程只是為了讓玩家更好地體驗所愛的單機遊戲,順便學到些逆向知識,我不會用網路遊戲做示範,請自重
上一章講了用CE讀寫記憶體,本章講如何自己程式設計實現
用到的API:
// 讀記憶體
BOOL WINAPI ReadProcessMemory(
_In_ HANDLE hProcess,
_In_ LPCVOID lpBaseAddress,
_Out_ LPVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesRead
);
// 寫記憶體
BOOL WINAPI WriteProcessMemory(
_In_ HANDLE hProcess,
_In_ LPVOID lpBaseAddress,
_In_ LPCVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesWritten
);
// 開啟程式
HANDLE WINAPI OpenProcess(
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ DWORD dwProcessId
);
本章開始最好學習彙編知識了,也不用太深,能做逆向工程就行了
逆向工程(一):彙編、逆向工程基礎篇 這篇文章講得不錯
另外VS2013(我就不告訴你VC6也有)除錯時在選單-除錯-視窗-反彙編可以看到C/C++程式碼的對應彙編程式碼,多看看就熟悉了
本章以製作東方輝針城修改器的實戰講解讀寫記憶體
分析
首先分析一下目標程式的記憶體
用CE搜尋一下HP地址,找到0x004F5864,然後用分析資料/結構分析一下它附近的記憶體(其實這些變數並不在一個struct或class內,但看看附近的記憶體總會有驚喜)
這是一個指向資源資訊的指標
然後是關於遊戲資料的
然後提取出有用的資料
取程式ID
要讀寫一個程式的記憶體首先要開啟程式,開啟程式需要程式ID(PID)
一般有兩種方式獲取PID,第一種通過視窗控制程式碼:
HWND hwnd = FindWindow(_T("BASE"), NULL);
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
第二種通過程式名:
#include <tlhelp32.h>
DWORD GetPid(LPCTSTR name)
{
DWORD pid = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 processEntry;
processEntry.dwSize = sizeof(PROCESSENTRY32);
// 列舉程式
BOOL hasNext = Process32First(snapshot, &processEntry);
while (hasNext)
{
// 比較程式名
if (_tcsicmp(processEntry.szExeFile, name) == 0)
{
pid = processEntry.th32ProcessID;
break;
}
hasNext = Process32Next(snapshot, &processEntry);
}
CloseHandle(snapshot);
return pid;
}
DWORD pid = GetPid(_T("th14.exe"));
開啟程式
沒什麼好講的,讀記憶體需要PROCESS_VM_READ許可權,寫記憶體需要PROCESS_VM_WRITE和PROCESS_VM_OPERATION許可權
HANDLE process = OpenProcess(/*PROCESS_ALL_ACCESS*/ PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
寫記憶體
需要注意的是靜態地址也不是不變的,準確來說應該用模組基址+偏移量來表示,因為模組基址可能會變,如果模組基址會變的話還要取模組基址(其實就是模組控制程式碼)
不過大部分exe模組的基址是不變的(32位預設0x00400000,64位預設0x100000000)
DWORD buffer;
WriteProcessMemory(m_process, (LPVOID)0x004F5864, &(buffer = 8), sizeof(DWORD), NULL);
東方輝針城修改器
然後我們就可以實現這個修改器了,依然用到了MFC(為了少寫UI程式碼)
// 處理定時器
void CTH14CheatDlg::OnTimer(UINT_PTR nIDEvent)
{
HWND hwnd = ::FindWindow(_T("BASE"), NULL);
if (hwnd == NULL) // 程式已關閉
{
if (m_process != NULL)
{
// 釋放控制程式碼
CloseHandle(m_process);
m_process = NULL;
}
}
else
{
// 開啟程式
if (m_process == NULL)
{
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
m_process = OpenProcess(/*PROCESS_ALL_ACCESS*/ PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
if (m_process == NULL)
{
CString msg;
msg.Format(_T("開啟程式失敗,錯誤程式碼:%u"), GetLastError());
MessageBox(msg, NULL, MB_ICONERROR);
CDialogEx::OnTimer(nIDEvent);
return;
}
}
// 寫記憶體
DWORD buffer;
if (m_lockHp)
{
WriteProcessMemory(m_process, (LPVOID)0x004F5864, &(buffer = 8), sizeof(DWORD), NULL);
}
if (m_lockBomb)
{
WriteProcessMemory(m_process, (LPVOID)0x004F5870, &(buffer = 8), sizeof(DWORD), NULL);
}
if (m_lockPower)
{
WriteProcessMemory(m_process, (LPVOID)0x004F5858, &(buffer = 400), sizeof(DWORD), NULL);
}
}
CDialogEx::OnTimer(nIDEvent);
}
東方輝針城修改器V2
每秒鐘寫記憶體的方法看上去太蠢了,而且會影響效能,一勞永逸的方法就是修改程式碼
首先找出減少殘機數的指令
地址是0x0044F618,機器碼A3 64 58 4F 00,把它全部改成90(nop指令)
減少bomb的指令
地址0x0041218A,機器碼A3 70 58 4F 00,改成nop
然後是判斷bomb夠不夠用的指令
要修改的是下面的jle指令(小於或等於時跳轉),把它改成nop
地址0x0044DD68,機器碼7E 0E
然後是遊戲剛開始時賦值靈力的
直接改這條指令長度會變長,改上面的mov eax吧,改成賦值400
地址0x00435DAF,原機器碼A3 58 58 4F 00,修改成B8 90 01 00 00
死亡後賦值靈力的
這堆程式碼的意思是把靈力讀到ecx暫存器,減少後寫回記憶體,改成賦值400吧
地址0x0044DDB8,原機器碼03 C8 3B CE 0F 4C CE,修改成B9 90 01 00 00 90 90
實現程式碼(完整原始碼地址同上):
// 修改關於殘機的程式碼
void CTH14CheatDlg::modifyHpCode()
{
static const BYTE originalCode[] = { 0xA3, 0x64, 0x58, 0x4F, 0x00 };
static const BYTE modifiedCode[] = { 0x90, 0x90, 0x90, 0x90, 0x90 };
if (m_process != NULL)
{
WriteProcessMemory(m_process, (LPVOID)0x0044F618, m_lockHp ? modifiedCode : originalCode, sizeof(originalCode), NULL);
}
}
// 修改關於炸彈的程式碼
void CTH14CheatDlg::modifyBombCode()
{
static const BYTE originalCode1[] = { 0xA3, 0x70, 0x58, 0x4F, 0x00 };
static const BYTE modifiedCode1[] = { 0x90, 0x90, 0x90, 0x90, 0x90 };
static const BYTE originalCode2[] = { 0x7E, 0x0E };
static const BYTE modifiedCode2[] = { 0x90, 0x90 };
if (m_process != NULL)
{
WriteProcessMemory(m_process, (LPVOID)0x0041218A, m_lockBomb ? modifiedCode1 : originalCode1, sizeof(originalCode1), NULL);
WriteProcessMemory(m_process, (LPVOID)0x0044DD68, m_lockBomb ? modifiedCode2 : originalCode2, sizeof(originalCode2), NULL);
}
}
// 修改關於靈力的程式碼
void CTH14CheatDlg::modifyPowerCode()
{
static const BYTE originalCode1[] = { 0xA3, 0x58, 0x58, 0x4F, 0x00 };
static const BYTE modifiedCode1[] = { 0xB8, 0x90, 0x01, 0x00, 0x00 };
static const BYTE originalCode2[] = { 0x03, 0xC8, 0x3B, 0xCE, 0x0F, 0x4C, 0xCE };
static const BYTE modifiedCode2[] = { 0xB9, 0x90, 0x01, 0x00, 0x00, 0x90, 0x90 };
if (m_process != NULL)
{
WriteProcessMemory(m_process, (LPVOID)0x00435DAF, m_lockPower ? modifiedCode1 : originalCode1, sizeof(originalCode1), NULL);
WriteProcessMemory(m_process, (LPVOID)0x0044DDB8, m_lockPower ? modifiedCode2 : originalCode2, sizeof(originalCode2), NULL);
if (m_lockPower)
{
DWORD buffer;
WriteProcessMemory(m_process, (LPVOID)0x004F5858, &(buffer = 400), sizeof(DWORD), NULL);
}
}
}
相關文章
- 遊戲修改器製作教程五:OllyDBG和其他除錯工具遊戲除錯
- Steam遊戲《Northgard(北境之地)》修改器製作遊戲
- Linux讀寫實體記憶體Linux記憶體
- 讀寫CMOS記憶體 (轉)記憶體
- CIH病毒原理的應用——實體記憶體的讀寫 (轉)記憶體
- python能讀寫記憶體嗎Python記憶體
- 7.7 實現程式記憶體讀寫記憶體
- 遊戲製作詳解自----OpenGL入門教程(四)(轉)遊戲
- 遊戲製作相關---HAM教程翻譯本(四)(轉)遊戲
- 用python+flask自己製作api(教程附原始碼)PythonFlaskAPI原始碼
- CIH 病毒原理的應用――實體記憶體的讀寫 (4千字)記憶體
- 記憶體不能為read 記憶體讀寫錯誤的解決辦法記憶體
- 記憶體清理、動畫製作、CPU檢測等五款實用軟體推薦記憶體動畫
- Objective-C記憶體管理教程和原理剖析(四)Object記憶體
- 遊戲記憶體對比普通記憶體區別 遊戲記憶體和普通記憶體相差大嗎?遊戲記憶體
- (譯) 記憶體補丁的製作例項-修改WDASM記憶體ASM
- OS實驗八:採用快取記憶體實現檔案讀寫快取記憶體
- 遊戲角色寫實頭髮製作遊戲
- 深度解讀昇騰CANN記憶體複用技術,降低網路記憶體佔用記憶體
- 讀懂作業系統之虛擬記憶體TLB與快取(cache)關係篇(四)作業系統記憶體快取
- 讓XP系統遠離記憶體讀寫錯誤記憶體
- 記憶體效能評估(四)記憶體
- Delphi 的記憶體操作函式(5): 複製記憶體記憶體函式
- 《ASP網頁製作教程》筆記網頁筆記
- 遊戲記憶體測試遊戲記憶體
- filebeat實踐-記憶體佔用-最大記憶體佔用記憶體
- Billy Belceb病毒編寫教程(DOS篇)---駐留記憶體病毒記憶體
- JavaScript 記憶體洩漏教程JavaScript記憶體
- 程式的記憶體四區模型記憶體模型
- JavaScript之記憶體洩漏【四】JavaScript記憶體
- ORACLE 記憶體管理 之四 SGAOracle記憶體
- 讀懂作業系統之虛擬記憶體頁表(五)作業系統記憶體
- 利用Lotus Connections API製作桌面應用API
- 利用 Lotus Connections API 製作桌面應用API
- 作業系統-記憶體管理作業系統記憶體
- 作業系統——記憶體管理作業系統記憶體
- Dreamweaver製作簡易的拼圖遊戲教程遊戲
- 用KEYMAKE製作記憶體序號產生器特殊一例 (11千字)記憶體