Qemu native hooks refactoring (#2480)

* qemu native hooks refactoring (companion patch of qemu-libafl-bridge#82)

* update stubs
This commit is contained in:
Romain Malmain 2024-08-13 18:40:51 +02:00 committed by GitHub
parent 2287afc59b
commit 00806b177d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 1340 additions and 198 deletions

View File

@ -82,10 +82,24 @@ const WRAPPER_HEADER: &str = r#"
#include "qemu/plugin-memory.h"
#include "libafl/exit.h"
#include "libafl/hook.h"
#include "libafl/jit.h"
#include "libafl/utils.h"
#include "libafl/hook.h"
#include "libafl/hooks/tcg/backdoor.h"
#include "libafl/hooks/tcg/block.h"
#include "libafl/hooks/tcg/cmp.h"
#include "libafl/hooks/tcg/edge.h"
#include "libafl/hooks/tcg/instruction.h"
#include "libafl/hooks/tcg/read_write.h"
#include "libafl/hooks/cpu_run.h"
#ifdef CONFIG_USER_ONLY
#include "libafl/hooks/thread.h"
#include "libafl/hooks/syscall.h"
#endif
"#;
pub fn generate(

View File

@ -11,7 +11,7 @@ use crate::cargo_add_rpath;
pub const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
pub const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
pub const QEMU_REVISION: &str = "24abc2a717226bedc047167f639aef0edc9ce92d";
pub const QEMU_REVISION: &str = "86d38fbfa7e632b3a4a14def14a11b9b9ba1642d";
#[allow(clippy::module_name_repetitions)]
pub struct BuildResult {

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,11 @@
/* 1.81.0-nightly */
/* qemu git hash: 712661c8200804c0bb0750f237048c6c3da2d863 */
/* 1.82.0-nightly */
/* qemu git hash: 8f61fadbec181bfcbd305ba92a86a41376a476f7 */
/* automatically generated by rust-bindgen 0.69.4 */
pub const _STDINT_H: u32 = 1;
pub const _FEATURES_H: u32 = 1;
pub const _DEFAULT_SOURCE: u32 = 1;
pub const __GLIBC_USE_ISOC2X: u32 = 0;
pub const __GLIBC_USE_ISOC23: u32 = 0;
pub const __USE_ISOC11: u32 = 1;
pub const __USE_ISOC99: u32 = 1;
pub const __USE_ISOC95: u32 = 1;
@ -23,12 +23,13 @@ pub const __WORDSIZE: u32 = 64;
pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1;
pub const __SYSCALL_WORDSIZE: u32 = 64;
pub const __TIMESIZE: u32 = 64;
pub const __USE_TIME_BITS64: u32 = 1;
pub const __USE_MISC: u32 = 1;
pub const __USE_ATFILE: u32 = 1;
pub const __USE_FORTIFY_LEVEL: u32 = 0;
pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0;
pub const __GLIBC_USE_DEPRECATED_SCANF: u32 = 0;
pub const __GLIBC_USE_C2X_STRTOL: u32 = 0;
pub const __GLIBC_USE_C23_STRTOL: u32 = 0;
pub const _STDC_PREDEF_H: u32 = 1;
pub const __STDC_IEC_559__: u32 = 1;
pub const __STDC_IEC_60559_BFP__: u32 = 201404;
@ -37,17 +38,17 @@ pub const __STDC_IEC_60559_COMPLEX__: u32 = 201404;
pub const __STDC_ISO_10646__: u32 = 201706;
pub const __GNU_LIBRARY__: u32 = 6;
pub const __GLIBC__: u32 = 2;
pub const __GLIBC_MINOR__: u32 = 39;
pub const __GLIBC_MINOR__: u32 = 40;
pub const _SYS_CDEFS_H: u32 = 1;
pub const __glibc_c99_flexarr_available: u32 = 1;
pub const __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI: u32 = 0;
pub const __HAVE_GENERIC_SELECTION: u32 = 1;
pub const __GLIBC_USE_LIB_EXT2: u32 = 0;
pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 0;
pub const __GLIBC_USE_IEC_60559_BFP_EXT_C2X: u32 = 0;
pub const __GLIBC_USE_IEC_60559_BFP_EXT_C23: u32 = 0;
pub const __GLIBC_USE_IEC_60559_EXT: u32 = 0;
pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 0;
pub const __GLIBC_USE_IEC_60559_FUNCS_EXT_C2X: u32 = 0;
pub const __GLIBC_USE_IEC_60559_FUNCS_EXT_C23: u32 = 0;
pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 0;
pub const _BITS_TYPES_H: u32 = 1;
pub const _BITS_TYPESIZES_H: u32 = 1;

View File

@ -5,7 +5,7 @@ use std::ptr::addr_of_mut;
use std::{fmt::Debug, marker::PhantomData, mem::transmute, pin::Pin, ptr};
use libafl::{executors::ExitKind, inputs::UsesInput, observers::ObserversTuple};
use libafl_qemu_sys::{CPUArchStatePtr, FatPtr, GuestAddr, GuestUsize, TCGTemp};
use libafl_qemu_sys::{CPUArchStatePtr, CPUStatePtr, FatPtr, GuestAddr, GuestUsize, TCGTemp};
#[cfg(emulation_mode = "usermode")]
use crate::qemu::{
@ -20,6 +20,7 @@ use crate::qemu::{
PreSyscallHookClosure, PreSyscallHookFn,
};
use crate::{
cpu_run_post_exec_hook_wrapper, cpu_run_pre_exec_hook_wrapper,
modules::{EmulatorModule, EmulatorModuleTuple},
qemu::{
block_0_exec_hook_wrapper, block_gen_hook_wrapper, block_post_gen_hook_wrapper,
@ -33,11 +34,11 @@ use crate::{
write_4_exec_hook_wrapper, write_gen_hook_wrapper, BackdoorHook, BackdoorHookClosure,
BackdoorHookFn, BackdoorHookId, BlockExecHook, BlockGenHook, BlockHookId, BlockPostGenHook,
CmpExecHook, CmpGenHook, CmpHookId, EdgeExecHook, EdgeGenHook, EdgeHookId, Hook, HookRepr,
HookState, InstructionHook, InstructionHookClosure, InstructionHookFn, InstructionHookId,
QemuHooks, ReadExecHook, ReadExecNHook, ReadGenHook, ReadHookId, WriteExecHook,
InstructionHook, InstructionHookClosure, InstructionHookFn, InstructionHookId, QemuHooks,
ReadExecHook, ReadExecNHook, ReadGenHook, ReadHookId, TcgHookState, WriteExecHook,
WriteExecNHook, WriteGenHook, WriteHookId,
},
MemAccessInfo, Qemu,
CpuPostRunHook, CpuPreRunHook, CpuRunHookId, HookState, MemAccessInfo, Qemu,
};
macro_rules! get_raw_hook {
@ -119,11 +120,13 @@ where
instruction_hooks: Vec<Pin<Box<(InstructionHookId, FatPtr)>>>,
backdoor_hooks: Vec<Pin<Box<(BackdoorHookId, FatPtr)>>>,
edge_hooks: Vec<Pin<Box<HookState<1, EdgeHookId>>>>,
block_hooks: Vec<Pin<Box<HookState<1, BlockHookId>>>>,
read_hooks: Vec<Pin<Box<HookState<5, ReadHookId>>>>,
write_hooks: Vec<Pin<Box<HookState<5, WriteHookId>>>>,
cmp_hooks: Vec<Pin<Box<HookState<4, CmpHookId>>>>,
edge_hooks: Vec<Pin<Box<TcgHookState<1, EdgeHookId>>>>,
block_hooks: Vec<Pin<Box<TcgHookState<1, BlockHookId>>>>,
read_hooks: Vec<Pin<Box<TcgHookState<5, ReadHookId>>>>,
write_hooks: Vec<Pin<Box<TcgHookState<5, WriteHookId>>>>,
cmp_hooks: Vec<Pin<Box<TcgHookState<4, CmpHookId>>>>,
cpu_run_hooks: Vec<Pin<Box<HookState<CpuRunHookId>>>>,
#[cfg(emulation_mode = "usermode")]
pre_syscall_hooks: Vec<Pin<Box<(PreSyscallHookId, FatPtr)>>>,
@ -156,6 +159,8 @@ where
write_hooks: Vec::new(),
cmp_hooks: Vec::new(),
cpu_run_hooks: Vec::new(),
#[cfg(emulation_mode = "usermode")]
pre_syscall_hooks: Vec::new(),
@ -252,7 +257,7 @@ where
generation_hook,
edge_gen_hook_wrapper::<ET, S>,
unsafe extern "C" fn(
&mut HookState<1, EdgeHookId>,
&mut TcgHookState<1, EdgeHookId>,
src: GuestAddr,
dest: GuestAddr,
) -> u64
@ -261,17 +266,17 @@ where
let exec = get_raw_hook!(
execution_hook,
edge_0_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<1, EdgeHookId>, id: u64)
unsafe extern "C" fn(&mut TcgHookState<1, EdgeHookId>, id: u64)
);
self.edge_hooks.push(Box::pin(HookState::new(
self.edge_hooks.push(Box::pin(TcgHookState::new(
EdgeHookId::invalid(),
hook_to_repr!(generation_hook),
HookRepr::Empty,
[hook_to_repr!(execution_hook)],
)));
let hook_state = &mut *ptr::from_mut::<HookState<1, EdgeHookId>>(
let hook_state = &mut *ptr::from_mut::<TcgHookState<1, EdgeHookId>>(
self.edge_hooks
.last_mut()
.unwrap()
@ -302,14 +307,14 @@ where
let gen = get_raw_hook!(
generation_hook,
block_gen_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<1, BlockHookId>, pc: GuestAddr) -> u64
unsafe extern "C" fn(&mut TcgHookState<1, BlockHookId>, pc: GuestAddr) -> u64
);
let postgen = get_raw_hook!(
post_generation_hook,
block_post_gen_hook_wrapper::<ET, S>,
unsafe extern "C" fn(
&mut HookState<1, BlockHookId>,
&mut TcgHookState<1, BlockHookId>,
pc: GuestAddr,
block_length: GuestUsize,
)
@ -318,17 +323,17 @@ where
let exec = get_raw_hook!(
execution_hook,
block_0_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<1, BlockHookId>, id: u64)
unsafe extern "C" fn(&mut TcgHookState<1, BlockHookId>, id: u64)
);
self.block_hooks.push(Box::pin(HookState::new(
self.block_hooks.push(Box::pin(TcgHookState::new(
BlockHookId::invalid(),
hook_to_repr!(generation_hook),
hook_to_repr!(post_generation_hook),
[hook_to_repr!(execution_hook)],
)));
let hook_state = &mut *ptr::from_mut::<HookState<1, BlockHookId>>(
let hook_state = &mut *ptr::from_mut::<TcgHookState<1, BlockHookId>>(
self.block_hooks
.last_mut()
.unwrap()
@ -351,6 +356,53 @@ where
}
}
pub fn cpu_runs(
&mut self,
pre_exec_hook: CpuPreRunHook<ET, S>,
post_exec_hook: CpuPostRunHook<ET, S>,
) -> CpuRunHookId {
unsafe {
let pre_run = get_raw_hook!(
pre_exec_hook,
cpu_run_pre_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<CpuRunHookId>, cpu: CPUStatePtr)
);
let post_run = get_raw_hook!(
post_exec_hook,
cpu_run_post_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<CpuRunHookId>, cpu: CPUStatePtr)
);
self.cpu_run_hooks.push(Box::pin(HookState::new(
CpuRunHookId::invalid(),
hook_to_repr!(pre_exec_hook),
hook_to_repr!(post_exec_hook),
)));
let hook_state = &mut *ptr::from_mut::<HookState<CpuRunHookId>>(
self.cpu_run_hooks
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut(),
);
let id = self
.qemu_hooks
.add_cpu_run_hooks(hook_state, pre_run, post_run);
self.cpu_run_hooks
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.set_id(id);
id
}
}
#[allow(clippy::similar_names)]
pub fn reads(
&mut self,
@ -366,7 +418,7 @@ where
generation_hook,
read_gen_hook_wrapper::<ET, S>,
unsafe extern "C" fn(
&mut HookState<5, ReadHookId>,
&mut TcgHookState<5, ReadHookId>,
pc: GuestAddr,
addr: *mut TCGTemp,
info: MemAccessInfo,
@ -375,35 +427,35 @@ where
let exec1 = get_raw_hook!(
execution_hook_1,
read_0_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<5, ReadHookId>, id: u64, addr: GuestAddr)
unsafe extern "C" fn(&mut TcgHookState<5, ReadHookId>, id: u64, addr: GuestAddr)
);
let exec2 = get_raw_hook!(
execution_hook_2,
read_1_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<5, ReadHookId>, id: u64, addr: GuestAddr)
unsafe extern "C" fn(&mut TcgHookState<5, ReadHookId>, id: u64, addr: GuestAddr)
);
let exec4 = get_raw_hook!(
execution_hook_4,
read_2_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<5, ReadHookId>, id: u64, addr: GuestAddr)
unsafe extern "C" fn(&mut TcgHookState<5, ReadHookId>, id: u64, addr: GuestAddr)
);
let exec8 = get_raw_hook!(
execution_hook_8,
read_3_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<5, ReadHookId>, id: u64, addr: GuestAddr)
unsafe extern "C" fn(&mut TcgHookState<5, ReadHookId>, id: u64, addr: GuestAddr)
);
let execn = get_raw_hook!(
execution_hook_n,
read_4_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(
&mut HookState<5, ReadHookId>,
&mut TcgHookState<5, ReadHookId>,
id: u64,
addr: GuestAddr,
size: usize,
)
);
self.read_hooks.push(Box::pin(HookState::new(
self.read_hooks.push(Box::pin(TcgHookState::new(
ReadHookId::invalid(),
hook_to_repr!(generation_hook),
HookRepr::Empty,
@ -416,7 +468,7 @@ where
],
)));
let hook_state = &mut *ptr::from_mut::<HookState<5, ReadHookId>>(
let hook_state = &mut *ptr::from_mut::<TcgHookState<5, ReadHookId>>(
self.read_hooks
.last_mut()
.unwrap()
@ -454,7 +506,7 @@ where
generation_hook,
write_gen_hook_wrapper::<ET, S>,
unsafe extern "C" fn(
&mut HookState<5, WriteHookId>,
&mut TcgHookState<5, WriteHookId>,
pc: GuestAddr,
addr: *mut TCGTemp,
info: MemAccessInfo,
@ -463,35 +515,35 @@ where
let exec1 = get_raw_hook!(
execution_hook_1,
write_0_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<5, WriteHookId>, id: u64, addr: GuestAddr)
unsafe extern "C" fn(&mut TcgHookState<5, WriteHookId>, id: u64, addr: GuestAddr)
);
let exec2 = get_raw_hook!(
execution_hook_2,
write_1_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<5, WriteHookId>, id: u64, addr: GuestAddr)
unsafe extern "C" fn(&mut TcgHookState<5, WriteHookId>, id: u64, addr: GuestAddr)
);
let exec4 = get_raw_hook!(
execution_hook_4,
write_2_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<5, WriteHookId>, id: u64, addr: GuestAddr)
unsafe extern "C" fn(&mut TcgHookState<5, WriteHookId>, id: u64, addr: GuestAddr)
);
let exec8 = get_raw_hook!(
execution_hook_8,
write_3_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<5, WriteHookId>, id: u64, addr: GuestAddr)
unsafe extern "C" fn(&mut TcgHookState<5, WriteHookId>, id: u64, addr: GuestAddr)
);
let execn = get_raw_hook!(
execution_hook_n,
write_4_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(
&mut HookState<5, WriteHookId>,
&mut TcgHookState<5, WriteHookId>,
id: u64,
addr: GuestAddr,
size: usize,
)
);
self.write_hooks.push(Box::pin(HookState::new(
self.write_hooks.push(Box::pin(TcgHookState::new(
WriteHookId::invalid(),
hook_to_repr!(generation_hook),
HookRepr::Empty,
@ -504,7 +556,7 @@ where
],
)));
let hook_state = &mut *ptr::from_mut::<HookState<5, WriteHookId>>(
let hook_state = &mut *ptr::from_mut::<TcgHookState<5, WriteHookId>>(
self.write_hooks
.last_mut()
.unwrap()
@ -540,7 +592,7 @@ where
generation_hook,
cmp_gen_hook_wrapper::<ET, S>,
unsafe extern "C" fn(
&mut HookState<4, CmpHookId>,
&mut TcgHookState<4, CmpHookId>,
pc: GuestAddr,
size: usize,
) -> u64
@ -548,25 +600,25 @@ where
let exec1 = get_raw_hook!(
execution_hook_1,
cmp_0_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<4, CmpHookId>, id: u64, v0: u8, v1: u8)
unsafe extern "C" fn(&mut TcgHookState<4, CmpHookId>, id: u64, v0: u8, v1: u8)
);
let exec2 = get_raw_hook!(
execution_hook_2,
cmp_1_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<4, CmpHookId>, id: u64, v0: u16, v1: u16)
unsafe extern "C" fn(&mut TcgHookState<4, CmpHookId>, id: u64, v0: u16, v1: u16)
);
let exec4 = get_raw_hook!(
execution_hook_4,
cmp_2_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<4, CmpHookId>, id: u64, v0: u32, v1: u32)
unsafe extern "C" fn(&mut TcgHookState<4, CmpHookId>, id: u64, v0: u32, v1: u32)
);
let exec8 = get_raw_hook!(
execution_hook_8,
cmp_3_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn(&mut HookState<4, CmpHookId>, id: u64, v0: u64, v1: u64)
unsafe extern "C" fn(&mut TcgHookState<4, CmpHookId>, id: u64, v0: u64, v1: u64)
);
self.cmp_hooks.push(Box::pin(HookState::new(
self.cmp_hooks.push(Box::pin(TcgHookState::new(
CmpHookId::invalid(),
hook_to_repr!(generation_hook),
HookRepr::Empty,
@ -578,7 +630,7 @@ where
],
)));
let hook_state = &mut *ptr::from_mut::<HookState<4, CmpHookId>>(
let hook_state = &mut *ptr::from_mut::<TcgHookState<4, CmpHookId>>(
self.cmp_hooks
.last_mut()
.unwrap()
@ -776,7 +828,12 @@ where
pub fn thread_creation_function(
&mut self,
hook: fn(&mut EmulatorModules<ET, S>, Option<&mut S>, tid: u32) -> bool,
hook: fn(
&mut EmulatorModules<ET, S>,
Option<&mut S>,
env: CPUArchStatePtr,
tid: u32,
) -> bool,
) -> NewThreadHookId {
unsafe {
self.qemu_hooks
@ -1206,7 +1263,12 @@ where
pub fn thread_creation_function(
&mut self,
hook: fn(&mut EmulatorModules<ET, S>, Option<&mut S>, tid: u32) -> bool,
hook: fn(
&mut EmulatorModules<ET, S>,
Option<&mut S>,
env: CPUArchStatePtr,
tid: u32,
) -> bool,
) -> NewThreadHookId {
self.hooks.thread_creation_function(hook)
}

View File

@ -6,7 +6,7 @@ use core::{ffi::c_void, fmt::Debug, mem::transmute, ptr};
use libafl::{executors::hooks::inprocess::inprocess_get_state, inputs::UsesInput};
#[cfg(emulation_mode = "usermode")]
use libafl_qemu_sys::libafl_dump_core_hook;
use libafl_qemu_sys::{CPUArchStatePtr, FatPtr, GuestAddr, GuestUsize};
use libafl_qemu_sys::{CPUArchStatePtr, CPUStatePtr, FatPtr, GuestAddr, GuestUsize};
#[cfg(feature = "python")]
use pyo3::{pyclass, pymethods, FromPyObject};
@ -29,14 +29,21 @@ pub enum HookRepr {
}
#[derive(Debug)]
pub struct HookState<const N: usize, H: HookId> {
pub struct TcgHookState<const N: usize, H: HookId> {
id: H,
gen: HookRepr,
post_gen: HookRepr,
execs: [HookRepr; N],
}
impl<const N: usize, H: HookId> HookState<N, H> {
#[derive(Debug)]
pub struct HookState<H: HookId> {
id: H,
pre_run: HookRepr,
post_run: HookRepr,
}
impl<const N: usize, H: HookId> TcgHookState<N, H> {
pub fn new(id: H, gen: HookRepr, post_gen: HookRepr, execs: [HookRepr; N]) -> Self {
Self {
id,
@ -51,6 +58,20 @@ impl<const N: usize, H: HookId> HookState<N, H> {
}
}
impl<H: HookId> HookState<H> {
pub fn new(id: H, pre_run: HookRepr, post_run: HookRepr) -> Self {
Self {
id,
pre_run,
post_run,
}
}
pub unsafe fn set_id(&mut self, id: H) {
self.id = id;
}
}
pub enum Hook<F, C, R: Clone> {
Function(F),
Closure(C),
@ -129,10 +150,72 @@ macro_rules! create_wrapper {
};
}
macro_rules! create_pre_exec_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $hook_id:ident) => {
paste::paste! {
pub extern "C" fn [<$name _pre_exec_hook_wrapper>]<ET, S>(hook: &mut HookState<$hook_id>, $($param: $param_type),*)
where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
{
unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
match &mut hook.pre_run {
HookRepr::Function(ptr) => {
let func: fn(&mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) =
transmute(*ptr);
func(modules, inprocess_get_state::<S>(), $($param),*)
}
HookRepr::Closure(ptr) => {
let func: &mut Box<
dyn FnMut(&mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*),
> = transmute(ptr);
func(modules, inprocess_get_state::<S>(), $($param),*)
}
_ => (),
}
}
}
}
}
}
macro_rules! create_post_exec_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $hook_id:ident) => {
paste::paste! {
pub extern "C" fn [<$name _post_exec_hook_wrapper>]<ET, S>(hook: &mut HookState<$hook_id>, $($param: $param_type),*)
where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
{
unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
match &mut hook.post_run {
HookRepr::Function(ptr) => {
let func: fn(&mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) =
transmute(*ptr);
func(modules, inprocess_get_state::<S>(), $($param),*);
}
HookRepr::Closure(ptr) => {
let func: &mut Box<
dyn FnMut(&mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*),
> = transmute(ptr);
func(modules, inprocess_get_state::<S>(), $($param),*);
}
_ => (),
}
}
}
}
}
}
macro_rules! create_gen_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $ret_type:ty, $execs:literal, $hook_id:ident) => {
paste::paste! {
pub extern "C" fn [<$name _gen_hook_wrapper>]<ET, S>(hook: &mut HookState<{ $execs }, $hook_id>, $($param: $param_type),*) -> $ret_type
pub extern "C" fn [<$name _gen_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*) -> $ret_type
where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
@ -163,7 +246,7 @@ macro_rules! create_gen_wrapper {
macro_rules! create_post_gen_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $execs:literal, $hook_id:ident) => {
paste::paste! {
pub extern "C" fn [<$name _post_gen_hook_wrapper>]<ET, S>(hook: &mut HookState<{ $execs }, $hook_id>, $($param: $param_type),*)
pub extern "C" fn [<$name _post_gen_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*)
where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
@ -193,7 +276,7 @@ macro_rules! create_post_gen_wrapper {
macro_rules! create_exec_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $execidx:literal, $execs:literal, $hook_id:ident) => {
paste::paste! {
pub extern "C" fn [<$name _ $execidx _exec_hook_wrapper>]<ET, S>(hook: &mut HookState<{ $execs }, $hook_id>, $($param: $param_type),*)
pub extern "C" fn [<$name _ $execidx _exec_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*)
where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
@ -271,11 +354,6 @@ macro_rules! create_hook_types {
};
}
#[cfg(emulation_mode = "usermode")]
create_hook_id!(PostSyscall, libafl_qemu_remove_post_syscall_hook, false);
#[cfg(emulation_mode = "usermode")]
create_hook_id!(NewThread, libafl_qemu_remove_new_thread_hook, false);
// Instruction hook wrappers
create_hook_types!(
Instruction,
@ -409,6 +487,8 @@ create_hook_types!(
) -> GuestAddr
);
#[cfg(emulation_mode = "usermode")]
create_hook_id!(PostSyscall, libafl_qemu_remove_post_syscall_hook, false);
#[cfg(emulation_mode = "usermode")]
create_wrapper!(
post_syscall,
(
@ -430,12 +510,39 @@ create_wrapper!(
#[cfg(emulation_mode = "usermode")]
create_hook_types!(
NewThread,
fn(&mut EmulatorModules<ET, S>, Option<&mut S>, tid: u32) -> bool,
Box<dyn for<'a> FnMut(&'a mut EmulatorModules<ET, S>, Option<&'a mut S>, u32) -> bool>,
extern "C" fn(*const (), tid: u32) -> bool
fn(&mut EmulatorModules<ET, S>, Option<&mut S>, env: CPUArchStatePtr, tid: u32) -> bool,
Box<
dyn for<'a> FnMut(
&'a mut EmulatorModules<ET, S>,
Option<&'a mut S>,
CPUArchStatePtr,
u32,
) -> bool,
>,
extern "C" fn(*const (), env: CPUArchStatePtr, tid: u32) -> bool
);
#[cfg(emulation_mode = "usermode")]
create_wrapper!(new_thread, (tid: u32), bool);
create_hook_id!(NewThread, libafl_qemu_remove_new_thread_hook, false);
#[cfg(emulation_mode = "usermode")]
create_wrapper!(new_thread, (env: CPUArchStatePtr, tid: u32), bool);
// CPU Run hook wrappers
create_hook_types!(
CpuPreRun,
fn(&mut EmulatorModules<ET, S>, Option<&mut S>, cpu: CPUStatePtr),
Box<dyn for<'a> FnMut(&'a mut EmulatorModules<ET, S>, Option<&'a mut S>, CPUStatePtr)>,
extern "C" fn(*const (), cpu: CPUStatePtr)
);
create_hook_types!(
CpuPostRun,
fn(&mut EmulatorModules<ET, S>, Option<&mut S>, cpu: CPUStatePtr),
Box<dyn for<'a> FnMut(&'a mut EmulatorModules<ET, S>, Option<&'a mut S>, CPUStatePtr)>,
extern "C" fn(*const (), cpu: CPUStatePtr)
);
create_hook_id!(CpuRun, libafl_qemu_remove_cpu_run_hook, false);
create_pre_exec_wrapper!(cpu_run, (cpu: CPUStatePtr), CpuRunHookId);
create_post_exec_wrapper!(cpu_run, (addr: CPUStatePtr), CpuRunHookId);
create_wrapper!(cpu_run, (cpu: CPUStatePtr));
// Edge hook wrappers
create_hook_types!(
@ -714,6 +821,22 @@ impl QemuHooks {
}
}
#[allow(clippy::missing_transmute_annotations)]
pub fn add_cpu_run_hooks<T: Into<HookData>>(
&self,
data: T,
pre_exec: Option<unsafe extern "C" fn(T, CPUStatePtr)>,
post_exec: Option<unsafe extern "C" fn(T, CPUStatePtr)>,
) -> CpuRunHookId {
unsafe {
let data: u64 = data.into().0;
let pre_exec: Option<unsafe extern "C" fn(u64, CPUStatePtr)> = transmute(pre_exec);
let post_gen: Option<unsafe extern "C" fn(u64, CPUStatePtr)> = transmute(post_exec);
let num = libafl_qemu_sys::libafl_hook_cpu_run_add(pre_exec, post_gen, data);
CpuRunHookId(num)
}
}
/// `data` can be used to pass data that can be accessed as the first argument in the `gen` and the `exec` functions
///
/// `gen` gets passed the current programm counter, mutable access to a `TCGTemp` and information about the memory
@ -873,11 +996,11 @@ impl QemuHooks {
pub fn add_new_thread_hook<T: Into<HookData>>(
&self,
data: T,
callback: extern "C" fn(T, tid: u32) -> bool,
callback: extern "C" fn(T, env: CPUArchStatePtr, tid: u32) -> bool,
) -> NewThreadHookId {
unsafe {
let data: u64 = data.into().0;
let callback: extern "C" fn(u64, u32) -> bool = transmute(callback);
let callback: extern "C" fn(u64, CPUArchStatePtr, u32) -> bool = transmute(callback);
let num = libafl_qemu_sys::libafl_add_new_thread_hook(Some(callback), data);
NewThreadHookId(num)
}