"""physobj_owner_diff.py Run owner-vtable scan on both dumps and report HIGH - LOW (instances delta). Only counts real vtable hits (slot 0 must be a function in .text). """ import struct, sys from collections import Counter from minidump.minidumpfile import MinidumpFile CPHYSOBJ_VT = 0x007c78e0 def _ei(v): if v is None: return 0 if hasattr(v, 'value'): return int(v.value) return int(v) def scan(dump_path): md = MinidumpFile.parse(dump_path) reader = md.get_reader().get_buffered_reader() text_ranges = [] image_ranges = [] for r in md.memory_info.infos: st, ty, pr = _ei(r.State), _ei(r.Type), _ei(r.Protect) & 0xff if st != 0x1000: continue if ty == 0x1000000: image_ranges.append((r.BaseAddress, r.BaseAddress + r.RegionSize)) if pr in (0x20, 0x10, 0x40, 0x02): # execute text_ranges.append((r.BaseAddress, r.BaseAddress + r.RegionSize)) image_ranges.sort() text_ranges.sort() def in_text(addr): for lo, hi in text_ranges: if lo <= addr < hi: return True return False def in_image(addr): for lo, hi in image_ranges: if lo <= addr < hi: return True return False scan_regions = [] for r in md.memory_info.infos: st, ty, pr = _ei(r.State), _ei(r.Type), _ei(r.Protect) & 0xff if st != 0x1000: continue if ty == 0x1000000: continue if pr not in (0x04, 0x40): continue scan_regions.append((r.BaseAddress, r.RegionSize)) # Helper to read DWORD from anywhere def read_dword(va): try: reader.move(va) data = reader.read(4) if len(data) == 4: return struct.unpack(' distinct owner-instance addresses seen_owners = set() # to dedupe per (vtable, owner_base) for base, buf in region_bufs: end = (len(buf) // 4) * 4 for off in range(0, end, 4): v = struct.unpack_from("10} {'delta':>8} {'low':>6} {'high':>6}") for vt, d, lo, hi in deltas[:30]: print(f" 0x{vt:08x} {d:>8} {lo:>6} {hi:>6}") if __name__ == "__main__": main()