<# .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 }