所谓 External Trainer, 就是我们的工具和游戏不在一个进程,需要进行跨进程修改。
Windows为我们提供了一系列的 External 类 API,我们可以在MSDN中搜索带有Ex的API:
我们可以看到很多External 跨进程的函数。这些我们都可以进行利用,进行跨进程创建,访问,或者读写。
还有几个比较经典的 跨进程 External 访问内存的函数是 CreateRemoteThread, ReadMemoryProcess, WriteMemoryProcess .....
下面以 寻找 太吾绘卷 的基址 作为例子
我已经找到天数的偏移为:
std::vector daysOffset = { 0x004A2308, 0x210, 0x170, 0x60, 0x38, 0x8, 0x10, 0x8EC};模块为: mono-2.0-bdwgc.dll
首先我们需要找到模块地址
ULONGLONG getModuleBaseAddr(TCHAR* name, DWORD pid) { HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid); //扫描游戏进程的所有模块 if (hSnap == INVALID_HANDLE_VALUE) //扫描失败,退出 { DWORD error = GetLastError(); return NULL; } MODULEENTRY32 me; me.dwSize = sizeof(MODULEENTRY32); if (Module32First(hSnap, &me)) { do { if (_tcscmp(me.szModule, name) == 0) // 如果找到了我们需要的模块 { CloseHandle(hSnap); return (ULONGLONG)(me.modBaseAddr); // 返回此模块地址 } } while (Module32Next(hSnap, &me)); }}接着我们需要通过找到的模块地址和偏移找到天数的地址:
ULONGLONG getFinalAddddy(std::vector offsetVector, ULONGLONG BaseAddr, HANDLE hProcess){ DWORD offsetNum = offsetVector.size(); // 获取偏移的数量 ULONGLONG myAddy = BaseAddr; for (int i = 0; i < offsetNum - 1; i++) { ReadProcessMemory(hProcess, LPCVOID(myAddy + offsetVector), &myAddy, sizeof(ULONGLONG), NULL); // 遍历偏移地址 } myAddy += offsetVector[offsetNum - 1]; return myAddy;}寻找天数最终的地址:
std::vector daysOffset = { 0x004A2308, 0x210, 0x170, 0x60, 0x38, 0x8, 0x10, 0x8EC}; // 天数偏移ULONGLONG bdwgcModuleBaseAddr = getModuleBaseAddr((TCHAR*)(TEXT("mono-2.0-bdwgc.dll")), processId); // 模块地址ULONGLONG dayAddress = getFinalAddddy(daysOffset, bdwgcModuleBaseAddr, hProcess); // 天数最终地址寻找到最终天数地址我们就可以使用WriteMemoryProcess(),ReadMemoryProcess()进行读写
External Trainer 修改游戏进程的流程如下:
工具雏形:
源码地址:
https://github.com/absolutelycold/TaiWuWarrior
proc.h 解释
DWORD getPIDByName(TCHAR* name); // 通过进程名获取Process IDHANDLE getProcessHandle(DWORD pid); // 通过 pid 获取进程句柄ULONGLONG getModuleBaseAddr(TCHAR* name, DWORD pid); // 获取模块地址ULONGLONG getFinalAddddy(std::vector offsetVector, ULONGLONG BaseAddr, HANDLE hProcess); // 通过偏移寻找地址BOOL writeToMemoryInt(HANDLE hProcess, ULONGLONG addr, DWORD value); // 写入目标进程指定地址 4 字节大小的数据DWORD readMemoryInt(HANDLE hProcess, ULONGLONG addr); // 读取目标进程指定地址 4 字节大小地址
来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |