"""ADVERSARIAL BATCH 7 -- finish the two open links.

 (a) 0x10c80b96 appears as data at 0x1800e1662, inside the function at vtable slot
     +0xa8 of the table 0x180215a80 -- the same table whose slot +0xd0 is
     FUN_1800e2a40. If that holds it independently proves the FUN_18003e370 ->
     FUN_1800e2a40 link the other agent could only infer semantically.
 (b) 0xed84b12 appears as data at 0x180113f52. Whatever class that belongs to is the
     service FUN_1801a7260 calls slot +0x270 on. Find its vtable and read slot 0x270.
"""
import traceback, struct

OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/cards/adv2/q7_raw.txt"
try:
    f = open(OUT, "w")

    def P(*a):
        f.write(" ".join(str(x) for x in a) + "\n")

    for a in (0x1800E1662, 0x180113F52):
        fn = fm.getFunctionContaining(addr(a))
        P("### data GUID at %#x -> containing function %s @%#x" %
          (a, fn.getName() if fn else None,
           int(fn.getEntryPoint().getOffset()) if fn else 0))
        if fn:
            e = int(fn.getEntryPoint().getOffset())
            P(dec(e))
            hits = find_all(struct.pack("<Q", e), blocks=(".rdata", ".data"))
            P("   8-byte pointer to it: %s" % [hex(h) for h in hits])
            for h in hits:
                start = h
                while True:
                    try:
                        v = qword(start - 8)
                    except Exception:
                        break
                    if not (0x180001000 <= v < 0x1801E5000):
                        break
                    start -= 8
                P("   run start %#x, this fn at slot +%#x" % (start, h - start))
                # find the first non-stub entry -- the secondary vtable base
                base = start
                while qword(base) == 0x1801C577A:
                    base += 8
                P("   first non-stub entry at %#x (offset +%#x from run start)" % (base, base - start))
                P("   => slot of this fn relative to first non-stub: +%#x" % (h - base))
                for i in range(0, 90):
                    v = qword(base + i * 8)
                    if not (0x180001000 <= v < 0x1801E5000):
                        break
                    f2 = fm.getFunctionAt(addr(v))
                    mark = ""
                    if i * 8 == 0x270:
                        mark = "   <== SLOT 0x270"
                    if i * 8 == 0x40:
                        mark = "   <== SLOT 0x40"
                    P("      +%#05x %#x %s%s" % (i * 8, v, f2.getName() if f2 else "", mark))
        P()

    f.close()
    print("WROTE", OUT)
except Exception:
    traceback.print_exc()
