138 lines
3.9 KiB
Rust
138 lines
3.9 KiB
Rust
/// 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
|
|
}
|