从之前的文章中,可以知道如何找到植物大战僵尸的游戏基址,以及其全部内存地址。。
下面将其实现出来。。
说明:通过游戏基址,再加上偏移量,修改游戏在内存中的值。实现无限阳光‘、无限金币、免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[] = "xC3x04x00"; 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("查找窗口失败 "); return 0; } DWORD dwProcessId; GetWindowThreadProcessId(hWnd, &dwProcessId); printf("进程ID:%d ", dwProcessId); //获取进程句柄 g_hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); if (NULL == g_hProcess) { printf("打开进程失败 "); return 0; } ModifySun(); ModifyGuanka(); ModifyMoney(); ModifyPause(); ModifyCDThread(0); getchar(); return 0; }