0

I am trying to read memory from a process (gameboy advance emulator) in Python using ReadProcessMemory. There is a memory viewer and I am supposed to get 81 at 0xD273 (see picture). I am new to this, I tried to do everything correctly by adding reference in the ReadProcessMemory, but there might be some things that are wrong. I am pretty sure I have the right process id since it matches the one in the task manager.

When I run my code, I get random byte values that are different everytime. 15, 255, 11, 195, but I think I should be getting 81.

I need to use python 32-bit to run the script otherwise I get error 299 (ERROR_PARTIAL_COPY).

Is there something that I'm doing wrong? I don’t specify the base address but I assumed it’s handled by the processHandle.

Here is my code and an example of the output:

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)

enter image description here

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • 2
    Are you trying to examine the address 0xD273 within the GameBoy emulator, or within the emulated GameBoy? Those are two entirely unrelated things.0 – jasonharper Dec 10 '22 at 20:39
  • I want to access the data from the game, so probably the emulated GameBoy – Jérémy Talbot-Pâquet Dec 10 '22 at 20:56
  • 2
    The emulated GameBoy memory is going to be somewhere within the memory space of the emulator process. It certainly cannot be at the very start of the memory space, which is effectively what you're trying to do with your current code. Unfortunately, I can't think of any good way of finding out the effect of the emulated memory. A not-so-good way would be to write down a distinctive-looking series of contiguous bytes from that Memory Viewer window, and search the process memory for that sequence - that will let you determine the offset (for this run of the emulator, at least). – jasonharper Dec 10 '22 at 21:09

1 Answers1

1

After reading @jasonharper answer, I found a way to get the actual address in the memory.

To get them, I used Cheat Engine, here was my procedure:

  1. In Cheat Engine, search for 87949181 (hex for BRUH, which is trainer's name). Any data that you know will not change is also fine.
  2. Find the address that really corresponds to it. Should have 0x00000050, 0x01000000, 0x0000FF99, 0x99000000, 0x00001600, 0x212D0316, DC00002D after (see picture 1). This address is a pointer. In my case, it's 0x07D2F370 (picture 2).
  3. Double click on the address and do a pointer scan. In my case, the pointer address 0x07D2F218. This is a dynamic address that will change everytime, so you need to find the static address.
  4. You can find that "visualboyadvance-m.exe"+02224064 -> 07D2F218. The base address is therefore 0x07D2F218 - 0x02224064 = 0x9a0000. The static address offset for the data I'm searching for is 0x02224064. The offset for the trainer's name data is 0x158.

After opening the process, to search in the memory, you can have a code like this:

base_addr = 0x9a0000 # "visualboyadvance-m.exe"
static_addr_offset = 0x02224064
address = base_addr + static_addr_offset + 0x158

k32 = c.WinDLL('kernel32', use_last_error=True)
buffer = c.create_string_buffer(buffer_size)
buffer_size=32
bytes_read = c.c_ulong(0)
if k32.ReadProcessMemory(processHandle, address, buffer, buffer_size, c.byref(bytes_read)):
    data = c.c_uint32.from_buffer(buffer)
    print(f"data: {data .value:X}")

This returns the right data that I'm looking for: data: 87949181.

Here are the pictures:

Memory Viewer Picture 1

Cheat Engine Picture 2

================================================================

================================================================

Bonus: The base address will change if you close the game and you will need to find it back everytime. There is some way of doing way it by getting the module with the name of the process pname. You can get it easily with psutil.

import win32process
import psutils

vba_process = [p for p in psutil.process_iter() if "visualboyadvance" in p.name()][0]
pid = vba_process.pid
pname = vba_process.name

k32 = c.WinDLL('kernel32', use_last_error=True)

processHandle = k32.OpenProcess(0x10, False, pid)

modules = win32process.EnumProcessModules(processHandle)
for module in modules:
   moduleFileName = win32process.GetModuleFileNameEx(processHandle, module)
   if pname in moduleFileName:
      base_address = module
      print("Success: Got Base Address:", hex(base_address))

Success: Got Base Address: 0x9a0000

Edit: Found how to get base address of process automatically