d1a71bd5a1
Modernize manual nul-terminated byte strings to C-string literals (c"...") at all Win32 GetModuleHandleA/GetProcAddress/getaddrinfo call sites (byte-identical), drop two redundant SOL_SOCKET-as-i32 casts, remove a needless return in the fifa17 install path, and add a # Safety section to DllMain. Scope the FIFA-23-path dead-code/unused-import lints (unused only under the fifa17 feature, stripped by the linker) with a documented crate-level cfg_attr allow. Cross-verified: both the default and fifa17 builds now pass clippy -D warnings and compile; probe and capture_baseline still build.
83 lines
3.0 KiB
Rust
83 lines
3.0 KiB
Rust
use std::{
|
|
ffi::CStr,
|
|
sync::{
|
|
atomic::{AtomicBool, Ordering},
|
|
OnceLock,
|
|
},
|
|
};
|
|
|
|
use windows_sys::Win32::Networking::WinSock::{getaddrinfo as sys_getaddrinfo, ADDRINFOA};
|
|
|
|
type GetaddrinfoFn =
|
|
unsafe extern "system" fn(*const u8, *const u8, *const ADDRINFOA, *mut *mut ADDRINFOA) -> i32;
|
|
|
|
static REAL: OnceLock<GetaddrinfoFn> = OnceLock::new();
|
|
static REDIRECT_IP: OnceLock<Vec<u8>> = OnceLock::new();
|
|
|
|
// Flipped to true the first time we successfully apply the runtime cert patch.
|
|
// The patch is deferred to here (rather than DllMain) because EAWebKit.dll may
|
|
// not be loaded yet when the hook DLL is injected.
|
|
static CERT_PATCHED: AtomicBool = AtomicBool::new(false);
|
|
|
|
pub fn set_real(f: GetaddrinfoFn) {
|
|
let _ = REAL.set(f);
|
|
}
|
|
|
|
pub fn set_redirect_ip(ip: String) {
|
|
let mut bytes = ip.into_bytes();
|
|
bytes.push(0);
|
|
let _ = REDIRECT_IP.set(bytes);
|
|
}
|
|
|
|
/// Returns true if `host` is an EA / EA-Sports domain that should be redirected
|
|
/// to the local OpenFUT bridge.
|
|
fn is_ea_host(host: &str) -> bool {
|
|
let h = host.to_ascii_lowercase();
|
|
h.ends_with(".ea.com")
|
|
|| h == "ea.com"
|
|
|| h.ends_with(".easports.com")
|
|
|| h == "easports.com"
|
|
|| h.ends_with(".ugc.footapi.com")
|
|
|| h.ends_with(".footapi.com")
|
|
}
|
|
|
|
pub unsafe extern "system" fn hooked_getaddrinfo(
|
|
node_name: *const u8,
|
|
service_name: *const u8,
|
|
hints: *const ADDRINFOA,
|
|
result: *mut *mut ADDRINFOA,
|
|
) -> i32 {
|
|
if !node_name.is_null() {
|
|
if let Ok(host) = CStr::from_ptr(node_name as *const i8).to_str() {
|
|
crate::write_log(&format!("openfut_hook: getaddrinfo({host})\n"));
|
|
// Milestone-0 transport watch (self-gates on OPENFUT_TRANSPORT_WATCH).
|
|
crate::transport_watch::note_getaddrinfo(host);
|
|
if is_ea_host(host) {
|
|
// Apply the ProtoSSL cert-verify bypass the first time we see an EA
|
|
// hostname — EAWebKit.dll must be loaded by now because it's calling us.
|
|
if !CERT_PATCHED.load(Ordering::Relaxed) {
|
|
if crate::ssl_patch::patch_eawebkit_cert_verify() {
|
|
CERT_PATCHED.store(true, Ordering::Relaxed);
|
|
crate::write_log(
|
|
"openfut_hook: ProtoSSL cert-verify patched (lazy, from getaddrinfo)\n",
|
|
);
|
|
} else {
|
|
crate::write_log(
|
|
"openfut_hook: ProtoSSL cert-verify patch FAILED in getaddrinfo\n",
|
|
);
|
|
}
|
|
}
|
|
|
|
let redirect = REDIRECT_IP
|
|
.get()
|
|
.map(|v| v.as_ptr())
|
|
.unwrap_or(c"127.0.0.1".as_ptr().cast());
|
|
let real = REAL.get().copied().unwrap_or(sys_getaddrinfo);
|
|
return real(redirect, service_name, hints, result);
|
|
}
|
|
}
|
|
}
|
|
let real = REAL.get().copied().unwrap_or(sys_getaddrinfo);
|
|
real(node_name, service_name, hints, result)
|
|
}
|