"""probe_rtd3d_total.py Full memory scan for RTD3D GR-view vtable 0x00801A18. Compare to s_Resources count to detect orphan shells (instances still in memory but not in s_Resources). Run as Admin (PROCESS_VM_READ on AC client). """ import ctypes, ctypes.wintypes as wt, sys, struct PROCESS_VM_READ = 0x10 PROCESS_QUERY_INFORMATION = 0x400 MEM_COMMIT = 0x1000 MEM_PRIVATE = 0x20000 PAGE_READWRITE = 0x4 PAGE_EXECUTE_READWRITE = 0x40 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 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)] k.VirtualQueryEx.argtypes = [wt.HANDLE, ctypes.c_void_p, ctypes.POINTER(MBI), ctypes.c_size_t] k.VirtualQueryEx.restype = ctypes.c_size_t VTABLES = { 'RTD3D_GR': 0x00801A18, 'RTD3D_DBObj': 0x00801AA8, 'RSD3D_GR': 0x00801A94, } S_RESOURCES_M_DATA = 0x008398C4 S_RESOURCES_M_NUM = 0x008398CC 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]) def rd_u32(h, va): b = rd(h, va, 4); return struct.unpack('= 0x80000000: break if addr <= (mbi.BaseAddress or 0): break print(f"pid {pid}: regions={regions}") print(f" s_Resources: RTD3D={sres_rtd3d} RSD3D={sres_rsd3d}") for name, cnt in counts.items(): print(f" vtable {name} ({VTABLES[name]:08x}) total in-process: {cnt}")