import ctypes
import struct

k32 = ctypes.windll.kernel32
pid = 43084
h = k32.OpenProcess(0x10 | 0x400, False, pid)
assert h, "cannot open process"

addr = 0x10000
mbi = (ctypes.c_byte * 48)()
br = ctypes.c_size_t()

keywords = [b"SkillIcons", b"skillicon", b"ActiveSkills", b"Metadata/Skills"]
found = set()

while k32.VirtualQueryEx(h, ctypes.c_void_p(addr), mbi, 48):
    base_addr = struct.unpack_from('<Q', bytes(mbi), 0)[0]
    region_size = struct.unpack_from('<Q', bytes(mbi), 24)[0]
    state = struct.unpack_from('<I', bytes(mbi), 32)[0]
    protect = struct.unpack_from('<I', bytes(mbi), 36)[0]

    if state == 0x1000 and (protect & 0xEE) and not (protect & 0x101):
        if region_size <= 64 * 1024 * 1024:
            buf = (ctypes.c_char * min(region_size, 4 * 1024 * 1024))()
            for off in range(0, region_size, len(buf)):
                cur_len = min(len(buf), region_size - off)
                if k32.ReadProcessMemory(h, ctypes.c_void_p(base_addr + off), buf, cur_len, ctypes.byref(br)):
                    raw = bytes(buf)[:br.value]
                    for kw in keywords:
                        p = 0
                        while True:
                            idx = raw.find(kw, p)
                            if idx == -1: break
                            # inspect full string (ascii or utf16)
                            # backwards to find start
                            start = idx
                            while start > 0 and raw[start-1] >= 0x20 and raw[start-1] <= 0x7E:
                                start -= 1
                            end = idx
                            while end < len(raw) and raw[end] >= 0x20 and raw[end] <= 0x7E:
                                end += 1
                            s = raw[start:end].decode('ascii', errors='ignore')
                            if len(s) > 10 and s not in found:
                                found.add(s)
                                print(f"0x{base_addr + off + start:012X}: {s}")
                                if len(found) >= 50: break
                            p = idx + len(kw)
                        if len(found) >= 50: break
                if len(found) >= 50: break
    addr = base_addr + region_size
    if len(found) >= 50: break

k32.CloseHandle(h)
