#!/usr/bin/env python3 """Byte-level diff of the two resident kit records in a live FIFA17 client. The pre-match selector draws each kit from a clone query keyed on the record's own fields, so if both tiles render identically the question is precisely: which bytes of the home record differ from the away record? This prints every differing offset with the known field names attached, and dumps the fields the decoded clone query consumes. Read-only. Never writes to the process. Decoded query (FUN_1801c3480 -> FUN_1801c44b0): teamtechid == record+0x94 teamkittypetechid == derived from itemState (101 -> 0 home, 102 -> 1 away) year == record+0xba """ import re import struct import sys PID = int(sys.argv[1]) WANT = [int(a) for a in sys.argv[2:]] or [100004874, 100004873] mem = open(f"/proc/{PID}/mem", "rb", buffering=0) def rd(a, n): mem.seek(a) return mem.read(n) def q(a): return struct.unpack(" (name, width) FIELDS = { 0x08: ("id", 8), 0x18: ("resourceId/definitionId", 4), # Offsets per club_items.json `_record_map`, which is authoritative: # cardassetid is +0x1c and assetId is +0x20 — NOT the other way round. 0x1C: ("cardassetid", 4), 0x20: ("assetId", 4), 0x38: ("discardValue", 4), 0x4C: ("cardtype", 4), 0x50: ("cardsubtypeid", 4), 0x5C: ("itemState", 4), 0x60: ("category(club slot)", 4), 0x8C: ("contract", 4), 0x94: ("teamid", 4), 0xB4: ("rating", 4), 0xB8: ("wire category", 1), 0xBA: ("year", 2), 0x148: ("nation", 4), 0x154: ("leagueId", 4), } def walk(node, out): if not node or node == sentinel: return walk(q(node + 0x00), out) # The record is EMBEDDED at node+0x28 — NOT a pointer stored there. out.append((struct.unpack("