1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
use libc::{c_char, c_void}; #[link(name = "dl")] extern "C" { fn dlsym(handle: *const c_void, symbol: *const c_char) -> *const c_void; } const RTLD_NEXT: *const c_void = -1isize as *const c_void; pub unsafe fn dlsym_next(symbol: &'static str) -> *const u8 { let ptr = dlsym(RTLD_NEXT, symbol.as_ptr() as *const c_char); if ptr.is_null() { panic!("redhook: Unable to find underlying function for {}", symbol); } ptr as *const u8 } #[macro_export] macro_rules! hook { (unsafe fn $real_fn:ident ( $($v:ident : $t:ty),* ) -> $r:ty => $hook_fn:ident $body:block) => { #[allow(non_camel_case_types)] pub struct $real_fn {__private_field: ()} #[allow(non_upper_case_globals)] static $real_fn: $real_fn = $real_fn {__private_field: ()}; impl $real_fn { fn get(&self) -> unsafe extern fn ( $($v : $t),* ) -> $r { use ::std::sync::Once; static mut REAL: *const u8 = 0 as *const u8; static mut ONCE: Once = Once::new(); unsafe { ONCE.call_once(|| { REAL = $crate::ld_preload::dlsym_next(concat!(stringify!($real_fn), "\0")); }); ::std::mem::transmute(REAL) } } #[no_mangle] pub unsafe extern fn $real_fn ( $($v : $t),* ) -> $r { ::std::panic::catch_unwind(|| $hook_fn ( $($v),* )).unwrap_or_else(|_| $real_fn.get() ( $($v),* )) } } pub unsafe fn $hook_fn ( $($v : $t),* ) -> $r { $body } }; (unsafe fn $real_fn:ident ( $($v:ident : $t:ty),* ) => $hook_fn:ident $body:block) => { $crate::hook! { unsafe fn $real_fn ( $($v : $t),* ) -> () => $hook_fn $body } }; } #[macro_export] macro_rules! real { ($real_fn:ident) => { $real_fn.get() }; }