ReadProcessMemory读不到玩家生命值是因为权限不足、地址动态变化及反作弊防护。需以管理员权限OpenProcess获取PROCESS_VM_READ句柄,计算模块基址+偏移得到真实地址,并匹配进程位数与数据类型,但PPL和内核级反作弊仍会拦截。

ReadProcessMemory 为什么读不到玩家生命值
因为目标进程通常没给你开 PROCESS_VM_READ 权限,更大概率连句柄都拿不到。Windows 默认禁止跨进程内存读取,ReadProcessMemory 不是“调用就能读”,而是“有权限+有地址+有句柄才能读”。多数游戏进程还启用了 Protected Process Light(PPL)或反作弊驱动(如 Easy Anti-Cheat、BattlEye),直接调用会返回 ERROR_ACCESS_DENIED 或 ERROR_PARTIAL_COPY。
常见错误现象:ReadProcessMemory 返回 false,GetLastError() 是 5(拒绝访问)或 299(只读到部分数据);或者读出来全是 0 或随机值——那多半是地址错了,不是权限问题。
- 必须先用
OpenProcess获取带PROCESS_VM_READ标志的句柄,且目标进程未被保护 - 32 位程序不能读 64 位进程(反之亦然),
sizeof(SIZE_T)必须匹配 - 游戏中的“生命值”通常是浮点数(
float)或整型(int),但地址是动态的:每次启动、甚至每次进房间都可能变 - 没有“直接读生命值”的 API;你读的是某个内存地址上的值,而这个地址得靠外挂工具(如 Cheat Engine)扫描+追踪得到
Cheat Engine 扫描出的地址怎么在 C++ 里用
扫描出来的地址(比如 0x12345678)几乎一定是“模块基址 + 偏移”,不是绝对地址。游戏更新、加载不同 DLL、启用 ASLR 后,模块基址会变,硬写死地址必然失败。
正确做法是:先用 GetModuleBaseAddress(配合 EnumProcessModules)找到目标模块(如 game.exe 或 engine.dll)的基址,再叠加偏移。例如扫描得偏移 0xABCDEF,模块基址是 0x7FF700000000,真实地址就是 0x7FF700000000 + 0xABCDEF。
- 别信 Cheat Engine 显示的“静态地址”——它只是当前会话有效;勾选“Pointer scan”并找一级/二级指针链才可能稳定
- 如果地址链含指针(如
[[game.exe+1234]+5678]+90),就得用多次ReadProcessMemory解引用,每次读出下一级地址 - 读指针时注意目标进程字长:64 位进程里指针是 8 字节,必须用
uint64_t接收,用int或DWORD会截断
ReadProcessMemory 调用失败的三个高频原因
不是代码写错,而是环境卡死。调试时建议每步都检查 GetLastError():
-
OpenProcess失败 → 检查目标进程是否以管理员权限运行,你的程序是否也以管理员身份启动;否则连句柄都拿不到 -
ReadProcessMemory返回 false 且GetLastError() == 299→ 目标地址所在内存页不可读(MEM_COMMIT但没PAGE_READONLY或PAGE_READWRITE),或该区域已被释放 - 读出来数值明显不对(如生命值=1.23e-38)→ 类型不匹配:用
int*去读float内存,或大小端搞反(但 x86/x64 都是小端,一般不用管)
示例片段(简化版,仅示意流程):
HANDLE hProc = OpenProcess(PROCESS_VM_READ, FALSE, dwPID);
if (!hProc) { /* 处理错误 */ }
uintptr_t baseAddr = GetModuleBaseAddress(dwPID, _T("game.exe"));
uintptr_t finalAddr = baseAddr + 0x123456;
float health;
SIZE_T bytesRead;
if (ReadProcessMemory(hProc, (LPCVOID)finalAddr, &health, sizeof(health), &bytesRead)) {
// 成功
}
反作弊和系统防护让这事变得极其脆弱
哪怕你绕过了基础权限检查(比如用驱动提权),现代游戏普遍使用内核级反作弊(如 Vanguard、Riot Vanguard、Easy Anti-Cheat 的 eac_game_x64.sys)。它们会监控 ReadProcessMemory 调用、挂钩 NtReadVirtualMemory、甚至直接蓝屏检测进程行为。一旦触发,轻则封号,重则系统级拦截——你的 ReadProcessMemory 可能根本发不到内核,就被中间层静默丢弃了。
真正稳定读内存的方式,基本只存在于:已关闭反作弊的单机游戏、本地测试环境、或你自己写的 demo 进程。线上多人游戏里,把地址算对、权限拿到、类型读准,只是第一步;能不能活过三秒,取决于反作弊今天心情如何。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











