107 lines
4.2 KiB
Rust
107 lines
4.2 KiB
Rust
//! FIFA 17 injection path (feature = "fifa17").
|
|
//!
|
|
//! This is a *separate, minimal* entry point from the FIFA-23 `install_hooks`.
|
|
//! FIFA 17 is a different game with different in-memory structures, so we run NONE
|
|
//! of the FIFA-23 connect/LSX/origin_spy/dial logic here — that would at best
|
|
//! no-op and at worst crash. For now this proves the version.dll hijack actually
|
|
//! loads us into FIFA17.exe and dumps the module map, which we need to locate
|
|
//! DirtySDK/ProtoSSL's cert-verify function (the next milestone: patch it so the
|
|
//! secure Blaze redirector's TLS handshake succeeds against our bridge cert).
|
|
//!
|
|
//! Everything here is read-only except the (not-yet-enabled) cert-verify patch.
|
|
|
|
use crate::write_log;
|
|
use windows_sys::Win32::Foundation::{CloseHandle, INVALID_HANDLE_VALUE};
|
|
use windows_sys::Win32::System::Diagnostics::ToolHelp::{
|
|
CreateToolhelp32Snapshot, Module32FirstW, Module32NextW, MODULEENTRY32W, TH32CS_SNAPMODULE,
|
|
TH32CS_SNAPMODULE32,
|
|
};
|
|
use windows_sys::Win32::System::LibraryLoader::GetModuleHandleA;
|
|
|
|
/// Read the SizeOfImage from a module's in-memory PE headers.
|
|
unsafe fn size_of_image(base: usize) -> u32 {
|
|
if base == 0 {
|
|
return 0;
|
|
}
|
|
// DOS header -> e_lfanew (i32 @ 0x3c) -> PE header. SizeOfImage is in the
|
|
// optional header at offset 0x50 from the PE signature (same for PE32/PE32+).
|
|
let e_lfanew = *((base + 0x3c) as *const i32);
|
|
let pe = base + e_lfanew as usize;
|
|
// sanity: 'PE\0\0'
|
|
if *(pe as *const u32) != 0x0000_4550 {
|
|
return 0;
|
|
}
|
|
*((pe + 24 + 0x38) as *const u32) // opt header +0x38 = SizeOfImage
|
|
}
|
|
|
|
fn wide_to_string(w: &[u16]) -> String {
|
|
let end = w.iter().position(|&c| c == 0).unwrap_or(w.len());
|
|
String::from_utf16_lossy(&w[..end])
|
|
}
|
|
|
|
/// Enumerate loaded modules (name, base, size) via ToolHelp and log them.
|
|
unsafe fn dump_modules() {
|
|
let snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, 0);
|
|
if snap == INVALID_HANDLE_VALUE {
|
|
write_log("fifa17: module snapshot FAILED\n");
|
|
return;
|
|
}
|
|
let mut me: MODULEENTRY32W = core::mem::zeroed();
|
|
me.dwSize = core::mem::size_of::<MODULEENTRY32W>() as u32;
|
|
if Module32FirstW(snap, &mut me) != 0 {
|
|
loop {
|
|
let name = wide_to_string(&me.szModule);
|
|
let base = me.modBaseAddr as usize;
|
|
let size = me.modBaseSize;
|
|
write_log(&format!(
|
|
"fifa17: module {name:<28} base={base:#018x} size={size:#x}\n"
|
|
));
|
|
me.dwSize = core::mem::size_of::<MODULEENTRY32W>() as u32;
|
|
if Module32NextW(snap, &mut me) == 0 {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
write_log("fifa17: Module32FirstW FAILED\n");
|
|
}
|
|
CloseHandle(snap);
|
|
}
|
|
|
|
/// Worker that runs AFTER DllMain returns (loader lock released). ToolHelp and
|
|
/// other loader-touching calls are unsafe under the loader lock, so we defer them
|
|
/// to this thread. This is what fixed the "game exits right after DllMain" issue.
|
|
unsafe extern "system" fn worker(_: *mut core::ffi::c_void) -> u32 {
|
|
write_log("=== fifa17 hook: worker thread start ===\n");
|
|
let main_base = GetModuleHandleA(core::ptr::null()) as usize;
|
|
let img = size_of_image(main_base);
|
|
write_log(&format!(
|
|
"fifa17: main exe base={main_base:#018x} SizeOfImage={img:#x}\n"
|
|
));
|
|
dump_modules();
|
|
write_log("fifa17: worker complete (injection healthy)\n");
|
|
// Every SBC detour is deferred and inert unless its exact environment gate is `1`.
|
|
crate::sbc_hook::install();
|
|
crate::sbc_trace::install();
|
|
crate::sbc_dispatch::install();
|
|
crate::sbc_request_trace::install();
|
|
0
|
|
}
|
|
|
|
/// Minimal FIFA-17 install. Keep DllMain itself trivial: only spawn a worker
|
|
/// thread and return immediately, so we never touch the loader lock from here.
|
|
pub unsafe fn install() {
|
|
use windows_sys::Win32::System::Threading::CreateThread;
|
|
write_log("=== fifa17 hook: DllMain ATTACH (spawning worker) ===\n");
|
|
let h = CreateThread(
|
|
core::ptr::null(),
|
|
0,
|
|
Some(worker),
|
|
core::ptr::null(),
|
|
0,
|
|
core::ptr::null_mut(),
|
|
);
|
|
if h == 0 as _ {
|
|
write_log("fifa17: CreateThread FAILED\n");
|
|
}
|
|
}
|