mirror of
https://github.com/beerpiss/saekawa.git
synced 2024-11-30 18:24:30 +01:00
Switch to crochet for hooking
This commit is contained in:
parent
d2a276923c
commit
cac66f0afe
13
src/lib.rs
13
src/lib.rs
@ -12,9 +12,9 @@ use std::{ptr, thread};
|
||||
use ::log::{error, warn};
|
||||
use lazy_static::lazy_static;
|
||||
use url::Url;
|
||||
use winapi::shared::minwindef::{BOOL, DWORD, HINSTANCE, LPVOID, TRUE, FALSE};
|
||||
use winapi::shared::minwindef::{BOOL, DWORD, FALSE, HINSTANCE, LPVOID, TRUE};
|
||||
use winapi::um::errhandlingapi::GetLastError;
|
||||
use winapi::um::handleapi::{DuplicateHandle, CloseHandle};
|
||||
use winapi::um::handleapi::{CloseHandle, DuplicateHandle};
|
||||
use winapi::um::processthreadsapi::{GetCurrentProcess, GetCurrentThread};
|
||||
use winapi::um::synchapi::WaitForSingleObject;
|
||||
use winapi::um::winnt::{DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH, SYNCHRONIZE};
|
||||
@ -123,11 +123,14 @@ extern "system" fn DllMain(dll_module: HINSTANCE, call_reason: DWORD, reserved:
|
||||
&mut cur_thread,
|
||||
SYNCHRONIZE,
|
||||
FALSE,
|
||||
0
|
||||
0,
|
||||
);
|
||||
|
||||
if result == 0 {
|
||||
warn!("Failed to get current thread handle, error code: {}", GetLastError());
|
||||
warn!(
|
||||
"Failed to get current thread handle, error code: {}",
|
||||
GetLastError()
|
||||
);
|
||||
}
|
||||
|
||||
(ThreadHandle(cur_thread), result)
|
||||
@ -137,7 +140,7 @@ extern "system" fn DllMain(dll_module: HINSTANCE, call_reason: DWORD, reserved:
|
||||
if result != 0 {
|
||||
unsafe { cur_thread.wait_and_close(100) };
|
||||
}
|
||||
|
||||
|
||||
if let Err(err) = hook_init() {
|
||||
error!("Failed to initialize hook: {:#}", err);
|
||||
}
|
||||
|
121
src/saekawa.rs
121
src/saekawa.rs
@ -1,5 +1,4 @@
|
||||
use std::{
|
||||
ffi::CString,
|
||||
fmt::Debug,
|
||||
fs::File,
|
||||
io::Read,
|
||||
@ -10,18 +9,12 @@ use std::{
|
||||
use ::log::{debug, error, info};
|
||||
use anyhow::{anyhow, Result};
|
||||
use log::warn;
|
||||
use retour::static_detour;
|
||||
use serde::de::DeserializeOwned;
|
||||
use widestring::U16CString;
|
||||
use winapi::{
|
||||
ctypes::c_void,
|
||||
shared::minwindef::{__some_function, BOOL, DWORD, FALSE, LPCVOID, LPDWORD, LPVOID, MAX_PATH},
|
||||
um::{
|
||||
errhandlingapi::GetLastError,
|
||||
libloaderapi::{GetModuleHandleA, GetProcAddress},
|
||||
winbase::GetPrivateProfileStringW,
|
||||
winhttp::HINTERNET,
|
||||
},
|
||||
shared::minwindef::{BOOL, DWORD, FALSE, LPCVOID, LPDWORD, LPVOID, MAX_PATH},
|
||||
um::{errhandlingapi::GetLastError, winbase::GetPrivateProfileStringW, winhttp::HINTERNET},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -42,14 +35,6 @@ use crate::{
|
||||
pub static GAME_MAJOR_VERSION: AtomicU16 = AtomicU16::new(0);
|
||||
pub static PB_IMPORTED: AtomicBool = AtomicBool::new(true);
|
||||
|
||||
type WinHttpWriteDataFunc = unsafe extern "system" fn(HINTERNET, LPCVOID, DWORD, LPDWORD) -> BOOL;
|
||||
type WinHttpReadDataFunc = unsafe extern "system" fn(HINTERNET, LPVOID, DWORD, LPDWORD) -> BOOL;
|
||||
|
||||
static_detour! {
|
||||
static DetourWriteData: unsafe extern "system" fn (HINTERNET, LPCVOID, DWORD, LPDWORD) -> BOOL;
|
||||
static DetourReadData: unsafe extern "system" fn(HINTERNET, LPVOID, DWORD, LPDWORD) -> BOOL;
|
||||
}
|
||||
|
||||
pub fn hook_init() -> Result<()> {
|
||||
if !CONFIGURATION.general.enable {
|
||||
return Ok(());
|
||||
@ -113,12 +98,9 @@ pub fn hook_init() -> Result<()> {
|
||||
let icf = decode_icf(&mut icf1_buf).map_err(|err| anyhow!("Reading ICF failed: {:#}", err))?;
|
||||
|
||||
for entry in icf {
|
||||
match entry {
|
||||
IcfData::App(app) => {
|
||||
info!("Running on {} {}", app.id, app.version);
|
||||
GAME_MAJOR_VERSION.store(app.version.major, Ordering::Relaxed);
|
||||
}
|
||||
_ => {}
|
||||
if let IcfData::App(app) = entry {
|
||||
info!("Running on {} {}", app.id, app.version);
|
||||
GAME_MAJOR_VERSION.store(app.version.major, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,7 +115,7 @@ pub fn hook_init() -> Result<()> {
|
||||
TachiResponse::Ok(resp) => {
|
||||
if !resp.body.permissions.iter().any(|v| v == "submit_score") {
|
||||
return Err(anyhow!(
|
||||
"API key has insufficient permission. The permission submit_score must be set."
|
||||
"API key has insufficient permissions. The permission submit_score must be set."
|
||||
));
|
||||
}
|
||||
|
||||
@ -149,39 +131,13 @@ pub fn hook_init() -> Result<()> {
|
||||
|
||||
info!("Logged in to Tachi with userID {user_id}");
|
||||
|
||||
debug!("Acquring addresses");
|
||||
|
||||
let winhttpwritedata = unsafe {
|
||||
let addr = get_proc_address("winhttp.dll", "WinHttpWriteData")
|
||||
.map_err(|err| anyhow!("{:#}", err))?;
|
||||
|
||||
debug!("WinHttpWriteData: winhttp.dll!{:p}", addr);
|
||||
|
||||
std::mem::transmute::<_, WinHttpWriteDataFunc>(addr)
|
||||
};
|
||||
|
||||
let winhttpreaddata = unsafe {
|
||||
let addr = get_proc_address("winhttp.dll", "WinHttpReadData")
|
||||
.map_err(|err| anyhow!("{:#}", err))?;
|
||||
|
||||
debug!("WinHttpReadData: winhttp.dll!{:p}", addr);
|
||||
|
||||
std::mem::transmute::<_, WinHttpReadDataFunc>(addr)
|
||||
};
|
||||
|
||||
debug!("Initializing detours");
|
||||
|
||||
unsafe {
|
||||
debug!("Initializing WinHttpWriteData detour");
|
||||
DetourWriteData
|
||||
.initialize(winhttpwritedata, winhttpwritedata_hook_wrapper)?
|
||||
.enable()?;
|
||||
crochet::enable!(winhttpwritedata_hook_wrapper)?;
|
||||
|
||||
debug!("Initializing WinHttpReadData detour");
|
||||
DetourReadData
|
||||
.initialize(winhttpreaddata, winhttpreaddata_hook_wrapper)?
|
||||
.enable()?;
|
||||
};
|
||||
if CONFIGURATION.general.export_pbs || cfg!(debug_assertions) {
|
||||
crochet::enable!(winhttpreaddata_hook_wrapper)?;
|
||||
}
|
||||
|
||||
info!("Hook successfully initialized");
|
||||
|
||||
@ -193,17 +149,18 @@ pub fn hook_release() -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if DetourWriteData.is_enabled() {
|
||||
unsafe { DetourWriteData.disable()? };
|
||||
if crochet::is_enabled!(winhttpreaddata_hook_wrapper) {
|
||||
crochet::disable!(winhttpreaddata_hook_wrapper)?;
|
||||
}
|
||||
|
||||
if DetourReadData.is_enabled() {
|
||||
unsafe { DetourReadData.disable()? };
|
||||
if crochet::is_enabled!(winhttpwritedata_hook_wrapper) {
|
||||
crochet::disable!(winhttpwritedata_hook_wrapper)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[crochet::hook(compile_check, "winhttp.dll", "WinHttpReadData")]
|
||||
fn winhttpreaddata_hook_wrapper(
|
||||
h_request: HINTERNET,
|
||||
lp_buffer: LPVOID,
|
||||
@ -212,14 +169,12 @@ fn winhttpreaddata_hook_wrapper(
|
||||
) -> BOOL {
|
||||
debug!("hit winhttpreaddata");
|
||||
|
||||
let result = unsafe {
|
||||
DetourReadData.call(
|
||||
h_request,
|
||||
lp_buffer,
|
||||
dw_number_of_bytes_to_read,
|
||||
lpdw_number_of_bytes_read,
|
||||
)
|
||||
};
|
||||
let result = call_original!(
|
||||
h_request,
|
||||
lp_buffer,
|
||||
dw_number_of_bytes_to_read,
|
||||
lpdw_number_of_bytes_read
|
||||
);
|
||||
|
||||
if result == FALSE {
|
||||
let ec = unsafe { GetLastError() };
|
||||
@ -265,6 +220,7 @@ fn winhttpreaddata_hook_wrapper(
|
||||
result
|
||||
}
|
||||
|
||||
#[crochet::hook(compile_check, "winhttp.dll", "WinHttpWriteData")]
|
||||
fn winhttpwritedata_hook_wrapper(
|
||||
h_request: HINTERNET,
|
||||
lp_buffer: LPCVOID,
|
||||
@ -295,14 +251,12 @@ fn winhttpwritedata_hook_wrapper(
|
||||
error!("{err:?}");
|
||||
}
|
||||
|
||||
unsafe {
|
||||
DetourWriteData.call(
|
||||
h_request,
|
||||
lp_buffer,
|
||||
dw_number_of_bytes_to_write,
|
||||
lpdw_number_of_bytes_written,
|
||||
)
|
||||
}
|
||||
call_original!(
|
||||
h_request,
|
||||
lp_buffer,
|
||||
dw_number_of_bytes_to_write,
|
||||
lpdw_number_of_bytes_written
|
||||
)
|
||||
}
|
||||
|
||||
/// Common hook for WinHttpWriteData/WinHttpReadData. The flow is similar for both
|
||||
@ -399,22 +353,3 @@ fn winhttprwdata_hook<'a, T: Debug + DeserializeOwned + ToTachiImport + 'static>
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_proc_address(module: &str, function: &str) -> Result<*mut __some_function> {
|
||||
let module_name = CString::new(module).unwrap();
|
||||
let fun_name = CString::new(function).unwrap();
|
||||
|
||||
let module = unsafe { GetModuleHandleA(module_name.as_ptr()) };
|
||||
if (module as *const c_void).is_null() {
|
||||
let ec = unsafe { GetLastError() };
|
||||
return Err(anyhow!("could not get module handle, error code {ec}"));
|
||||
}
|
||||
|
||||
let addr = unsafe { GetProcAddress(module, fun_name.as_ptr()) };
|
||||
if (addr as *const c_void).is_null() {
|
||||
let ec = unsafe { GetLastError() };
|
||||
return Err(anyhow!("could not get function address, error code {ec}"));
|
||||
}
|
||||
|
||||
Ok(addr)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user