"""ADVERSARIAL VERIFY BATCH 3 (namespaced q_zver_* -- another agent is clobbering q_adv_*).

Targets:
 T1 dim4: the four claimed duplicateItemIdList consumers really accept atom 0xec and
    really run the identical fixup reading ONLY record qword0 and qword2.
      0x180162880 CreatePack, 0x18013bd40 purchased/massinfo, 0x1801293d0 FutViewCards,
      0x18013e7f0 IS-list.
    Ladder decode (raw instructions, catches sub/dec ladders and reports switch bounds)
    + full decompile of each.
 T2 dim4: FUN_18009bc40 branches on item+0x10 and suppresses PUT /item when set.
 T3 dim5 claim 12: FUN_1801340e0 is a COPY CONSTRUCTOR of one 0x158 record, not a
    vector-grow with element size 0x108. Full decompile + the tail of FUN_18013af30.
 T4 dim5: pack element record offset rule (0x268 - N) and the 0x35d/0x2e3 nesting.
CONTROL for the ladder decoder: reproduced {0xeb,0xed,0x16d,0x16f} on 0x180138e10 and
{0x1f2,0x1f3,0x1f4,0x383} on 0x180142470 and {0x5d,0x1a5,0x2cd,0x2e5,0x36d} on
0x18014cc60 in batch 2 -- all three are sub/dec ladders, the SAME form as the targets.
"""
import traceback


def ladder(entry, note=""):
    f = func(entry)
    if f is None:
        print("!! no function at %#x" % entry)
        return
    print("=" * 90)
    print("### LADDER %#x %s body=%s" % (entry, note, f.getBody()))
    acc = {}
    hits = []
    n = 0
    it = listing.getInstructions(f.getBody(), True)
    while it.hasNext():
        ins = it.next(); n += 1
        m = str(ins.getMnemonicString()).upper()
        a = int(ins.getAddress().getOffset())
        ops = [str(ins.getDefaultOperandRepresentation(i)) for i in range(ins.getNumOperands())]
        def imm(i):
            try:
                sc = ins.getScalar(i)
                return None if sc is None else int(sc.getUnsignedValue())
            except Exception:
                return None
        if m in ("CMP", "SUB", "ADD") and len(ops) == 2:
            v = imm(1)
            if v is not None:
                r = ops[0]
                if m == "CMP":
                    hits.append((a, m, r, (acc.get(r, 0) + v) & 0xFFFFFFFF))
                elif m == "SUB":
                    acc[r] = (acc.get(r, 0) + v) & 0xFFFFFFFF; hits.append((a, m, r, acc[r]))
                else:
                    acc[r] = (acc.get(r, 0) - v) & 0xFFFFFFFF; hits.append((a, m, r, acc[r]))
        elif m in ("DEC", "INC") and len(ops) == 1:
            r = ops[0]
            acc[r] = (acc.get(r, 0) + (1 if m == "DEC" else -1)) & 0xFFFFFFFF
            hits.append((a, m, r, acc[r]))
        elif m == "JMP" and ops and "[" in ops[0]:
            hits.append((a, "SWITCHJMP", ops[0], 0))
        elif m in ("MOV", "MOVZX", "MOVSX", "MOVSXD", "LEA", "XOR", "POP"):
            if ops:
                acc.pop(ops[0], None)
        elif m == "CALL":
            for r in ("EAX", "RAX", "ECX", "RCX", "EDX", "RDX", "R8D", "R9D", "R10D", "R11D"):
                acc.pop(r, None)
    print("  instructions: %d" % n)
    for a, k, r, v in hits:
        if k == "SWITCHJMP":
            print("    %#x  SWITCHJMP %s   <<< JUMP TABLE, case labels NOT in this list" % (a, r))
        else:
            print("    %#x  %-4s %-28s -> atom %#x (%d)" % (a, k, r, v, v))


try:
    for a, t in [(0x180162880, "CreatePack deser"),
                 (0x18013bd40, "purchased/massinfo body"),
                 (0x1801293d0, "FutViewCards"),
                 (0x18013e7f0, "IS-list body")]:
        ladder(a, t)
    print()
    for a, t in [(0x180162880, "CreatePack deser"),
                 (0x18013e7f0, "IS-list body"),
                 (0x18009bc40, "claimed loan-sign completion"),
                 (0x1801340e0, "claimed copy-ctor of 0x158 pack record")]:
        s = dec(a)
        print("=" * 100)
        print("### DECOMPILE %s %#x len=%d" % (t, a, len(s)))
        print("=" * 100)
        print(s)
        print("### END %#x len=%d PRINTED IN FULL" % (a, len(s)))
except Exception:
    traceback.print_exc()
