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
k32.VirtualQueryEx.argtypes = [w.HANDLE, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t]
k32.VirtualQueryEx.restype = ctypes.c_size_t

class MEMORY_BASIC_INFORMATION(ctypes.Structure):
    _fields_ = [
        ("BaseAddress", ctypes.c_void_p),
        ("AllocationBase", ctypes.c_void_p),
        ("AllocationProtect", w.DWORD),
        ("PartitionId", w.WORD),
        ("RegionSize", ctypes.c_size_t),
        ("State", w.DWORD),
        ("Protect", w.DWORD),
        ("Type", w.DWORD),
    ]

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])

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
ai = struct.unpack("<Q", rpm(h, igs + 0x290, 8))[0]
print(f"AreaInstance: {ai:#x}")

b_ai = rpm(h, ai, 0x1200)

print("Scanning AreaInstance for std::vector or pointers to buffers 50KB - 4MB...")
for off in range(0, len(b_ai) - 24, 8):
    p1, p2, p3 = struct.unpack_from("<3Q", b_ai, off)
    # std::vector layout: First, Last, End
    if 0x100000000 <= p1 <= 0x7FFFFFFFFFF and 0x100000000 <= p2 <= 0x7FFFFFFFFFF:
        if p2 >= p1 and (p2 - p1) >= 40000 and (p2 - p1) <= 10000000:
            count = p2 - p1
            mbi = MEMORY_BASIC_INFORMATION()
            k32.VirtualQueryEx(h, ctypes.c_void_p(p1), ctypes.byref(mbi), ctypes.sizeof(mbi))
            print(f"Candidate StdVector at ai+{off:#x}: First={p1:#x}, Last={p2:#x}, Size={count} bytes ({count/1024:.1f} KB)")
            # sample first 32 bytes
            sample = rpm(h, p1, 32)
            if sample:
                print(f"   Sample: {sample[:16].hex(' ')} | non-zero={sum(1 for x in sample if x != 0)}")
