use dobby_sys::ffi;
use std::ffi::{c_void, CString};
pub type Address = *mut c_void;
pub fn resolve_symbol(image_name: &str, symbol_name: &str) -> Option<Address> {
let image_name = CString::new(image_name).unwrap();
let symbol_name = CString::new(symbol_name).unwrap();
let addr = unsafe { ffi::DobbySymbolResolver(image_name.as_ptr(), symbol_name.as_ptr()) };
if addr.is_null() {
None
} else {
Some(addr)
}
}
#[derive(Debug, thiserror::Error)]
pub enum DobbyHookError {
#[error("hook error")]
HookError,
}
pub unsafe fn hook(addr: Address, replace: Address) -> Result<Address, DobbyHookError> {
let mut origin = std::ptr::null_mut();
hook_and_update_origin(addr, replace, &mut origin)?;
Ok(origin)
}
pub unsafe fn hook_and_update_origin(
addr: Address,
replace: Address,
origin: &mut Address,
) -> Result<(), DobbyHookError> {
let ret = ffi::DobbyHook(addr, replace, origin as *mut _);
if ret == 0 {
Ok(())
} else {
Err(DobbyHookError::HookError)
}
}
pub unsafe fn unhook(addr: Address) -> Result<(), DobbyHookError> {
let ret = ffi::DobbyDestroy(addr);
if ret == 0 {
Ok(())
} else {
Err(DobbyHookError::HookError)
}
}
#[derive(Debug, thiserror::Error)]
pub enum DobbyMemoryOperationError {
#[error("memory operation error")]
MemoryOperationError,
#[error("not enough memory")]
NotEnough,
#[error("not support allocate executable memory")]
NotSupportAllocateExecutableMemory,
#[error("unknown error")]
None,
}
pub unsafe fn patch_code(addr: Address, code: &[u8]) -> Result<(), DobbyMemoryOperationError> {
let ret = ffi::CodePatch(addr, code.as_ptr() as *mut _, code.len() as u32);
match ret {
ffi::MemoryOperationError_kMemoryOperationSuccess => Ok(()),
ffi::MemoryOperationError_kMemoryOperationError => {
Err(DobbyMemoryOperationError::MemoryOperationError)
}
ffi::MemoryOperationError_kNotEnough => Err(DobbyMemoryOperationError::NotEnough),
ffi::MemoryOperationError_kNotSupportAllocateExecutableMemory => {
Err(DobbyMemoryOperationError::NotSupportAllocateExecutableMemory)
}
ffi::MemoryOperationError_kNone => Err(DobbyMemoryOperationError::None),
_ => unreachable!(),
}
}