"""D3 Q11: fix the failed control from Q10. Q10's control was INVALID BY CONSTRUCTION, not a scan failure: xrefs_to(0x1801a7260) reported two DATA references, but those live at 0x180284468 / 0x180300d1c which are 4-byte RVA entries (RVA of the function is 0x1a7260) in the exception/unwind tables, so an 8-byte-pointer search can never find them. Re-do the control properly and then answer the real question: what is the slot INDEX of FUN_1800e2a40 in the table that contains it? The action-flag attribution needs index 8 (= vtable +0x40). CONTROL (valid this time): the same 8-byte pointer search must find FUN_18013fe00, which we know sits nowhere in a vtable, AND must find the item vtable 0x1801eaac0's own three slots. Concretely: read 0x1801eaac0 and confirm its slots are .text addresses -- an 8-byte-pointer table we have already relied on. """ import struct, traceback try: print("### the 4-byte RVA check that explains the Q10 control failure") for a in (0x180284468, 0x180300d1c): try: v = dword(a) print(" %#x -> dword %#x (RVA of 0x1801a7260 is 0x1a7260)" % (a, v)) except Exception as e: print(" %#x unreadable %s" % (a, e)) print() print("### CONTROL: the known item vtable 0x1801eaac0") for k in range(4): t = qword(0x1801eaac0 + k*8) print(" slot %+#4x %#x %s" % (k*8, t, fname(t) if 0x180000000 <= t < 0x181000000 else "")) print() print("### walk back from 0x180215b50 to the start of its pointer table") a = 0x180215b50 start = a while True: p = a - 8 try: t = qword(p) except Exception: break if not (0x180001000 <= t < 0x1801d0000): break start = p a = p if 0x180215b50 - start > 0x800: break print(" table start %#x, FUN_1800e2a40 is at %#x -> slot %#x (index %d)" % (start, 0x180215b50, 0x180215b50 - start, (0x180215b50 - start)//8)) for off in range(0, 0x180215b50 - start + 0x40, 8): t = qword(start + off) print(" %+#6x %#x %s" % (off, t, fname(t) if 0x180000000 <= t < 0x181000000 else "")) except Exception: traceback.print_exc()