本文详解 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),即“只能读取部分内存”,本质是目标地址不可访问。
你原始代码中的核心问题有三处:
✅ 正确解法:使用 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, 0x4
C8, 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)? 关键注意事项:
总结:PyMem 的 RemotePointer 是处理多级指针的黄金标准。抛弃手动 read_long() 嵌套,改用该类不仅能规避 ERROR_PARTIAL_COPY (299) 和类型转换错误,还能让代码更清晰、鲁棒性更强。记住——安全的内存操作 = 显式校验 + 分层解引用 + 异常捕获。