fifa17-recon: sweep can target the non-player card tables

The merge FUN_180141660 dispatches on record+0x4c, which FUN_1800d8330 derives
from cardsubtypeid alone, and each branch queries a different table by
carddbid = record+0x18 -- the same field players use for playerid:

    0..3 -> 1  players (live-proven)   5 -> 3  headcoachcards
    4    -> 2  manager                 8 -> 4  fitnesscoachcards
    6    -> 10 gkcoachcards            7 -> 5  physiocards
    9..b -> 7  unidentified            absent -> 0x156 -> 0, no merge at all

So a 't<subtype>@' prefix on the sweep window probes any of them the same way
players were probed: 't5@auto:1-20000:5000'.

Only cardsubtypeid changes. itemType stays 'player' because the merge dispatches
on the subtype alone and the wire shape of a real staff item has NEVER been
observed -- across every logged session the client has only ever asked for
type=player and type=custom. Inventing a shape for an unobserved request is the
change class behind every freeze this project has had.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUT92pz6RWKih9dSr8ZpxW
This commit is contained in:
funman300
2026-08-04 21:18:01 -07:00
parent 0a1c9dc2ce
commit c28cad281b
+38 -6
View File
@@ -1305,10 +1305,34 @@ def sweep_window():
# fetches; one probe at the end reads them all.
_SWEEP_SPEC = None
_SWEEP_POS = 0
_SWEEP_SUBTYPE = 0 # 0..3 = player; see _parse_window for the other tables
def _parse_window(win):
"""'lo-hi' or 'auto:lo-hi:step' -> (lo, hi, step or None). None on garbage."""
"""'lo-hi' or 'auto:lo-hi:step' -> (lo, hi, step or None). None on garbage.
An optional 't<subtype>@' prefix sweeps a NON-PLAYER card table. The merge
FUN_180141660 dispatches on record+0x4c, which FUN_1800d8330 derives from
cardsubtypeid alone, and each branch queries a different table by
carddbid = record+0x18 (the same field players use for playerid):
0..3 -> 1 players 5 -> 3 headcoachcards
4 -> 2 manager 8 -> 4 fitnesscoachcards
6 -> 10 gkcoachcards 7 -> 5 physiocards
9..b -> 7 (unidentified) absent -> 0x156 -> 0, NO merge at all
So 't5@auto:1-20000:5000' sweeps head coaches exactly the way the default
sweeps players. Nothing about the non-player branches is live-proven yet;
they are read out of the binary.
"""
global _SWEEP_SUBTYPE
_SWEEP_SUBTYPE = 0
if win.startswith("t") and "@" in win:
head, win = win.split("@", 1)
try:
_SWEEP_SUBTYPE = int(head[1:], 0)
except ValueError:
return None
auto = win.startswith("auto:")
step = None
if auto:
@@ -1358,13 +1382,21 @@ def sweep_items():
else:
start, end = lo, hi
out = [_item(SWEEP_ID_BASE + (pid - lo), pid, SWEEP_SENTINEL_RATING,
"ST", 0, 0, 0, [1, 1, 1, 1, 1, 1])
for pid in range(start, end + 1)]
log(" SWEEP: serving %d candidate playerid(s) %d..%d%s "
out = []
for pid in range(start, end + 1):
it = _item(SWEEP_ID_BASE + (pid - lo), pid, SWEEP_SENTINEL_RATING,
"ST", 0, 0, 0, [1, 1, 1, 1, 1, 1])
if _SWEEP_SUBTYPE:
# Only the subtype is changed. itemType stays "player" because the
# merge dispatches on cardsubtypeid alone and the wire shape for a
# staff item has never been observed -- inventing one is the change
# class that freezes the client.
it["cardsubtypeid"] = _SWEEP_SUBTYPE
out.append(it)
log(" SWEEP: serving %d candidate id(s) %d..%d%s subtype=%d "
"[synthetic, nothing saved]"
% (len(out), start, end,
(" (auto, %d..%d done)" % (lo, end)) if step else ""))
(" (auto, %d..%d done)" % (lo, end)) if step else "", _SWEEP_SUBTYPE))
return out