feat(hook): expand IAT hook coverage with TLS bypass, connect/recv hooks, and logging
Adds connect_hook, connectex_hook, recv_hook, ssl_patch, tls_bypass, lsx, ea_stub, and origin_spy modules to intercept EA's TLS and socket layers in addition to getaddrinfo. Adds DLL-level logging to C:\openfut_hook.log for debugging. Also patches windows-sys feature flags to include Cryptography and Threading APIs needed by the new hooks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
/// Hooks RegQueryValueExA/W and OpenMutexA/W to log what the Origin SDK is checking.
|
||||
use std::sync::OnceLock;
|
||||
|
||||
type RegQueryValueExAFn = unsafe extern "system" fn(
|
||||
hkey: isize,
|
||||
lpvaluename: *const u8,
|
||||
lpreserved: *mut u32,
|
||||
lptype: *mut u32,
|
||||
lpdata: *mut u8,
|
||||
lpcbdata: *mut u32,
|
||||
) -> i32;
|
||||
|
||||
type RegQueryValueExWFn = unsafe extern "system" fn(
|
||||
hkey: isize,
|
||||
lpvaluename: *const u16,
|
||||
lpreserved: *mut u32,
|
||||
lptype: *mut u32,
|
||||
lpdata: *mut u8,
|
||||
lpcbdata: *mut u32,
|
||||
) -> i32;
|
||||
|
||||
type OpenMutexAFn = unsafe extern "system" fn(u32, i32, *const u8) -> isize;
|
||||
type OpenMutexWFn = unsafe extern "system" fn(u32, i32, *const u16) -> isize;
|
||||
|
||||
static REAL_REG_A: OnceLock<RegQueryValueExAFn> = OnceLock::new();
|
||||
static REAL_REG_W: OnceLock<RegQueryValueExWFn> = OnceLock::new();
|
||||
static REAL_MUTEX_A: OnceLock<OpenMutexAFn> = OnceLock::new();
|
||||
static REAL_MUTEX_W: OnceLock<OpenMutexWFn> = OnceLock::new();
|
||||
|
||||
pub fn set_real_reg_a(f: RegQueryValueExAFn) { let _ = REAL_REG_A.set(f); }
|
||||
pub fn set_real_reg_w(f: RegQueryValueExWFn) { let _ = REAL_REG_W.set(f); }
|
||||
pub fn set_real_mutex_a(f: OpenMutexAFn) { let _ = REAL_MUTEX_A.set(f); }
|
||||
pub fn set_real_mutex_w(f: OpenMutexWFn) { let _ = REAL_MUTEX_W.set(f); }
|
||||
|
||||
fn narrow_to_string(p: *const u8) -> String {
|
||||
if p.is_null() { return "(null)".into(); }
|
||||
let bytes = unsafe { std::ffi::CStr::from_ptr(p as *const i8) };
|
||||
bytes.to_string_lossy().into_owned()
|
||||
}
|
||||
|
||||
fn wide_to_string(p: *const u16) -> String {
|
||||
if p.is_null() { return "(null)".into(); }
|
||||
let mut len = 0usize;
|
||||
unsafe { while *p.add(len) != 0 { len += 1; } }
|
||||
String::from_utf16_lossy(unsafe { std::slice::from_raw_parts(p, len) })
|
||||
}
|
||||
|
||||
fn is_interesting(name: &str) -> bool {
|
||||
name.contains("LSX") || name.contains("Origin") || name.contains("EAL") ||
|
||||
name.contains("Client") || name.contains("lsx") || name.contains("Port") ||
|
||||
name.contains("EA") || name.contains("Connection")
|
||||
}
|
||||
|
||||
pub unsafe extern "system" fn hooked_reg_query_a(
|
||||
hkey: isize,
|
||||
lpvaluename: *const u8,
|
||||
lpreserved: *mut u32,
|
||||
lptype: *mut u32,
|
||||
lpdata: *mut u8,
|
||||
lpcbdata: *mut u32,
|
||||
) -> i32 {
|
||||
let name = narrow_to_string(lpvaluename);
|
||||
let real = REAL_REG_A.get().copied().unwrap();
|
||||
let ret = real(hkey, lpvaluename, lpreserved, lptype, lpdata, lpcbdata);
|
||||
if is_interesting(&name) {
|
||||
crate::write_log(&format!("origin_spy: RegQueryValueExA({name}) → {ret}\n"));
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub unsafe extern "system" fn hooked_reg_query_w(
|
||||
hkey: isize,
|
||||
lpvaluename: *const u16,
|
||||
lpreserved: *mut u32,
|
||||
lptype: *mut u32,
|
||||
lpdata: *mut u8,
|
||||
lpcbdata: *mut u32,
|
||||
) -> i32 {
|
||||
let name = wide_to_string(lpvaluename);
|
||||
let real = REAL_REG_W.get().copied().unwrap();
|
||||
let ret = real(hkey, lpvaluename, lpreserved, lptype, lpdata, lpcbdata);
|
||||
if is_interesting(&name) {
|
||||
crate::write_log(&format!("origin_spy: RegQueryValueExW({name}) → {ret}\n"));
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub unsafe extern "system" fn hooked_open_mutex_a(
|
||||
dwdesiredaccess: u32,
|
||||
binherithandle: i32,
|
||||
lpmutexname: *const u8,
|
||||
) -> isize {
|
||||
let name = narrow_to_string(lpmutexname);
|
||||
let real = REAL_MUTEX_A.get().copied().unwrap();
|
||||
let handle = real(dwdesiredaccess, binherithandle, lpmutexname);
|
||||
crate::write_log(&format!("origin_spy: OpenMutexA({name}) → {}\n",
|
||||
if handle == 0 { "NOT_FOUND" } else { "FOUND" }));
|
||||
handle
|
||||
}
|
||||
|
||||
pub unsafe extern "system" fn hooked_open_mutex_w(
|
||||
dwdesiredaccess: u32,
|
||||
binherithandle: i32,
|
||||
lpmutexname: *const u16,
|
||||
) -> isize {
|
||||
let name = wide_to_string(lpmutexname);
|
||||
let real = REAL_MUTEX_W.get().copied().unwrap();
|
||||
let handle = real(dwdesiredaccess, binherithandle, lpmutexname);
|
||||
crate::write_log(&format!("origin_spy: OpenMutexW({name}) → {}\n",
|
||||
if handle == 0 { "NOT_FOUND" } else { "FOUND" }));
|
||||
handle
|
||||
}
|
||||
Reference in New Issue
Block a user