Skip to main content

Hook

Struct Hook 

Source
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

Source

pub fn at(target: *const ()) -> HookBuilder

Starts building a hook of the function at target.

Nothing is patched until install.

Source

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>

Source

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.

Source

pub fn disable(&self) -> Result<()>

Disables the hook, restoring the original function.

Does nothing if already disabled. Suspends other threads while patching; see Hook for threads and batches.

§Errors

As for enable.

Source

pub unsafe fn enable_unsuspended(&self) -> Result<()>

Enables the hook without suspending other threads.

Faster than enable, and applied at once even inside a batch; see Hook.

§Errors

As for enable.

§Safety

No other thread may run the target’s first bytes while they are written, or it may execute a half-written instruction.

Source

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.

Source

pub fn is_enabled(&self) -> bool

Returns whether the hook is enabled.

Source

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.

Source

pub unsafe fn trampoline(&self) -> F

Returns the original function as a pointer not tied to the hook’s lifetime.

Prefer original unless the pointer has to outlive a borrow.

§Safety

Don’t call the returned function after the hook is dropped. Use leak if it must stay callable.

Source

pub fn leak(self) -> F

Keeps the hook installed for the rest of the process and returns the original function.

The hook stays in its current state, so enable it first if it should stay active. The target address stays reserved.

Trait Implementations§

Source§

impl<F: Function> Debug for Hook<F>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<F: Function> Drop for Hook<F>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl<F> Freeze for Hook<F>

§

impl<F> RefUnwindSafe for Hook<F>
where F: RefUnwindSafe,

§

impl<F> Send for Hook<F>
where F: Send,

§

impl<F> Sync for Hook<F>

§

impl<F> Unpin for Hook<F>

§

impl<F> UnsafeUnpin for Hook<F>

§

impl<F> UnwindSafe for Hook<F>
where F: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.