Files
OpenFUT/fifa17-recon/docker/fifa17-python/tools/store_enable_poke.py
T
root 70a64e3709 fifa17-python: commit working FUT backend deployment (client/server split)
Freeze the running offline FUT backend into version control as
fifa17-recon/docker/fifa17-python/ - declarative and rebuildable from a
fresh checkout:

* OPENFUT_BIND / OPENFUT_ADVERTISE client/server split in the responders
  (lsx, blaze, roster, utas, pow) + entrypoint.sh; OPENFUT_ADVERTISE is
  required for remote mode (compose and entrypoint fail without it)
* docker-compose.yml reproducing the frozen baseline container exactly
  (env, ports incl. the 8085->8080 POW-content remap, /state bind, restart)
* .env.example / .env for site config - the LAN IP is never hardcoded in source
* tools/ + data/ staged from openfut-fut-backend:python-baseline-2026-08-10,
  verified byte-identical to the running container at freeze time
* client_arm.sh (the 105 client-side arming counterpart)
* Dockerfile bakes /app/SHA256SUMS.txt so any image is self-identifying
* docs/BASELINE-python-2026-08-10.md: frozen image/container/hash record,
  restore instructions and rebuild-equivalence procedure

Secrets (redir key/cert, .env) and runtime state (docker/state) stay gitignored.
The live container is untouched pending the .105 launcher audit.
2026-08-10 23:54:04 +00:00

84 lines
3.2 KiB
Python

#!/usr/bin/env python3
"""Force the FIFA 17 FUT store OPEN by patching CardsDLL's online-readiness gate.
The "store is not available" screen is gated by FIFA's online-mode manager
(FUT::CompetitionManager). Three CardsDLL methods report store-enabled and only
return true once that manager reaches the online "service ready" state -- an
online/Blaze wall we can't reach offline. This pokes them to return true.
Reversible: originals are saved to /tmp/orig_<va>.bin; `restore` puts them back;
a FIFA restart also clears the patch (live-memory only, per session).
Needs ptrace_scope=0 (tools/root_arm.sh) and FIFA running. Run as YOUR action:
!python3 tools/store_enable_poke.py # patch (open the store)
!python3 tools/store_enable_poke.py restore # undo
Static gate methods (CardsDLL image base 0x180000000), patched to `mov eax,1; ret`:
0x1800f7fb0 IS_EASTORE_SERVICE_READY (mgr[0x6d4]==0x1fbd0)
0x1800fb850 IS_STORE_ENABLED (online-mode state stack non-empty)
0x180100500 IS_COIN_PURCHASABLE (commerce config)
"""
import sys, glob, os
IMG_BASE = 0x180000000
RET_TRUE = bytes.fromhex("b801000000c3") # mov eax,1 ; ret
NOP2 = bytes.fromhex("9090")
PATCHES = {
0x1800f7fb0: ("IS_EASTORE_SERVICE_READY", RET_TRUE),
0x1800fb850: ("IS_STORE_ENABLED", RET_TRUE),
0x180100500: ("IS_COIN_PURCHASABLE", RET_TRUE),
0x180013cf0: ("IS_STORE_AVAILABLE", RET_TRUE),
0x180017543: ("JMP_BYPASS_RESOLUTION", bytes.fromhex("eb3f")),
0x180017487: ("NOP_JE_STORE_AVAILABLE", NOP2),
0x180017490: ("NOP_JNE_STORE_CACHED", NOP2),
0x1800175aa: ("NOP_JE_STORE_ENTITLEMENT", NOP2),
}
DLL_MATCH = "CardsDLL"
def find_pid():
for d in glob.glob('/proc/[0-9]*'):
try:
if open(d + '/comm').read().strip() == 'FIFA17.exe':
return int(d.split('/')[-1])
except Exception:
pass
raise SystemExit("FIFA17.exe not running")
def cardsdll_base(pid):
for line in open(f'/proc/{pid}/maps'):
if DLL_MATCH in line:
return int(line.split('-')[0], 16) # lowest mapping = module base
raise SystemExit("CardsDLL not mapped in FIFA process")
def main():
restore = len(sys.argv) > 1 and sys.argv[1] == "restore"
pid = find_pid()
base = cardsdll_base(pid)
print(f"FIFA pid={pid} CardsDLL base={base:#x} ({'RESTORE' if restore else 'PATCH'})")
mem = f'/proc/{pid}/mem'
for va, (name, patch_bytes) in PATCHES.items():
live = base + (va - IMG_BASE)
origf = f'/tmp/orig_{live:x}.bin'
if restore:
if not os.path.exists(origf):
print(f" {name}: no saved original, skip"); continue
data = open(origf, 'rb').read()
else:
with open(mem, 'rb') as f:
f.seek(live); orig = f.read(len(patch_bytes))
open(origf, 'wb').write(orig)
data = patch_bytes
with open(mem, 'r+b') as f:
f.seek(live); f.write(data)
f.seek(live); chk = f.read(len(data))
print(f" {name:26s} @ {live:#x} -> {chk.hex()}")
print("Done." + ("" if restore else " Now open the FUT Store in-game."))
if __name__ == "__main__":
main()