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:
@@ -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 }
|
||||
Reference in New Issue
Block a user