libafl_qemu: add jmp instrumentation

This commit is contained in:
Alwin Berger 2022-12-19 13:12:37 +01:00
parent 79bca99cc7
commit 7595d25192
2 changed files with 123 additions and 0 deletions

View File

@ -399,6 +399,15 @@ extern "C" {
data: *const (), data: *const (),
); );
fn libafl_qemu_gdb_reply(buf: *const u8, len: usize); fn libafl_qemu_gdb_reply(buf: *const u8, len: usize);
// void libafl_add_jmp_hook(uint64_t (*gen)(target_ulong src, target_ulong dst, uint64_t data),
// void (*exec)(target_ulong src, target_ulong dst, uint64_t id, uint64_t data),
// uint64_t data);
fn libafl_add_jmp_hook(
gen: Option<extern "C" fn(GuestAddr, GuestAddr, u64) -> u64>,
exec: Option<extern "C" fn(GuestAddr, GuestAddr, u64, u64)>,
data: u64,
);
} }
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
@ -1054,6 +1063,15 @@ impl Emulator {
} }
} }
pub fn add_jmp_hooks(
&self,
gen: Option<extern "C" fn(GuestAddr, GuestAddr, u64) -> u64>,
exec: Option<extern "C" fn(GuestAddr, GuestAddr, u64, u64)>,
data: u64,
) {
unsafe { libafl_add_jmp_hook(gen, exec, data) }
}
#[cfg(emulation_mode = "systemmode")] #[cfg(emulation_mode = "systemmode")]
pub fn save_snapshot(&self, name: &str, sync: bool) { pub fn save_snapshot(&self, name: &str, sync: bool) {
let s = CString::new(name).expect("Invalid snapshot name"); let s = CString::new(name).expect("Invalid snapshot name");

View File

@ -655,6 +655,78 @@ where
} }
} }
static mut JMP_HOOKS: Vec<(Hook, Hook)> = vec![];
extern "C" fn gen_jmp_hook_wrapper<QT, S>(src: GuestAddr, dst: GuestAddr, index: u64) -> u64
where
S: UsesInput,
QT: QemuHelperTuple<S>,
{
unsafe {
let hooks = get_qemu_hooks::<QT, S>();
let (gen, _) = &mut JMP_HOOKS[index as usize];
match gen {
Hook::Function(ptr) => {
let func: fn(
&mut QemuHooks<'_, QT, S>,
Option<&mut S>,
GuestAddr,
GuestAddr,
) -> Option<u64> = transmute(*ptr);
(func)(hooks, inprocess_get_state::<S>(), src, dst).map_or(SKIP_EXEC_HOOK, |id| id)
}
Hook::Closure(ptr) => {
let func: &mut Box<
dyn FnMut(
&mut QemuHooks<'_, QT, S>,
Option<&mut S>,
GuestAddr,
GuestAddr,
) -> Option<u64>,
> = transmute(ptr);
(func)(hooks, inprocess_get_state::<S>(), src, dst).map_or(SKIP_EXEC_HOOK, |id| id)
}
_ => 0,
}
}
}
extern "C" fn exec_jmp_hook_wrapper<QT, S>(src: GuestAddr, dst: GuestAddr, id: u64, index: u64)
where
S: UsesInput,
QT: QemuHelperTuple<S>,
{
unsafe {
let hooks = get_qemu_hooks::<QT, S>();
let (_, exec) = &mut JMP_HOOKS[index as usize];
match exec {
Hook::Function(ptr) => {
let func: fn(
&mut QemuHooks<'_, QT, S>,
Option<&mut S>,
GuestAddr,
GuestAddr,
u64,
) = transmute(*ptr);
(func)(hooks, inprocess_get_state::<S>(), src, dst, id);
}
Hook::Closure(ptr) => {
let func: &mut Box<
dyn FnMut(
&mut QemuHooks<'_, QT, S>,
Option<&mut S>,
GuestAddr,
GuestAddr,
u64,
),
> = transmute(ptr);
(func)(hooks, inprocess_get_state::<S>(), src, dst, id);
}
_ => (),
}
}
}
static mut HOOKS_IS_INITIALIZED: bool = false; static mut HOOKS_IS_INITIALIZED: bool = false;
pub struct QemuHooks<'a, QT, S> pub struct QemuHooks<'a, QT, S>
@ -1556,4 +1628,37 @@ where
self.emulator self.emulator
.set_post_syscall_hook(syscall_after_hooks_wrapper::<QT, S>); .set_post_syscall_hook(syscall_after_hooks_wrapper::<QT, S>);
} }
pub fn jmps(
&self,
generation_hook: Option<
fn(&mut Self, Option<&mut S>, src: GuestAddr, dest: GuestAddr) -> Option<u64>,
>,
execution_hook: Option<fn(&mut Self, Option<&mut S>, src: GuestAddr, dest: GuestAddr, id: u64)>,
) {
unsafe {
let index = JMP_HOOKS.len();
self.emulator.add_jmp_hooks(
if generation_hook.is_none() {
None
} else {
Some(gen_jmp_hook_wrapper::<QT, S>)
},
if execution_hook.is_none() {
None
} else {
Some(exec_jmp_hook_wrapper::<QT, S>)
},
index as u64,
);
JMP_HOOKS.push((
generation_hook.map_or(Hook::Empty, |hook| {
Hook::Function(hook as *const libc::c_void)
}),
execution_hook.map_or(Hook::Empty, |hook| {
Hook::Function(hook as *const libc::c_void)
}),
));
}
}
} }