Cherry-pick of 4b1d5aa from wip/kit-selector-re, which forked before the TLS
work and cannot be rebased: that branch predates fifa17_tls.rs/patch_mem.rs and
carries a large unrelated lineage (probe/lsx/recv_hook). Only the kit_trace
commit's own contents are taken.
Traces the client-side FUT pre-match kit path in CardsDLL: the GetMatchKits_DP
gate (KITS_AVAILABLE), setAvailableKits (home/away list count), the kit-item
clone driver (item type/subid/teamid at FUN_1801c3480), and the local teamkits
DB clone. Read-only passive detours reusing season_trace's installers, which
this widens to pub(crate).
The one open unknown it answers: the selector requires item+0x60 == 4, a pile
value the server has never been observed to produce (/club emits 1,
/purchased 6).
Verified in the cross-built artifact that the roster TLS gate patch is intact
alongside the new trace (fifa17_tls markers present, KIT_* markers present).
Milestone B: move FIFA17 ProtoSSL certificate compatibility into version.dll so
the client-local contract is openfut.cfg + LSX + version.dll with no external
/proc-writing patcher. The proven external openfut-autopatch remains the oracle
and is NOT removed; this reaches behavioral parity for the fail-closed patches.
Patch set (ASLR-relocated at runtime; fail-closed byte-verified; one-shot):
- FIFA17.exe ProtoSSL cert gates (REQUIRED_FOR_TLS), preferred base 0x140000000:
GATE1 rva 0x6132548 0f85 76010000 (JNZ) -> 90*6 (NOP)
GATE2 rva 0x61361b0 48 89 5c (prologue) -> 31 c0 c3 (xor eax,eax; ret)
Applied as a pair only when BOTH read their known original, exactly like the
external patcher's cert_pass; polled until the STEAMPUNKS packer unpacks them.
- CardsDLL empty-My-Packs store crash-guard (REQUIRED_FOR_STORE_TLS, bug 6c),
preferred base 0x180000000: rva 0x14858 75 0f (JNZ) -> 7f 0f (JG). Applied once
CardsDLL maps (module-late).
Deliberately NOT ported: the external patcher's 8 unconditional STORE_PATCHES.
They carry no recovered original bytes (cannot be fail-closed) and are re-applied
every tick (would require the constant-rewrite loop this milestone forbids); the
external source records no rationale for them. Documented in the Vault ADR.
Architecture:
- patch_mem.rs: generic fail-closed primitive over a Mem trait — classify
(ORIGINAL/ALREADY_PATCHED/MISMATCH), apply_checked (read->classify->write only on
ORIGINAL->reread verify), VirtualQuery-guarded read + VirtualProtect/Flush write
(WinMem). Trait abstraction makes every outcome host-testable without FIFA.
- fifa17_tls.rs: FIFA17-specific patch table + bounded poll worker (250ms, 15min
cap, no busy-spin) started from fifa17::install() after the network redirect.
Never patches an absolute address; never blind-writes on mismatch; a write/verify
failure is reported, never pretended.
Phase 11: removed the season_trace CACHE_PACKNAMES_FAILED->SUCCESS force-success
bypass (a staging-only behavior-changer that was armed unconditionally in the
candidate); season_trace is now genuinely read-only passive tracing. sbc_dispatch
and store_entry remain the intended REPAIR_PROMOTED fixes.
Tests: 39 hook tests (26 baseline + 13 new: classify states, apply/idempotence,
no-blind-write on mismatch, unreadable-module wait, write-failure reporting, RVA/
live-addr relocation across bases, cert-gate pairing, patch-table integrity).
clippy --features fifa17 -D warnings clean; fmt clean; x86_64-pc-windows-gnu
cross-build. No network-config authority added (routing stays Milestone A).
Runtime validation (x64dbg site check + Windows/Linux retail) still outstanding.
Behavior-preserving cargo fmt of two FIFA17 diagnostic modules that carried
long unwrapped macro-invocation / argument lines predating this work. Split
out of the FIFA23-retirement commit to keep that focused. No logic change.
- Passive: log FUN_18017ff90 param_1 = the pack-names/cards-tournament-list
WEBFILE_DL url (via relocating installer; rip-relative MOV R8,[DAT_1802e6580]).
- Guarded one-shot (staging client only): in the final completion FUN_1800ffe90,
when the delivered result string is CACHE_PACKNAMES_FAILED, rewrite result byte0
so it delivers SUCCESS -> LoadSeasons_Complete advances to LoadCurrentOfflineSeason.
String-verified, once per process.
Adds passive field-logging detours on the FutCompetitionServiceImpl::LoadOfflineSeasons
async chain resolved by static RE:
final completion FUN_1800ffe90 -> logs the exact status string delivered to the
AS LoadSeasons_Complete callback ("SUCCESS" vs error string at result+8);
stage-1 completion FUN_180106240 -> logs whether the first async stage's
status (+0x1c) is ok or CACHE_PACKNAMES_FAILED.
Read-only; safe bounded C-string reader (rd_cstr).
Adds openfut-hook/src/season_trace.rs: read-only CardsDLL detours that log the
FIFA17 FUT offline-season entry native call sequence (no behavior change; each
wrapper logs then calls the original via a trampoline). Traces the FUT_Season
natives proven by the registration table FUN_18004e3f0:
GetUsersOfflineDivision 0x4eb50 (NOT LoadOfflineSeasons),
LoadOfflineSeasons 0x4ee10 + async impl 0x57560,
LoadCurrentOfflineSeason 0x4eb70 + impl 0x57230 + completion 0x578e0,
StartSeason 0x4f340, GetOfflineSeasonInfo 0x4e850.
Includes a near-trampoline installer (install_detour_reloc) that relocates a
single rip-relative disp32 so functions with rip-relative prologues can be
detoured (trampoline allocated within +/-1.5GiB of CardsDLL).