edab23f04a
Emulates FIFA 17's full online + Ultimate Team stack against an offline,
clean-room backend (no EA servers). Proven end-to-end 2026-08-01:
Origin login -> Blaze login -> device-trust -> the FUT hub.
Package:
- tools/openfut-fut.sh one-command orchestrator (start/stop/status/restart)
- tools/root_arm.sh idempotent host arm (sysctls, DNAT, /etc/hosts easw)
- tools/{lsx_responder_v2,blaze_responder_v3b,roster_server,utas_server,autopatch}.py
the 5 servers (Origin LSX :4216, Blaze :42127/42130/42131, roster :8081,
FUT/UTAS :8099) + heat2.py (Fire2/Heat2 TDF codec)
- FUT-RUNBOOK.md runbook + gate-ladder troubleshooting
- docs/, tools/login_dump/*.md the reverse-engineering write-ups
All findings are clean-room, from binaries we own; nothing from any leak.
The wire protocol maps 1:1 to FIFA 23.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PN5bmpDVQR1aXgefyWAt7o
50 lines
1.8 KiB
Python
50 lines
1.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Watch for a (re)launched FIFA17.exe and auto-apply both ProtoSSL cert patches
|
|
the moment its unpacked code is mapped. Idempotent; keeps watching across relaunches."""
|
|
import glob, time, struct
|
|
|
|
GATE2=0x1461361b0; GATE2_ORIG=bytes.fromhex("48895c"); GATE2_PATCH=bytes.fromhex("31c0c3")
|
|
GATE1=0x146132548; GATE1_ORIG=bytes.fromhex("0f8576010000"); GATE1_PATCH=bytes.fromhex("90"*6)
|
|
LOG="/tmp/autopatch.log"
|
|
|
|
def log(m):
|
|
line=f"[{time.strftime('%H:%M:%S')}] {m}"
|
|
print(line,flush=True); open(LOG,"a").write(line+"\n")
|
|
|
|
def find_pids():
|
|
out=[]
|
|
for d in glob.glob('/proc/[0-9]*'):
|
|
try:
|
|
if open(d+'/comm').read().strip()=='FIFA17.exe': out.append(int(d.split('/')[-1]))
|
|
except: pass
|
|
return out
|
|
|
|
def rd(pid,va,n):
|
|
with open(f'/proc/{pid}/mem','rb') as f:
|
|
f.seek(va); return f.read(n)
|
|
def wr(pid,va,b):
|
|
with open(f'/proc/{pid}/mem','r+b') as f:
|
|
f.seek(va); f.write(b)
|
|
|
|
patched=set()
|
|
log("=== AUTOPATCH watching for FIFA17.exe ===")
|
|
while True:
|
|
for pid in find_pids():
|
|
if pid in patched: continue
|
|
try:
|
|
g2=rd(pid,GATE2,3); g1=rd(pid,GATE1,6)
|
|
except Exception:
|
|
continue # code not mapped yet / no ptrace perm yet
|
|
if g2==GATE2_PATCH and g1==GATE1_PATCH:
|
|
log(f"pid {pid}: already patched"); patched.add(pid); continue
|
|
if g2==GATE2_ORIG and g1==GATE1_ORIG:
|
|
try:
|
|
wr(pid,GATE2,GATE2_PATCH); wr(pid,GATE1,GATE1_PATCH)
|
|
v2=rd(pid,GATE2,3).hex(); v1=rd(pid,GATE1,6).hex()
|
|
log(f"pid {pid}: PATCHED gate2={v2} gate1={v1}")
|
|
patched.add(pid)
|
|
except Exception as e:
|
|
log(f"pid {pid}: patch write failed: {e}")
|
|
# else: partial/unknown state -> wait
|
|
time.sleep(1)
|