wraith/manipulation/inline_hook/mod.rs
1//! Inline hooking framework
2//!
3//! Provides comprehensive 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//! - IAT (Import Address Table) hooks
9//! - EAT (Export Address Table) hooks
10//! - VEH (Vectored Exception Handler) hooks
11//! - VMT (Virtual Method Table) hooks
12//!
13//! # Architecture Support
14//!
15//! Both x86 and x86_64 are supported via the `Architecture` trait.
16//! Use `NativeArch` for compile-time architecture selection.
17//!
18//! # Example
19//!
20//! ```ignore
21//! use wraith::manipulation::inline_hook::{hook, NativeArch};
22//!
23//! // define the original function type
24//! type TargetFn = extern "system" fn(i32) -> i32;
25//!
26//! // your detour function
27//! extern "system" fn my_detour(x: i32) -> i32 {
28//! // do something
29//! // call original via trampoline
30//! unsafe { ORIGINAL.unwrap()(x) }
31//! }
32//!
33//! static mut ORIGINAL: Option<TargetFn> = None;
34//!
35//! // install hook
36//! let guard = hook::<NativeArch>(target_addr, my_detour as usize)?;
37//! unsafe {
38//! ORIGINAL = Some(std::mem::transmute(guard.trampoline().unwrap()));
39//! }
40//!
41//! // hook is active until guard is dropped
42//! // or call guard.leak() to keep it permanently
43//! ```
44//!
45//! # Hook Types
46//!
47//! ## Code Modification Hooks
48//! - [`InlineHook`]: Standard prologue replacement hook
49//! - [`HotPatchHook`]: Uses Windows hot-patching space (2-byte atomic)
50//! - [`MidFunctionHook`]: Hook at arbitrary location with context
51//! - [`HookChain`]: Multiple hooks on same target with priorities
52//!
53//! ## Table Modification Hooks
54//! - [`IatHook`]: Import Address Table hook (per-module imports)
55//! - [`EatHook`]: Export Address Table hook (affects GetProcAddress)
56//! - [`VmtHook`]: Virtual Method Table hook (C++ virtual functions)
57//! - [`ShadowVmt`]: Shadow VMT for instance-specific hooking
58//!
59//! ## Exception-Based Hooks
60//! - [`VehHook`]: Vectored Exception Handler hook (hardware/software breakpoints)
61//!
62//! # Builder Pattern
63//!
64//! For more control, use the type-state builder:
65//!
66//! ```ignore
67//! use wraith::manipulation::inline_hook::{HookBuilder, NativeArch};
68//!
69//! let guard = HookBuilder::<NativeArch, _>::new()
70//! .target(target_addr)?
71//! .detour(detour_addr)?
72//! .allocate_trampoline()?
73//! .build_trampoline()?
74//! .prepare()?
75//! .install()?;
76//! ```
77
78pub mod arch;
79pub mod asm;
80pub mod builder;
81pub mod guard;
82pub mod hook;
83#[cfg(feature = "std")]
84pub mod registry;
85pub mod trampoline;
86
87// re-exports
88pub use arch::{Architecture, NativeArch, X64, X86};
89pub use builder::{state as BuilderState, HookBuilder};
90pub use guard::{HookGuard, HookState, StatefulHookGuard};
91pub use hook::{Hook, HookChain, HotPatchHook, InlineHook, MidFunctionHook};
92#[cfg(feature = "std")]
93pub use registry::{HookRegistry, HookType, RegisteredHook};
94pub use trampoline::ExecutableMemory;
95
96// IAT hooks
97pub use hook::iat::{IatHook, IatHookGuard, IatEntry, enumerate_iat_entries, find_iat_entry, hook_import, hook_import_all};
98
99// EAT hooks
100pub use hook::eat::{EatHook, EatHookBuilder, EatHookGuard, EatEntry, enumerate_eat_entries, find_eat_entry, find_eat_entry_by_ordinal};
101
102// VEH hooks
103pub use hook::veh::{VehHook, VehHookType, DebugRegister, BreakCondition, BreakLength, get_available_debug_register};
104
105// VMT hooks
106pub use hook::vmt::{VmtHook, VmtHookGuard, VmtHookBuilder, ShadowVmt, VmtObject, get_vtable, get_vtable_entry, estimate_vtable_size};
107
108#[cfg(target_arch = "x86_64")]
109pub use hook::mid::HookContext;
110#[cfg(target_arch = "x86")]
111pub use hook::mid::HookContext;
112pub use hook::mid::MidHookFn;
113
114use crate::error::Result;
115
116/// install an inline hook with native architecture
117///
118/// this is the simplest way to install a hook. returns a guard that
119/// automatically restores the original function when dropped.
120///
121/// # Arguments
122/// * `target` - address of the function to hook
123/// * `detour` - address of the detour function
124///
125/// # Returns
126/// `HookGuard` that restores the original on drop
127///
128/// # Example
129/// ```ignore
130/// let guard = hook::<NativeArch>(target, detour)?;
131/// let trampoline = guard.trampoline().unwrap();
132/// ```
133pub fn hook<A: Architecture>(target: usize, detour: usize) -> Result<HookGuard<A>> {
134 InlineHook::<A>::new(target, detour).install()
135}
136
137/// install an inline hook using the native architecture
138#[cfg(target_arch = "x86_64")]
139pub fn hook_native(target: usize, detour: usize) -> Result<HookGuard<X64>> {
140 hook::<X64>(target, detour)
141}
142
143#[cfg(target_arch = "x86")]
144pub fn hook_native(target: usize, detour: usize) -> Result<HookGuard<X86>> {
145 hook::<X86>(target, detour)
146}
147
148/// install a hot-patch hook
149///
150/// uses the Windows hot-patching mechanism for minimal disruption.
151/// only works on functions compiled with /hotpatch.
152pub fn hotpatch<A: Architecture>(target: usize, detour: usize) -> Result<HookGuard<A>> {
153 HotPatchHook::<A>::new(target, detour).install()
154}
155
156/// check if a function is hot-patchable
157pub fn is_hot_patchable(target: usize) -> bool {
158 hook::hotpatch::is_hot_patchable(target)
159}
160
161/// install a mid-function hook
162///
163/// hooks at an arbitrary location within a function.
164/// the detour receives a context pointer with all registers.
165pub fn mid_hook<A: Architecture>(
166 address: usize,
167 detour: MidHookFn,
168) -> Result<HookGuard<A>> {
169 MidFunctionHook::<A>::new(address, detour).install()
170}
171
172/// create a hook chain on a target function
173///
174/// allows multiple hooks on the same target with priority ordering.
175pub fn create_chain<A: Architecture>(target: usize) -> Result<HookChain<A>> {
176 HookChain::new(target)
177}
178
179/// convenience function to hook by module export name
180#[cfg(feature = "navigation")]
181pub fn hook_export<A: Architecture>(
182 module: &str,
183 export: &str,
184 detour: usize,
185) -> Result<HookGuard<A>> {
186 use crate::navigation::ModuleQuery;
187 use crate::structures::Peb;
188
189 let peb = Peb::current()?;
190 let query = ModuleQuery::new(&peb);
191 let module = query.find_by_name(module)?;
192 let target = module.get_export(export)?;
193
194 hook::<A>(target, detour)
195}
196
197/// convenience function to hook export using native architecture
198#[cfg(all(feature = "navigation", target_arch = "x86_64"))]
199pub fn hook_export_native(
200 module: &str,
201 export: &str,
202 detour: usize,
203) -> Result<HookGuard<X64>> {
204 hook_export::<X64>(module, export, detour)
205}
206
207#[cfg(all(feature = "navigation", target_arch = "x86"))]
208pub fn hook_export_native(
209 module: &str,
210 export: &str,
211 detour: usize,
212) -> Result<HookGuard<X86>> {
213 hook_export::<X86>(module, export, detour)
214}
215
216// ============================================================================
217// IAT Hook convenience functions
218// ============================================================================
219
220/// hook an import in the current module's IAT
221///
222/// # Arguments
223/// * `import_dll` - the DLL containing the function (e.g., "kernel32.dll")
224/// * `function_name` - the function to hook
225/// * `detour` - address of the detour function
226///
227/// # Example
228/// ```ignore
229/// let hook = iat_hook("kernel32.dll", "CreateFileW", my_create_file as usize)?;
230/// ```
231#[cfg(feature = "navigation")]
232pub fn iat_hook(import_dll: &str, function_name: &str, detour: usize) -> Result<IatHook> {
233 hook_import(import_dll, function_name, detour)
234}
235
236/// hook an import in a specific module's IAT
237#[cfg(feature = "navigation")]
238pub fn iat_hook_in(
239 target_module: &str,
240 import_dll: &str,
241 function_name: &str,
242 detour: usize,
243) -> Result<IatHook> {
244 IatHook::new(target_module, import_dll, function_name, detour)
245}
246
247// ============================================================================
248// EAT Hook convenience functions
249// ============================================================================
250
251/// hook an export in a module's EAT
252///
253/// # Arguments
254/// * `module_name` - the module containing the export (e.g., "kernel32.dll")
255/// * `function_name` - the function to hook
256/// * `detour` - address of the detour function
257///
258/// # Note
259/// Detour must be within ±2GB of module for RVA encoding.
260///
261/// # Example
262/// ```ignore
263/// let hook = eat_hook("ntdll.dll", "NtQueryInformationProcess", my_detour as usize)?;
264/// ```
265#[cfg(feature = "navigation")]
266pub fn eat_hook(module_name: &str, function_name: &str, detour: usize) -> Result<EatHook> {
267 EatHook::new(module_name, function_name, detour)
268}
269
270// ============================================================================
271// VEH Hook convenience functions
272// ============================================================================
273
274/// create a VEH hook using a hardware breakpoint
275///
276/// automatically selects an available debug register.
277///
278/// # Arguments
279/// * `target` - address to hook
280/// * `detour` - address of the detour function
281///
282/// # Example
283/// ```ignore
284/// let hook = veh_hook_hardware(target_addr, my_detour as usize)?;
285/// ```
286pub fn veh_hook_hardware(target: usize, detour: usize) -> Result<VehHook> {
287 let dr = get_available_debug_register()?;
288 VehHook::hardware(target, detour, dr)
289}
290
291/// create a VEH hook using INT3 software breakpoint
292///
293/// # Arguments
294/// * `target` - address to hook
295/// * `detour` - address of the detour function
296pub fn veh_hook_int3(target: usize, detour: usize) -> Result<VehHook> {
297 VehHook::int3(target, detour)
298}
299
300// ============================================================================
301// VMT Hook convenience functions
302// ============================================================================
303
304/// hook a virtual function in an object's VMT
305///
306/// # Safety
307/// Object must be a valid C++ object with a vtable.
308///
309/// # Arguments
310/// * `object` - pointer to the C++ object
311/// * `index` - vtable index of the function
312/// * `detour` - address of the detour function
313///
314/// # Example
315/// ```ignore
316/// let hook = unsafe { vmt_hook(object_ptr, 5, my_detour as usize)? };
317/// let original: fn() = unsafe { std::mem::transmute(hook.original()) };
318/// ```
319pub unsafe fn vmt_hook(object: *const (), index: usize, detour: usize) -> Result<VmtHook> {
320 // SAFETY: caller ensures object is valid C++ polymorphic object
321 unsafe { VmtHook::new(object, index, detour) }
322}
323
324/// create a shadow VMT for instance-specific hooking
325///
326/// # Safety
327/// Object must be a valid C++ object with a vtable.
328///
329/// # Arguments
330/// * `object` - pointer to the C++ object
331/// * `vtable_size` - number of entries in the vtable
332pub unsafe fn shadow_vmt<T>(object: *mut (), vtable_size: usize) -> Result<ShadowVmt<T>> {
333 // SAFETY: caller ensures object is valid C++ polymorphic object with vtable_size entries
334 unsafe { ShadowVmt::new(object, vtable_size) }
335}
336
337#[cfg(test)]
338mod tests {
339 use super::*;
340
341 #[test]
342 fn test_native_arch_defined() {
343 // just verify NativeArch type is available
344 let _: usize = NativeArch::JMP_REL_SIZE;
345 let _: usize = NativeArch::JMP_ABS_SIZE;
346 let _: usize = NativeArch::PTR_SIZE;
347 }
348}