import ctypes
import struct

PROCESS_ALL_ACCESS = 0x1F0FFF
kernel32 = ctypes.windll.kernel32
h_proc = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, 43084)

def rpm(addr, size):
    buf = ctypes.create_string_buffer(size)
    bytes_read = ctypes.c_size_t(0)
    if kernel32.ReadProcessMemory(h_proc, ctypes.c_void_p(addr), buf, size, ctypes.byref(bytes_read)):
        return buf.raw
    return None

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

def rpm_f32(addr):
    d = rpm(addr, 4)
    return struct.unpack("<f", d)[0] if d else 0.0

def rpm_u32(addr):
    d = rpm(addr, 4)
    return struct.unpack("<I", d)[0] if d else 0

mod_base = 0x7FF6AFC20000
igs = rpm_u64(mod_base + 0x4430108)
print(f"InGameState: {hex(igs)}")

# UI Root at InGameState + 0x38 or check children vector
ui_root = rpm_u64(igs + 0x38)
print(f"UI Root (igs + 0x38): {hex(ui_root)}")

# In POE UI Element:
# children vector is at +0x20..+0x38, +0x40..+0x58 or +0x58..+0x70?
# Let's inspect ui_root memory 0x0 .. 0x100
for off in range(0, 0x100, 8):
    val = rpm_u64(ui_root + off)
    if 0x20000000000 <= val <= 0x30000000000:
        print(f"ui_root + {hex(off)}: {hex(val)}")

# Let's check children vector at +0x58, +0x60, +0x68 or +0x68, +0x70, +0x78
for off in [0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68, 0x70]:
    p_start = rpm_u64(ui_root + off)
    p_end = rpm_u64(ui_root + off + 8)
    if 0x20000000000 <= p_start <= 0x30000000000 and 0x20000000000 <= p_end <= 0x30000000000:
        count = (p_end - p_start) // 8
        if 0 < count < 200:
            print(f"Children vector found at ui_root + {hex(off)}: count={count}, p_start={hex(p_start)}")
            for i in range(min(count, 30)):
                child_ptr = rpm_u64(p_start + i * 8)
                child_vtable = rpm_u64(child_ptr)
                print(f"  Child [{i}]: {hex(child_ptr)}, vtable={hex(child_vtable)} (RVA: +{hex(child_vtable - mod_base)})")

kernel32.CloseHandle(h_proc)
