
本文详解 pymem 中多级指针(pointer-to-pointer)的正确解析方法,解决 `could not read memory` 和 `typeerror: cannot be converted to pointer` 等常见错误,通过 `remotepointer` 安全获取最终内存地址并写入 float 值。
在使用 PyMem 进行游戏内存修改时,直接对多级指针链(如 base + offset1 → ptr1 + offset2 → ptr2 + offset3 → target)进行手动 read_long() 嵌套极易出错——尤其当某一级指针为空(0x0)、指向受保护/未分配内存,或地址计算溢出时,就会触发 WinAPIError: 299(ERROR_PARTIAL_COPY),即“只能读取部分内存”,本质是目标地址不可访问。
你原始代码中的核心问题有三处:
- 指针解引用逻辑错误:getPtrAdrr() 中循环内对非末尾 offset 使用了 pm.read_long(addr + i),但未校验 addr 是否为有效指针(可能为 0 或非法地址),导致首次 read_long() 就崩溃;
- 类型误用:pm.write_float() 要求传入有效的、可写的内存地址(int 类型),而你的 getPtrAdrr() 返回值若因异常中断,可能为 None 或非整数,引发 TypeError: cannot be converted to pointer;
- 缺乏错误防护与调试信息:未检查模块基址是否获取成功、未验证每级指针有效性,难以定位哪一级失效。
✅ 正确解法:使用 PyMem 内置的 RemotePointer 类(推荐方式)
RemotePointer 是 PyMem 专为多级指针设计的安全封装,它自动处理地址有效性检查(内部调用 ReadProcessMemory 并捕获 WinAPI 错误),并支持链式解引用,显著提升健壮性。
以下是修复后的完整、可运行示例:
from pymem import Pymem
from pymem.process import module_from_name
# 初始化进程
pm = Pymem("xxx.exe")
game_module = module_from_name(pm.process_handle, "xxx")
if not game_module:
raise RuntimeError("Failed to find module 'xxx.dll'")
base_address = game_module.lpBaseOfDll
def get_pointer_address(base: int, offsets: list) -> int:
"""
安全解析多级指针,返回最终目标地址(含最后一级偏移)
:param base: 模块基址或一级指针地址
:param offsets: 偏移量列表,如 [0x410, 0xC8, 0x3B0, 0x4C8, 0x158, 0xAF0]
:return: 最终内存地址(int)
"""
from pymem.pointer import RemotePointer
pointer = RemotePointer(pm.process_handle, base)
for i, offset in enumerate(offsets):
if i == len(offsets) - 1: # 最后一级:返回地址+偏移(即目标值位置)
return pointer.value + offset
else: # 中间级:解引用,更新 pointer 为下一级地址
pointer = RemotePointer(pm.process_handle, pointer.value + offset)
return pointer.value # fallback(理论上不会执行到此处)
def unlimited_hunger():
"""持续将饥饿值设为 100.0"""
target_addr = get_pointer_address(
base_address + 0x08959C68,
[0x410, 0xC8, 0x3B0, 0x4C8, 0x158, 0xAF0]
)
try:
pm.write_float(target_addr, 100.0)
print(f"[✓] Hunger updated at {hex(target_addr)}")
except Exception as e:
print(f"[✗] Failed to write hunger: {e}")
# 启动循环(注意:实际 GUI 中应避免阻塞主线程,建议用 threading.Timer 或异步调度)
# while True:
# unlimited_hunger()
# time.sleep(0.5)? 关键注意事项:
- ✅ 始终校验模块加载:module_from_name() 可能返回 None,需显式判断;
- ✅ RemotePointer 自动处理异常:若某级指针无效(如 0x0 或无读权限),pointer.value 会抛出 MemoryReadError,你可在 get_pointer_address 外层加 try/except 提供友好提示;
- ✅ GUI 集成避坑:你报错栈显示 command=utility.unlimitedHunger() —— 这是在创建控件时立即执行函数,而非绑定回调!正确写法应为 command=utility.unlimitedHunger(不带括号),否则会启动时就进入死循环;
- ✅ 权限与稳定性:确保以管理员权限运行脚本;部分游戏启用 EAC/BattlEye 等反作弊,直接读写内存可能被封禁,请仅用于单机学习场景;
- ✅ 调试技巧:临时加入 print(hex(pointer.value)) 在每级解引用后输出地址,快速定位哪一级为空或异常。
总结:PyMem 的 RemotePointer 是处理多级指针的黄金标准。抛弃手动 read_long() 嵌套,改用该类不仅能规避 ERROR_PARTIAL_COPY (299) 和类型转换错误,还能让代码更清晰、鲁棒性更强。记住——安全的内存操作 = 显式校验 + 分层解引用 + 异常捕获。










