Files
OpenFUT/tools/windows
funman300 1e0124c197 hook: redirect the FIFA 17 roster dial in-process, drop the DNS workaround
The client fetches the roster from the URL our own Blaze hands it,
https://winter15.gosredirector.ea.com:8081/fifa17/fut/rosterupdate.xml, and
ProtoSSL verifies that certificate by dNSName only. An IP-addressed roster host
is refused even with IP Address:10.10.0.120 in the SANs (retested on Windows
2026-08-23), so the hostname has to survive into SNI while the connection lands
on us.

The hook log showed the dial was ALREADY being intercepted:

    connect_hook: call 20.51.153.159:8081   (octets logged reversed)

It simply was not rewritten, because 8081 was not in the EA port table. So this
is a table entry, not new hook surface: ea_ports::FIFA17_ROSTER makes the
existing connect/WSAConnect/ConnectEx detour rewrite the destination while
leaving the URL untouched, and the certificate still validates.

That removes the scoped DNS responder and the client NRPT rule from the normal
path. scoped-dns.py stays as the documented contingency for EA withdrawing the
public record, which is the one dependency this cannot remove: the name must
still resolve to something for connect() to be reached at all.

roster_port is accepted in openfut.cfg but written only when non-default. The
parser rejects unknown keys, so emitting it unconditionally would make every
already-deployed hook reject the file and install NO redirect, breaking the game
rather than degrading.

Also corrects two documented claims that are false on the real machine:
elevation comes from the shortcuts' RunAsAdmin bit, not from an AppCompatFlags
RUNASADMIN entry (there is none), and hook_dll_path must point at a source copy
rather than the deployed version.dll it is copied onto.
2026-08-23 01:57:46 +00:00
..

OpenFUT FIFA 17 - native Windows client

The FIFA 17 client host (10.10.0.105, Windows 11 Pro) runs FIFA 17 natively (no Wine/Proton/umu). This directory holds the read-only preflight verifier and documents the native launch/routing/rollback model.

Install layout (C:\FIFA 17)

File Role
FIFA17.exe retail game exe (sha256 29C31CEF…). Never modify/patch. ImageBase 0x140000000.
_fifa17.exe native crack loader (Chemicalflood). This is what you launch. asInvoker manifest -> must be elevated externally.
version.dll OpenFUT hook (in-process via the version.dll load-order hijack). ImageBase 0x180000000.
version.dll.stale-849k.bak rollback copy of the previous hook.
CardsDLL_Win64_retail.dll FUT card/SBC/kit logic. ImageBase 0x180000000.
powdll_Win64_retail.dll Pack-Opening-World (EASFC store). ImageBase 0x180000000.
sysdll_Win64_retail.dll EA networking / ProtoSSL (cert, ea.com).
stp-origin_emu.dll + stp-origin_emu.ini Origin/LSX login emulator (in-process; opens LSX :4216 locally at runtime). Persona configured in the .ini.
stp-selector.exe ssl/LSX selector companion.
openfut.cfg operator-facing routing override (see below).

Launch — the OpenFUT Launcher is the normal entry point

Use the "OpenFUT Launcher" shortcut (Desktop / Start Menu). It reconciles openfut.cfg from its settings, shows backend health, and starts the game, so Windows and Linux are driven exactly the same way.

Launching the game directly still works and is the smaller-blast-radius option when validating a hook change, because it does not rewrite openfut.cfg: double-click the "FIFA 17 (OpenFUT)" shortcut, which targets _fifa17.exe with working dir C:\FIFA 17.

Elevation comes from the shortcuts, not from AppCompatFlags. Both .lnk files carry the RunAsAdmin bit (byte 21, flag 0x20); there is NO RUNASADMIN entry under HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers. So running _fifa17.exe straight from Explorer does not elevate, and the hook then fails to write C:\openfut_hook.log. Always go through a shortcut, or right-click → Run as administrator. The launcher elevates once and the game it spawns inherits that token, so there is no second UAC prompt.

On launch the Windows loader maps version.dll from the game directory (hijack), stp-origin_emu.dll emulates Origin login for the configured persona, and the hook redirects EA endpoints to the OpenFUT backend.

Do not wrap the launch in a script. FIFA under native Windows ignores synthetic input, so in-game steps are performed by the operator one at a time.

OpenFUT Launcher (GUI)

The openfut-launcher egui app runs natively on Windows (built for x86_64-pc-windows-gnu; the Linux Proton path is cfg-gated out). It is the one-button front end: it checks the backend, reconciles openfut.cfg from its settings, and starts the game.

  • Binary: C:\openfut\openfut-launcher.exe; config: %APPDATA%\openfut-launcher\config.json.
  • hook_dll_path MUST point at a source copy of the hook, not at the deployed C:\FIFA 17\version.dll. Pointing it at the destination makes "Deploy" a self-copy, and Remove-then-Deploy leaves no source to deploy from. Canonical location: C:\openfut\openfut_hook.dll.
  • The Deploy button only appears when no version.dll is present, so a normal launch never overwrites a hand-deployed hook.
  • game_profile.runner is unused on Windows (validate() only requires it on unix); executable + game_dir are what matter.
  • On Windows the launcher does NOT spawn LSX/autopatch (they are in-process: stp-origin_emu.dll + the version.dll hook) and does NOT arm the host (routing is purely openfut.cfg, which it writes into C:\FIFA 17).
  • Rebuild from Linux: cargo build -p openfut-launcher --release --target x86_64-pc-windows-gnu.

Routing (openfut.cfg)

host=10.10.0.120
https_port=8443
blaze_redirector_port=42127
blaze_main_port=42130

The hook carries 10.10.0.120 as its baked-in default; openfut.cfg is the override. 10.10.0.120 hosts both production and staging.

Production safety: blaze_main_port=42130 is the production Blaze. Before any match/economy exercise, repoint blaze_main_port (and the matching UTAS/HTTPS route) to the staging port so no traffic reaches the prod container. The preflight raises a WARN whenever 42130 is configured.

Rollback

The hook is a single file swap; no installer state.

# disable OpenFUT hook (restore previous DLL)
Copy-Item 'C:\FIFA 17\version.dll' 'C:\FIFA 17\version.dll.disabled.bak' -Force
Copy-Item 'C:\FIFA 17\version.dll.stale-849k.bak' 'C:\FIFA 17\version.dll' -Force
# re-arm: copy the desired hook build over version.dll again

Always keep a *.bak of the live hook before redeploying (the preflight checks that a rollback backup exists and differs from the live DLL).

Roster / "FUT Squad Update" — handled in-client, no client DNS changes

If FUT fails with "An error occurred downloading the FUT Squad Update", the client could not fetch https://<roster>/fifa17/fut/rosterupdate.xml.

FIFA 17's ProtoSSL verifies that certificate by dNSName only. Pointing the roster at an IP does not work even though our certificate carries IP Address:10.10.0.120 in its SANs — retested on Windows 2026-08-23 and rejected, confirming the divergence on Windows and not just under Wine. Do not retry an IP roster host and do not reissue the certificate for an IP SAN.

The hook solves this at the socket. ea_ports::FIFA17_ROSTER (8081) is a recognised signature, so the existing connect/WSAConnect/ConnectEx detour rewrites the roster dial to the configured server while leaving the URL — and therefore SNI — as winter15.gosredirector.ea.com. The certificate still validates because the name never changed; only the destination did. Nothing is required on the client: no hosts entry, no NRPT rule, no external resolver.

Confirm from the hook log (C:\openfut_hook.log); note it prints octets reversed:

connect_hook: call 20.51.153.159:8081     <- 159.153.51.20, the dial
connect_hook: v4 :8081 → 10.10.0.120:8081 <- the rewrite

Serve the roster on the destination port and start Blaze with OPENFUT_ROSTER_HOST=winter15.gosredirector.ea.com:8081. Use roster_port= in openfut.cfg only to move the destination; the parser rejects unknown keys, so that key is written only when it differs from the default.

Contingency: EA's DNS record disappears

One dependency survives: the client must resolve winter15.gosredirector.ea.com to something to reach connect() at all. EA's record is live today. If it is ever withdrawn, resolution fails before the hook can act, and the fallback is tools/windows/scoped-dns.py — a resolver that pins that one name to us and forwards every other query upstream verbatim, so it cannot strand the client:

sudo python3 tools/windows/scoped-dns.py

Point the client at it with an NRPT rule, never a hosts entry (a hosts edit on this machine previously took its whole internet down):

Add-DnsClientNrptRule -Namespace "winter15.gosredirector.ea.com" -NameServers "10.10.0.120"
# revert:
Get-DnsClientNrptRule | Where-Object { $_.Namespace -like "*winter15*" } | Remove-DnsClientNrptRule -Force

Preflight

openfut-client-preflight.ps1 is read-only: it never launches the game, never elevates, never writes game files, never mutates economy state. It verifies the retail exe hash, companion DLLs, hook + rollback, routing + backend reachability, login persona, launcher elevation, and the RE toolchain (x64dbg, cargo). Exit 0 = OK, 1 = blocking failure.

powershell -NoProfile -ExecutionPolicy Bypass -File .\openfut-client-preflight.ps1

Runtime RE (x64dbg)

See the Vault note 02 Reverse Engineering/FIFA 17/Windows Client Runtime & x64dbg.md for the attach workflow and the RVA<->VA (ASLR) math. In short: these modules' preferred ImageBase is 0x180000000 (0x140000000 for FIFA17.exe); in x64dbg a module name evaluates to its runtime (ASLR) base, so a Ghidra address maps to a breakpoint as bp CardsDLL_Win64_retail.dll+<RVA> where RVA = ghidra_addr - 0x180000000.