"""position_sample_dump.py [count=10] For a few Position hits, print the surrounding bytes raw so we can visually inspect the layout. Goal: see if there's a heap-block header pattern we missed. """ import ctypes import ctypes.wintypes as wt import struct import sys POSITION_VT = 0x00797910 PROCESS_VM_READ = 0x10 PROCESS_QUERY_INFORMATION = 0x400 class MBI(ctypes.Structure): _fields_ = [('BaseAddress', ctypes.c_void_p), ('AllocationBase', ctypes.c_void_p), ('AllocationProtect', wt.DWORD), ('PartitionId', wt.WORD), ('RegionSize', ctypes.c_size_t), ('State', wt.DWORD), ('Protect', wt.DWORD), ('Type', wt.DWORD)] k = ctypes.windll.kernel32 k.OpenProcess.argtypes = [wt.DWORD, wt.BOOL, wt.DWORD]; k.OpenProcess.restype = wt.HANDLE k.CloseHandle.argtypes = [wt.HANDLE]; k.CloseHandle.restype = wt.BOOL 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, ctypes.c_void_p, ctypes.POINTER(MBI), ctypes.c_size_t] k.VirtualQueryEx.restype = ctypes.c_size_t def hexdump(addr, data, prefix=""): for i in range(0, len(data), 16): chunk = data[i:i+16] h = " ".join(f"{b:02x}" for b in chunk) a = "".join(chr(b) if 32 <= b < 127 else '.' for b in chunk) dws = " ".join(f"{struct.unpack_from(' 2 else 10 h = k.OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, False, pid) if not h: print(f"OpenProcess err={ctypes.get_last_error()}"); return 1 shown = 0 mbi = MBI() addr = 0 while k.VirtualQueryEx(h, addr, ctypes.byref(mbi), ctypes.sizeof(mbi)) and shown < want: pr = mbi.Protect & 0xff if (mbi.State == 0x1000 and mbi.Type == 0x20000 and pr in (0x04, 0x40)): buf = (ctypes.c_ubyte * mbi.RegionSize)() sz = ctypes.c_size_t(0) if k.ReadProcessMemory(h, mbi.BaseAddress, buf, mbi.RegionSize, ctypes.byref(sz)): data = bytes(buf[:sz.value]) end = (len(data) // 4) * 4 # find positions in this region pos_offs = [] for off in range(0, end, 4): if struct.unpack_from("= want: break shown += 1 va_pos = mbi.BaseAddress + off region_kb = mbi.RegionSize // 1024 print(f"\n=== Position #{shown} @ VA 0x{va_pos:08x} " f"(region 0x{mbi.BaseAddress:08x} {region_kb}KB, " f"in-region offset 0x{off:x}, " f"positions-in-region={len(pos_offs)}) ===") # dump 64 bytes BEFORE position vt lo = max(0, off - 64) hexdump(mbi.BaseAddress + lo, data[lo:off], prefix=" before ") print(" POSITION:") hexdump(mbi.BaseAddress + off, data[off:off + 128], prefix=" pos+ctx ") addr = (mbi.BaseAddress or 0) + mbi.RegionSize if addr >= 0x80000000 or shown >= want: break k.CloseHandle(h) return 0 if __name__ == "__main__": sys.exit(main())