1

I'm using cheat engine to find a multipointer that leads to an address that has value of list of entities. I found said multipointer, but I have no clue how to read it using python.

2
  • Which OS do you use? Commented Jan 27, 2024 at 14:17
  • I use Windows 10. Commented Jan 27, 2024 at 14:50

1 Answer 1

1

Here's an example on how to read from a process, on Windows, using the Windows API and ctypes. Doesn't require external packages / modules.

Error and argument handling is minimal.

Basically:

  • Open the process using OpenProcess for address space read. This only requires the process PID.

  • Read a whole page from the process, using ReadProcessMemory. You'll need to offset in the returned buffer if you want something within the page.

  • Demonstrate how to "cast" from bytes to, in this instance, DWORD. You can of course use another ctypes numerous types instead of DWORD (which is defined as ctypes.c_uint32 iirc).

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import ctypes
import ctypes.wintypes as wt

# Windows API


kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

OpenProcess = kernel32.OpenProcess
OpenProcess.restype = wt.HANDLE
OpenProcess.argtypes = (
    wt.DWORD,  # DWORD dwAccess
    wt.BOOL,  # BOOL bInheritHandle
    wt.DWORD,  # DWORD ProcessId
)

ReadProcessMemory = kernel32.ReadProcessMemory
ReadProcessMemory.restype = wt.BOOL
ReadProcessMemory.argtypes = (
    ctypes.c_void_p,  # HANDLE hProcess
    ctypes.c_void_p,  # LPCVOID lpBaseAddress
    ctypes.c_void_p,  # LPVOID  lpBuffer
    ctypes.c_size_t,  # SIZE_T  nSize
    ctypes.POINTER(ctypes.c_size_t)  # SIZE_T  *lpNumberOfBytesRead
)

CloseHandle = kernel32.CloseHandle
CloseHandle.restype = wt.BOOL
CloseHandle.argtypes = (wt.HANDLE,)


def read_from_process(base_addr: int, pid: int) -> bytes:
    """Read a whole page from the given process.

    Args:
        base_addr: The base address to read from. This address is always rounded down to a 4KB page boundary.
        pid: the pid of the process.

    Raises:
        OsError: either the process couldn't be opened or there was an error reading from the process.

    Returns:
        The content of the page read from the process as a bytes instance.
    """
    # size of a page, in bytes.
    page_size = 4096

    # base of the page.
    base_addr &= 0xfffffffffffff000

    # open the process for address space reading.
    h_proc = OpenProcess(0x8 | 0x10,  # PROCESS_VM_OPERATION | PROCESS_VM_READ
                         False,
                         pid)
    if h_proc == 0:
        # couldn't open the process; either wrong pid or not enough rights to open it.
        raise ctypes.WinError()

    # read from the process.
    buffer = ctypes.create_string_buffer(b'', page_size)
    nobr = ctypes.c_size_t(0)
    ret_val = ReadProcessMemory(h_proc, base_addr, buffer, page_size, ctypes.byref(nobr))
    if ret_val == 0:
        CloseHandle(h_proc)
        raise ctypes.WinError()

    CloseHandle(h_proc)
    return buffer.raw


def main():
    pid = 9708
    base_addr = 0x7ff6947c0000

    buffer = read_from_process(base_addr, pid)

    # example how to read 2 DWORDs (unsigned 32-bit) from the bytes buffer.
    dword_buffer = (wt.DWORD * 2).from_buffer_copy(buffer)

    # print some bytes from the bytes instance.
    print(buffer[0:8])

    # print DWORDs.
    print(f"{dword_buffer[0]:08x}")
    print(f"{dword_buffer[1]:08x}")

if __name__ == '__main__':
    main()

Test on the base of a PE module:

b'MZ\x90\x00\x03\x00\x00\x00'
00905a4d
00000003

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.