fifa17-recon: package the working offline FUT backend
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
This commit is contained in:
Executable
+104
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================================
|
||||
# OpenFUT — FIFA 17 offline FUT backend orchestrator
|
||||
#
|
||||
# ./openfut-fut.sh start bring up the whole harness (arm host + all servers)
|
||||
# ./openfut-fut.sh stop shut the servers down
|
||||
# ./openfut-fut.sh restart stop + start
|
||||
# ./openfut-fut.sh status show what's up
|
||||
#
|
||||
# After `start`, launch FIFA 17 and select Ultimate Team. See RUNBOOK below (status).
|
||||
# Volatile host state (sysctls/iptables/cert) does NOT survive a reboot; `start`
|
||||
# re-arms everything, so just re-run it after booting. /etc/hosts persists.
|
||||
# ============================================================================
|
||||
set -uo pipefail
|
||||
cd "$(dirname "$(readlink -f "$0")")" # tools/
|
||||
|
||||
CERT=redir_cert.pem; KEY=redir_key.pem
|
||||
# name script "port[,port...]" extra-env
|
||||
SERVERS=(
|
||||
"lsx lsx_responder_v2.py 4216 OPENFUT_LSX_EVENT_COUNT=100000"
|
||||
"blaze blaze_responder_v3b.py 42127,42130,42131 -"
|
||||
"roster roster_server.py 8081 -"
|
||||
"utas utas_server.py 8099 -"
|
||||
"autopatch autopatch.py - -"
|
||||
)
|
||||
|
||||
c() { printf ' %s\n' "$*"; }
|
||||
up() { ss -tlnp 2>/dev/null | grep -q ":$1 "; }
|
||||
|
||||
ensure_cert() {
|
||||
[ -s "$CERT" ] && [ -s "$KEY" ] && return 0
|
||||
echo "[*] generating self-signed TLS cert (redirector MITM; ProtoSSL verify is patched)"
|
||||
openssl req -x509 -newkey rsa:2048 -nodes -keyout "$KEY" -out "$CERT" -days 3650 \
|
||||
-subj "/CN=winter15.gosredirector.ea.com" \
|
||||
-addext "subjectAltName=DNS:winter15.gosredirector.ea.com,DNS:*.gosredirector.ea.com,DNS:*.ea.com,IP:127.0.0.1" \
|
||||
>/dev/null 2>&1
|
||||
}
|
||||
|
||||
armed() {
|
||||
[ "$(cat /proc/sys/kernel/yama/ptrace_scope 2>/dev/null)" = 0 ] \
|
||||
&& [ "$(cat /proc/sys/net/ipv4/conf/lo/route_localnet 2>/dev/null)" = 1 ] \
|
||||
&& grep -q '[[:space:]]easw\.easports\.com\b' /etc/hosts 2>/dev/null
|
||||
}
|
||||
|
||||
ensure_armed() {
|
||||
if armed; then c "host already armed (ptrace_scope=0, route_localnet=1, /etc/hosts ok)"; return 0; fi
|
||||
echo "[*] arming host state (needs root — a password dialog will appear)"
|
||||
pkexec sh "$PWD/root_arm.sh" || { echo "!! root_arm failed. Run manually: pkexec sh $PWD/root_arm.sh"; return 1; }
|
||||
}
|
||||
|
||||
start() {
|
||||
ensure_cert
|
||||
ensure_armed || exit 1
|
||||
echo "[*] starting servers (detached)…"
|
||||
for s in "${SERVERS[@]}"; do
|
||||
read -r name script ports env <<<"$s"
|
||||
pkill -9 -f "$script" 2>/dev/null; :
|
||||
done
|
||||
sleep 1
|
||||
for s in "${SERVERS[@]}"; do
|
||||
read -r name script ports env <<<"$s"
|
||||
local envprefix=""; [ "$env" != "-" ] && envprefix="env $env"
|
||||
: > "/tmp/${name}.log" 2>/dev/null || true
|
||||
setsid bash -c "exec $envprefix python3 -u $script" </dev/null >"/tmp/${name}.log" 2>&1 &
|
||||
disown
|
||||
done
|
||||
sleep 2
|
||||
status
|
||||
}
|
||||
|
||||
stop() {
|
||||
echo "[*] stopping servers…"
|
||||
for s in "${SERVERS[@]}"; do read -r name script _ <<<"$s"; pkill -9 -f "$script" 2>/dev/null; :; done
|
||||
sleep 1; c "servers stopped (host arm + /etc/hosts left intact)"
|
||||
}
|
||||
|
||||
status() {
|
||||
echo "== OpenFUT FIFA17 FUT backend =="
|
||||
armed && c "host: ARMED ✓" || c "host: NOT armed (run: pkexec sh $PWD/root_arm.sh)"
|
||||
for s in "${SERVERS[@]}"; do
|
||||
read -r name script ports env <<<"$s"
|
||||
if pgrep -f "$script" >/dev/null; then
|
||||
if [ "$ports" = "-" ]; then c "$name ✓ (running)"
|
||||
else
|
||||
local ok=1; IFS=',' read -ra ps <<<"$ports"
|
||||
for p in "${ps[@]}"; do up "$p" || ok=0; done
|
||||
[ $ok = 1 ] && c "$name ✓ ($ports)" || c "$name ⚠ running but a port is down ($ports)"
|
||||
fi
|
||||
else c "$name ✗ DOWN"; fi
|
||||
done
|
||||
echo "-- RUNBOOK --"
|
||||
c "1. (this must be done BEFORE launching FIFA — servers bind the ports the game needs)"
|
||||
c "2. Launch FIFA 17 fresh: ~/Desktop/launch-fifa17.sh (a FRESH launch avoids the live-DB error)"
|
||||
c "3. In-game: select Ultimate Team. At the 'security question', type ANY answer -> Continue -> OK."
|
||||
c "4. -> the FUT hub. Logs: /tmp/{lsx,blaze,roster,utas,autopatch}.log"
|
||||
}
|
||||
|
||||
case "${1:-status}" in
|
||||
start) start ;;
|
||||
stop) stop ;;
|
||||
restart) stop; start ;;
|
||||
status) status ;;
|
||||
*) echo "usage: $0 {start|stop|restart|status}"; exit 1 ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user