使用ReadProcessMemory读取GBA模拟器内存值异常求助
问题描述
尝试用Python调用ReadProcessMemory读取VisualBoyAdvance模拟器的GBA内存,内存查看器显示GBA内存地址0xD273的值应为81,但代码每次返回随机字节值(如15、255、11、195等)。已确认进程ID正确,且必须使用32位Python运行,否则会出现ERROR_PARTIAL_COPY(错误码299)。疑惑未指定基地址是否是问题所在。
示例输出:
result: 1, err code: 0, bytesRead: 1 data: 0000000000000015h 21
原代码:
import ctypes as c from ctypes import wintypes as w import psutil # Must use py -3-32 vba_script.py vba_process_id = [p.pid for p in psutil.process_iter() if "visualboyadvance" in p.name()][0] pid = vba_process_id # I assume you have this from somewhere. k32 = c.WinDLL('kernel32', use_last_error=True) OpenProcess = k32.OpenProcess ReadProcessMemory = k32.ReadProcessMemory CloseHandle = k32.CloseHandle processHandle = OpenProcess(0x10, False, pid) addr = c.c_void_p(0xD273) dataLen = 8 data = c.c_byte() bytesRead = c.c_byte() result = ReadProcessMemory(processHandle, c.byref(addr), c.byref(data), c.sizeof(data), c.byref(bytesRead)) e = c.get_last_error() print('result: {}, err code: {}, bytesRead: {}'.format(result,e,bytesRead.value)) print('data: {:016X}h'.format(data.value)) print(data.value) CloseHandle(processHandle)
问题原因与解决办法
1. 核心错误:地址混淆
你直接使用的0xD273是GBA模拟器内部的游戏内存地址,而非Windows系统中VBA进程的虚拟内存地址。VBA会将GBA的内存映射到自身进程的虚拟内存空间中,你需要先找到这个映射区域的基地址,再加上0xD273的偏移量,才是要读取的正确虚拟内存地址。
可以用Cheat Engine这类工具查找VBA进程中对应GBA内存的基地址:
- 打开Cheat Engine,附加到VBA进程
- 在游戏中找到一个已知值(比如生命值),搜索该值找到对应的内存地址,查看该地址的基地址与偏移,最终得到GBA内存区域的基地址。
2. ReadProcessMemory参数错误
你调用ReadProcessMemory时,第二个参数传递了c.byref(addr),这是错误的。该参数需要的是目标内存的地址值,而不是addr变量自身的地址。你之前的写法导致读取的是Python进程中addr变量所在的内存区域,自然得到随机值。
修正后的代码示例
import ctypes as c import psutil # 必须使用32位Python运行 vba_process_id = [p.pid for p in psutil.process_iter() if "visualboyadvance" in p.name().lower()][0] k32 = c.WinDLL('kernel32', use_last_error=True) OpenProcess = k32.OpenProcess ReadProcessMemory = k32.ReadProcessMemory CloseHandle = k32.CloseHandle # 打开进程,使用PROCESS_VM_READ权限 PROCESS_VM_READ = 0x0010 processHandle = OpenProcess(PROCESS_VM_READ, False, vba_process_id) # ===== 替换为你实际找到的GBA内存基地址 ===== gba_memory_base = 0x00400000 # 示例值,需自行查找 # 计算目标地址:基地址 + GBA内存偏移0xD273 target_addr = c.c_void_p(gba_memory_base + 0xD273) data = c.c_byte() bytes_read = c.c_size_t() # 修正第二个参数,直接传递target_addr(目标内存地址) result = ReadProcessMemory( processHandle, target_addr, c.byref(data), c.sizeof(data), c.byref(bytes_read) ) err_code = c.get_last_error() print(f'result: {result}, err code: {err_code}, bytesRead: {bytes_read.value}') print(f'data: {data.value:#018X}') print(f'decimal value: {data.value}') CloseHandle(processHandle)
关键修正点:
- 替换
gba_memory_base为你通过工具找到的实际基地址 - 调用
ReadProcessMemory时,第二个参数直接传递target_addr,而非c.byref(addr) - 使用
c.c_size_t()存储bytes_read,符合Windows API的参数类型要求
内容的提问来源于stack exchange,提问作者Jérémie Talbot-Pâquet
相关产品推荐
相关产品推荐

