#include <stdio.h> class SunClass{ public: int SunTime; int SunValue; int SunAttr; }; int main() { SunClass *Sun=new SunClass; Sun->SunValue=100;javascript:void(0) printf("SunValue: %d ",Sun->SunValue); return 0; }如上代码定义了`SunClass`类,在主函数中我们为Sun实例指针动态分配了内存,分配的内存存储在栈中,而栈地址每次都会发生变化,所以分配的内存地址是不固定的,从而导致阳光的地址是动态的 好!现在我们就进入正题,开始挖掘游戏数据,先从最简单的阳光地址找起来吧,首先你需要运行游戏并附加植物大战僵尸进程,然后我们开启新的游戏,首次扫描我们先来遍历4字节的50,也就是搜索当前阳光的数量,当然你也可以尝试搜索金钱数量等,道理都是一样的,这里就拿阳光的搜索方法作为演示目标。
#include <iostream> #include <Windows.h> int GetDyAddr(int Pid,int Base, int Offset[], int len) { int temp; HANDLE Process; Process = OpenProcess(PROCESS_ALL_ACCESS, false, Pid); ReadProcessMemory(Process, (LPVOID)Base, &temp, 4, NULL); for (int i = 0; i < len; i++) { if (i == len - 1) temp += Offset[i]; else ReadProcessMemory(Process, (LPVOID)(temp + Offset[i]), &temp, 4, NULL); } return temp; } int main() { int base; int offset[3]; int PID = 5772; base = 0x006a9ec0; offset[0] = 0x768; offset[1] = 0x5560; int addr = GetDyAddr(PID, base, offset, 2); printf("进程地址:%x ", addr); HANDLE Process = OpenProcess(PROCESS_ALL_ACCESS, false, PID); WriteProcessMemory(Process, (LPVOID)addr,&PID,4,0); }
#include <stdio.h> #include <Windows.h> byte *ReadByteSet(DWORD Pid, DWORD Base, DWORD Size) { HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, 0, Pid); byte *buf = new byte[Size]; ReadProcessMemory(handle, (LPVOID)Base, buf, Size, NULL); return buf; } int main() { byte *Buff = new byte[10]; Buff = ReadByteSet(2232, 0x00401000, 10); for (int i = 0; i < 10; i++) printf("%02X ", Buff[i]); return 0; }既然有读取内存字节集,那么就有写入字节集,如下代码就是一种字节集写入的实现方式。
#include <stdio.h> #include <Windows.h> BOOL WriteByteSet(DWORD Pid, DWORD Base, unsigned char *ShellCode, DWORD Size) { BYTE *Buff = new BYTE[Size]; memset(Buff, *ShellCode, Size); HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, 0, Pid); BOOL Ret = WriteProcessMemory(handle, (LPVOID)Base, Buff, Size, NULL); if (Ret) return TRUE; else return FALSE; } int main() { unsigned char shell[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }; BOOL temp = WriteByteSet(3772, 0x00401010, shell, 8); return 0; }想要实现阳光自动收集,只需要将`0x0043158F`机器码`0x75 0x08`修改为`0xEB 0x08`即可实现效果。
unsigned char shell[] = { 0xEB }; BOOL temp = WriteByteSet(9744, 0x0043158F, shell, 1);
int main() { int base; int offset[4]; int PID = 1292; base = 0x006a9f38; offset[0] = 0x768; offset[1] = 0xac; offset[2] = 0x58; int addr = GetDyAddr(PID, base, offset, 3); printf("阳光吐出动态地址:%x ", addr); HANDLE Process = OpenProcess(PROCESS_ALL_ACCESS, false, PID); int SunOffset = 0; int SunNum = 10; while (TRUE) { for (int i = 0; i < 5; i++) { WriteProcessMemory(Process, (LPVOID)(addr + SunOffset), &SunNum, 4, NULL); SunOffset = SunOffset + 0x14c; printf("搞事 fuck ok "); } SunOffset = 0; Sleep(1000); } return 0; }当我们进入游戏种植好太阳花以后,我们开启这个辅助,即可实现让前四个太阳花吐出阳光,最后种植的太阳花则不修改,为了防止程序出现假死我通过sleep函数让太阳花每一秒吐出一个阳光,这样修改的话会很有节奏感。
int main() { int PID = 3612; unsigned char Auto[] = { 0xEB }; unsigned char Suns[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }; BOOL ret = WriteByteSet(PID, 0x0043158F, Auto, 1); BOOL ret1 = WriteByteSet(PID, 0x0045FA7D, Suns, 6); if (ret != 0 & ret1 != 0) { printf("您的向日葵已打包,请注意查收 "); } return 0; }最终配合自动收集阳光,即可实现如下图所示的变态功能,其实这也不算变态,毕竟还有更加变态的,其实这种修改方式并不完美,因为我们的阳光数量可能是一个整数类型,如果不加以控制,当整数变量到达所能承载的最大范围时,则程序会发生整数溢出,轻则阳光变为负数,重则直接崩溃卡死。
mov eax,226 call 0x005AF400 mov edi,eax add edi,64再来分析第二个,第二个相对于第一个来说就好找许多了,因为它是一个动态地址,如下图我们记下 `13DCE000` 这个动态地址,然后直接在X64dbg中脱离游戏,这里不能结束游戏,如果结束了下次该地址又会发生变化。
pushad mov eax,226 call 0x005AF400 mov edi,eax add edi,64 mov esi,dword ptr ds:[ 006a9ec0 ] mov esi,dword ptr ds:[ esi + 768 ] push 0 push 4 push 3c push edi mov ecx,esi call 0x40cb10 popad发现每当我们点击注入以后,程序中就会多出一个太阳,说明我们的汇编代码没有问题
#include <stdio.h> #include <Windows.h> void AddSun() { __asm{ pushad mov eax, 226 mov ebx, 0x005AF400 call ebx mov edi, eax add edi, 64 mov esi, dword ptr ds : [0x006a9ec0] mov esi, dword ptr ds : [esi + 0x768] push 0h push 0x4 push 0x3c push edi mov ecx, esi mov edx, 0x40cb10 call edx popad } } void InjectCode(DWORD dwProcId, LPVOID mFunc) { HANDLE hProcess,hThrea? LPVOID mFuncAddr,ParamAddr; DWORD NumberOfByte; hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcId); mFuncAddr = VirtualAllocEx(hProcess, NULL, 128, MEM_COMMIT, PAGE_EXECUTE_READWRITE); WriteProcessMemory(hProcess, mFuncAddr, mFunc, 128, &NumberOfByte); hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)mFuncAddr, ParamAddr, 0, &NumberOfByte); WaitForSingleObject(hThread, INFINITE); VirtualFreeEx(hProcess, mFuncAddr, 128, MEM_RELEASE); CloseHandle(hThread); CloseHandle(hProcess); } int main() { for (int i = 0; i < 10;i++) InjectCode(3644, AddSun); }