從之前的文章中,可以知道如何找到植物大戰僵屍的游戲基址,以及其全部內存地址。。
下面將其實現出來。。
說明:通過游戲基址,再加上偏移量,修改游戲在內存中的值。實現無限陽光‘、無限金幣、免CD、免暫停的功能。。。。,本例子的游戲是植物大戰僵屍-----英文原版。
注意:不同版本的游戲的游戲基址不一定相同。’
思路:
1.打開進程,並獲取進程句柄。
方式:1.可以遍歷當前所有的進程。
CreateToolhelp32Snapshot(),Process32First(),Process32Next(),OpenProcess()。
2.直接利用VS的SPY++,得到進程的句柄。(或者得到進程的標題、類名,再通過標題得到窗口句柄,再得到進程ID,再得到進程句柄)
FindWindow(),GetWindowThreadProcessId(),OpenProcess().
2.根據游戲基址+偏移量,得到修改地址。將值修改成自定義值。(具體偏移多少次,看之前的文章----游戲內存地址)
主要用到函數:
ReadProcessMemory(),讀取內存
WriteProcessMemory(),修改內存
修改內存權限后,在寫入。。。。。
VirtualProtectEx(g_hProcess, pCode, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect); WriteProcessMemory(g_hProcess, pCode, opCode, 4, NULL); VirtualProtectEx(g_hProcess, pCode, 4, dwOldProtect, NULL);
// jsConsole.cpp : 定義控制台應用程序的入口點。 #include "stdafx.h" #include <Windows.h> //游戲基址 int g_nBaseAddr = 0x006A9EC0; //游戲句柄 HANDLE g_hProcess; //根據基址計算出兩次偏移后的地址 int *get2Point(int g_nBaseAddr, int p1, int p2) { int iBase, iP1, *iP2; if (!ReadProcessMemory(g_hProcess, (LPVOID)g_nBaseAddr, &iBase, 4, NULL)) { return NULL; } if (!ReadProcessMemory(g_hProcess, (LPVOID)(iBase + p1), &iP1, 4, NULL)) { return NULL; } //返回最終地址 iP2 = (int *)(iP1 + p2); return iP2; } //根據基址計算出三次偏移后的地址 int *get3Point(int g_nBaseAddr, int p1, int p2, int p3) { int iBase, iP1, iP2, *iP3; if (!ReadProcessMemory(g_hProcess, (LPVOID)g_nBaseAddr, &iBase, 4, NULL)) { return NULL; } if (!ReadProcessMemory(g_hProcess, (LPVOID)(iBase + p1), &iP1, 4, NULL)) { return NULL; } if (!ReadProcessMemory(g_hProcess, (LPVOID)(iP1 + p2), &iP2, 4, NULL)) { return NULL; } iP3 = (int *)(iP2 + p3); return iP3; } //改變陽光值 void ModifySun() { //獲取陽光所在地址 int *pSun = get2Point(g_nBaseAddr, 0x768, 0x5560); //將陽光改為多少 int nSunValue = 999999; //修改 WriteProcessMemory(g_hProcess, pSun, &nSunValue, 4, NULL); } //修改關卡 void ModifyGuanka() { int *pGuanka = get2Point(g_nBaseAddr, 0x82C, 0x24); int guankaValue = 58; WriteProcessMemory(g_hProcess, pGuanka, &guankaValue, 4, NULL); } //修改金幣 void ModifyMoney() { int *pMoney = get2Point(g_nBaseAddr, 0x82C, 0x28); int moneyValue = 999999; WriteProcessMemory(g_hProcess, pMoney, &moneyValue, 4, NULL); } //點擊其他程序,游戲不會暫停。免暫停 void ModifyPause() { unsigned char *pCode = (unsigned char *)0x4502C0; //修改內存讀寫權限 DWORD dwOldProtect; VirtualProtectEx(g_hProcess, pCode, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect); unsigned char opCode[] = "\xC3\x04\x00"; WriteProcessMemory(g_hProcess, pCode, opCode, 4, NULL); VirtualProtectEx(g_hProcess, pCode, 4, dwOldProtect, NULL); } //利用線程不斷更新陽光和金幣、免CD。實現無限金幣 DWORD WINAPI ModifyCDThread( LPVOID lpParameter // thread data ) { while (1) { //修改陽光 ModifySun(); //獲取卡槽數目地址 int *pCount = get3Point(g_nBaseAddr, 0x768, 0x144, 0x24); if (pCount == NULL) continue; //獲取第一個卡槽地址 int *pFirst = get3Point(g_nBaseAddr, 0x768, 0x144, 0x4C); if (pFirst == NULL) continue; //獲取卡槽數目 int nCount = 0; ReadProcessMemory(g_hProcess, pCount, &nCount, 4, NULL); //對每一個卡槽進行免CD for (int i = 0; i < nCount; i++) { //pFirst[0] = pFirst[1];//讀和寫 int nRecoveryTime; ReadProcessMemory(g_hProcess, pFirst + 1, &nRecoveryTime, 4, NULL); WriteProcessMemory(g_hProcess, pFirst, &nRecoveryTime, 4, NULL); //卡槽間的偏移量為50 pFirst = (int *)((int)pFirst + 0x50); } Sleep(100); } } void ModifyCD() { CreateThread(0, 0, ModifyCDThread, 0, 0, 0); } int _tmain(int argc, _TCHAR* argv[]) { //獲取游戲窗口所在進程的進程ID,也就是PID HWND hWnd = FindWindow(NULL, TEXT("植物大戰僵屍中文版")); if (NULL == hWnd) { printf("查找窗口失敗\n"); return 0; } DWORD dwProcessId; GetWindowThreadProcessId(hWnd, &dwProcessId); printf("進程ID:%d\n", dwProcessId); //獲取進程句柄 g_hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); if (NULL == g_hProcess) { printf("打開進程失敗\n"); return 0; } ModifySun(); ModifyGuanka(); ModifyMoney(); ModifyPause(); ModifyCDThread(0); getchar(); return 0; }