From 95d3de0f4b17fac1748736d54df7b5a886339dd9 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 21 Feb 2022 18:30:02 +0100 Subject: [PATCH] Closure hooks and on thread create hook (#542) * Closure hooks and on thread create hook * on thread once hook * clippy * fix * fix --- libafl_qemu/build_linux.rs | 2 +- libafl_qemu/src/emu.rs | 8 + libafl_qemu/src/hooks.rs | 1407 ++++++++++++++++++++++++++++-------- 3 files changed, 1101 insertions(+), 316 deletions(-) diff --git a/libafl_qemu/build_linux.rs b/libafl_qemu/build_linux.rs index a91ad84cce..70e7b46f8d 100644 --- a/libafl_qemu/build_linux.rs +++ b/libafl_qemu/build_linux.rs @@ -3,7 +3,7 @@ use which::which; const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; -const QEMU_REVISION: &str = "152fdbe024493f31e60060714caee3b90fdf3d9e"; +const QEMU_REVISION: &str = "35dcfc0c115da262622fdc811d089155f26a2abe"; fn build_dep_check(tools: &[&str]) { for tool in tools { diff --git a/libafl_qemu/src/emu.rs b/libafl_qemu/src/emu.rs index 36725b8ab1..2332b24266 100644 --- a/libafl_qemu/src/emu.rs +++ b/libafl_qemu/src/emu.rs @@ -240,6 +240,8 @@ extern "C" { static mut libafl_exec_cmp_hook8: unsafe extern "C" fn(u64, u64, u64); static mut libafl_gen_cmp_hook: unsafe extern "C" fn(u64, u32) -> u64; + static mut libafl_on_thread_hook: unsafe extern "C" fn(u32); + static mut libafl_pre_syscall_hook: unsafe extern "C" fn(i32, u64, u64, u64, u64, u64, u64, u64, u64) -> SyscallHookResult; static mut libafl_post_syscall_hook: @@ -662,6 +664,12 @@ impl Emulator { } } + pub fn set_on_thread_hook(&self, hook: extern "C" fn(tid: u32)) { + unsafe { + libafl_on_thread_hook = hook; + } + } + pub fn set_pre_syscall_hook( &self, hook: extern "C" fn(i32, u64, u64, u64, u64, u64, u64, u64, u64) -> SyscallHookResult, diff --git a/libafl_qemu/src/hooks.rs b/libafl_qemu/src/hooks.rs index c32dcc573a..29e1ee9315 100644 --- a/libafl_qemu/src/hooks.rs +++ b/libafl_qemu/src/hooks.rs @@ -1,4 +1,6 @@ //! The high-level hooks +#![allow(clippy::type_complexity)] + use core::{ ffi::c_void, fmt::{self, Debug, Formatter}, @@ -17,6 +19,28 @@ use crate::{ GuestAddr, }; +#[repr(C)] +#[derive(PartialEq, Clone, Copy)] +struct FatPtr(*const c_void, *const c_void); + +// all kinds of hooks +#[derive(PartialEq, Clone, Copy)] +enum Hook { + Function(*const c_void), + Closure(FatPtr), + Once(FatPtr), + Empty, +} + +// function signature for Read or Write hook functions with known length (1, 2, 4, 8) +type FixedLenHookFn = fn(&Emulator, &mut QT, Option<&mut S>, u64, GuestAddr); +type FixedLenHookCl = Box, u64, GuestAddr)>; + +// function signature for Read or Write hook functions with runtime length n +type DynamicLenHookFn = fn(&Emulator, &mut QT, Option<&mut S>, u64, GuestAddr, usize); +type DynamicLenHookCl = + Box, u64, GuestAddr, usize)>; + static mut QEMU_HELPERS_PTR: *const c_void = ptr::null(); unsafe fn get_qemu_helpers<'a, QT>() -> &'a mut QT { (QEMU_HELPERS_PTR as *mut QT) @@ -24,7 +48,20 @@ unsafe fn get_qemu_helpers<'a, QT>() -> &'a mut QT { .expect("A high-level hook is installed but QemuHooks is not initialized") } -static mut GEN_EDGE_HOOK_PTR: *const c_void = ptr::null(); +static mut QEMU_HOOKS_PTR: *const c_void = ptr::null(); +unsafe fn get_qemu_hooks<'a, I, QT, S>() -> Pin<&'a mut QemuHooks<'a, I, QT, S>> +where + I: Input, + QT: QemuHelperTuple, +{ + Pin::new_unchecked( + (QEMU_HOOKS_PTR as *mut QemuHooks<'a, I, QT, S>) + .as_mut() + .expect("A high-level hook is installed but QemuHooks is not initialized"), + ) +} + +static mut GEN_EDGE_HOOK: Hook = Hook::Empty; extern "C" fn gen_edge_hook_wrapper(src: u64, dst: u64) -> u64 where I: Input, @@ -33,28 +70,52 @@ where unsafe { let helpers = get_qemu_helpers::(); let emulator = Emulator::new_empty(); - let func: fn(&Emulator, &mut QT, Option<&mut S>, u64, u64) -> Option = - transmute(GEN_EDGE_HOOK_PTR); - (func)(&emulator, helpers, inprocess_get_state::(), src, dst) - .map_or(SKIP_EXEC_HOOK, |id| id) + match &GEN_EDGE_HOOK { + Hook::Function(ptr) => { + let func: fn(&Emulator, &mut QT, Option<&mut S>, u64, u64) -> Option = + transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), src, dst) + .map_or(SKIP_EXEC_HOOK, |id| id) + } + Hook::Closure(ptr) => { + let mut func: Box< + dyn FnMut(&Emulator, &mut QT, Option<&mut S>, u64, u64) -> Option, + > = transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), src, dst) + .map_or(SKIP_EXEC_HOOK, |id| id) + } + _ => SKIP_EXEC_HOOK, + } } } -static mut EDGE_HOOKS: Vec<*const c_void> = vec![]; +static mut EDGE_HOOKS: Vec = vec![]; extern "C" fn edge_hooks_wrapper(id: u64) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &EDGE_HOOKS } { - let func: fn(&Emulator, &mut QT, Option<&mut S>, u64) = unsafe { transmute(*hook) }; - (func)(&emulator, helpers, inprocess_get_state::(), id); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &EDGE_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: fn(&Emulator, &mut QT, Option<&mut S>, u64) = transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), id); + } + Hook::Closure(ptr) => { + let mut func: Box, u64)> = + transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), id); + } + _ => (), + } + } } } -static mut GEN_BLOCK_HOOK_PTR: *const c_void = ptr::null(); +static mut GEN_BLOCK_HOOK: Hook = Hook::Empty; extern "C" fn gen_block_hook_wrapper(pc: u64) -> u64 where I: Input, @@ -63,27 +124,52 @@ where unsafe { let helpers = get_qemu_helpers::(); let emulator = Emulator::new_empty(); - let func: fn(&Emulator, &mut QT, Option<&mut S>, u64) -> Option = - transmute(GEN_BLOCK_HOOK_PTR); - (func)(&emulator, helpers, inprocess_get_state::(), pc).map_or(SKIP_EXEC_HOOK, |id| id) + match &GEN_BLOCK_HOOK { + Hook::Function(ptr) => { + let func: fn(&Emulator, &mut QT, Option<&mut S>, u64) -> Option = + transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), pc) + .map_or(SKIP_EXEC_HOOK, |id| id) + } + Hook::Closure(ptr) => { + let mut func: Box< + dyn FnMut(&Emulator, &mut QT, Option<&mut S>, u64) -> Option, + > = transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), pc) + .map_or(SKIP_EXEC_HOOK, |id| id) + } + _ => SKIP_EXEC_HOOK, + } } } -static mut BLOCK_HOOKS: Vec<*const c_void> = vec![]; +static mut BLOCK_HOOKS: Vec = vec![]; extern "C" fn block_hooks_wrapper(id: u64) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &BLOCK_HOOKS } { - let func: fn(&Emulator, &mut QT, Option<&mut S>, u64) = unsafe { transmute(*hook) }; - (func)(&emulator, helpers, inprocess_get_state::(), id); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &BLOCK_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: fn(&Emulator, &mut QT, Option<&mut S>, u64) = transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), id); + } + Hook::Closure(ptr) => { + let mut func: Box, u64)> = + transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), id); + } + _ => (), + } + } } } -static mut GEN_READ_HOOK_PTR: *const c_void = ptr::null(); +static mut GEN_READ_HOOK: Hook = Hook::Empty; extern "C" fn gen_read_hook_wrapper(size: u32) -> u64 where I: Input, @@ -92,19 +178,36 @@ where unsafe { let helpers = get_qemu_helpers::(); let emulator = Emulator::new_empty(); - let func: fn(&Emulator, &mut QT, Option<&mut S>, usize) -> Option = - transmute(GEN_READ_HOOK_PTR); - (func)( - &emulator, - helpers, - inprocess_get_state::(), - size as usize, - ) - .map_or(SKIP_EXEC_HOOK, |id| id) + match &GEN_READ_HOOK { + Hook::Function(ptr) => { + let func: fn(&Emulator, &mut QT, Option<&mut S>, usize) -> Option = + transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + size as usize, + ) + .map_or(SKIP_EXEC_HOOK, |id| id) + } + Hook::Closure(ptr) => { + let mut func: Box< + dyn FnMut(&Emulator, &mut QT, Option<&mut S>, usize) -> Option, + > = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + size as usize, + ) + .map_or(SKIP_EXEC_HOOK, |id| id) + } + _ => SKIP_EXEC_HOOK, + } } } -static mut GEN_WRITE_HOOK_PTR: *const c_void = ptr::null(); +static mut GEN_WRITE_HOOK: Hook = Hook::Empty; extern "C" fn gen_write_hook_wrapper(size: u32) -> u64 where I: Input, @@ -113,227 +216,410 @@ where unsafe { let helpers = get_qemu_helpers::(); let emulator = Emulator::new_empty(); - let func: fn(&Emulator, &mut QT, Option<&mut S>, usize) -> Option = - transmute(GEN_WRITE_HOOK_PTR); - (func)( - &emulator, - helpers, - inprocess_get_state::(), - size as usize, - ) - .map_or(SKIP_EXEC_HOOK, |id| id) + match &GEN_WRITE_HOOK { + Hook::Function(ptr) => { + let func: fn(&Emulator, &mut QT, Option<&mut S>, usize) -> Option = + transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + size as usize, + ) + .map_or(SKIP_EXEC_HOOK, |id| id) + } + Hook::Closure(ptr) => { + let mut func: Box< + dyn FnMut(&Emulator, &mut QT, Option<&mut S>, usize) -> Option, + > = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + size as usize, + ) + .map_or(SKIP_EXEC_HOOK, |id| id) + } + _ => SKIP_EXEC_HOOK, + } } } -// function signature for Read or Write hook functions with known length (1, 2, 4, 8) -type FixedLenHook = fn(&Emulator, &mut QT, Option<&mut S>, u64, GuestAddr); - -// function signature for Read or Write hook functions with runtime length n -type DynamicLenHook = fn(&Emulator, &mut QT, Option<&mut S>, u64, GuestAddr, usize); - -static mut READ1_HOOKS: Vec<*const c_void> = vec![]; +static mut READ1_HOOKS: Vec = vec![]; extern "C" fn read1_hooks_wrapper(id: u64, addr: u64) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &READ1_HOOKS } { - let func: FixedLenHook = unsafe { transmute(*hook) }; - (func)( - &emulator, - helpers, - inprocess_get_state::(), - id, - addr as GuestAddr, - ); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &READ1_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: FixedLenHookFn = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + Hook::Closure(ptr) => { + let mut func: FixedLenHookCl = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + _ => (), + } + } } } -static mut READ2_HOOKS: Vec<*const c_void> = vec![]; +static mut READ2_HOOKS: Vec = vec![]; extern "C" fn read2_hooks_wrapper(id: u64, addr: u64) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &READ2_HOOKS } { - let func: FixedLenHook = unsafe { transmute(*hook) }; - (func)( - &emulator, - helpers, - inprocess_get_state::(), - id, - addr as GuestAddr, - ); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &READ2_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: FixedLenHookFn = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + Hook::Closure(ptr) => { + let mut func: FixedLenHookCl = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + _ => (), + } + } } } -static mut READ4_HOOKS: Vec<*const c_void> = vec![]; +static mut READ4_HOOKS: Vec = vec![]; extern "C" fn read4_hooks_wrapper(id: u64, addr: u64) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &READ4_HOOKS } { - let func: FixedLenHook = unsafe { transmute(*hook) }; - (func)( - &emulator, - helpers, - inprocess_get_state::(), - id, - addr as GuestAddr, - ); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &READ4_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: FixedLenHookFn = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + Hook::Closure(ptr) => { + let mut func: FixedLenHookCl = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + _ => (), + } + } } } -static mut READ8_HOOKS: Vec<*const c_void> = vec![]; +static mut READ8_HOOKS: Vec = vec![]; extern "C" fn read8_hooks_wrapper(id: u64, addr: u64) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &READ8_HOOKS } { - let func: FixedLenHook = unsafe { transmute(*hook) }; - (func)( - &emulator, - helpers, - inprocess_get_state::(), - id, - addr as GuestAddr, - ); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &READ8_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: FixedLenHookFn = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + Hook::Closure(ptr) => { + let mut func: FixedLenHookCl = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + _ => (), + } + } } } -static mut READ_N_HOOKS: Vec<*const c_void> = vec![]; +static mut READ_N_HOOKS: Vec = vec![]; extern "C" fn read_n_hooks_wrapper(id: u64, addr: u64, size: u32) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &READ_N_HOOKS } { - let func: DynamicLenHook = unsafe { transmute(*hook) }; - (func)( - &emulator, - helpers, - inprocess_get_state::(), - id, - addr as GuestAddr, - size as usize, - ); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &READ_N_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: DynamicLenHookFn = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + size as usize, + ); + } + Hook::Closure(ptr) => { + let mut func: DynamicLenHookCl = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + size as usize, + ); + } + _ => (), + } + } } } -static mut WRITE1_HOOKS: Vec<*const c_void> = vec![]; +static mut WRITE1_HOOKS: Vec = vec![]; extern "C" fn write1_hooks_wrapper(id: u64, addr: u64) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &WRITE1_HOOKS } { - let func: FixedLenHook = unsafe { transmute(*hook) }; - (func)( - &emulator, - helpers, - inprocess_get_state::(), - id, - addr as GuestAddr, - ); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &WRITE1_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: FixedLenHookFn = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + Hook::Closure(ptr) => { + let mut func: FixedLenHookCl = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + _ => (), + } + } } } -static mut WRITE2_HOOKS: Vec<*const c_void> = vec![]; +static mut WRITE2_HOOKS: Vec = vec![]; extern "C" fn write2_hooks_wrapper(id: u64, addr: u64) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &WRITE2_HOOKS } { - let func: FixedLenHook = unsafe { transmute(*hook) }; - (func)( - &emulator, - helpers, - inprocess_get_state::(), - id, - addr as GuestAddr, - ); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &WRITE2_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: FixedLenHookFn = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + Hook::Closure(ptr) => { + let mut func: FixedLenHookCl = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + _ => (), + } + } } } -static mut WRITE4_HOOKS: Vec<*const c_void> = vec![]; +static mut WRITE4_HOOKS: Vec = vec![]; extern "C" fn write4_hooks_wrapper(id: u64, addr: u64) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &WRITE4_HOOKS } { - let func: FixedLenHook = unsafe { transmute(*hook) }; - (func)( - &emulator, - helpers, - inprocess_get_state::(), - id, - addr as GuestAddr, - ); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &WRITE4_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: FixedLenHookFn = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + Hook::Closure(ptr) => { + let mut func: FixedLenHookCl = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + _ => (), + } + } } } -static mut WRITE8_HOOKS: Vec<*const c_void> = vec![]; +static mut WRITE8_HOOKS: Vec = vec![]; extern "C" fn write8_hooks_wrapper(id: u64, addr: u64) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &WRITE8_HOOKS } { - let func: FixedLenHook = unsafe { transmute(*hook) }; - (func)( - &emulator, - helpers, - inprocess_get_state::(), - id, - addr as GuestAddr, - ); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &WRITE8_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: FixedLenHookFn = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + Hook::Closure(ptr) => { + let mut func: FixedLenHookCl = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + ); + } + _ => (), + } + } } } -static mut WRITE_N_HOOKS: Vec<*const c_void> = vec![]; +static mut WRITE_N_HOOKS: Vec = vec![]; extern "C" fn write_n_hooks_wrapper(id: u64, addr: u64, size: u32) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &WRITE_N_HOOKS } { - let func: DynamicLenHook = unsafe { transmute(*hook) }; - (func)( - &emulator, - helpers, - inprocess_get_state::(), - id, - addr as GuestAddr, - size as usize, - ); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &WRITE1_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: DynamicLenHookFn = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + size as usize, + ); + } + Hook::Closure(ptr) => { + let mut func: DynamicLenHookCl = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + id, + addr as GuestAddr, + size as usize, + ); + } + _ => (), + } + } } } -static mut GEN_CMP_HOOK_PTR: *const c_void = ptr::null(); +static mut GEN_CMP_HOOK: Hook = Hook::Empty; extern "C" fn gen_cmp_hook_wrapper(pc: u64, size: u32) -> u64 where I: Input, @@ -342,79 +628,197 @@ where unsafe { let helpers = get_qemu_helpers::(); let emulator = Emulator::new_empty(); - let func: fn(&Emulator, &mut QT, Option<&mut S>, u64, usize) -> Option = - transmute(GEN_CMP_HOOK_PTR); - (func)( - &emulator, - helpers, - inprocess_get_state::(), - pc, - size as usize, - ) - .map_or(SKIP_EXEC_HOOK, |id| id) + match &GEN_CMP_HOOK { + Hook::Function(ptr) => { + let func: fn(&Emulator, &mut QT, Option<&mut S>, u64, usize) -> Option = + transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + pc, + size as usize, + ) + .map_or(SKIP_EXEC_HOOK, |id| id) + } + Hook::Closure(ptr) => { + let mut func: Box< + dyn FnMut(&Emulator, &mut QT, Option<&mut S>, u64, usize) -> Option, + > = transmute(*ptr); + (func)( + &emulator, + helpers, + inprocess_get_state::(), + pc, + size as usize, + ) + .map_or(SKIP_EXEC_HOOK, |id| id) + } + _ => SKIP_EXEC_HOOK, + } } } -static mut CMP1_HOOKS: Vec<*const c_void> = vec![]; +static mut CMP1_HOOKS: Vec = vec![]; extern "C" fn cmp1_hooks_wrapper(id: u64, v0: u8, v1: u8) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &CMP1_HOOKS } { - let func: fn(&Emulator, &mut QT, Option<&mut S>, u64, u8, u8) = unsafe { transmute(*hook) }; - (func)(&emulator, helpers, inprocess_get_state::(), id, v0, v1); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &CMP1_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: fn(&Emulator, &mut QT, Option<&mut S>, u64, u8, u8) = transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), id, v0, v1); + } + Hook::Closure(ptr) => { + let mut func: Box, u64, u8, u8)> = + transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), id, v0, v1); + } + _ => (), + } + } } } -static mut CMP2_HOOKS: Vec<*const c_void> = vec![]; +static mut CMP2_HOOKS: Vec = vec![]; extern "C" fn cmp2_hooks_wrapper(id: u64, v0: u16, v1: u16) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &CMP2_HOOKS } { - let func: fn(&Emulator, &mut QT, Option<&mut S>, u64, u16, u16) = - unsafe { transmute(*hook) }; - (func)(&emulator, helpers, inprocess_get_state::(), id, v0, v1); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &CMP2_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: fn(&Emulator, &mut QT, Option<&mut S>, u64, u16, u16) = + transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), id, v0, v1); + } + Hook::Closure(ptr) => { + let mut func: Box< + dyn FnMut(&Emulator, &mut QT, Option<&mut S>, u64, u16, u16), + > = transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), id, v0, v1); + } + _ => (), + } + } } } -static mut CMP4_HOOKS: Vec<*const c_void> = vec![]; +static mut CMP4_HOOKS: Vec = vec![]; extern "C" fn cmp4_hooks_wrapper(id: u64, v0: u32, v1: u32) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &CMP4_HOOKS } { - let func: fn(&Emulator, &mut QT, Option<&mut S>, u64, u32, u32) = - unsafe { transmute(*hook) }; - (func)(&emulator, helpers, inprocess_get_state::(), id, v0, v1); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &CMP4_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: fn(&Emulator, &mut QT, Option<&mut S>, u64, u32, u32) = + transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), id, v0, v1); + } + Hook::Closure(ptr) => { + let mut func: Box< + dyn FnMut(&Emulator, &mut QT, Option<&mut S>, u64, u32, u32), + > = transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), id, v0, v1); + } + _ => (), + } + } } } -static mut CMP8_HOOKS: Vec<*const c_void> = vec![]; +static mut CMP8_HOOKS: Vec = vec![]; extern "C" fn cmp8_hooks_wrapper(id: u64, v0: u64, v1: u64) where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - for hook in unsafe { &CMP8_HOOKS } { - let func: fn(&Emulator, &mut QT, Option<&mut S>, u64, u64, u64) = - unsafe { transmute(*hook) }; - (func)(&emulator, helpers, inprocess_get_state::(), id, v0, v1); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + for hook in &CMP8_HOOKS { + match hook { + Hook::Function(ptr) => { + let func: fn(&Emulator, &mut QT, Option<&mut S>, u64, u64, u64) = + transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), id, v0, v1); + } + Hook::Closure(ptr) => { + let mut func: Box< + dyn FnMut(&Emulator, &mut QT, Option<&mut S>, u64, u64, u64), + > = transmute(*ptr); + (func)(&emulator, helpers, inprocess_get_state::(), id, v0, v1); + } + _ => (), + } + } } } -static mut SYSCALL_HOOKS: Vec<*const c_void> = vec![]; +static mut ON_THREAD_HOOKS: Vec = vec![]; +extern "C" fn on_thread_hooks_wrapper(tid: u32) +where + I: Input, + QT: QemuHelperTuple, +{ + unsafe { + let emu = Emulator::new_empty(); + for hook in &mut ON_THREAD_HOOKS { + let hooks = get_qemu_hooks::(); + match hook { + Hook::Function(ptr) => { + let func: fn( + &Emulator, + Pin<&mut QemuHooks<'_, I, QT, S>>, + Option<&mut S>, + u32, + ) = transmute(*ptr); + (func)(&emu, hooks, inprocess_get_state::(), tid); + } + Hook::Closure(ptr) => { + let mut func: Box< + dyn FnMut( + &Emulator, + Pin<&mut QemuHooks<'_, I, QT, S>>, + Option<&mut S>, + u32, + ), + > = transmute(*ptr); + (func)(&emu, hooks, inprocess_get_state::(), tid); + } + Hook::Once(ptr) => { + let func: Box< + dyn FnOnce( + &Emulator, + Pin<&mut QemuHooks<'_, I, QT, S>>, + Option<&mut S>, + u32, + ), + > = transmute(*ptr); + (func)(&emu, hooks, inprocess_get_state::(), tid); + *hook = Hook::Empty; + } + Hook::Empty => (), + } + } + } +} + +static mut SYSCALL_HOOKS: Vec = vec![]; extern "C" fn syscall_hooks_wrapper( sys_num: i32, a0: u64, @@ -430,48 +834,92 @@ where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - let mut res = SyscallHookResult::new(None); - for hook in unsafe { &SYSCALL_HOOKS } { - #[allow(clippy::type_complexity)] - let func: fn( - &Emulator, - &mut QT, - Option<&mut S>, - i32, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - ) -> SyscallHookResult = unsafe { transmute(*hook) }; - let r = (func)( - &emulator, - helpers, - inprocess_get_state::(), - sys_num, - a0, - a1, - a2, - a3, - a4, - a5, - a6, - a7, - ); - if r.skip_syscall { - res.skip_syscall = true; - res.retval = r.retval; + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + let mut res = SyscallHookResult::new(None); + for hook in &SYSCALL_HOOKS { + match hook { + Hook::Function(ptr) => { + #[allow(clippy::type_complexity)] + let func: fn( + &Emulator, + &mut QT, + Option<&mut S>, + i32, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + ) -> SyscallHookResult = transmute(*ptr); + let r = (func)( + &emulator, + helpers, + inprocess_get_state::(), + sys_num, + a0, + a1, + a2, + a3, + a4, + a5, + a6, + a7, + ); + if r.skip_syscall { + res.skip_syscall = true; + res.retval = r.retval; + } + } + Hook::Closure(ptr) => { + #[allow(clippy::type_complexity)] + let mut func: Box< + dyn FnMut( + &Emulator, + &mut QT, + Option<&mut S>, + i32, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + ) -> SyscallHookResult, + > = transmute(*ptr); + let r = (func)( + &emulator, + helpers, + inprocess_get_state::(), + sys_num, + a0, + a1, + a2, + a3, + a4, + a5, + a6, + a7, + ); + if r.skip_syscall { + res.skip_syscall = true; + res.retval = r.retval; + } + } + _ => (), + } } + res } - res } -static mut SYSCALL_POST_HOOKS: Vec<*const c_void> = vec![]; +static mut SYSCALL_POST_HOOKS: Vec = vec![]; extern "C" fn syscall_after_hooks_wrapper( result: u64, sys_num: i32, @@ -488,43 +936,85 @@ where I: Input, QT: QemuHelperTuple, { - let helpers = unsafe { get_qemu_helpers::() }; - let emulator = Emulator::new_empty(); - let mut res = result; - for hook in unsafe { &SYSCALL_POST_HOOKS } { - #[allow(clippy::type_complexity)] - let func: fn( - &Emulator, - &mut QT, - Option<&mut S>, - u64, - i32, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - ) -> u64 = unsafe { transmute(*hook) }; - res = (func)( - &emulator, - helpers, - inprocess_get_state::(), - res, - sys_num, - a0, - a1, - a2, - a3, - a4, - a5, - a6, - a7, - ); + unsafe { + let helpers = get_qemu_helpers::(); + let emulator = Emulator::new_empty(); + let mut res = result; + for hook in &SYSCALL_POST_HOOKS { + match hook { + Hook::Function(ptr) => { + #[allow(clippy::type_complexity)] + let func: fn( + &Emulator, + &mut QT, + Option<&mut S>, + u64, + i32, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + ) -> u64 = transmute(*ptr); + res = (func)( + &emulator, + helpers, + inprocess_get_state::(), + res, + sys_num, + a0, + a1, + a2, + a3, + a4, + a5, + a6, + a7, + ); + } + Hook::Closure(ptr) => { + #[allow(clippy::type_complexity)] + let mut func: Box< + dyn FnMut( + &Emulator, + &mut QT, + Option<&mut S>, + u64, + i32, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + ) -> u64, + > = transmute(*ptr); + res = (func)( + &emulator, + helpers, + inprocess_get_state::(), + res, + sys_num, + a0, + a1, + a2, + a3, + a4, + a5, + a6, + a7, + ); + } + _ => (), + } + } + res } - res } static mut HOOKS_IS_INITIALIZED: bool = false; @@ -575,6 +1065,7 @@ where slf.helpers.init_hooks_all(slf.as_ref()); unsafe { QEMU_HELPERS_PTR = addr_of!(slf.helpers) as *const c_void; + QEMU_HOOKS_PTR = addr_of!(*slf) as *const c_void; } slf } @@ -617,7 +1108,18 @@ where hook: fn(&Emulator, &mut QT, Option<&mut S>, src: u64, dest: u64) -> Option, ) { unsafe { - GEN_EDGE_HOOK_PTR = hook as *const _; + GEN_EDGE_HOOK = Hook::Function(hook as *const libc::c_void); + } + self.emulator + .set_gen_edge_hook(gen_edge_hook_wrapper::); + } + + pub fn edge_generation_closure( + &self, + hook: Box, u64, u64) -> Option>, + ) { + unsafe { + GEN_EDGE_HOOK = Hook::Closure(transmute(hook)); } self.emulator .set_gen_edge_hook(gen_edge_hook_wrapper::); @@ -625,7 +1127,18 @@ where pub fn edge_execution(&self, hook: fn(&Emulator, &mut QT, Option<&mut S>, id: u64)) { unsafe { - EDGE_HOOKS.push(hook as *const _); + EDGE_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + } + self.emulator + .set_exec_edge_hook(edge_hooks_wrapper::); + } + + pub fn edge_execution_closure( + &self, + hook: Box, u64)>, + ) { + unsafe { + EDGE_HOOKS.push(Hook::Closure(transmute(hook))); } self.emulator .set_exec_edge_hook(edge_hooks_wrapper::); @@ -636,7 +1149,18 @@ where hook: fn(&Emulator, &mut QT, Option<&mut S>, pc: u64) -> Option, ) { unsafe { - GEN_BLOCK_HOOK_PTR = hook as *const _; + GEN_BLOCK_HOOK = Hook::Function(hook as *const libc::c_void); + } + self.emulator + .set_gen_block_hook(gen_block_hook_wrapper::); + } + + pub fn block_generation_closure( + &self, + hook: Box, u64) -> Option>, + ) { + unsafe { + GEN_BLOCK_HOOK = Hook::Closure(transmute(hook)); } self.emulator .set_gen_block_hook(gen_block_hook_wrapper::); @@ -644,7 +1168,18 @@ where pub fn block_execution(&self, hook: fn(&Emulator, &mut QT, Option<&mut S>, id: u64)) { unsafe { - BLOCK_HOOKS.push(hook as *const _); + BLOCK_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + } + self.emulator + .set_exec_block_hook(block_hooks_wrapper::); + } + + pub fn block_execution_closure( + &self, + hook: Box, u64)>, + ) { + unsafe { + BLOCK_HOOKS.push(Hook::Closure(transmute(hook))); } self.emulator .set_exec_block_hook(block_hooks_wrapper::); @@ -655,47 +1190,98 @@ where hook: fn(&Emulator, &mut QT, Option<&mut S>, size: usize) -> Option, ) { unsafe { - GEN_READ_HOOK_PTR = hook as *const _; + GEN_READ_HOOK = Hook::Function(hook as *const libc::c_void); } self.emulator .set_gen_read_hook(gen_read_hook_wrapper::); } - pub fn read1_execution(&self, hook: FixedLenHook) { + pub fn read_generation_closure( + &self, + hook: Box, usize) -> Option>, + ) { unsafe { - READ1_HOOKS.push(hook as *const _); + GEN_READ_HOOK = Hook::Closure(transmute(hook)); + } + self.emulator + .set_gen_read_hook(gen_read_hook_wrapper::); + } + + pub fn read1_execution(&self, hook: FixedLenHookFn) { + unsafe { + READ1_HOOKS.push(Hook::Function(hook as *const libc::c_void)); } self.emulator .set_exec_read1_hook(read1_hooks_wrapper::); } - pub fn read2_execution(&self, hook: FixedLenHook) { + pub fn read1_execution_closure(&self, hook: FixedLenHookCl) { unsafe { - READ2_HOOKS.push(hook as *const _); + READ1_HOOKS.push(Hook::Closure(transmute(hook))); + } + self.emulator + .set_exec_read1_hook(read1_hooks_wrapper::); + } + + pub fn read2_execution(&self, hook: FixedLenHookFn) { + unsafe { + READ2_HOOKS.push(Hook::Function(hook as *const libc::c_void)); } self.emulator .set_exec_read2_hook(read2_hooks_wrapper::); } - pub fn read4_execution(&self, hook: FixedLenHook) { + pub fn read2_execution_closure(&self, hook: FixedLenHookCl) { unsafe { - READ4_HOOKS.push(hook as *const _); + READ2_HOOKS.push(Hook::Closure(transmute(hook))); + } + self.emulator + .set_exec_read2_hook(read2_hooks_wrapper::); + } + + pub fn read4_execution(&self, hook: FixedLenHookFn) { + unsafe { + READ4_HOOKS.push(Hook::Function(hook as *const libc::c_void)); } self.emulator .set_exec_read4_hook(read4_hooks_wrapper::); } - pub fn read8_execution(&self, hook: FixedLenHook) { + pub fn read4_execution_closure(&self, hook: FixedLenHookCl) { unsafe { - READ8_HOOKS.push(hook as *const _); + READ4_HOOKS.push(Hook::Closure(transmute(hook))); + } + self.emulator + .set_exec_read4_hook(read4_hooks_wrapper::); + } + + pub fn read8_execution(&self, hook: FixedLenHookFn) { + unsafe { + READ8_HOOKS.push(Hook::Function(hook as *const libc::c_void)); } self.emulator .set_exec_read8_hook(read8_hooks_wrapper::); } - pub fn read_n_execution(&self, hook: DynamicLenHook) { + pub fn read8_execution_closure(&self, hook: FixedLenHookCl) { unsafe { - READ_N_HOOKS.push(hook as *const _); + READ8_HOOKS.push(Hook::Closure(transmute(hook))); + } + self.emulator + .set_exec_read8_hook(read8_hooks_wrapper::); + } + + pub fn read_n_execution(&self, hook: DynamicLenHookFn) { + unsafe { + READ_N_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + } + self.emulator + .set_exec_read_n_hook(read_n_hooks_wrapper::); + } + + pub fn read_n_execution_closure(&self, hook: DynamicLenHookCl) { + unsafe { + READ_N_HOOKS.push(Hook::Closure(transmute(hook))); } self.emulator .set_exec_read_n_hook(read_n_hooks_wrapper::); @@ -706,47 +1292,98 @@ where hook: fn(&Emulator, &mut QT, Option<&mut S>, size: usize) -> Option, ) { unsafe { - GEN_WRITE_HOOK_PTR = hook as *const _; + GEN_WRITE_HOOK = Hook::Function(hook as *const libc::c_void); } self.emulator .set_gen_write_hook(gen_write_hook_wrapper::); } - pub fn write1_execution(&self, hook: FixedLenHook) { + pub fn write_generation_closure( + &self, + hook: Box, usize) -> Option>, + ) { unsafe { - WRITE1_HOOKS.push(hook as *const _); + GEN_WRITE_HOOK = Hook::Closure(transmute(hook)); + } + self.emulator + .set_gen_write_hook(gen_write_hook_wrapper::); + } + + pub fn write1_execution(&self, hook: FixedLenHookFn) { + unsafe { + WRITE1_HOOKS.push(Hook::Function(hook as *const libc::c_void)); } self.emulator .set_exec_write1_hook(write1_hooks_wrapper::); } - pub fn write2_execution(&self, hook: FixedLenHook) { + pub fn write1_execution_closure(&self, hook: FixedLenHookCl) { unsafe { - WRITE2_HOOKS.push(hook as *const _); + WRITE1_HOOKS.push(Hook::Closure(transmute(hook))); + } + self.emulator + .set_exec_write1_hook(write1_hooks_wrapper::); + } + + pub fn write2_execution(&self, hook: FixedLenHookFn) { + unsafe { + WRITE2_HOOKS.push(Hook::Function(hook as *const libc::c_void)); } self.emulator .set_exec_write2_hook(write2_hooks_wrapper::); } - pub fn write4_execution(&self, hook: FixedLenHook) { + pub fn write2_execution_closure(&self, hook: FixedLenHookCl) { unsafe { - WRITE4_HOOKS.push(hook as *const _); + WRITE2_HOOKS.push(Hook::Closure(transmute(hook))); + } + self.emulator + .set_exec_write2_hook(write2_hooks_wrapper::); + } + + pub fn write4_execution(&self, hook: FixedLenHookFn) { + unsafe { + WRITE4_HOOKS.push(Hook::Function(hook as *const libc::c_void)); } self.emulator .set_exec_write4_hook(write4_hooks_wrapper::); } - pub fn write8_execution(&self, hook: FixedLenHook) { + pub fn write4_execution_closure(&self, hook: FixedLenHookCl) { unsafe { - WRITE8_HOOKS.push(hook as *const _); + WRITE4_HOOKS.push(Hook::Closure(transmute(hook))); + } + self.emulator + .set_exec_write4_hook(write4_hooks_wrapper::); + } + + pub fn write8_execution(&self, hook: FixedLenHookFn) { + unsafe { + WRITE8_HOOKS.push(Hook::Function(hook as *const libc::c_void)); } self.emulator .set_exec_write8_hook(write8_hooks_wrapper::); } - pub fn write_n_execution(&self, hook: DynamicLenHook) { + pub fn write8_execution_closure(&self, hook: FixedLenHookCl) { unsafe { - WRITE_N_HOOKS.push(hook as *const _); + WRITE8_HOOKS.push(Hook::Closure(transmute(hook))); + } + self.emulator + .set_exec_write8_hook(write8_hooks_wrapper::); + } + + pub fn write_n_execution(&self, hook: DynamicLenHookFn) { + unsafe { + WRITE_N_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + } + self.emulator + .set_exec_write_n_hook(write_n_hooks_wrapper::); + } + + pub fn write_n_execution_closure(&self, hook: DynamicLenHookCl) { + unsafe { + WRITE_N_HOOKS.push(Hook::Closure(transmute(hook))); } self.emulator .set_exec_write_n_hook(write_n_hooks_wrapper::); @@ -757,7 +1394,18 @@ where hook: fn(&Emulator, &mut QT, Option<&mut S>, pc: u64, size: usize) -> Option, ) { unsafe { - GEN_CMP_HOOK_PTR = hook as *const _; + GEN_CMP_HOOK = Hook::Function(hook as *const libc::c_void); + } + self.emulator + .set_gen_cmp_hook(gen_cmp_hook_wrapper::); + } + + pub fn cmp_generation_closure( + &self, + hook: Box, u64, usize) -> Option>, + ) { + unsafe { + GEN_CMP_HOOK = Hook::Closure(transmute(hook)); } self.emulator .set_gen_cmp_hook(gen_cmp_hook_wrapper::); @@ -768,7 +1416,18 @@ where hook: fn(&Emulator, &mut QT, Option<&mut S>, id: u64, v0: u8, v1: u8), ) { unsafe { - CMP1_HOOKS.push(hook as *const _); + CMP1_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + } + self.emulator + .set_exec_cmp1_hook(cmp1_hooks_wrapper::); + } + + pub fn cmp1_execution_closure( + &self, + hook: Box, u64, u8, u8)>, + ) { + unsafe { + CMP1_HOOKS.push(Hook::Closure(transmute(hook))); } self.emulator .set_exec_cmp1_hook(cmp1_hooks_wrapper::); @@ -779,7 +1438,18 @@ where hook: fn(&Emulator, &mut QT, Option<&mut S>, id: u64, v0: u16, v1: u16), ) { unsafe { - CMP2_HOOKS.push(hook as *const _); + CMP2_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + } + self.emulator + .set_exec_cmp2_hook(cmp2_hooks_wrapper::); + } + + pub fn cmp2_execution_closure( + &self, + hook: Box, u64, u16, u16)>, + ) { + unsafe { + CMP2_HOOKS.push(Hook::Closure(transmute(hook))); } self.emulator .set_exec_cmp2_hook(cmp2_hooks_wrapper::); @@ -790,7 +1460,18 @@ where hook: fn(&Emulator, &mut QT, Option<&mut S>, id: u64, v0: u32, v1: u32), ) { unsafe { - CMP4_HOOKS.push(hook as *const _); + CMP4_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + } + self.emulator + .set_exec_cmp4_hook(cmp4_hooks_wrapper::); + } + + pub fn cmp4_execution_closure( + &self, + hook: Box, u64, u32, u32)>, + ) { + unsafe { + CMP4_HOOKS.push(Hook::Closure(transmute(hook))); } self.emulator .set_exec_cmp4_hook(cmp4_hooks_wrapper::); @@ -801,12 +1482,53 @@ where hook: fn(&Emulator, &mut QT, Option<&mut S>, id: u64, v0: u64, v1: u64), ) { unsafe { - CMP8_HOOKS.push(hook as *const _); + CMP8_HOOKS.push(Hook::Function(hook as *const libc::c_void)); } self.emulator .set_exec_cmp8_hook(cmp8_hooks_wrapper::); } + pub fn cmp8_execution_closure( + &self, + hook: Box, u64, u64, u64)>, + ) { + unsafe { + CMP8_HOOKS.push(Hook::Closure(transmute(hook))); + } + self.emulator + .set_exec_cmp8_hook(cmp8_hooks_wrapper::); + } + + pub fn thread_creation(&self, hook: fn(&Emulator, Pin<&mut Self>, Option<&mut S>, tid: u32)) { + unsafe { + ON_THREAD_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + } + self.emulator + .set_on_thread_hook(on_thread_hooks_wrapper::); + } + + pub fn thread_creation_closure( + &self, + hook: Box, Option<&mut S>, u32) + 'a>, + ) { + unsafe { + ON_THREAD_HOOKS.push(Hook::Closure(transmute(hook))); + } + self.emulator + .set_on_thread_hook(on_thread_hooks_wrapper::); + } + + pub fn thread_creation_once( + &self, + hook: Box, Option<&mut S>, u32) + 'a>, + ) { + unsafe { + ON_THREAD_HOOKS.push(Hook::Once(transmute(hook))); + } + self.emulator + .set_on_thread_hook(on_thread_hooks_wrapper::); + } + #[allow(clippy::type_complexity)] pub fn syscalls( &self, @@ -826,7 +1548,34 @@ where ) -> SyscallHookResult, ) { unsafe { - SYSCALL_HOOKS.push(hook as *const _); + SYSCALL_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + } + self.emulator + .set_pre_syscall_hook(syscall_hooks_wrapper::); + } + + #[allow(clippy::type_complexity)] + pub fn syscalls_closure( + &self, + hook: Box< + dyn FnMut( + &Emulator, + &mut QT, + Option<&mut S>, + i32, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + ) -> SyscallHookResult, + >, + ) { + unsafe { + SYSCALL_HOOKS.push(Hook::Closure(transmute(hook))); } self.emulator .set_pre_syscall_hook(syscall_hooks_wrapper::); @@ -852,7 +1601,35 @@ where ) -> u64, ) { unsafe { - SYSCALL_POST_HOOKS.push(hook as *const _); + SYSCALL_POST_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + } + self.emulator + .set_post_syscall_hook(syscall_after_hooks_wrapper::); + } + + #[allow(clippy::type_complexity)] + pub fn after_syscalls_closure( + &self, + hook: Box< + dyn FnMut( + &Emulator, + &mut QT, + Option<&mut S>, + u64, + i32, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + ) -> u64, + >, + ) { + unsafe { + SYSCALL_POST_HOOKS.push(Hook::Closure(transmute(hook))); } self.emulator .set_post_syscall_hook(syscall_after_hooks_wrapper::);