feat(windows): native client preflight + launch/RE docs

Add read-only preflight verifier and Windows-client documentation for the
reimaged native-Windows FIFA17 client host (10.10.0.105). No launcher script:
the native model is _fifa17.exe run as admin (RUNASADMIN + shortcut). Covers
routing (openfut.cfg -> 10.10.0.120), rollback (version.dll swap), and the
x64dbg RVA<->VA (ASLR) attach workflow (ImageBase 0x180000000 CardsDLL/powdll).
This commit is contained in:
funman300
2026-08-20 18:43:19 +00:00
parent d8d704d441
commit 9f1fc1b47c
2 changed files with 219 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
# 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 (native - there is NO launcher script by design)
Run `C:\FIFA 17\_fifa17.exe` **as Administrator**. The correct, reproducible 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.
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.
## 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.
```powershell
# 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).
## 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
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`.
+129
View File
@@ -0,0 +1,129 @@
<#
.SYNOPSIS
OpenFUT FIFA 17 Windows client preflight - READ ONLY.
.DESCRIPTION
Non-destructive verification of the native Windows FIFA 17 OpenFUT client on
this machine. It NEVER launches the game, never elevates, never writes to
game files, and never mutates any economy state. It only reads files,
registry, and performs TCP connect probes to the configured backend.
Exit code 0 = all PASS/WARN, 1 = one or more FAIL.
Native launch model (there is NO launcher script by design):
run C:\FIFA 17\_fifa17.exe as Administrator
(use the "FIFA 17 (OpenFUT)" shortcut, which carries the RunAsAdmin bit).
#>
[CmdletBinding()]
param(
[string]$FifaRoot = 'C:\FIFA 17'
)
$ProgressPreference = 'SilentlyContinue'
$ErrorActionPreference = 'SilentlyContinue'
# --- known-good fingerprints -------------------------------------------------
# Retail executable MUST NOT be modified/patched (Denuvo + anti-cheat sensitive).
$EXPECT_FIFA17_EXE_SHA256 = '29C31CEF12B0C3C2A7305220617C7B4FA139AB76B8C857851BDBE88987962899'
# Currently deployed OpenFUT hook (base-supply + VEH build). Update on redeploy.
$EXPECT_HOOK_SHA256 = '8844A6BCEE7BE37DD55B989246B312AF52FA711CCBC1220D25FEC64CBAD077D8'
$ROLLBACK_BAK = Join-Path $FifaRoot 'version.dll.stale-849k.bak'
$script:fail = 0
function Say([string]$level, [string]$msg) {
switch ($level) {
'PASS' { $c = 'Green' }
'WARN' { $c = 'Yellow' }
'FAIL' { $c = 'Red'; $script:fail++ }
default { $c = 'Gray' }
}
Write-Host ('[{0}] {1}' -f $level, $msg) -ForegroundColor $c
}
function Sha([string]$p) { if (Test-Path $p) { (Get-FileHash $p -Algorithm SHA256).Hash } else { $null } }
Write-Host '=== OpenFUT FIFA 17 Windows client preflight (read-only) ===' -ForegroundColor Cyan
Say 'INFO' ("host={0} user={1} {2}" -f $env:COMPUTERNAME, $env:USERNAME, (Get-CimInstance Win32_OperatingSystem).Caption)
# --- 1. FIFA install + retail exe integrity ---------------------------------
$exe = Join-Path $FifaRoot 'FIFA17.exe'
$loader = Join-Path $FifaRoot '_fifa17.exe'
if (Test-Path $exe) {
$h = Sha $exe
if ($h -eq $EXPECT_FIFA17_EXE_SHA256) { Say 'PASS' "FIFA17.exe present and unmodified ($($h.Substring(0,16))...)" }
else { Say 'FAIL' "FIFA17.exe hash MISMATCH - retail exe changed! got $($h.Substring(0,16))... expected $($EXPECT_FIFA17_EXE_SHA256.Substring(0,16))..." }
} else { Say 'FAIL' "FIFA17.exe missing at $exe" }
if (Test-Path $loader) { Say 'PASS' "native loader _fifa17.exe present ($((Sha $loader).Substring(0,16))...)" }
else { Say 'FAIL' "_fifa17.exe (native loader) missing - cannot launch" }
# --- 2. companion DLLs -------------------------------------------------------
$companions = 'CardsDLL_Win64_retail.dll','powdll_Win64_retail.dll','sysdll_Win64_retail.dll',
'FootballCompEng_Win64_retail.dll','stp-origin_emu.dll','stp-selector.exe'
foreach ($c in $companions) {
$p = Join-Path $FifaRoot $c
if (Test-Path $p) { Say 'PASS' "companion present: $c" } else { Say 'FAIL' "companion MISSING: $c" }
}
# --- 3. OpenFUT hook (version.dll) + rollback backup ------------------------
$hook = Join-Path $FifaRoot 'version.dll'
if (Test-Path $hook) {
$hh = Sha $hook
if ($hh -eq $EXPECT_HOOK_SHA256) { Say 'PASS' "hook version.dll deployed (expected build $($hh.Substring(0,16))...)" }
else { Say 'WARN' "hook version.dll present but hash differs from recorded build ($($hh.Substring(0,16))...) - may be a newer/older hook" }
$bytes = [IO.File]::ReadAllBytes($hook); $ascii = [Text.Encoding]::ASCII.GetString($bytes)
$markers = @('OpenFUT','fifa17','CardsDLL','SBC_DISPATCH') | Where-Object { $ascii -match [regex]::Escape($_) }
if ($markers.Count -ge 3) { Say 'PASS' "hook markers found: $($markers -join ', ')" }
else { Say 'WARN' "hook markers thin: $($markers -join ', ') - is this the OpenFUT hook?" }
} else { Say 'FAIL' "hook version.dll NOT deployed - client will run vanilla (no OpenFUT)" }
if (Test-Path $ROLLBACK_BAK) {
if ((Sha $ROLLBACK_BAK) -ne (Sha $hook)) { Say 'PASS' "rollback backup present and differs from live: $(Split-Path $ROLLBACK_BAK -Leaf)" }
else { Say 'WARN' "rollback backup equals live version.dll - rollback would be a no-op" }
} else { Say 'WARN' "no rollback backup ($(Split-Path $ROLLBACK_BAK -Leaf)) - keep one before redeploying the hook" }
# --- 4. routing config + backend reachability -------------------------------
$cfg = Join-Path $FifaRoot 'openfut.cfg'
$host120 = $null; $ports = @()
if (Test-Path $cfg) {
$kv = @{}; foreach ($l in Get-Content $cfg) { if ($l -match '^\s*([^=#]+)=(.+)$') { $kv[$matches[1].Trim()] = $matches[2].Trim() } }
$host120 = $kv['host']
Say 'PASS' "openfut.cfg routing: host=$($kv['host']) https=$($kv['https_port']) redirector=$($kv['blaze_redirector_port']) blaze=$($kv['blaze_main_port'])"
foreach ($k in 'https_port','blaze_redirector_port','blaze_main_port') { if ($kv[$k]) { $ports += [int]$kv[$k] } }
if ($kv['blaze_main_port'] -eq '42130') { Say 'WARN' 'blaze_main_port=42130 targets PRODUCTION - repoint to a staging port before match/economy testing' }
} else { Say 'WARN' "openfut.cfg absent - hook uses its baked-in default host" }
if ($host120) {
foreach ($p in $ports) {
$t = New-Object Net.Sockets.TcpClient
try {
$ar = $t.BeginConnect($host120, $p, $null, $null)
if ($ar.AsyncWaitHandle.WaitOne(2500) -and $t.Connected) { Say 'PASS' "backend reachable ${host120}:$p" }
else { Say 'FAIL' "backend UNREACHABLE ${host120}:$p" }
} catch { Say 'FAIL' "backend probe error ${host120}:$p - $($_.Exception.Message)" } finally { $t.Close() }
}
}
# --- 5. login persona (stp origin emulator) ---------------------------------
$ini = Join-Path $FifaRoot 'stp-origin_emu.ini'
if (Test-Path $ini) {
$persona = (Get-Content $ini | Select-String 'PersonaId|PersonaName') -join ' '
Say 'PASS' "login emulator config: $persona"
} else { Say 'FAIL' "stp-origin_emu.ini missing - no login persona" }
# --- 6. native launcher elevation setup -------------------------------------
$lk = 'HKCU:\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers'
$layer = (Get-ItemProperty $lk).$loader
if ($layer -match 'RUNASADMIN') { Say 'PASS' "_fifa17.exe RUNASADMIN flag set ($layer)" }
else { Say 'WARN' '_fifa17.exe has no RUNASADMIN flag - launch must be manual "Run as administrator"' }
$sc = Join-Path $env:USERPROFILE 'Desktop\FIFA 17 (OpenFUT).lnk'
if (Test-Path $sc) { Say 'PASS' "desktop launcher shortcut present: $(Split-Path $sc -Leaf)" }
else { Say 'WARN' 'no desktop launcher shortcut' }
# --- 7. RE toolchain ---------------------------------------------------------
$x = Get-ChildItem "$env:LOCALAPPDATA\Microsoft\WinGet\Packages" -Recurse -Depth 4 -Include x64dbg.exe -Attributes !ReparsePoint -EA SilentlyContinue | Select-Object -First 1 -Expand FullName
if (-not $x) { $x = (Get-Command x64dbg.exe -EA SilentlyContinue).Source }
if ($x) { Say 'PASS' "x64dbg present: $x (v$((Get-Item $x).VersionInfo.FileVersion))" } else { Say 'WARN' 'x64dbg not located - install for runtime RE' }
$cargo = (Get-Command cargo -EA SilentlyContinue).Source
if ($cargo) { Say 'PASS' "rust toolchain: $cargo" } else { Say 'WARN' 'cargo not found - needed to rebuild the hook natively' }
# --- summary -----------------------------------------------------------------
Write-Host ''
if ($script:fail -eq 0) { Write-Host 'PREFLIGHT: PASS (no blocking failures)' -ForegroundColor Green; exit 0 }
else { Write-Host "PREFLIGHT: FAIL ($script:fail blocking issue(s))" -ForegroundColor Red; exit 1 }