wraith/manipulation/inline_hook/
mod.rs

1//! Inline hooking framework
2//!
3//! Provides comprehensive inline hooking capabilities including:
4//! - Standard inline hooks (prologue replacement)
5//! - Hot-patch style hooks
6//! - Mid-function hooks with context
7//! - Hook chaining with priorities
8//!
9//! # Architecture Support
10//!
11//! Both x86 and x86_64 are supported via the `Architecture` trait.
12//! Use `NativeArch` for compile-time architecture selection.
13//!
14//! # Example
15//!
16//! ```ignore
17//! use wraith::manipulation::inline_hook::{hook, NativeArch};
18//!
19//! // define the original function type
20//! type TargetFn = extern "system" fn(i32) -> i32;
21//!
22//! // your detour function
23//! extern "system" fn my_detour(x: i32) -> i32 {
24//!     // do something
25//!     // call original via trampoline
26//!     unsafe { ORIGINAL.unwrap()(x) }
27//! }
28//!
29//! static mut ORIGINAL: Option<TargetFn> = None;
30//!
31//! // install hook
32//! let guard = hook::<NativeArch>(target_addr, my_detour as usize)?;
33//! unsafe {
34//!     ORIGINAL = Some(std::mem::transmute(guard.trampoline().unwrap()));
35//! }
36//!
37//! // hook is active until guard is dropped
38//! // or call guard.leak() to keep it permanently
39//! ```
40//!
41//! # Hook Types
42//!
43//! - [`InlineHook`]: Standard prologue replacement hook
44//! - [`HotPatchHook`]: Uses Windows hot-patching space (2-byte atomic)
45//! - [`MidFunctionHook`]: Hook at arbitrary location with context
46//! - [`HookChain`]: Multiple hooks on same target with priorities
47//!
48//! # Builder Pattern
49//!
50//! For more control, use the type-state builder:
51//!
52//! ```ignore
53//! use wraith::manipulation::inline_hook::{HookBuilder, NativeArch};
54//!
55//! let guard = HookBuilder::<NativeArch, _>::new()
56//!     .target(target_addr)?
57//!     .detour(detour_addr)?
58//!     .allocate_trampoline()?
59//!     .build_trampoline()?
60//!     .prepare()?
61//!     .install()?;
62//! ```
63
64pub mod arch;
65pub mod asm;
66pub mod builder;
67pub mod guard;
68pub mod hook;
69pub mod registry;
70pub mod trampoline;
71
72// re-exports
73pub use arch::{Architecture, NativeArch, X64, X86};
74pub use builder::{state as BuilderState, HookBuilder};
75pub use guard::{HookGuard, HookState, StatefulHookGuard};
76pub use hook::{Hook, HookChain, HotPatchHook, InlineHook, MidFunctionHook};
77pub use registry::{HookRegistry, HookType, RegisteredHook};
78pub use trampoline::ExecutableMemory;
79
80#[cfg(target_arch = "x86_64")]
81pub use hook::mid::HookContext;
82#[cfg(target_arch = "x86")]
83pub use hook::mid::HookContext;
84pub use hook::mid::MidHookFn;
85
86use crate::error::Result;
87
88/// install an inline hook with native architecture
89///
90/// this is the simplest way to install a hook. returns a guard that
91/// automatically restores the original function when dropped.
92///
93/// # Arguments
94/// * `target` - address of the function to hook
95/// * `detour` - address of the detour function
96///
97/// # Returns
98/// `HookGuard` that restores the original on drop
99///
100/// # Example
101/// ```ignore
102/// let guard = hook::<NativeArch>(target, detour)?;
103/// let trampoline = guard.trampoline().unwrap();
104/// ```
105pub fn hook<A: Architecture>(target: usize, detour: usize) -> Result<HookGuard<A>> {
106    InlineHook::<A>::new(target, detour).install()
107}
108
109/// install an inline hook using the native architecture
110#[cfg(target_arch = "x86_64")]
111pub fn hook_native(target: usize, detour: usize) -> Result<HookGuard<X64>> {
112    hook::<X64>(target, detour)
113}
114
115#[cfg(target_arch = "x86")]
116pub fn hook_native(target: usize, detour: usize) -> Result<HookGuard<X86>> {
117    hook::<X86>(target, detour)
118}
119
120/// install a hot-patch hook
121///
122/// uses the Windows hot-patching mechanism for minimal disruption.
123/// only works on functions compiled with /hotpatch.
124pub fn hotpatch<A: Architecture>(target: usize, detour: usize) -> Result<HookGuard<A>> {
125    HotPatchHook::<A>::new(target, detour).install()
126}
127
128/// check if a function is hot-patchable
129pub fn is_hot_patchable(target: usize) -> bool {
130    hook::hotpatch::is_hot_patchable(target)
131}
132
133/// install a mid-function hook
134///
135/// hooks at an arbitrary location within a function.
136/// the detour receives a context pointer with all registers.
137pub fn mid_hook<A: Architecture>(
138    address: usize,
139    detour: MidHookFn,
140) -> Result<HookGuard<A>> {
141    MidFunctionHook::<A>::new(address, detour).install()
142}
143
144/// create a hook chain on a target function
145///
146/// allows multiple hooks on the same target with priority ordering.
147pub fn create_chain<A: Architecture>(target: usize) -> Result<HookChain<A>> {
148    HookChain::new(target)
149}
150
151/// convenience function to hook by module export name
152#[cfg(feature = "navigation")]
153pub fn hook_export<A: Architecture>(
154    module: &str,
155    export: &str,
156    detour: usize,
157) -> Result<HookGuard<A>> {
158    use crate::navigation::ModuleQuery;
159    use crate::structures::Peb;
160
161    let peb = Peb::current()?;
162    let query = ModuleQuery::new(&peb);
163    let module = query.find_by_name(module)?;
164    let target = module.get_export(export)?;
165
166    hook::<A>(target, detour)
167}
168
169/// convenience function to hook export using native architecture
170#[cfg(all(feature = "navigation", target_arch = "x86_64"))]
171pub fn hook_export_native(
172    module: &str,
173    export: &str,
174    detour: usize,
175) -> Result<HookGuard<X64>> {
176    hook_export::<X64>(module, export, detour)
177}
178
179#[cfg(all(feature = "navigation", target_arch = "x86"))]
180pub fn hook_export_native(
181    module: &str,
182    export: &str,
183    detour: usize,
184) -> Result<HookGuard<X86>> {
185    hook_export::<X86>(module, export, detour)
186}
187
188#[cfg(test)]
189mod tests {
190    use super::*;
191
192    #[test]
193    fn test_native_arch_defined() {
194        // just verify NativeArch type is available
195        let _: usize = NativeArch::JMP_REL_SIZE;
196        let _: usize = NativeArch::JMP_ABS_SIZE;
197        let _: usize = NativeArch::PTR_SIZE;
198    }
199}