To all ctypes experts:
I am running this code in Python to read 0x400 entries from memory. Unfortunately the returned list only contains ~20 entries. It seems to stop reading at the first entry with the value equal to 0.
read_buffer = (ctypes.c_char * buffsize)()
lp_buffer = ctypes.byref(read_buffer)
n_size = ctypes.sizeof(read_buffer)
lp_number_of_bytes_read = ctypes.c_ulong(0)
ctypes.windll.kernel32.ReadProcessMemory(self.handle, ctypes.c_void_p(lp_base_address), lp_buffer, n_size, lp_number_of_bytes_read)
return read_buffer.value
Is there any explanation/fix for this? Here is an example output from my C++ implementation, where all 0x400 entries were read:
.value
reads a null-terminated string from the buffer. Use .raw
and trim to the known returned size.
Here's a comparison:
>>> import ctypes
>>> read_buffer = (ctypes.c_char * 20)(bytes([1,2,3,0,4,5,6]))
>>> read_buffer.value # reads until null byte
b'\x01\x02\x03'
>>> read_buffer.raw # entire 20-byte buffer
b'\x01\x02\x03\x00\x04\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> read_buffer.raw[:7] # trimmed to a known size
b'\x01\x02\x03\x00\x04\x05\x06'
This example read's CPython's own memory space and compares the memory read using two methods. Note that in CPython, id()
returns the memory address of a Python object:
import sys
import ctypes as ct
import ctypes.wintypes as w
k32 = ct.WinDLL('kernel32')
ReadProcessMemory = k32.ReadProcessMemory
ReadProcessMemory.argtypes = w.HANDLE, w.LPCVOID, w.LPVOID, ct.c_size_t, ct.POINTER(ct.c_size_t)
ReadProcessMemory.restype = w.BOOL
GetCurrentProcess = k32.GetCurrentProcess
GetCurrentProcess.argtypes = ()
GetCurrentProcess.restype = w.HANDLE
s = b'ABC\x00DEF' # object to example
obj_len = sys.getsizeof(s) # total object length (not string length)
data = ct.create_string_buffer(obj_len)
read = ct.c_size_t()
if ReadProcessMemory(GetCurrentProcess(), id(s), data, len(data), ct.byref(read)):
print(f'{data.raw[:read.value]}')
print(ct.string_at(id(s), obj_len))
Output:
b'\x02\x00\x00\x00\x00\x00\x00\x00\xb0\xb10\xa8\xf8\x7f\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\xc2\xe23-\xea\x99\xdd\x97ABC\x00DEF\x00'
b'\x02\x00\x00\x00\x00\x00\x00\x00\xb0\xb10\xa8\xf8\x7f\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\xc2\xe23-\xea\x99\xdd\x97ABC\x00DEF\x00'