feat: add guarded FIFA 17 SBC diagnostics

This commit is contained in:
funman300
2026-08-07 11:43:08 -07:00
parent 7dcf610b71
commit 3d895fb7ac
9 changed files with 2510 additions and 38 deletions
+141 -38
View File
@@ -2,6 +2,8 @@ mod config;
mod connect_hook;
mod connectex_hook;
mod dial_notification;
#[cfg(feature = "fifa17")]
mod fifa17;
mod hooks;
mod iat;
mod origin_spy;
@@ -9,22 +11,32 @@ mod origin_spy;
mod probe;
#[cfg(feature = "capture_baseline")]
mod recv_hook;
#[cfg(feature = "fifa17")]
mod sbc_hook;
#[cfg(feature = "fifa17")]
mod sbc_request_trace;
#[cfg(feature = "fifa17")]
mod sbc_trace;
mod ssl_patch;
mod tls_bypass;
mod transport_watch;
mod version_proxy;
use windows_sys::Win32::{
Foundation::{BOOL, HMODULE, TRUE},
System::SystemServices::DLL_PROCESS_ATTACH,
Networking::WinSock::ADDRINFOA,
System::SystemServices::DLL_PROCESS_ATTACH,
};
pub(crate) fn write_log(msg: &str) {
use std::io::Write;
if let Ok(mut f) = std::fs::OpenOptions::new()
.create(true).append(true)
.create(true)
.append(true)
.open(r"C:\openfut_hook.log")
{ let _ = f.write_all(msg.as_bytes()); }
{
let _ = f.write_all(msg.as_bytes());
}
}
/// Force the log to stable storage. `write_log` already opens+closes the file per line,
@@ -34,18 +46,41 @@ pub(crate) fn write_log(msg: &str) {
/// pre-call log line is guaranteed on disk if the call faults.
#[allow(dead_code)]
pub(crate) fn flush_log() {
if let Ok(f) = std::fs::OpenOptions::new().append(true).open(r"C:\openfut_hook.log") {
if let Ok(f) = std::fs::OpenOptions::new()
.append(true)
.open(r"C:\openfut_hook.log")
{
let _ = f.sync_all();
}
}
#[no_mangle]
pub unsafe extern "system" fn DllMain(module: HMODULE, reason: u32, _: *mut ()) -> BOOL {
if reason == DLL_PROCESS_ATTACH { install_hooks(module); }
if reason == DLL_PROCESS_ATTACH {
// VERSION forwarding must be ready before DllMain returns. Hook setup
// may be deferred, but a caller can use any proxy export immediately.
if version_proxy::resolve() {
install_hooks(module);
}
}
TRUE
}
unsafe fn install_hooks(module: HMODULE) {
// FIFA 17 path: run ONLY the minimal, FIFA-17-safe logic and skip every
// FIFA-23-specific hook below (they assume FIFA 23's memory layout).
#[cfg(feature = "fifa17")]
{
let _ = module;
fifa17::install();
return;
}
#[cfg(not(feature = "fifa17"))]
install_hooks_fifa23(module)
}
#[cfg(not(feature = "fifa17"))]
unsafe fn install_hooks_fifa23(module: HMODULE) {
write_log("openfut_hook: DllMain fired\n");
// Milestone-0 transport watch: arm (or note disarmed) from env once, up front, so
// the getaddrinfo/connect/ConnectEx detours below can log Blaze-flavored activity.
@@ -55,38 +90,68 @@ unsafe fn install_hooks(module: HMODULE) {
let ga = iat::resolve(b"ws2_32.dll\0", b"getaddrinfo\0");
if !ga.is_null() {
let f: unsafe extern "system" fn(*const u8,*const u8,*const ADDRINFOA,*mut *mut ADDRINFOA)->i32
= std::mem::transmute(ga);
let f: unsafe extern "system" fn(
*const u8,
*const u8,
*const ADDRINFOA,
*mut *mut ADDRINFOA,
) -> i32 = std::mem::transmute(ga);
hooks::set_real(f);
let n = iat::patch_iat(ga, hooks::hooked_getaddrinfo as *const ());
let m = iat::patch_iat_in(b"EAWebKit.dll\0", ga, hooks::hooked_getaddrinfo as *const ());
let m = iat::patch_iat_in(
b"EAWebKit.dll\0",
ga,
hooks::hooked_getaddrinfo as *const (),
);
write_log(&format!("openfut_hook: getaddrinfo IAT patched {n}+{m}\n"));
}
if ssl_patch::patch_main_exe_cert_verify() { write_log("ssl: main exe cert-verify patched\n"); }
else { write_log("ssl: main exe cert-verify NOT FOUND\n"); }
if ssl_patch::patch_eawebkit_cert_verify() { write_log("ssl: EAWebKit cert-verify patched\n"); }
else { write_log("ssl: EAWebKit cert-verify deferred\n"); }
if ssl_patch::patch_main_exe_cert_verify() {
write_log("ssl: main exe cert-verify patched\n");
} else {
write_log("ssl: main exe cert-verify NOT FOUND\n");
}
if ssl_patch::patch_eawebkit_cert_verify() {
write_log("ssl: EAWebKit cert-verify patched\n");
} else {
write_log("ssl: EAWebKit cert-verify deferred\n");
}
if connect_hook::install_inline_connect_hook() { write_log("connect: inline-hooked\n"); }
else { write_log("connect: hook FAILED\n"); }
if connect_hook::install_inline_connect_hook() {
write_log("connect: inline-hooked\n");
} else {
write_log("connect: hook FAILED\n");
}
let wp = iat::resolve(b"ws2_32.dll\0", b"WSAConnect\0");
if !wp.is_null() {
let f: unsafe extern "system" fn(usize,*const u8,i32,*const(),*const(),*const(),*const())->i32
= std::mem::transmute(wp);
let f: unsafe extern "system" fn(
usize,
*const u8,
i32,
*const (),
*const (),
*const (),
*const (),
) -> i32 = std::mem::transmute(wp);
connect_hook::set_real_wsa_connect(f);
iat::patch_iat(wp, connect_hook::hooked_wsa_connect as *const ());
write_log("connect: WSAConnect IAT patched\n");
}
if connectex_hook::install_wsaioctl_hook() { write_log("connectex: WSAIoctl inline-hooked\n"); }
else { write_log("connectex: WSAIoctl hook FAILED\n"); }
if connectex_hook::install_wsaioctl_hook() {
write_log("connectex: WSAIoctl inline-hooked\n");
} else {
write_log("connectex: WSAIoctl hook FAILED\n");
}
// RE instrumentation: passive logging detours on FIFA's in-process online-flow
// functions (GoOnline, GetInternetConnectedState, event deserializers) to see
// where FIFA stalls after our pushed LSX events. Deferred until anadius loads.
#[cfg(feature = "probe")]
{ probe::install_probes_deferred(); write_log("probe: deferred install scheduled\n"); }
{
probe::install_probes_deferred();
write_log("probe: deferred install scheduled\n");
}
// recv/send hooks removed — LSX is now handled by the native openfut-bridge
// LSX server (port 3216), so in-process interception is no longer needed.
@@ -96,10 +161,16 @@ unsafe fn install_hooks(module: HMODULE) {
// frames (pass-through, no emulation) so we can diff them against our bridge.
#[cfg(feature = "capture_baseline")]
{
if recv_hook::install_recv_hook() { write_log("CAP: recv inline-hooked\n"); }
else { write_log("CAP: recv hook FAILED\n"); }
if recv_hook::install_send_hook() { write_log("CAP: send inline-hooked\n"); }
else { write_log("CAP: send hook FAILED\n"); }
if recv_hook::install_recv_hook() {
write_log("CAP: recv inline-hooked\n");
} else {
write_log("CAP: recv hook FAILED\n");
}
if recv_hook::install_send_hook() {
write_log("CAP: send inline-hooked\n");
} else {
write_log("CAP: send hook FAILED\n");
}
}
macro_rules! hook_iat {
@@ -110,31 +181,63 @@ unsafe fn install_hooks(module: HMODULE) {
origin_spy::$setter(f);
iat::patch_iat(ptr, $handler as *const ());
"ok"
} else { "miss" }
} else {
"miss"
}
}};
}
let ra = hook_iat!(b"advapi32.dll\0", b"RegQueryValueExA\0", set_real_reg_a,
let ra = hook_iat!(
b"advapi32.dll\0",
b"RegQueryValueExA\0",
set_real_reg_a,
origin_spy::hooked_reg_query_a,
unsafe extern "system" fn(isize,*const u8,*mut u32,*mut u32,*mut u8,*mut u32)->i32);
let rw = hook_iat!(b"advapi32.dll\0", b"RegQueryValueExW\0", set_real_reg_w,
unsafe extern "system" fn(isize, *const u8, *mut u32, *mut u32, *mut u8, *mut u32) -> i32
);
let rw = hook_iat!(
b"advapi32.dll\0",
b"RegQueryValueExW\0",
set_real_reg_w,
origin_spy::hooked_reg_query_w,
unsafe extern "system" fn(isize,*const u16,*mut u32,*mut u32,*mut u8,*mut u32)->i32);
let ma = hook_iat!(b"kernel32.dll\0", b"OpenMutexA\0", set_real_mutex_a,
unsafe extern "system" fn(isize, *const u16, *mut u32, *mut u32, *mut u8, *mut u32) -> i32
);
let ma = hook_iat!(
b"kernel32.dll\0",
b"OpenMutexA\0",
set_real_mutex_a,
origin_spy::hooked_open_mutex_a,
unsafe extern "system" fn(u32,i32,*const u8)->isize);
let mw = hook_iat!(b"kernel32.dll\0", b"OpenMutexW\0", set_real_mutex_w,
unsafe extern "system" fn(u32, i32, *const u8) -> isize
);
let mw = hook_iat!(
b"kernel32.dll\0",
b"OpenMutexW\0",
set_real_mutex_w,
origin_spy::hooked_open_mutex_w,
unsafe extern "system" fn(u32,i32,*const u16)->isize);
write_log(&format!("origin_spy: RegA={ra} RegW={rw} MutexA={ma} MutexW={mw}\n"));
unsafe extern "system" fn(u32, i32, *const u16) -> isize
);
write_log(&format!(
"origin_spy: RegA={ra} RegW={rw} MutexA={ma} MutexW={mw}\n"
));
let cv = iat::resolve(b"crypt32.dll\0", b"CertVerifyCertificateChainPolicy\0");
if !cv.is_null() {
let f: unsafe extern "system" fn(*const u8,*const(),*const(),*mut u32)->BOOL
= std::mem::transmute(cv);
let f: unsafe extern "system" fn(*const u8, *const (), *const (), *mut u32) -> BOOL =
std::mem::transmute(cv);
tls_bypass::set_real(f);
iat::patch_iat(cv, tls_bypass::hooked_cert_verify_chain_policy as *const ());
iat::patch_iat_in(b"EAWebKit.dll\0", cv, tls_bypass::hooked_cert_verify_chain_policy as *const ());
iat::patch_iat_in(b"winhttp.dll\0", cv, tls_bypass::hooked_cert_verify_chain_policy as *const ());
iat::patch_iat_in(b"wininet.dll\0", cv, tls_bypass::hooked_cert_verify_chain_policy as *const ());
iat::patch_iat_in(
b"EAWebKit.dll\0",
cv,
tls_bypass::hooked_cert_verify_chain_policy as *const (),
);
iat::patch_iat_in(
b"winhttp.dll\0",
cv,
tls_bypass::hooked_cert_verify_chain_policy as *const (),
);
iat::patch_iat_in(
b"wininet.dll\0",
cv,
tls_bypass::hooked_cert_verify_chain_policy as *const (),
);
}
}