[Win32] 实现内存修改器
0. 實(shí)現(xiàn)原理
直接使用CUI操作, 沒有GUI美麗的外衣.(加上GUI不就成了金山某俠了嗎?)
1. 找到目標(biāo)進(jìn)程
首先將游戲運(yùn)行起來(lái), Windows為每個(gè)進(jìn)程分配4GB的地址空間, 前2GB歸應(yīng)用程序所有, 后2GB屬于整個(gè)操作系統(tǒng)共用. 我們要向在指定的進(jìn)程地址空間中修改數(shù)據(jù)就先要得到此進(jìn)程的操作句柄.
實(shí)現(xiàn)原理: 輸出當(dāng)前所有運(yùn)行中的進(jìn)程及進(jìn)程ID, 主動(dòng)輸入指定的進(jìn)程ID, 返回目標(biāo)進(jìn)程的操作句柄. 通過句柄就能在找到指定的空間修改數(shù)據(jù)了.
實(shí)現(xiàn)輸出和查找進(jìn)程ID的demo
#include <iostream> #include <Windows.h> #include <TlHelp32.h>using namespace std;int main() {PROCESSENTRY32 pe32;pe32.dwSize = sizeof(pe32);PROCESSENTRY32 _pe32;_pe32.dwSize = sizeof(_pe32);HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if (hProcessSnap == INVALID_HANDLE_VALUE){cout << "調(diào)用失敗" << endl;return -1;}BOOL bMore = Process32First(hProcessSnap, &pe32);while (bMore){cout << "進(jìn)程名稱: " << pe32.szExeFile << endl;cout << "進(jìn)程ID: " << pe32.th32ProcessID << endl;bMore = Process32Next(hProcessSnap, &pe32);}bMore = Process32First(hProcessSnap, &_pe32);DWORD ProcessID;cout << "Input ProcessID: ";cin >> ProcessID;while (bMore){if (_pe32.th32ProcessID == ProcessID){cout << "find ID: " << ProcessID << " 進(jìn)程名稱: " << _pe32.szExeFile << endl;break;}bMore = Process32Next(hProcessSnap, &_pe32);}CloseHandle(hProcessSnap);system("pause");return 0; }這樣就能將所有正在運(yùn)行中的進(jìn)程名與進(jìn)程ID打印出來(lái), 得到ID即可使用函數(shù)得到句柄
2. 找到指定數(shù)據(jù)所在的地址
Windows采用分頁(yè)機(jī)制來(lái)管理數(shù)據(jù), 以4KB為單位搜索可以提高搜索速率. 下面的CompareAPage函數(shù)的功能就是比較目標(biāo)進(jìn)程內(nèi)存1頁(yè)大小的內(nèi)存. 得到的地址可能不止一個(gè), 故將符合的所有地址保存在一個(gè)set中, 接下來(lái)會(huì)在這些地址中再篩選.
BOOL CompareAPage(DWORD dwBaseAddr, DWORD dwValue) {// 讀取1頁(yè)內(nèi)存BYTE arBytes[4096];if (!ReadProcessMemory(g_hProcess, (LPVOID)dwBaseAddr, arBytes, 4096, NULL)){return FALSE;}// 在這1頁(yè)中查找DWORD* pdw;for (int i = 0; i < 4 * 1024 - 3; i++){pdw = (DWORD*)&arBytes[i];if (pdw[0] == dwValue){if (g_HashMap.size() >= 1024){return FALSE;}else{g_HashMap.insert(dwBaseAddr + i);}}}return TRUE; }使用FindFirst函數(shù)來(lái)在2GB的內(nèi)存中搜索
BOOL FindFirst(DWORD dwValue) {const DWORD dwOneGB = 1024 * 1024 * 1024;const DWORD dwOnewPage = 4 * 1024;if (g_hProcess == NULL){return FALSE;}// 在用戶地址空間進(jìn)行搜索, Win98為應(yīng)用地址預(yù)留地址為4MB至2GB// Win2000預(yù)留地址為64KB至2GB// 故需判斷操作系統(tǒng)類型, 用以決定開始地址DWORD dwBase;OSVERSIONINFO vi = { sizeof(vi) };GetVersionEx(&vi);if (vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS){dwBase = 4 * 1024 * 1024; // Win98系列, 4MB起}else{dwBase = 64 * 1024;}// 從開始地址到2GB的地址空間進(jìn)行查找for (; dwBase < 2 * dwOneGB; dwBase += dwOnewPage){CompareAPage(dwBase, dwValue);}return TRUE; }3. 在所得到的地址中篩選得到正確的地址
數(shù)值改變后再到之前保存的地址中查找數(shù)據(jù)變化相同的數(shù)據(jù), 直到滿足結(jié)果
BOOL FindNext(DWORD dwValue) {// 在g_HashMap中查找BOOL bRet = FALSE;DWORD dwReadValue;unordered_set<DWORD> newSet;for (auto& e : g_HashMap){if (ReadProcessMemory(g_hProcess, (LPVOID)e, &dwReadValue, sizeof(DWORD), NULL)){if (dwReadValue == dwValue){newSet.insert(e);bRet = TRUE;}}}g_HashMap.swap(newSet);return bRet; }4. 修改數(shù)值
BOOL WriteMemory(DWORD dwAddr, DWORD dwValue) {return WriteProcessMemory(g_hProcess, (LPVOID)dwAddr, &dwValue, sizeof(DWORD), NULL); }
5. 主函數(shù)
#include "MemRepair.h"HANDLE g_hProcess; // 保存游戲進(jìn)程句柄 unordered_set<DWORD> g_HashMap; // 保存數(shù)據(jù)地址int main() {ShowProcess();DWORD ProcessID;cout << "Input ProcessID: ";cin >> ProcessID;g_hProcess = FindProcess(ProcessID);cout << endl << "-----------------------------" << endl;int val;cout << "Input val = ";cin >> val;FindFirst(val);ShowHash();cout << endl << "----------------" << endl;size_t countAddr = 0;// 若地址數(shù)量不再減少, 則將所有的數(shù)據(jù)都修改了!while (g_HashMap.size() > 1 && countAddr != g_HashMap.size()){countAddr = g_HashMap.size();cout << "Input val = ";cin >> val;FindNext(val);if (FindNext == false){cout << "找不到此數(shù)據(jù)! " << endl;return -1;}ShowHash();cout << "----------------" << endl;}cout << "Input new val = ";cin >> val;auto it = g_HashMap.begin();while (it != g_HashMap.end()){if (WriteMemory(*it, val)){cout << "Write data success!" << endl;}else{cout << "Write data fail!" << endl;}it++;}return 0; }
6. 測(cè)試
本來(lái)想使用紅警2測(cè)試, 由于游戲版本過低原因我無(wú)法切回桌面, 故使用紅警3
打開游戲, 開始游戲, 這個(gè)時(shí)候只有15000很少.
打開修改器程序. 輸入指定游戲進(jìn)程ID
輸入5692, 等待輸入金額
輸入15000的金額, 程序進(jìn)行搜索, 將保存此數(shù)值的地址打印并保存起來(lái)
發(fā)現(xiàn)多個(gè)地址, 我們?cè)谟螒蛑薪ㄒ粋€(gè)電廠花費(fèi)點(diǎn)錢, 金錢變?yōu)?4200, 再在窗口輸入這個(gè)數(shù)
這時(shí)在剛剛保存的地址中僅有兩個(gè)地址存儲(chǔ)的數(shù)據(jù)為14200, 再重復(fù)上一步花點(diǎn)錢. 再輸入進(jìn)去
最后, 輸入你想要的數(shù)字, 回車, 返回游戲查看
ohhhhhhhhhhhhhhhhhhhhhhhh, 讓我們使用先鋒轟炸機(jī)轟平Tokyo吧 !
需要原碼可以聯(lián)系作者哦
參考文獻(xiàn):
Windows程序設(shè)計(jì)(第三版) 張錚 孫寶山 周天立
總結(jié)
以上是生活随笔為你收集整理的[Win32] 实现内存修改器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 腾讯轻量云FREEBSD11.1安装pa
- 下一篇: 充气娃娃也好玩——在ESXi上安装Pan