"""Two closers.

(1) THE SCALAR-DECODE TRAP. FUN_18013adb0 compares the DECODED key
    (iVar2 = FUN_1800d7b30(rawint)) against 2 and 4, and decodes the value with the
    same FUN_1800d7b30. The settings deser uses a DIFFERENT decoder FUN_1800d7af0
    for most fields. If FUN_1800d7b30 is not identity, "key":2 on the wire is not
    key 2 in the comparison and the whole recommendation is wrong. This is exactly
    the failure the brief flags ("a scalar can be raw OR decoded, which broke a
    control only yesterday"). Decompile both decoders and the int primitive.

(2) THE massInfo TAIL KILL-SWITCH. FUN_180174630 ends with
        if (*(char *)(param_1 + 0x17c) != 0) *(u32 *)(param_1 + 0x50) = 0;
    and resp+0x50 is PROVEN to be tradingEnabled (atom 0x336 -> settings deser
    param_2[0xa] -> S2[10] -> model+0x1fd2e). So a non-zero byte at resp+0x17c
    ZEROES the trading gate no matter what /settings said. Find its writer.

SEARCH FORM: 0x17c cannot be a disp8 (>0x7f), so every memory operand naming it
carries the literal 4 bytes 7c 01 00 00. A raw disp32 scan is therefore
form-independent here and catches mov/movzx/cmp/lea in all encodings -- the same
search that found the +0x1fd2e writer. CONTROL: run the identical scan for 0x50,
which IS a disp8 offset, and confirm it produces garbage -- that proves I know
which offsets this technique is valid for and am not over-claiming.
"""
import struct, traceback

try:
    for a, tag in [(0x1800d7b30, "decoder used by pileSizeClientData (key AND value)"),
                   (0x1800d7af0, "decoder used by the settings deser"),
                   (0x1801c79d0, "INT primitive getter")]:
        s = dec(a)
        print("\n\n########## %#x %s len=%d ##########" % (a, tag, len(s)))
        print(s)
except Exception:
    traceback.print_exc()

try:
    def sect(name):
        for b in mem.getBlocks():
            if b.getName() == name:
                return int(b.getStart().getOffset()), int(b.getEnd().getOffset()) - int(b.getStart().getOffset()) + 1
    TB, TS = sect(".text")
    TEXT = read_bytes(TB, TS)
    print("\n\n########## disp32 scan for +0x17c (form-independent) ##########")
    for disp, note in [(0x17c, "the kill-switch condition byte"),
                       (0x50, "CONTROL: a disp8 offset, scan must be meaningless")]:
        pat = struct.pack("<I", disp)
        hits = []
        j = TEXT.find(pat)
        while j != -1:
            hits.append(TB + j)
            j = TEXT.find(pat, j + 1)
        agg = {}
        for h in hits:
            f = fm.getFunctionContaining(addr(h))
            agg.setdefault(f.getName() if f else "?", []).append(h)
        print("\n--- disp %#x (%s): %d raw hit(s) in %d function(s)" % (disp, note, len(hits), len(agg)))
        if len(hits) > 60:
            print("    TOO NOISY TO BE EVIDENCE -- not reporting individual sites")
            continue
        for k, v in sorted(agg.items()):
            for h in v:
                ctx = read_bytes(h - 6, 16)
                print("    %-22s %#x  bytes[-6..+10]=%s" % (k, h, ctx.hex()))
except Exception:
    traceback.print_exc()
