tools(fifa17): resolve the itemState comparator live — it is CASE-SENSITIVE
The plan recorded this as "almost certainly unresolvable statically", because `FUN_180008190` is only a forwarding stub through a slot the host fills at runtime: `mov rax,[DAT_1802ddfd8]; mov r9,[rax+0x248]; jmp r9`. It IS resolvable — just not from disk. Read read-only out of the running client (pid 6580): the slot forwards through two FIFA17.exe thunks into msvcr120.dll+0x3c330, whose body is strncmp (`test r8,r8` count, `test al,al` NUL stop, `cmp al,[rcx+rdx]`, then MSVC's 0x8080../0xfefe.. NUL-detect fast path). No `or ..,0x20`, no folding table: the compare is raw bytes. So the casing in the table at 0x180229cc0 is a CONTRACT. A mis-cased token does not degrade gracefully — FUN_180166660 returns 0xffffffff, the record keeps 0 = invalid, and the item fails the squad builder. This confirms what fut::item_state already emits; it was previously true by convention and is now true by measurement. The probe follows the chain and attributes each hop to its module, which needs care under Wine: PE sections are mapped anonymously, so a module is identified by the nearest preceding named mapping rather than the containing one.
This commit is contained in:
@@ -14,6 +14,18 @@
|
||||
//! absent key leaves `0` = [`INVALID`], and an item left at `0` fails the squad
|
||||
//! builder's `state == 1 || state == 2` acceptance test. Always send it.
|
||||
//!
|
||||
//! **The casing is a CONTRACT, not a convention** — measured, not assumed. The
|
||||
//! table lookup compares through a slot the host fills at runtime
|
||||
//! (`FUN_180008190` is just `mov rax,[DAT_1802ddfd8]; mov r9,[rax+0x248]; jmp r9`),
|
||||
//! so this was long recorded as unresolvable without a live process. Resolved
|
||||
//! read-only against the running client on 2026-08-21
|
||||
//! (`fifa17-recon/tools/service_ptr_probe.py`): the slot forwards through two
|
||||
//! FIFA17.exe thunks into `msvcr120.dll+0x3c330`, whose body is `strncmp` — a
|
||||
//! plain byte compare (`cmp al,[rcx+rdx]`) with NO case folding anywhere. So a
|
||||
//! mis-cased token does not "mostly work": it matches nothing, decodes to
|
||||
//! [`INVALID`], and the item fails the squad builder. Emit these strings
|
||||
//! verbatim.
|
||||
//!
|
||||
//! (Source: `fifa17-recon/docs/plan-2026-08-06-card-subsystem.md` §4, which also
|
||||
//! corrects `CARD_SYSTEM.md`'s earlier ten-row reading — that one started at
|
||||
//! `0x180229d20`, the MIDDLE of the table, and so missed `invalid`, `free`,
|
||||
|
||||
Reference in New Issue
Block a user