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 "qemu/plugin-memory.h"
#include "libafl/exit.h" #include "libafl/exit.h"
#include "libafl/hook.h"
#include "libafl/jit.h" #include "libafl/jit.h"
#include "libafl/utils.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( 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_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
pub const QEMU_DIRNAME: &str = "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)] #[allow(clippy::module_name_repetitions)]
pub struct BuildResult { pub struct BuildResult {

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,11 @@
/* 1.81.0-nightly */ /* 1.82.0-nightly */
/* qemu git hash: 712661c8200804c0bb0750f237048c6c3da2d863 */ /* qemu git hash: 8f61fadbec181bfcbd305ba92a86a41376a476f7 */
/* automatically generated by rust-bindgen 0.69.4 */ /* automatically generated by rust-bindgen 0.69.4 */
pub const _STDINT_H: u32 = 1; pub const _STDINT_H: u32 = 1;
pub const _FEATURES_H: u32 = 1; pub const _FEATURES_H: u32 = 1;
pub const _DEFAULT_SOURCE: 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_ISOC11: u32 = 1;
pub const __USE_ISOC99: u32 = 1; pub const __USE_ISOC99: u32 = 1;
pub const __USE_ISOC95: 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 __WORDSIZE_TIME64_COMPAT32: u32 = 1;
pub const __SYSCALL_WORDSIZE: u32 = 64; pub const __SYSCALL_WORDSIZE: u32 = 64;
pub const __TIMESIZE: u32 = 64; pub const __TIMESIZE: u32 = 64;
pub const __USE_TIME_BITS64: u32 = 1;
pub const __USE_MISC: u32 = 1; pub const __USE_MISC: u32 = 1;
pub const __USE_ATFILE: u32 = 1; pub const __USE_ATFILE: u32 = 1;
pub const __USE_FORTIFY_LEVEL: u32 = 0; pub const __USE_FORTIFY_LEVEL: u32 = 0;
pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0; pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0;
pub const __GLIBC_USE_DEPRECATED_SCANF: 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_PREDEF_H: u32 = 1;
pub const __STDC_IEC_559__: u32 = 1; pub const __STDC_IEC_559__: u32 = 1;
pub const __STDC_IEC_60559_BFP__: u32 = 201404; 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 __STDC_ISO_10646__: u32 = 201706;
pub const __GNU_LIBRARY__: u32 = 6; pub const __GNU_LIBRARY__: u32 = 6;
pub const __GLIBC__: u32 = 2; 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 _SYS_CDEFS_H: u32 = 1;
pub const __glibc_c99_flexarr_available: u32 = 1; pub const __glibc_c99_flexarr_available: u32 = 1;
pub const __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI: u32 = 0; pub const __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI: u32 = 0;
pub const __HAVE_GENERIC_SELECTION: u32 = 1; pub const __HAVE_GENERIC_SELECTION: u32 = 1;
pub const __GLIBC_USE_LIB_EXT2: u32 = 0; 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: 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_EXT: u32 = 0;
pub const __GLIBC_USE_IEC_60559_FUNCS_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 __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 0;
pub const _BITS_TYPES_H: u32 = 1; pub const _BITS_TYPES_H: u32 = 1;
pub const _BITS_TYPESIZES_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 std::{fmt::Debug, marker::PhantomData, mem::transmute, pin::Pin, ptr};
use libafl::{executors::ExitKind, inputs::UsesInput, observers::ObserversTuple}; 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")] #[cfg(emulation_mode = "usermode")]
use crate::qemu::{ use crate::qemu::{
@ -20,6 +20,7 @@ use crate::qemu::{
PreSyscallHookClosure, PreSyscallHookFn, PreSyscallHookClosure, PreSyscallHookFn,
}; };
use crate::{ use crate::{
cpu_run_post_exec_hook_wrapper, cpu_run_pre_exec_hook_wrapper,
modules::{EmulatorModule, EmulatorModuleTuple}, modules::{EmulatorModule, EmulatorModuleTuple},
qemu::{ qemu::{
block_0_exec_hook_wrapper, block_gen_hook_wrapper, block_post_gen_hook_wrapper, 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, write_4_exec_hook_wrapper, write_gen_hook_wrapper, BackdoorHook, BackdoorHookClosure,
BackdoorHookFn, BackdoorHookId, BlockExecHook, BlockGenHook, BlockHookId, BlockPostGenHook, BackdoorHookFn, BackdoorHookId, BlockExecHook, BlockGenHook, BlockHookId, BlockPostGenHook,
CmpExecHook, CmpGenHook, CmpHookId, EdgeExecHook, EdgeGenHook, EdgeHookId, Hook, HookRepr, CmpExecHook, CmpGenHook, CmpHookId, EdgeExecHook, EdgeGenHook, EdgeHookId, Hook, HookRepr,
HookState, InstructionHook, InstructionHookClosure, InstructionHookFn, InstructionHookId, InstructionHook, InstructionHookClosure, InstructionHookFn, InstructionHookId, QemuHooks,
QemuHooks, ReadExecHook, ReadExecNHook, ReadGenHook, ReadHookId, WriteExecHook, ReadExecHook, ReadExecNHook, ReadGenHook, ReadHookId, TcgHookState, WriteExecHook,
WriteExecNHook, WriteGenHook, WriteHookId, WriteExecNHook, WriteGenHook, WriteHookId,
}, },
MemAccessInfo, Qemu, CpuPostRunHook, CpuPreRunHook, CpuRunHookId, HookState, MemAccessInfo, Qemu,
}; };
macro_rules! get_raw_hook { macro_rules! get_raw_hook {
@ -119,11 +120,13 @@ where
instruction_hooks: Vec<Pin<Box<(InstructionHookId, FatPtr)>>>, instruction_hooks: Vec<Pin<Box<(InstructionHookId, FatPtr)>>>,
backdoor_hooks: Vec<Pin<Box<(BackdoorHookId, FatPtr)>>>, backdoor_hooks: Vec<Pin<Box<(BackdoorHookId, FatPtr)>>>,
edge_hooks: Vec<Pin<Box<HookState<1, EdgeHookId>>>>, edge_hooks: Vec<Pin<Box<TcgHookState<1, EdgeHookId>>>>,
block_hooks: Vec<Pin<Box<HookState<1, BlockHookId>>>>, block_hooks: Vec<Pin<Box<TcgHookState<1, BlockHookId>>>>,
read_hooks: Vec<Pin<Box<HookState<5, ReadHookId>>>>, read_hooks: Vec<Pin<Box<TcgHookState<5, ReadHookId>>>>,
write_hooks: Vec<Pin<Box<HookState<5, WriteHookId>>>>, write_hooks: Vec<Pin<Box<TcgHookState<5, WriteHookId>>>>,
cmp_hooks: Vec<Pin<Box<HookState<4, CmpHookId>>>>, cmp_hooks: Vec<Pin<Box<TcgHookState<4, CmpHookId>>>>,
cpu_run_hooks: Vec<Pin<Box<HookState<CpuRunHookId>>>>,
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
pre_syscall_hooks: Vec<Pin<Box<(PreSyscallHookId, FatPtr)>>>, pre_syscall_hooks: Vec<Pin<Box<(PreSyscallHookId, FatPtr)>>>,
@ -156,6 +159,8 @@ where
write_hooks: Vec::new(), write_hooks: Vec::new(),
cmp_hooks: Vec::new(), cmp_hooks: Vec::new(),
cpu_run_hooks: Vec::new(),
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
pre_syscall_hooks: Vec::new(), pre_syscall_hooks: Vec::new(),
@ -252,7 +257,7 @@ where
generation_hook, generation_hook,
edge_gen_hook_wrapper::<ET, S>, edge_gen_hook_wrapper::<ET, S>,
unsafe extern "C" fn( unsafe extern "C" fn(
&mut HookState<1, EdgeHookId>, &mut TcgHookState<1, EdgeHookId>,
src: GuestAddr, src: GuestAddr,
dest: GuestAddr, dest: GuestAddr,
) -> u64 ) -> u64
@ -261,17 +266,17 @@ where
let exec = get_raw_hook!( let exec = get_raw_hook!(
execution_hook, execution_hook,
edge_0_exec_hook_wrapper::<ET, S>, 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(), EdgeHookId::invalid(),
hook_to_repr!(generation_hook), hook_to_repr!(generation_hook),
HookRepr::Empty, HookRepr::Empty,
[hook_to_repr!(execution_hook)], [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 self.edge_hooks
.last_mut() .last_mut()
.unwrap() .unwrap()
@ -302,14 +307,14 @@ where
let gen = get_raw_hook!( let gen = get_raw_hook!(
generation_hook, generation_hook,
block_gen_hook_wrapper::<ET, S>, 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!( let postgen = get_raw_hook!(
post_generation_hook, post_generation_hook,
block_post_gen_hook_wrapper::<ET, S>, block_post_gen_hook_wrapper::<ET, S>,
unsafe extern "C" fn( unsafe extern "C" fn(
&mut HookState<1, BlockHookId>, &mut TcgHookState<1, BlockHookId>,
pc: GuestAddr, pc: GuestAddr,
block_length: GuestUsize, block_length: GuestUsize,
) )
@ -318,17 +323,17 @@ where
let exec = get_raw_hook!( let exec = get_raw_hook!(
execution_hook, execution_hook,
block_0_exec_hook_wrapper::<ET, S>, 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(), BlockHookId::invalid(),
hook_to_repr!(generation_hook), hook_to_repr!(generation_hook),
hook_to_repr!(post_generation_hook), hook_to_repr!(post_generation_hook),
[hook_to_repr!(execution_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 self.block_hooks
.last_mut() .last_mut()
.unwrap() .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)] #[allow(clippy::similar_names)]
pub fn reads( pub fn reads(
&mut self, &mut self,
@ -366,7 +418,7 @@ where
generation_hook, generation_hook,
read_gen_hook_wrapper::<ET, S>, read_gen_hook_wrapper::<ET, S>,
unsafe extern "C" fn( unsafe extern "C" fn(
&mut HookState<5, ReadHookId>, &mut TcgHookState<5, ReadHookId>,
pc: GuestAddr, pc: GuestAddr,
addr: *mut TCGTemp, addr: *mut TCGTemp,
info: MemAccessInfo, info: MemAccessInfo,
@ -375,35 +427,35 @@ where
let exec1 = get_raw_hook!( let exec1 = get_raw_hook!(
execution_hook_1, execution_hook_1,
read_0_exec_hook_wrapper::<ET, S>, 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!( let exec2 = get_raw_hook!(
execution_hook_2, execution_hook_2,
read_1_exec_hook_wrapper::<ET, S>, 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!( let exec4 = get_raw_hook!(
execution_hook_4, execution_hook_4,
read_2_exec_hook_wrapper::<ET, S>, 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!( let exec8 = get_raw_hook!(
execution_hook_8, execution_hook_8,
read_3_exec_hook_wrapper::<ET, S>, 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!( let execn = get_raw_hook!(
execution_hook_n, execution_hook_n,
read_4_exec_hook_wrapper::<ET, S>, read_4_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn( unsafe extern "C" fn(
&mut HookState<5, ReadHookId>, &mut TcgHookState<5, ReadHookId>,
id: u64, id: u64,
addr: GuestAddr, addr: GuestAddr,
size: usize, size: usize,
) )
); );
self.read_hooks.push(Box::pin(HookState::new( self.read_hooks.push(Box::pin(TcgHookState::new(
ReadHookId::invalid(), ReadHookId::invalid(),
hook_to_repr!(generation_hook), hook_to_repr!(generation_hook),
HookRepr::Empty, 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 self.read_hooks
.last_mut() .last_mut()
.unwrap() .unwrap()
@ -454,7 +506,7 @@ where
generation_hook, generation_hook,
write_gen_hook_wrapper::<ET, S>, write_gen_hook_wrapper::<ET, S>,
unsafe extern "C" fn( unsafe extern "C" fn(
&mut HookState<5, WriteHookId>, &mut TcgHookState<5, WriteHookId>,
pc: GuestAddr, pc: GuestAddr,
addr: *mut TCGTemp, addr: *mut TCGTemp,
info: MemAccessInfo, info: MemAccessInfo,
@ -463,35 +515,35 @@ where
let exec1 = get_raw_hook!( let exec1 = get_raw_hook!(
execution_hook_1, execution_hook_1,
write_0_exec_hook_wrapper::<ET, S>, 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!( let exec2 = get_raw_hook!(
execution_hook_2, execution_hook_2,
write_1_exec_hook_wrapper::<ET, S>, 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!( let exec4 = get_raw_hook!(
execution_hook_4, execution_hook_4,
write_2_exec_hook_wrapper::<ET, S>, 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!( let exec8 = get_raw_hook!(
execution_hook_8, execution_hook_8,
write_3_exec_hook_wrapper::<ET, S>, 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!( let execn = get_raw_hook!(
execution_hook_n, execution_hook_n,
write_4_exec_hook_wrapper::<ET, S>, write_4_exec_hook_wrapper::<ET, S>,
unsafe extern "C" fn( unsafe extern "C" fn(
&mut HookState<5, WriteHookId>, &mut TcgHookState<5, WriteHookId>,
id: u64, id: u64,
addr: GuestAddr, addr: GuestAddr,
size: usize, size: usize,
) )
); );
self.write_hooks.push(Box::pin(HookState::new( self.write_hooks.push(Box::pin(TcgHookState::new(
WriteHookId::invalid(), WriteHookId::invalid(),
hook_to_repr!(generation_hook), hook_to_repr!(generation_hook),
HookRepr::Empty, 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 self.write_hooks
.last_mut() .last_mut()
.unwrap() .unwrap()
@ -540,7 +592,7 @@ where
generation_hook, generation_hook,
cmp_gen_hook_wrapper::<ET, S>, cmp_gen_hook_wrapper::<ET, S>,
unsafe extern "C" fn( unsafe extern "C" fn(
&mut HookState<4, CmpHookId>, &mut TcgHookState<4, CmpHookId>,
pc: GuestAddr, pc: GuestAddr,
size: usize, size: usize,
) -> u64 ) -> u64
@ -548,25 +600,25 @@ where
let exec1 = get_raw_hook!( let exec1 = get_raw_hook!(
execution_hook_1, execution_hook_1,
cmp_0_exec_hook_wrapper::<ET, S>, 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!( let exec2 = get_raw_hook!(
execution_hook_2, execution_hook_2,
cmp_1_exec_hook_wrapper::<ET, S>, 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!( let exec4 = get_raw_hook!(
execution_hook_4, execution_hook_4,
cmp_2_exec_hook_wrapper::<ET, S>, 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!( let exec8 = get_raw_hook!(
execution_hook_8, execution_hook_8,
cmp_3_exec_hook_wrapper::<ET, S>, 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(), CmpHookId::invalid(),
hook_to_repr!(generation_hook), hook_to_repr!(generation_hook),
HookRepr::Empty, 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 self.cmp_hooks
.last_mut() .last_mut()
.unwrap() .unwrap()
@ -776,7 +828,12 @@ where
pub fn thread_creation_function( pub fn thread_creation_function(
&mut self, &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 { ) -> NewThreadHookId {
unsafe { unsafe {
self.qemu_hooks self.qemu_hooks
@ -1206,7 +1263,12 @@ where
pub fn thread_creation_function( pub fn thread_creation_function(
&mut self, &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 { ) -> NewThreadHookId {
self.hooks.thread_creation_function(hook) 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}; use libafl::{executors::hooks::inprocess::inprocess_get_state, inputs::UsesInput};
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
use libafl_qemu_sys::libafl_dump_core_hook; 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")] #[cfg(feature = "python")]
use pyo3::{pyclass, pymethods, FromPyObject}; use pyo3::{pyclass, pymethods, FromPyObject};
@ -29,14 +29,21 @@ pub enum HookRepr {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct HookState<const N: usize, H: HookId> { pub struct TcgHookState<const N: usize, H: HookId> {
id: H, id: H,
gen: HookRepr, gen: HookRepr,
post_gen: HookRepr, post_gen: HookRepr,
execs: [HookRepr; N], 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 { pub fn new(id: H, gen: HookRepr, post_gen: HookRepr, execs: [HookRepr; N]) -> Self {
Self { Self {
id, 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> { pub enum Hook<F, C, R: Clone> {
Function(F), Function(F),
Closure(C), 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 { macro_rules! create_gen_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $ret_type:ty, $execs:literal, $hook_id:ident) => { ($name:ident, ($($param:ident : $param_type:ty),*), $ret_type:ty, $execs:literal, $hook_id:ident) => {
paste::paste! { 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 where
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput, S: Unpin + UsesInput,
@ -163,7 +246,7 @@ macro_rules! create_gen_wrapper {
macro_rules! create_post_gen_wrapper { macro_rules! create_post_gen_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $execs:literal, $hook_id:ident) => { ($name:ident, ($($param:ident : $param_type:ty),*), $execs:literal, $hook_id:ident) => {
paste::paste! { 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 where
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput, S: Unpin + UsesInput,
@ -193,7 +276,7 @@ macro_rules! create_post_gen_wrapper {
macro_rules! create_exec_wrapper { macro_rules! create_exec_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $execidx:literal, $execs:literal, $hook_id:ident) => { ($name:ident, ($($param:ident : $param_type:ty),*), $execidx:literal, $execs:literal, $hook_id:ident) => {
paste::paste! { 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 where
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput, 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 // Instruction hook wrappers
create_hook_types!( create_hook_types!(
Instruction, Instruction,
@ -409,6 +487,8 @@ create_hook_types!(
) -> GuestAddr ) -> GuestAddr
); );
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
create_hook_id!(PostSyscall, libafl_qemu_remove_post_syscall_hook, false);
#[cfg(emulation_mode = "usermode")]
create_wrapper!( create_wrapper!(
post_syscall, post_syscall,
( (
@ -430,12 +510,39 @@ create_wrapper!(
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
create_hook_types!( create_hook_types!(
NewThread, NewThread,
fn(&mut EmulatorModules<ET, S>, Option<&mut S>, 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>, u32) -> bool>, Box<
extern "C" fn(*const (), tid: u32) -> bool 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")] #[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 // Edge hook wrappers
create_hook_types!( 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 /// `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 /// `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>>( pub fn add_new_thread_hook<T: Into<HookData>>(
&self, &self,
data: T, data: T,
callback: extern "C" fn(T, tid: u32) -> bool, callback: extern "C" fn(T, env: CPUArchStatePtr, tid: u32) -> bool,
) -> NewThreadHookId { ) -> NewThreadHookId {
unsafe { unsafe {
let data: u64 = data.into().0; 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); let num = libafl_qemu_sys::libafl_add_new_thread_hook(Some(callback), data);
NewThreadHookId(num) NewThreadHookId(num)
} }