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.
This commit is contained in:
+61
-31
@@ -19,23 +19,32 @@ documents the native launch/routing/rollback model.
|
||||
| `stp-selector.exe` | ssl/LSX selector companion. |
|
||||
| `openfut.cfg` | operator-facing routing override (see below). |
|
||||
|
||||
## Launch (native - there is NO launcher script by design)
|
||||
## Launch — the OpenFUT Launcher is the normal entry point
|
||||
|
||||
Run `C:\FIFA 17\_fifa17.exe` **as Administrator**. The correct, reproducible way:
|
||||
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.
|
||||
|
||||
- Double-click the **"FIFA 17 (OpenFUT)"** shortcut (Desktop and Start Menu).
|
||||
It targets `_fifa17.exe`, working dir `C:\FIFA 17`, with the RunAsAdmin bit set.
|
||||
- `_fifa17.exe` is also flagged `RUNASADMIN` in
|
||||
`HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers`,
|
||||
so any launch (Explorer double-click included) elevates via UAC.
|
||||
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. The elevation + shortcut is the
|
||||
> supported mechanism. FIFA under native Windows also ignores synthetic input,
|
||||
> so in-game steps are performed by the operator one at a time.
|
||||
> 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)
|
||||
|
||||
@@ -44,11 +53,15 @@ The `openfut-launcher` egui app runs natively on Windows (built for
|
||||
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`.
|
||||
- Launch it from the **"OpenFUT Launcher"** shortcut (Desktop / Start Menu). The
|
||||
launcher itself is flagged `RUNASADMIN`, so it elevates once at start; the game
|
||||
it spawns inherits that elevation (no second UAC prompt, no crack loader
|
||||
"run as admin" failure).
|
||||
- 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`).
|
||||
@@ -85,39 +98,56 @@ Copy-Item 'C:\FIFA 17\version.dll.stale-849k.bak' 'C:\FIFA 17\version.dll' -Forc
|
||||
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" — the client MUST reach the roster by HOSTNAME
|
||||
## 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 — this was retested on Windows on
|
||||
2026-08-23 and rejected. Do not retry an IP roster host, and do not reissue the
|
||||
certificate for an IP SAN. The roster must be reached as
|
||||
`winter15.gosredirector.ea.com`, which our certificate does carry as a dNSName.
|
||||
`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.
|
||||
|
||||
Public DNS resolves that name to EA's dead `159.153.51.20`, so the client has to
|
||||
be told to resolve it to us. **Use an NRPT rule, not the hosts file.** A hosts
|
||||
edit on this machine previously took its entire internet down; NRPT is per-name,
|
||||
auditable with `Get-DnsClientNrptRule`, and reverts in one command.
|
||||
**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.
|
||||
|
||||
On the server, run the scoped resolver (needs root for UDP 53):
|
||||
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:
|
||||
|
||||
```bash
|
||||
sudo python3 tools/windows/scoped-dns.py
|
||||
```
|
||||
|
||||
It answers **only** `winter15.gosredirector.ea.com` and forwards every other
|
||||
query upstream verbatim, so it cannot strand a client that is pointed at it.
|
||||
Then start Blaze with `OPENFUT_ROSTER_HOST=winter15.gosredirector.ea.com:8081`.
|
||||
|
||||
On the client, as Administrator:
|
||||
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):
|
||||
|
||||
```powershell
|
||||
Add-DnsClientNrptRule -Namespace "winter15.gosredirector.ea.com" -NameServers "10.10.0.120"
|
||||
# revert:
|
||||
Get-DnsClientNrptRule | Where-Object Namespace -eq "winter15.gosredirector.ea.com" | Remove-DnsClientNrptRule -Force
|
||||
Get-DnsClientNrptRule | Where-Object { $_.Namespace -like "*winter15*" } | Remove-DnsClientNrptRule -Force
|
||||
```
|
||||
|
||||
## Preflight
|
||||
|
||||
Reference in New Issue
Block a user