"""DIM4. Several VAs listed as "deserializer" in ENDPOINT_MAP are in fact the response object's CONSTRUCTOR or FACTORY (they end in `*obj = &PTR_FUN_`). Resolve the REAL deserializer properly: RS4 name -> factory (xref) -> the .rdata vtable the factory installs -> slot +0x08. CONTROL: FutISSearchServerResponse must resolve to 0x180163420 and FutGetTradePileServerResponse to 0x180170810 -- the two VAs just PROVEN correct in q_mk_wire_4 (both visibly tail-call the shared IS-list body 0x18013e7f0). If the method reproduces those two it can be trusted for the four that were only MED. """ import traceback try: NAMES = ["FutISSearchServerResponse", "FutGetTradePileServerResponse", "FutISStartServerResponse", "FutISViewTradeServerResponse", "FutISWatchListServerResponse", "FutISWatchTradeServerResponse", "FutISOfferTradeServerResponse", "FutISRemoveTradeServerResponse", "FutISRemoveWatchServerResponse", "FutRelistAllServerResponse", "FutGetAuctionCountServerResponse", "FutGetSuggestedPricingServerResponse"] def vtables_in(ent): out = set() f = func(ent) if f is None: return out it = refs.getReferencesFrom(f.getEntryPoint()) body = f.getBody() ai = listing.getInstructions(body, True) while ai.hasNext(): ins = ai.next() for r in ins.getReferencesFrom(): t = int(r.getToAddress().getOffset()) if 0x1801e5000 <= t < 0x18028a000: try: s0 = qword(t); s1 = qword(t + 8) except Exception: continue if 0x180001000 <= s0 < 0x1801e5000 and 0x180001000 <= s1 < 0x1801e5000: out.add(t) return out resolved = {} for cls in NAMES: print("\n===== %s =====" % cls) hits = find_all(b"RS4:" + cls.encode() + b"\x00") print(" RS4 literal at %s" % [hex(h) for h in hits]) for h in hits: for frm, typ, fn, ent in xrefs_to(h): print(" factory ref from %#x in %s @ %#x" % (frm, fn, ent)) for vt in sorted(vtables_in(ent)): d8 = qword(vt + 8) f8 = fm.getFunctionAt(addr(d8)) print(" vtable %#x slot+0x00=%#x slot+0x08=%#x %s" % (vt, qword(vt), d8, f8.getName() if f8 else "(undef)")) resolved.setdefault(cls, set()).add(d8) print("\n\n==================== REAL DESERIALIZERS ====================") for cls in NAMES: print(" %-40s %s" % (cls, [hex(x) for x in sorted(resolved.get(cls, []))])) done = set() for cls in NAMES: for a in sorted(resolved.get(cls, [])): if a in done: continue done.add(a) print("\n########## DESER for %s @ %#x ##########" % (cls, a)) s = dec(a) print("len(src)=%d" % len(s)); print(s) except Exception: traceback.print_exc()