How do I look up the value of a multi-level pointer inside a process in Python?

后端 未结 1 1675
傲寒
傲寒 2021-01-27 19:13

I have a process, and I want to look up a value of an address inside that process but that address is a multi-level pointer and has a few offsets attached to it. How do I do thi

相关标签:
1条回答
  • 2021-01-27 19:34

    I'm answering my own question to document a way of doing this in Python 3.

    First you need some way to look up the pid of the process we are working on.

    I used the module psutil to do this, but there are other ways to do it too.

    import psutil
    
    def get_pid(process_name):
        pid = None
        for proc in psutil.process_iter():
            try:
                if (proc.name() == process_name):
                    pid = proc.pid
            except (PermissionError, psutil.AccessDenied):
                pass
        return pid
    

    Now we have the pid of the process we want to work on. We'll use that later to get the handle of the process we want to work on.

    Now I said it's a multi-level pointer. How that works is that we have an initial address. and a list of offsets. We first of all look up the value of our initial address. We then apply the first offset to that value to get the next address. We look up the value of that address, apply the next offset to that value and get the next address to look up. This can keep going depending on the size of your list of offsets, but say that last look up was the last one and that gives us our final address. When we get the value of that we get the actual value that we are after.

    To do this programmatically, we need the pid(For example 4045), the address(For example 0x0163B4D8), the list of offsets(For example [0x37C, 0x3C]) and the size of data(For example an unsigned int is 4 bytes, so that's the size of our data).

    from ctypes import *
    from ctypes.wintypes import *
    
    PROCESS_ALL_ACCESS = 0x1F0FFF
    
    def read_process_memory(pid, address, offsets, size_of_data):
        # Open the process and get the handle.
        process_handle = windll.kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
        size_of_data = 4 # Size of your data
        data = ""
        read_buff = create_string_buffer(size_of_data)
        count = c_ulong(0)
        current_address = address
        offsets.append(None) # We want a final loop where we actually get the data out, this lets us do that in one go.
        for offset in offsets:
            if not windll.kernel32.ReadProcessMemory(process_handle, current_address, cast(read_buff, LPVOID), size_of_data, byref(count)):
                return -1 # Error, so we're quitting.
            else:
                val = read_buff.value
                result = int.from_bytes(val, byteorder='little')
                # Here that None comes into play.
                if(offset != None):
                    current_address = result+offset
                else:
                    windll.kernel32.CloseHandle(process_handle)
                    return result
    

    That's the basic concept, and of course the code could be improved.

    0 讨论(0)
提交回复
热议问题