use crate::utils::*;
use cradle_shared::bytes2wide;
use cradle_shared::errors::CradleResult;
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::System::Diagnostics::Debug::CONTEXT;
pub enum HookAction {
Continue,
Modify,
Block(u64),
}
pub struct HookContext<'a> {
pub registers: &'a mut CONTEXT,
pub process: HANDLE,
pub ret_value: u64,
pub export_name: &'a str,
pub module_name: &'a str,
#[cfg(feature = "unstable")]
pub(crate) return_hook: Option<unstable::ReturnHookHandler>,
}
impl<'a> HookContext<'a> {
pub fn arg(&self, idx: usize) -> u64 {
match idx {
0 => self.registers.Rcx,
1 => self.registers.Rdx,
2 => self.registers.R8,
3 => self.registers.R9,
_ => {
let addr = self.registers.Rsp + 0x28 + ((idx - 4) as u64) * 8;
read_remote_or(self.process, addr as usize, 0u64)
}
}
}
pub fn set_arg(&mut self, idx: usize, val: u64) {
match idx {
0 => self.registers.Rcx = val,
1 => self.registers.Rdx = val,
2 => self.registers.R8 = val,
3 => self.registers.R9 = val,
_ => {
let addr = self.registers.Rsp + 0x28 + ((idx - 4) as u64) * 8;
let bytes = val.to_le_bytes();
unsafe {
let _ = write_process_memory(self.process, addr as usize, &bytes);
}
}
}
}
pub fn read_wide_string(&self, addr: u64, max_bytes: usize) -> String {
let raw = self.read_buf(addr, max_bytes);
let wide = bytes2wide(&raw);
String::from_utf16_lossy(&wide)
}
pub fn read_string(&self, addr: u64, max_len: usize) -> String {
let raw = self.read_buf(addr, max_len);
let end = raw.iter().position(|&b| b == 0).unwrap_or(raw.len());
String::from_utf8_lossy(&raw[..end]).into_owned()
}
pub fn read_struct<T: Copy>(&self, addr: u64) -> CradleResult<T> {
read_remote::<T>(self.process, addr as usize)
}
pub fn read_buf(&self, addr: u64, len: usize) -> Vec<u8> {
let mut buf = vec![0u8; len];
unsafe {
read_process_memory(self.process, addr as usize, &mut buf, len).unwrap_or_default();
}
buf
}
pub fn write_buf(&self, addr: u64, data: &[u8]) -> CradleResult {
unsafe { write_process_memory(self.process, addr as usize, data) }
}
pub fn write_struct<T: Copy>(&self, addr: u64, val: &T) -> CradleResult {
let bytes =
unsafe { std::slice::from_raw_parts(val as *const T as *const u8, size_of::<T>()) };
self.write_buf(addr, bytes)
}
}
pub type HookResult = CradleResult<HookAction>;
pub type HookHandler = Box<dyn Fn(&mut HookContext) -> HookResult + Send>;
#[cfg(feature = "unstable")]
pub mod unstable {
use crate::{HookContext, HookResult};
pub struct ReturnHookContext {
pub module_name: String,
pub export_name: String,
pub entry_rsp: u64,
pub return_rsp: u64,
pub return_addr: usize,
}
pub type ReturnHookHandler =
Box<dyn for<'a> FnOnce(&mut HookContext<'a>, &ReturnHookContext) -> HookResult + Send>;
impl HookContext<'_> {
pub fn on_return<F>(&mut self, handler: F)
where
F: for<'a> FnOnce(&mut HookContext<'a>, &ReturnHookContext) -> HookResult
+ Send
+ 'static,
{
self.return_hook = Some(Box::new(handler));
}
#[allow(dead_code)]
pub(crate) fn take_rhook(&mut self) -> Option<ReturnHookHandler> {
self.return_hook.take()
}
}
}