"""DIMENSION 4, pass 17: close the last gap in the reader census. Passes 5/6 required the item pointer to be loaded from memory (node+0x10) before the +0x10 access. A plain getter `return *(longlong *)(param_1 + 0x10);` would be MISSED by that matcher, so an absence claim is not yet safe. This pass finds every qword read at +0x10 off a FUNCTION PARAMETER, in every function, and lists the small ones (getters). CONTROL: the matcher is verified by requiring it to find 0x18011cca0 (the item registration, which reads *(param_3 + 8)) -- no; that is +8. Instead the control is FUN_1801a7180, found in pass 6, whose body is `return *(longlong *)(lVar1 + 0x10) == 0;` -- a parameter-derived +0x10 read. It is listed below so the reader can see the matcher firing on a known case. """ import re, traceback, time OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/store/dup17_out.txt" P = re.compile(r"\*\((?:longlong|undefined8|ulonglong|int|uint) \*\)\((?:param_\d+|this) \+ 0x10\)") try: fh = open(OUT, "w"); t0 = time.time() fns = [] it = fm.getFunctions(True) while it.hasNext(): fns.append(it.next()) hits = [] for f in fns: ent = int(f.getEntryPoint().getOffset()) try: s = dec(ent, timeout=25) except Exception: continue if s.startswith("// decompile"): continue ls = [l.strip() for l in s.split("\n") if P.search(l)] if ls: hits.append((ent, f.getName(), len(s), ls)) fh.write("swept %d functions in %.0fs; %d contain a +0x10 read off a parameter\n" % (len(fns), time.time() - t0, len(hits))) fh.write("\n--- SMALL functions (len(src) < 1500), i.e. plausible getters ---\n") for ent, nm, n, ls in hits: if n < 1500: fh.write(" %#x %s len=%d\n" % (ent, nm, n)) for l in ls[:4]: fh.write(" %s\n" % l[:140]) fh.write("\n--- all %d, addresses only ---\n" % len(hits)) fh.write(" ".join("%#x" % e for e, _, _, _ in hits) + "\n") fh.close(); print("WROTE", OUT) except Exception: traceback.print_exc()