Skip to content

About

Trampline hook libaray for rust

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

23 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hooking-rs

github-badge crates-hooking-badge docs-hooking-badge License

Function hooking in rust

A library for hooking and intercepting functions in rust for windows and linux, on x86_64 and x86.

Arenas and patchers

Creating or applying a hook never makes code that may be running non-executable, so hooks can be added and removed while hooked functions are being called on other threads.

Where the generated hook code lives is chosen by a CodeArena:

Arena Description
DualMappedArena (default) Maps memory twice, writable and executable. Hooks are written through the writable view, so executable memory never changes protection and hooks share pages.
SealedArena Each hook gets fresh memory that is made executable once and never written again. Uses at least a page per hook.

How the jump is written into the hooked function is chosen by a PatchWriter:

Patcher Description
AliasPatcher (default on linux) Swaps the target's pages for an identical memfd-backed copy with a writable alias, then patches through the alias. Protection never changes.
ProtectPatcher (default on windows) Makes the target's pages read/write/execute while patching, then restores their original protection.
use hooking::{HookWriter, arena::SealedArena, patch::ProtectPatcher};

static ARENA: SealedArena = SealedArena::new();
static PATCHER: ProtectPatcher = ProtectPatcher::new();

let writer = HookWriter::new(&ARENA).with_patcher(&PATCHER);
let mut hook = unsafe { writer.create_hook(target, destination)? };
unsafe { hook.apply_hook()? };

Example

Each function creates a stub in memory that consists of

Section Description
Original fn detour stub address A function pointer the generated detour stub to call the original function
Hooking stub A small stub that jumps to the hook. On x86_64 it first passes the original fn detour stub address in r10, for original_function_ptr
Original fn detour stub stub that re-creates the original fn call instructions and patches the instructions to work with ling jumps, then calls the hooked function

A simple hook:

// MessageBoxA is stdcall on x86, so the hook must be "system" too.
#[hook(lib = "user32.dll", method = "MessageBoxA")]
unsafe extern "system" fn hook_destination(
    _: *mut std::ffi::c_void,
    lp_text: *const i8,
    lp_caption: *const i8,
    _: u32,
) -> i32 {
    let original_msgbox = unsafe {
        hook_destination::original_function().expect("the hook was created")
    };

    original_msgbox(
        std::ptr::null_mut(),
        c"msgbox was hooked!".as_ptr(),
        c"Intercepted hook".as_ptr(),
        0,
    )
}

unsafe { hook_destination::enable_hook().unwrap() };

Without the macro, Hook::original_function gives the original function, which the hook can read from wherever it was stored. On x86_64, hooking::original_function_ptr() also returns it from inside the hook, as long as it is called before anything else in the hook. x86 passes arguments on the stack, so it has no register to spare for this.

You can see more examples in the example directory of the repository.

About

Trampline hook libaray for rust

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages