"""broader_vtable_sweep.py Find vtables in the acclient image range that have very high count in larsson and low count in time, EXCLUDING the already-tracked ones. Aim: surface previously-untracked leak classes. """ import struct, sys from collections import Counter from minidump.minidumpfile import MinidumpFile # Known/already-investigated vtables KNOWN = { 0x007c0498: "UIElement_UIItem", 0x007caa08: "Palette", 0x007c78ec: "CPhysicsObj", 0x0079a67c: "RenderSurface", 0x00801a94: "RenderSurfaceD3D", 0x00801a18: "RenderTextureD3D", 0x007ca4dc: "CSurface", 0x007cab04: "ImgTex", 0x007ca418: "CGfxObj", 0x007ed3b0: "D3DXMesh", 0x0079bf64: "GraphicsResource", 0x007ccb60: "NoticeHandler_subvt", 0x007c98e8: "CObjCell_primary", 0x007c9a60: "CEnvCell_primary", 0x0079385c: "CObjCell_subvt", 0x00400c08: "CPhys_data_sentinel", 0x007c9b58: "CPhys_inner", # speculative 0x0079c198: "RenderTexture", } # Acclient image VA range (32-bit) IMG_LO = 0x00400000 IMG_HI = 0x00880000 def _ei(v): if v is None: return 0 if hasattr(v, 'value'): return int(v.value) return int(v) def scan(dmp_path): md = MinidumpFile.parse(dmp_path) reader = md.get_reader().get_buffered_reader() counts = Counter() for r in md.memory_info.infos: st, ty, pr = _ei(r.State), _ei(r.Type), _ei(r.Protect) & 0xff if st != 0x1000 or ty == 0x1000000 or pr not in (0x04, 0x40): continue try: reader.move(r.BaseAddress) buf = reader.read(r.RegionSize) except Exception: continue if not buf: continue end = (len(buf) // 4) * 4 for off in range(0, end, 4): v = struct.unpack_from("> 8) & 0xff, (v >> 16) & 0xff, (v >> 24) & 0xff if b1 == 0 and b3 == 0 and 0x20 <= b0 <= 0x7e and 0x20 <= b2 <= 0x7e: continue # UTF-16 string fragment counts[v] += 1 return counts def main(): larsson = sys.argv[1] time_path = sys.argv[2] print(f"scanning larsson: {larsson}") lc = scan(larsson) print(f" unique vtables: {len(lc)}") print(f"scanning time: {time_path}") tc = scan(time_path) print(f" unique vtables: {len(tc)}") # Compute diff rows = [] for vt, c in lc.items(): if vt in KNOWN: continue if c < 20: continue t = tc.get(vt, 0) ratio = c / max(t, 0.5) delta = c - t rows.append((vt, t, c, ratio, delta)) rows.sort(key=lambda x: -x[4]) print() print("UN-tracked acclient vtables, sorted by absolute delta (larsson - time):") print(f"{'vtable':12} {'time':>6} {'larsson':>8} {'ratio':>7} {'delta':>7}") for vt, t, c, ratio, delta in rows[:40]: print(f"0x{vt:08x} {t:>6} {c:>8} {ratio:>7.1f} {delta:>7}") if __name__ == "__main__": main()