"""dump_260k_content.py For a few 260KB regions, dump first 128 bytes + mid + tail to characterize whether they're zeroed (free pool), structured (live d3d9 surface), or texture data.""" import ctypes, ctypes.wintypes as wt, sys, struct k = ctypes.windll.kernel32 k.OpenProcess.argtypes = [wt.DWORD, wt.BOOL, wt.DWORD]; k.OpenProcess.restype = wt.HANDLE k.ReadProcessMemory.argtypes = [wt.HANDLE, wt.LPCVOID, wt.LPVOID, ctypes.c_size_t, ctypes.POINTER(ctypes.c_size_t)] k.ReadProcessMemory.restype = wt.BOOL k.VirtualQueryEx.argtypes = [wt.HANDLE, wt.LPCVOID, ctypes.c_void_p, ctypes.c_size_t] k.VirtualQueryEx.restype = ctypes.c_size_t class MBI(ctypes.Structure): _fields_ = [("BaseAddress", ctypes.c_void_p), ("AllocationBase", ctypes.c_void_p), ("AllocationProtect", wt.DWORD), ("RegionSize", ctypes.c_size_t), ("State", wt.DWORD), ("Protect", wt.DWORD), ("Type", wt.DWORD)] def rd(h, va, n): buf = (ctypes.c_ubyte * n)(); sz = ctypes.c_size_t(0) if not k.ReadProcessMemory(h, va, buf, n, ctypes.byref(sz)): return None return bytes(buf[:sz.value]) pid = int(sys.argv[1]) h = k.OpenProcess(0x410, False, pid) if not h: print("OpenProcess fail"); sys.exit(2) # Find 260KB regions candidates = [] mbi = MBI(); addr = 0 while k.VirtualQueryEx(h, addr, ctypes.byref(mbi), ctypes.sizeof(mbi)): base = mbi.BaseAddress or 0 if mbi.State == 0x1000 and mbi.RegionSize == 266240 and (mbi.Type & 0x20000): candidates.append(base) next_addr = base + mbi.RegionSize if next_addr <= addr: break addr = next_addr if addr >= 0x80000000: break print(f"260KB regions: {len(candidates)}") # Histogram of first DWORD across ALL of them from collections import Counter first_dwords = [] for b in candidates: d = rd(h, b, 4) if d: first_dwords.append(struct.unpack('32 else ''}") k.CloseHandle(h)