Skip to content Skip to sidebar Skip to footer

Python Readprocessmemory Not Reading Enough Bytes

Okay all you ctypes gurus out there... I've got a python script that reads a memory address a hundred times a second. The value stored at this memory address represents an unsigned

Solution 1:

The expression b'.'*4 created the constant '....' in the code object for your module. This constant is an object like any other in Python, except it's supposed to be immutable. You violated that assumption by using ctypes. For example:

>>>from ctypes import *>>>deff():...  s = b'.'*4...  buf = c_char_p(s)...  memset(buf, 0, 1)...>>>f.__code__.co_consts
(None, '.', 4, 0, 1, '....')
>>>c_char_p(f.__code__.co_consts[5]).value
'....'

>>>f() # set the first character to "\x00">>>f.__code__.co_consts
(None, '.', 4, 0, 1, '\x00...')
>>>c_char_p(f.__code__.co_consts[5]).value
''

The value descriptor of a c_char_p expects the buffer to be a null-terminated string. With the first byte mutated to 0, value returns an empty string. Now look at the value of 191 packed as a little-endian, unsigned long:

>>>import struct>>>struct.pack("<L", 191)
'\xbf\x00\x00\x00'

That should explain why bufferSize became 1 on the 2nd pass.

If the string had been interned, you could either crash the interpreter or render it unusable. Most strings used within the CPython API are interned, as are names of modules, classes, functions, attributes, and variables. For example:

>>>from ctypes import *>>>import numbers>>>s = 'numbers'>>>b = c_char_p(s)>>>r = memset(b, 100, 1)>>>s
'dumbers'

>>>numbers.Number
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'numbers' is not defined

>>>globals()[s].Number
<class 'numbers.Number'>

create_string_buffer is a convenience function to create and set a char array in one pass:

>>>b1 = create_string_buffer('test1')>>>type(b1)
<class 'ctypes.c_char_Array_6'>
>>>b1.value
'test1'

>>>b2 = (c_char * 6)()>>>b2.value = 'test2'>>>type(b2)
<class 'ctypes.c_char_Array_6'>
>>>b2.value
'test2'
>>>b2.raw
'test2\x00'

You could also have passed a reference to an unsigned long instead:

value = c_ulong() 
bytesRead = c_ulong()
rpm(ph, addy, byref(value), sizeof(value), byref(bytesRead))

Another example violating the immutability assumption. Integers less than 256 are cached, i.e. code that uses them always refers to the same set of objects. So if you mutate one of them, it affects the entire system:

>>>offset = sizeof(c_size_t)*2>>>addr = id(200) + offset>>>n = c_int.from_address(addr)>>>n
c_long(200)
>>>n.value = 2000000>>>>>>200 + 1
2000001

Solution 2:

Okay, well I figured it out. I needed to use ctypes.create_string_buffer(init_or_size[, size]) instead of the c_char_p that I tried.

The working code:

from time import sleep
from ctypes import *
from struct import *
pid = 0x0D50
op = windll.kernel32.OpenProcess
rpm = windll.kernel32.ReadProcessMemory
ch = windll.kernel32.CloseHandle
PAA = 0x1F0FFF
addy = 0x543A88F0
ph = op(PAA,False,int(pid)) #program handle
lastvalue = 0whileTrue:

   buff = create_string_buffer(4)
   bufferSize = (sizeof(buff))
   bytesRead = c_ulong(0)

   if rpm(ph,addy,buff,bufferSize,byref(bytesRead)):
       value = unpack('I',buff)[0]
       if lastvalue != value:
           print value
           print bytesRead
           lastvalue = value
   sleep(.01)

Post a Comment for "Python Readprocessmemory Not Reading Enough Bytes"