pub struct Hook<F: Function = fn()> { /* private fields */ }Expand description
A typed function detour, and the RAII guard that owns it.
While enabled, calls to the target run a detour of the same signature F
instead; the original stays callable through original.
Build one with Hook::at, or Hook::scan to find the target by a byte
pattern.
§Threads
enable, disable and drop suspend every
other thread while patching and move any thread stopped inside the patched
bytes, so hooks can be toggled in a running, multi-threaded process. Don’t
toggle or drop a hook from inside its own target on the same thread. The
unsafe *_unsuspended methods skip the suspension.
§Batches
Inside batch, enable and disable are queued and
applied together when the batch ends. The *_unsuspended methods apply at
once even there, and replace any change queued for the same hook.
§Dropping
Dropping a hook disables it and frees its generated code. If it can’t be
disabled, say because a third party rewrote the target, the code is leaked
instead so the target never jumps into freed memory. leak
keeps a hook installed on purpose.
§Examples
use imping_hook::Hook;
#[inline(never)]
extern "C" fn add(a: i32, b: i32) -> i32 { a + b }
extern "C" fn sub(a: i32, b: i32) -> i32 { a - b }
// SAFETY: `add` is a real function with the signature below, and `sub`
// shares it.
let hook = unsafe {
Hook::at(add as *const ())
.redirect(sub as extern "C" fn(i32, i32) -> i32)
.install()?
};
assert_eq!(add(3, 2), 5);
hook.enable()?;
assert_eq!(add(3, 2), 1);
assert_eq!(hook.original().call(3, 2), 5);
hook.disable()?;
assert_eq!(add(3, 2), 5);Implementations§
Source§impl Hook
impl Hook
Sourcepub fn at(target: *const ()) -> HookBuilder
pub fn at(target: *const ()) -> HookBuilder
Starts building a hook of the function at target.
Nothing is patched until install.
Sourcepub fn scan(pattern: &str) -> HookScan
pub fn scan(pattern: &str) -> HookScan
Starts building a hook of the function a byte pattern finds.
The pattern is searched for in the main module’s code when the hook is
installed, and must match exactly once; see scan for
the syntax.
§Examples
// SAFETY: the pattern finds a function with the detour's signature.
let hook = unsafe {
Hook::scan("48 89 5C 24 ?? 57 48 83 EC 20")
.in_module("engine.dll")
.redirect(my_detour as extern "C" fn(i32) -> i32)
.install()?
};Source§impl<F: Function> Hook<F>
impl<F: Function> Hook<F>
Sourcepub fn enable(&self) -> Result<()>
pub fn enable(&self) -> Result<()>
Enables the hook, redirecting the target to the detour.
Does nothing if already enabled. Suspends other threads while patching;
see Hook for threads and batches.
§Errors
Returns an error naming the target if patching fails, such as
Error::TargetModified when a third party changed its code.
Sourcepub unsafe fn enable_unsuspended(&self) -> Result<()>
pub unsafe fn enable_unsuspended(&self) -> Result<()>
Sourcepub unsafe fn disable_unsuspended(&self) -> Result<()>
pub unsafe fn disable_unsuspended(&self) -> Result<()>
Disables the hook without suspending other threads.
Applied at once like enable_unsuspended.
§Errors
As for enable.
§Safety
No other thread may run the target’s first bytes while the original ones are written back.
Sourcepub fn is_enabled(&self) -> bool
pub fn is_enabled(&self) -> bool
Returns whether the hook is enabled.
Sourcepub fn original(&self) -> F::Original<'_>
pub fn original(&self) -> F::Original<'_>
Returns the original, unhooked function, borrowed from the hook.
Callable whether or not the hook is enabled; see Original.