6

I'm trying to read data from memory of a process by inputing the process name, then finding PID using psutil. So far I have this:

import ctypes
from ctypes import *
from ctypes.wintypes import *
import win32ui
import psutil # install, not a default module
import sys

# input process name
nameprocess = "notepad.exe"

# find pid
def getpid():
    for proc in psutil.process_iter():
        if proc.name() == nameprocess:
            return proc.pid

PROCESS_ID = getpid()

if PROCESS_ID == None:
    print "Process was not found"
    sys.exit(1)


# read from addresses
STRLEN = 255

PROCESS_VM_READ = 0x0010
process = windll.kernel32.OpenProcess(PROCESS_VM_READ, 0, PROCESS_ID)
readProcMem = windll.kernel32.ReadProcessMemory
buf = ctypes.create_string_buffer(STRLEN)

for i in range(1,100): 
    if readProcMem(process, hex(i), buf, STRLEN, 0):
        print buf.raw


The last for loop should read and print contents of the first 100 addresses in the process if I'm getting this right. Only thing is, the output looks like complete gibberish.


There are 2 problems for me here: first, am I really reading the addresses from the selected process this way? And second, how can I figure how long in the loop I should go, if there is maybe some kind of end address?

Mazdak
  • 105,000
  • 18
  • 159
  • 188
DoctorEvil
  • 453
  • 3
  • 6
  • 18
  • I'm surprised you get any output. Address 1 is not committed memory normally. I'll make a working example and post an answer. – Mark Tolonen Sep 29 '18 at 17:17

2 Answers2

8

I didn't install psutil, but just pulled a process ID and valid virtual address using Task Manager and SysInternals VMMap. The numbers will vary of course.

Good practice with ctypes is to define the argument types and return value via .argtypes and .restype. Get your own instance of the kernel32 library because changing the attributes of the cached windll.kernel32 instance could cause issues with other modules using ctypes and kernel32.

You need a valid virtual address. In answer to your 2nd problem, I think VMMap proves there is a way to do it. Pick up a copy of Windows Internals to learn the techniques.

from ctypes import *
from ctypes.wintypes import *

PROCESS_ID = 9476 # From TaskManager for Notepad.exe
PROCESS_HEADER_ADDR = 0x7ff7b81e0000 # From SysInternals VMMap utility

# read from addresses
STRLEN = 255

PROCESS_VM_READ = 0x0010

k32 = WinDLL('kernel32')
k32.OpenProcess.argtypes = DWORD,BOOL,DWORD
k32.OpenProcess.restype = HANDLE
k32.ReadProcessMemory.argtypes = HANDLE,LPVOID,LPVOID,c_size_t,POINTER(c_size_t)
k32.ReadProcessMemory.restype = BOOL

process = k32.OpenProcess(PROCESS_VM_READ, 0, PROCESS_ID)
buf = create_string_buffer(STRLEN)
s = c_size_t()
if k32.ReadProcessMemory(process, PROCESS_HEADER_ADDR, buf, STRLEN, byref(s)):
    print(s.value,buf.raw)

Output (Note 'MZ' is the start of a program header):

255 b'MZ\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xff\xff\x00\x00\xb8\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x00\x00\x00\x0e\x1f\xba\x0e\x00\xb4\t\xcd!\xb8\x01L\xcd!This program cannot be run in DOS mode.\r\r\n$\x00\x00\x00\x00\x00\x00\x00\xd0\x92\xa7\xd1\x94\xf3\xc9\x82\x94\xf3\xc9\x82\x94\xf3\xc9\x82\x9d\x8bZ\x82\x8a\xf3\xc9\x82\xfb\x97\xca\x83\x97\xf3\xc9\x82\xfb\x97\xcd\x83\x83\xf3\xc9\x82\xfb\x97\xcc\x83\x91\xf3\xc9\x82\xfb\x97\xc8\x83\x8f\xf3\xc9\x82\x94\xf3\xc8\x82\x82\xf2\xc9\x82\xfb\x97\xc1\x83\x8d\xf3\xc9\x82\xfb\x976\x82\x95\xf3\xc9\x82\xfb\x97\xcb\x83\x95\xf3\xc9\x82Rich\x94\xf3\xc9\x82\x00\x00\x00\x00\x00\x00\x00\x00PE\x00\x00d\x86\x06\x00^\'\x0f\x84\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x00"'

Here's a screenshot of VMMap indicating the header address of notepad.exe:

VMMap Screenshot

Here's a screenshot of a hexdump of the content of notepad.exe that matches the output of the program:

hedump of the notepad.exe binary file

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • thanks for your answer. my endgoal with something like this would be to read data from a PC game while it is being played and get some info, but I feel like this is over my head. still, thanks for answering. – DoctorEvil Sep 30 '18 at 19:52
  • @DoctorEvil Yes, you do need to know what addresses have interesting information. VMMap can help find the data areas of a program, but you still need to make (or find a pre-made) tool to look at the memory and figure out where stuff like current hit points, max hit points, etc. are stored. It's often not too hard. You search for your character name in the data areas and the other stats are usually close by. Good luck! FYI, thanks == upvotes ;^) – Mark Tolonen Sep 30 '18 at 20:19
  • There's the upvote :) Would a tool like HxD be able to see something like player name for example while the game is running, just to determine the right address? Also, what if I turn off PC and then next day run the game, would the same address have the info again? – DoctorEvil Oct 01 '18 at 07:06
  • @DoctorEvil I’m not familiar with that tool, but the address of items is very likely to change between launchings of the process. – Mark Tolonen Oct 01 '18 at 15:53
0

On Windows, the PyMem library can help you with that: https://pymem.readthedocs.io/

2080
  • 1,223
  • 1
  • 14
  • 37