import ctypes
import ctypes.wintypes as w
import struct
import subprocess

k32 = ctypes.WinDLL("kernel32", use_last_error=True)
k32.OpenProcess.restype = w.HANDLE
k32.ReadProcessMemory.argtypes = [
    w.HANDLE, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t, ctypes.POINTER(ctypes.c_size_t)
]
k32.ReadProcessMemory.restype = w.BOOL

def rpm(h, addr, size):
    buf = (ctypes.c_ubyte * size)()
    got = ctypes.c_size_t(0)
    if not k32.ReadProcessMemory(h, ctypes.c_void_p(addr), buf, size, ctypes.byref(got)):
        return None
    return bytes(buf[: got.value])

def rpm_u64(h, addr):
    b = rpm(h, addr, 8)
    return struct.unpack("<Q", b)[0] if b and len(b) == 8 else 0

out = subprocess.check_output(['powershell', '-Command', '(Get-Process -Name *PathOfExile*).Id'])
pid = int(out.decode().split()[0])
h = k32.OpenProcess(0x1F0FFF, False, pid)

igs = 0x48514e50f10
for aio in [0x290, 0x2A0]:
    ai = rpm_u64(h, igs + aio)
    if not ai: continue
    print(f"=== Testing AreaInstance at igs+{aio:#x} = {ai:#x} ===")
    for toff in [0x8A0, 0x8B8, 0x8C8, 0x8D0, 0x61C, 0x644]:
        b = rpm(h, ai + toff, 64)
        if b:
            vals = struct.unpack("<16I", b)
            print(f"  toff {toff:#x}: {vals[:8]}")
            # check pointers
            ptrs = struct.unpack("<8Q", b)
            for pi, p in enumerate(ptrs):
                if 0x100000000 <= p <= 0x7FFFFFFFFFF:
                    pb = rpm(h, p, 32)
                    if pb:
                        pvals = struct.unpack("<8I", pb)
                        print(f"    ptr[{pi}] @ +{toff+pi*8:#x} -> {p:#x}: {pvals}")
