inline only.Expand description
Inline hooking.
-
Supported CPU architectures: x86, x64, ARM64.
-
Support all common ABIs.
- On x86/x64, system ABI (
system,stdcall/win64) and System V ABI (sysv64) are tested.
- On x86/x64, system ABI (
-
no_stdand depend onNtdll.dllonly (iftracingis not enabled). -
RAII (drop guard) design.
To leak the hook, wrap
InlineHookasstd::mem::ManuallyDrop<InlineHook>(or callstd::mem::forget()). -
Thread unsafe at the moment.
If you may enable/disable hooks from multiple threads at the same time, use a
std::sync::Mutexlock. -
To init a (
mut)static,InlineHook::new()can be used.
§Examples
// cargo add ib-hook --features inline
use ib_hook::inline::InlineHook;
extern "system" fn original(x: u32) -> u32 { x + 1 }
// Hook the function with a detour
extern "system" fn hooked(x: u32) -> u32 { x + 0o721 }
let mut hook = InlineHook::<extern "system" fn(u32) -> u32>::new_enabled(original, hooked).unwrap();
assert!(hook.is_enabled());
// Now calls to original are redirected to hooked
assert_eq!(original(0x100), 721); // redirected to hooked: 0x100 + 0o721 = 721
// Access original via trampoline
assert_eq!(hook.trampoline()(0x100), 0x101); // 0x100 + 1
// Disable the hook manually (or automatically on drop)
hook.disable().unwrap();
assert!(!hook.is_enabled());
assert_eq!(original(0x100), 0x101); // back to original§Multiple hooks
There are mainly four ways to storing multiple hooks:
- Custom
struct: Store static hooks.no_std
Vec<InlineHook<F>>: Store dynamic hooks of the same function type.HashMap<F, InlineHook<F>>: Store dynamic hooks of the same function type, indexed by target function.InlineHookMap: Store dynamic hooks of different function types, indexed by target function.
However, as ID args aren’t supported at the moment,
dynamic hooks aren’t quite useful unless you don’t need trampoline.
§InlineHookMap example
// cargo add ib-hook --features inline
use ib_hook::inline::{InlineHook, InlineHookMap};
type MyFn = extern "system" fn(u32) -> u32;
extern "system" fn original1(x: u32) -> u32 { x + 1 }
extern "system" fn original2(x: u32) -> u32 { x + 2 }
extern "system" fn hooked1(x: u32) -> u32 { x + 0o721 }
extern "system" fn hooked2(x: u32) -> u32 { x + 0o722 }
// Create a collection of hooks
let mut hooks = InlineHookMap::new();
hooks.insert::<MyFn>(original1, hooked1);
// Insert and enable a hook
hooks.insert::<MyFn>(original2, hooked2).enable().unwrap();
// Enable all hooks at once
hooks.enable().on_error(|target, e| eprintln!("Target {target:?} failed: {e:?}"));
// Verify hooks are enabled
assert_eq!(original1(0x100), 721); // redirected to hooked1
assert_eq!(original2(0x100), 722); // redirected to hooked2
// Disable all hooks at once
hooks.disable().on_error(|target, e| eprintln!("Target {target:?} failed: {e:?}"));
// Verify hooks are disabled
assert_eq!(original1(0x100), 0x101); // back to original
assert_eq!(original2(0x100), 0x102); // back to original
// Access individual hooks by target function
if let Some(hook) = hooks.get::<MyFn>(original1) {
println!("Hook is enabled: {}", hook.is_enabled());
}§Disclaimer
This is currently implemented as a wrapper of KNSoft.SlimDetours, for type safety and RAII (drop guard).
Ref: https://github.com/Chaoses-Ib/ib-shell/pull/1
Structs§
- Inline
Hook - Type-safe and RAII (drop guard) wrapper of an inline hook.
- Inline
Hook Map std - A type-erased map of inline hooks indexed by target function pointer.