New hooks for libafl_qemu (#673)
* new block and edge hooks * Wrking new hooks * no Pin, just box * working call tracing * invalidate_block flag * working call stack tracking helper * callstack push * fixes * py * fixes * clippy * clippy * gdb api * kill introspection * fix * upd qemu * upd qemu
This commit is contained in:
parent
93048f6270
commit
7147170240
@ -332,7 +332,7 @@ fn fuzz(
|
||||
ExitKind::Ok
|
||||
};
|
||||
|
||||
let hooks = QemuHooks::new(
|
||||
let mut hooks = QemuHooks::new(
|
||||
&emu,
|
||||
tuple_list!(
|
||||
QemuEdgeCoverageHelper::default(),
|
||||
@ -343,7 +343,7 @@ fn fuzz(
|
||||
);
|
||||
|
||||
let executor = QemuExecutor::new(
|
||||
hooks,
|
||||
&mut hooks,
|
||||
&mut harness,
|
||||
tuple_list!(edges_observer, time_observer),
|
||||
&mut fuzzer,
|
||||
|
@ -157,11 +157,11 @@ pub fn fuzz() {
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||
|
||||
let hooks = QemuHooks::new(&emu, tuple_list!(QemuEdgeCoverageHelper::default(),));
|
||||
let mut hooks = QemuHooks::new(&emu, tuple_list!(QemuEdgeCoverageHelper::default()));
|
||||
|
||||
// Create a QEMU in-process executor
|
||||
let executor = QemuExecutor::new(
|
||||
hooks,
|
||||
&mut hooks,
|
||||
&mut harness,
|
||||
tuple_list!(edges_observer, time_observer),
|
||||
&mut fuzzer,
|
||||
|
@ -12,7 +12,7 @@ edition = "2021"
|
||||
categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"]
|
||||
|
||||
[features]
|
||||
default = ["std", "derive", "llmp_compression", "rand_trait", "fork", "introspection"]
|
||||
default = ["std", "derive", "llmp_compression", "rand_trait", "fork"]
|
||||
std = ["serde_json", "serde_json/std", "hostname", "nix", "serde/std", "bincode", "wait-timeout", "regex", "byteorder", "once_cell", "uuid", "tui_monitor", "ctor", "backtrace", "num_cpus"] # print, env, launcher ... support
|
||||
derive = ["libafl_derive"] # provide derive(SerdeAny) macro.
|
||||
fork = [] # uses the fork() syscall to spawn children, instead of launching a new command, if supported by the OS (has no effect on Windows, no_std).
|
||||
|
@ -71,6 +71,7 @@ Welcome to `LibAFL`
|
||||
)
|
||||
)]
|
||||
// Till they fix this buggy lint in clippy
|
||||
#![allow(clippy::borrow_as_ptr)]
|
||||
#![allow(clippy::borrow_deref_ref)]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
|
@ -132,12 +132,14 @@ impl TuiUI {
|
||||
let tabs = Tabs::new(titles)
|
||||
.block(
|
||||
Block::default()
|
||||
.title(Span::styled(
|
||||
.title(
|
||||
Span::styled(
|
||||
"charts (`g` switch)",
|
||||
Style::default()
|
||||
.fg(Color::LightCyan)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
))
|
||||
),
|
||||
)
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
.highlight_style(Style::default().fg(Color::LightYellow))
|
||||
@ -275,12 +277,14 @@ impl TuiUI {
|
||||
let chart = Chart::new(datasets)
|
||||
.block(
|
||||
Block::default()
|
||||
.title(Span::styled(
|
||||
.title(
|
||||
Span::styled(
|
||||
title,
|
||||
Style::default()
|
||||
.fg(Color::LightCyan)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
))
|
||||
),
|
||||
)
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
.x_axis(
|
||||
@ -357,12 +361,14 @@ impl TuiUI {
|
||||
let table = Table::new(items)
|
||||
.block(
|
||||
Block::default()
|
||||
.title(Span::styled(
|
||||
.title(
|
||||
Span::styled(
|
||||
"generic",
|
||||
Style::default()
|
||||
.fg(Color::LightCyan)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
))
|
||||
),
|
||||
)
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
.widths(&[Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]);
|
||||
@ -468,7 +474,8 @@ impl TuiUI {
|
||||
};
|
||||
}
|
||||
|
||||
let table = Table::new(items)
|
||||
let table =
|
||||
Table::new(items)
|
||||
.block(
|
||||
Block::default()
|
||||
.title(Span::styled(
|
||||
@ -496,12 +503,14 @@ impl TuiUI {
|
||||
.map(|msg| ListItem::new(Span::raw(msg)))
|
||||
.collect();
|
||||
let logs = List::new(logs).block(
|
||||
Block::default().borders(Borders::ALL).title(Span::styled(
|
||||
Block::default().borders(Borders::ALL).title(
|
||||
Span::styled(
|
||||
"clients logs (`t` to show/hide)",
|
||||
Style::default()
|
||||
.fg(Color::LightCyan)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
)),
|
||||
),
|
||||
),
|
||||
);
|
||||
f.render_widget(logs, area);
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ strum_macros = "0.21"
|
||||
syscall-numbers = "2.0"
|
||||
bio = "0.39"
|
||||
thread_local = "1.1.3"
|
||||
capstone = "0.10"
|
||||
#pyo3 = { version = "0.15", features = ["extension-module"], optional = true }
|
||||
pyo3 = { version = "0.15", optional = true }
|
||||
|
||||
|
@ -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 = "6a9a929222cbc8b10adfb048aa24f73486e0a886";
|
||||
const QEMU_REVISION: &str = "03e283c85800496b60fb757d68a7df2821fb7a90";
|
||||
|
||||
fn build_dep_check(tools: &[&str]) {
|
||||
for tool in tools {
|
||||
|
@ -59,3 +59,8 @@ impl IntoPy<PyObject> for Regs {
|
||||
n.into_py(py)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an ARM64 ArchCapstoneBuilder
|
||||
pub fn capstone() -> capstone::arch::arm64::ArchCapstoneBuilder {
|
||||
capstone::Capstone::new().arm()
|
||||
}
|
||||
|
@ -47,3 +47,8 @@ impl IntoPy<PyObject> for Regs {
|
||||
n.into_py(py)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an ARM ArchCapstoneBuilder
|
||||
pub fn capstone() -> capstone::arch::arm::ArchCapstoneBuilder {
|
||||
capstone::Capstone::new().arm()
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use libafl::{inputs::Input, state::HasMetadata};
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use std::{env, fs, pin::Pin, ptr};
|
||||
use std::{env, fs, ptr};
|
||||
|
||||
use crate::{
|
||||
emu::{Emulator, SyscallHookResult},
|
||||
@ -413,23 +413,27 @@ where
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||
|
||||
fn init_hooks<'a, QT>(&self, hooks: Pin<&QemuHooks<'a, I, QT, S>>)
|
||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
//hooks.read_generation(gen_readwrite_asan::<I, QT, S>);
|
||||
hooks.read8_execution(trace_read8_asan::<I, QT, S>);
|
||||
hooks.read4_execution(trace_read4_asan::<I, QT, S>);
|
||||
hooks.read2_execution(trace_read2_asan::<I, QT, S>);
|
||||
hooks.read1_execution(trace_read1_asan::<I, QT, S>);
|
||||
hooks.read_n_execution(trace_read_n_asan::<I, QT, S>);
|
||||
hooks.reads(
|
||||
Some(gen_readwrite_asan::<I, QT, S>),
|
||||
Some(trace_read1_asan::<I, QT, S>),
|
||||
Some(trace_read2_asan::<I, QT, S>),
|
||||
Some(trace_read4_asan::<I, QT, S>),
|
||||
Some(trace_read8_asan::<I, QT, S>),
|
||||
Some(trace_read_n_asan::<I, QT, S>),
|
||||
);
|
||||
|
||||
//hooks.write_generation(gen_readwrite_asan::<I, QT, S>);
|
||||
hooks.write8_execution(trace_write8_asan::<I, QT, S>);
|
||||
hooks.write4_execution(trace_write4_asan::<I, QT, S>);
|
||||
hooks.write2_execution(trace_write2_asan::<I, QT, S>);
|
||||
hooks.write1_execution(trace_write1_asan::<I, QT, S>);
|
||||
hooks.write_n_execution(trace_write_n_asan::<I, QT, S>);
|
||||
hooks.writes(
|
||||
Some(gen_readwrite_asan::<I, QT, S>),
|
||||
Some(trace_write1_asan::<I, QT, S>),
|
||||
Some(trace_write2_asan::<I, QT, S>),
|
||||
Some(trace_write4_asan::<I, QT, S>),
|
||||
Some(trace_write8_asan::<I, QT, S>),
|
||||
Some(trace_write_n_asan::<I, QT, S>),
|
||||
);
|
||||
|
||||
hooks.syscalls(qasan_fake_syscall::<I, QT, S>);
|
||||
}
|
||||
@ -439,11 +443,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO add pc to generation hooks
|
||||
pub fn gen_readwrite_asan<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: u64,
|
||||
_size: usize,
|
||||
@ -452,18 +453,16 @@ where
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
if h.must_instrument(pc) {
|
||||
Some(pc)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn trace_read1_asan<I, QT, S>(
|
||||
emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -471,13 +470,13 @@ pub fn trace_read1_asan<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap();
|
||||
h.read_1(emulator, addr);
|
||||
let emulator = hooks.emulator().clone();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
h.read_1(&emulator, addr);
|
||||
}
|
||||
|
||||
pub fn trace_read2_asan<I, QT, S>(
|
||||
emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -485,13 +484,13 @@ pub fn trace_read2_asan<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap();
|
||||
h.read_2(emulator, addr);
|
||||
let emulator = hooks.emulator().clone();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
h.read_2(&emulator, addr);
|
||||
}
|
||||
|
||||
pub fn trace_read4_asan<I, QT, S>(
|
||||
emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -499,13 +498,13 @@ pub fn trace_read4_asan<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap();
|
||||
h.read_4(emulator, addr);
|
||||
let emulator = hooks.emulator().clone();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
h.read_4(&emulator, addr);
|
||||
}
|
||||
|
||||
pub fn trace_read8_asan<I, QT, S>(
|
||||
emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -513,13 +512,13 @@ pub fn trace_read8_asan<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap();
|
||||
h.read_8(emulator, addr);
|
||||
let emulator = hooks.emulator().clone();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
h.read_8(&emulator, addr);
|
||||
}
|
||||
|
||||
pub fn trace_read_n_asan<I, QT, S>(
|
||||
emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -528,13 +527,13 @@ pub fn trace_read_n_asan<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap();
|
||||
h.read_n(emulator, addr, size);
|
||||
let emulator = hooks.emulator().clone();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
h.read_n(&emulator, addr, size);
|
||||
}
|
||||
|
||||
pub fn trace_write1_asan<I, QT, S>(
|
||||
emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -542,13 +541,13 @@ pub fn trace_write1_asan<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap();
|
||||
h.write_1(emulator, addr);
|
||||
let emulator = hooks.emulator().clone();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
h.write_1(&emulator, addr);
|
||||
}
|
||||
|
||||
pub fn trace_write2_asan<I, QT, S>(
|
||||
emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -556,13 +555,13 @@ pub fn trace_write2_asan<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap();
|
||||
h.write_2(emulator, addr);
|
||||
let emulator = hooks.emulator().clone();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
h.write_2(&emulator, addr);
|
||||
}
|
||||
|
||||
pub fn trace_write4_asan<I, QT, S>(
|
||||
emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -570,13 +569,13 @@ pub fn trace_write4_asan<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap();
|
||||
h.write_4(emulator, addr);
|
||||
let emulator = hooks.emulator().clone();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
h.write_4(&emulator, addr);
|
||||
}
|
||||
|
||||
pub fn trace_write8_asan<I, QT, S>(
|
||||
emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -584,13 +583,13 @@ pub fn trace_write8_asan<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap();
|
||||
h.write_8(emulator, addr);
|
||||
let emulator = hooks.emulator().clone();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
h.write_8(&emulator, addr);
|
||||
}
|
||||
|
||||
pub fn trace_write_n_asan<I, QT, S>(
|
||||
emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -599,14 +598,14 @@ pub fn trace_write_n_asan<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap();
|
||||
h.read_n(emulator, addr, size);
|
||||
let emulator = hooks.emulator().clone();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
h.read_n(&emulator, addr, size);
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn qasan_fake_syscall<I, QT, S>(
|
||||
emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
sys_num: i32,
|
||||
a0: u64,
|
||||
@ -623,39 +622,40 @@ where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
if sys_num == QASAN_FAKESYS_NR {
|
||||
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap();
|
||||
let emulator = hooks.emulator().clone();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
let mut r = 0;
|
||||
match QasanAction::try_from(a0).expect("Invalid QASan action number") {
|
||||
QasanAction::CheckLoad => {
|
||||
h.read_n(emulator, a1 as GuestAddr, a2 as usize);
|
||||
h.read_n(&emulator, a1 as GuestAddr, a2 as usize);
|
||||
}
|
||||
QasanAction::CheckStore => {
|
||||
h.write_n(emulator, a1 as GuestAddr, a2 as usize);
|
||||
h.write_n(&emulator, a1 as GuestAddr, a2 as usize);
|
||||
}
|
||||
QasanAction::Poison => {
|
||||
h.poison(
|
||||
emulator,
|
||||
&emulator,
|
||||
a1 as GuestAddr,
|
||||
a2 as usize,
|
||||
PoisonKind::try_from(a3 as u8).unwrap(),
|
||||
);
|
||||
}
|
||||
QasanAction::UserPoison => {
|
||||
h.poison(emulator, a1 as GuestAddr, a2 as usize, PoisonKind::User);
|
||||
h.poison(&emulator, a1 as GuestAddr, a2 as usize, PoisonKind::User);
|
||||
}
|
||||
QasanAction::UnPoison => {
|
||||
h.unpoison(emulator, a1 as GuestAddr, a2 as usize);
|
||||
h.unpoison(&emulator, a1 as GuestAddr, a2 as usize);
|
||||
}
|
||||
QasanAction::IsPoison => {
|
||||
if h.is_poisoned(emulator, a1 as GuestAddr, a2 as usize) {
|
||||
if h.is_poisoned(&emulator, a1 as GuestAddr, a2 as usize) {
|
||||
r = 1;
|
||||
}
|
||||
}
|
||||
QasanAction::Alloc => {
|
||||
h.alloc(emulator, a1, a2);
|
||||
h.alloc(&emulator, a1, a2);
|
||||
}
|
||||
QasanAction::Dealloc => {
|
||||
h.dealloc(emulator, a1);
|
||||
h.dealloc(&emulator, a1);
|
||||
}
|
||||
QasanAction::Enable => {
|
||||
h.set_enabled(true);
|
||||
|
182
libafl_qemu/src/calls.rs
Normal file
182
libafl_qemu/src/calls.rs
Normal file
@ -0,0 +1,182 @@
|
||||
use capstone::prelude::*;
|
||||
use libafl::inputs::Input;
|
||||
|
||||
use crate::{
|
||||
capstone,
|
||||
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
hooks::QemuHooks,
|
||||
Emulator, GuestAddr, Regs,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct QemuCallTracerHelper {
|
||||
filter: QemuInstrumentationFilter,
|
||||
cs: Capstone,
|
||||
callstack: Vec<GuestAddr>,
|
||||
}
|
||||
|
||||
impl QemuCallTracerHelper {
|
||||
#[must_use]
|
||||
pub fn new(filter: QemuInstrumentationFilter) -> Self {
|
||||
Self {
|
||||
filter,
|
||||
cs: capstone().detail(true).build().unwrap(),
|
||||
callstack: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn must_instrument(&self, addr: u64) -> bool {
|
||||
self.filter.allowed(addr)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn callstack(&self) -> &[GuestAddr] {
|
||||
&self.callstack
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.callstack.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for QemuCallTracerHelper {
|
||||
fn default() -> Self {
|
||||
Self::new(QemuInstrumentationFilter::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, S> QemuHelper<I, S> for QemuCallTracerHelper
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
fn init_hooks<'a, QT>(&self, hooks: &QemuHooks<'a, I, QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
hooks.blocks(Some(gen_blocks_calls::<I, QT, S>), None);
|
||||
}
|
||||
|
||||
fn pre_exec(&mut self, _emulator: &Emulator, _input: &I) {
|
||||
self.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/*pub fn on_call<I, QT, S>(hooks: &mut QemuHooks<'_, I, QT, S>, _state: Option<&mut S>, pc: GuestAddr)
|
||||
where
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
}*/
|
||||
|
||||
pub fn on_ret<I, QT, S>(hooks: &mut QemuHooks<'_, I, QT, S>, _state: Option<&mut S>, _pc: GuestAddr)
|
||||
where
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
#[cfg(cpu_target = "x86_64")]
|
||||
let ret_addr = {
|
||||
let emu = hooks.emulator();
|
||||
let stack_ptr: GuestAddr = emu.read_reg(Regs::Rsp).unwrap();
|
||||
let mut ret_addr = [0; 8];
|
||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
||||
GuestAddr::from_le_bytes(ret_addr)
|
||||
};
|
||||
|
||||
#[cfg(cpu_target = "i386")]
|
||||
let ret_addr = {
|
||||
let emu = hooks.emulator();
|
||||
let stack_ptr: GuestAddr = emu.read_reg(Regs::Esp).unwrap();
|
||||
let mut ret_addr = [0; 4];
|
||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
||||
GuestAddr::from_le_bytes(ret_addr)
|
||||
};
|
||||
|
||||
#[cfg(any(cpu_target = "arm", cpu_target = "aarch64"))]
|
||||
let ret_addr = {
|
||||
let emu = hooks.emulator();
|
||||
let ret_addr: GuestAddr = emu.read_reg(Regs::Lr).unwrap();
|
||||
ret_addr
|
||||
};
|
||||
|
||||
// eprintln!("RET @ 0x{:#x}", ret_addr);
|
||||
|
||||
if let Some(h) = hooks
|
||||
.helpers_mut()
|
||||
.match_first_type_mut::<QemuCallTracerHelper>()
|
||||
{
|
||||
while let Some(addr) = h.callstack.pop() {
|
||||
if addr == ret_addr {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_blocks_calls<I, QT, S>(
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
) -> Option<u64>
|
||||
where
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let emu = hooks.emulator();
|
||||
if let Some(h) = hooks.helpers().match_first_type::<QemuCallTracerHelper>() {
|
||||
if !h.must_instrument(pc) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut code = unsafe { std::slice::from_raw_parts(emu.g2h(pc), 512) };
|
||||
let mut iaddr = pc;
|
||||
|
||||
'disasm: while let Ok(insns) = h.cs.disasm_count(code, iaddr, 1) {
|
||||
if insns.is_empty() {
|
||||
break;
|
||||
}
|
||||
let insn = insns.first().unwrap();
|
||||
let insn_detail: InsnDetail = h.cs.insn_detail(insn).unwrap();
|
||||
for detail in insn_detail.groups() {
|
||||
match u32::from(detail.0) {
|
||||
capstone::InsnGroupType::CS_GRP_CALL => {
|
||||
// hooks.instruction_closure(insn.address() as GuestAddr, on_call, false);
|
||||
let call_len = insn.bytes().len() as GuestAddr;
|
||||
let call_cb = move |hooks: &mut QemuHooks<'_, I, QT, S>, _, pc| {
|
||||
// eprintln!("CALL @ 0x{:#x}", pc + call_len);
|
||||
if let Some(h) = hooks
|
||||
.helpers_mut()
|
||||
.match_first_type_mut::<QemuCallTracerHelper>()
|
||||
{
|
||||
h.callstack.push(pc + call_len);
|
||||
}
|
||||
};
|
||||
unsafe {
|
||||
hooks.instruction_closure(
|
||||
insn.address() as GuestAddr,
|
||||
Box::new(call_cb),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
capstone::InsnGroupType::CS_GRP_RET => {
|
||||
hooks.instruction(insn.address() as GuestAddr, on_ret, false);
|
||||
break 'disasm;
|
||||
}
|
||||
capstone::InsnGroupType::CS_GRP_INVALID
|
||||
| capstone::InsnGroupType::CS_GRP_JUMP
|
||||
| capstone::InsnGroupType::CS_GRP_IRET
|
||||
| capstone::InsnGroupType::CS_GRP_PRIVILEGE => {
|
||||
break 'disasm;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
iaddr += insn.bytes().len() as u64;
|
||||
code = unsafe { std::slice::from_raw_parts(emu.g2h(iaddr), 512) };
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
use core::pin::Pin;
|
||||
use hashbrown::HashMap;
|
||||
use libafl::{inputs::Input, state::HasMetadata};
|
||||
pub use libafl_targets::{
|
||||
@ -8,7 +7,6 @@ pub use libafl_targets::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
emu::Emulator,
|
||||
helper::{hash_me, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
hooks::QemuHooks,
|
||||
};
|
||||
@ -59,15 +57,17 @@ where
|
||||
I: Input,
|
||||
S: HasMetadata,
|
||||
{
|
||||
fn init_hooks<'a, QT>(&self, hooks: Pin<&QemuHooks<'a, I, QT, S>>)
|
||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
hooks.cmp_generation(gen_unique_cmp_ids::<I, QT, S>);
|
||||
hooks.emulator().set_exec_cmp8_hook(trace_cmp8_cmplog);
|
||||
hooks.emulator().set_exec_cmp4_hook(trace_cmp4_cmplog);
|
||||
hooks.emulator().set_exec_cmp2_hook(trace_cmp2_cmplog);
|
||||
hooks.emulator().set_exec_cmp1_hook(trace_cmp1_cmplog);
|
||||
hooks.cmps_raw(
|
||||
Some(gen_unique_cmp_ids::<I, QT, S>),
|
||||
Some(trace_cmp1_cmplog),
|
||||
Some(trace_cmp2_cmplog),
|
||||
Some(trace_cmp4_cmplog),
|
||||
Some(trace_cmp8_cmplog),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,21 +101,22 @@ where
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||
|
||||
fn init_hooks<'a, QT>(&self, hooks: Pin<&QemuHooks<'a, I, QT, S>>)
|
||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
hooks.cmp_generation(gen_hashed_cmp_ids::<I, QT, S>);
|
||||
hooks.emulator().set_exec_cmp8_hook(trace_cmp8_cmplog);
|
||||
hooks.emulator().set_exec_cmp4_hook(trace_cmp4_cmplog);
|
||||
hooks.emulator().set_exec_cmp2_hook(trace_cmp2_cmplog);
|
||||
hooks.emulator().set_exec_cmp1_hook(trace_cmp1_cmplog);
|
||||
hooks.cmps_raw(
|
||||
Some(gen_hashed_cmp_ids::<I, QT, S>),
|
||||
Some(trace_cmp1_cmplog),
|
||||
Some(trace_cmp2_cmplog),
|
||||
Some(trace_cmp4_cmplog),
|
||||
Some(trace_cmp8_cmplog),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_unique_cmp_ids<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
state: Option<&mut S>,
|
||||
pc: u64,
|
||||
_size: usize,
|
||||
@ -125,7 +126,7 @@ where
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
if let Some(h) = helpers.match_first_type::<QemuCmpLogHelper>() {
|
||||
if let Some(h) = hooks.match_helper_mut::<QemuCmpLogHelper>() {
|
||||
if !h.must_instrument(pc) {
|
||||
return None;
|
||||
}
|
||||
@ -147,8 +148,7 @@ where
|
||||
}
|
||||
|
||||
pub fn gen_hashed_cmp_ids<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: u64,
|
||||
_size: usize,
|
||||
@ -158,7 +158,7 @@ where
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
if let Some(h) = helpers.match_first_type::<QemuCmpLogChildHelper>() {
|
||||
if let Some(h) = hooks.match_helper_mut::<QemuCmpLogChildHelper>() {
|
||||
if !h.must_instrument(pc) {
|
||||
return None;
|
||||
}
|
||||
@ -166,25 +166,25 @@ where
|
||||
Some(hash_me(pc) & (CMPLOG_MAP_W as u64 - 1))
|
||||
}
|
||||
|
||||
pub extern "C" fn trace_cmp1_cmplog(id: u64, v0: u8, v1: u8) {
|
||||
pub extern "C" fn trace_cmp1_cmplog(id: u64, v0: u8, v1: u8, _data: u64) {
|
||||
unsafe {
|
||||
__libafl_targets_cmplog_instructions(id as usize, 1, u64::from(v0), u64::from(v1));
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn trace_cmp2_cmplog(id: u64, v0: u16, v1: u16) {
|
||||
pub extern "C" fn trace_cmp2_cmplog(id: u64, v0: u16, v1: u16, _data: u64) {
|
||||
unsafe {
|
||||
__libafl_targets_cmplog_instructions(id as usize, 2, u64::from(v0), u64::from(v1));
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn trace_cmp4_cmplog(id: u64, v0: u32, v1: u32) {
|
||||
pub extern "C" fn trace_cmp4_cmplog(id: u64, v0: u32, v1: u32, _data: u64) {
|
||||
unsafe {
|
||||
__libafl_targets_cmplog_instructions(id as usize, 4, u64::from(v0), u64::from(v1));
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn trace_cmp8_cmplog(id: u64, v0: u64, v1: u64) {
|
||||
pub extern "C" fn trace_cmp8_cmplog(id: u64, v0: u64, v1: u64, _data: u64) {
|
||||
unsafe {
|
||||
__libafl_targets_cmplog_instructions(id as usize, 8, v0, v1);
|
||||
}
|
||||
|
@ -4,17 +4,17 @@ pub use libafl_targets::{
|
||||
edges_max_num, EDGES_MAP, EDGES_MAP_PTR, EDGES_MAP_PTR_SIZE, EDGES_MAP_SIZE, MAX_EDGES_NUM,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{cell::UnsafeCell, cmp::max, pin::Pin};
|
||||
use std::{cell::UnsafeCell, cmp::max};
|
||||
|
||||
use crate::{
|
||||
emu::Emulator,
|
||||
emu::GuestAddr,
|
||||
helper::{hash_me, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
hooks::QemuHooks,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct QemuEdgesMapMetadata {
|
||||
pub map: HashMap<(u64, u64), u64>,
|
||||
pub map: HashMap<(GuestAddr, GuestAddr), u64>,
|
||||
pub current_id: u64,
|
||||
}
|
||||
|
||||
@ -70,15 +70,20 @@ where
|
||||
I: Input,
|
||||
S: HasMetadata,
|
||||
{
|
||||
fn init_hooks<'a, QT>(&self, hooks: Pin<&QemuHooks<'a, I, QT, S>>)
|
||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
hooks.edge_generation(gen_unique_edge_ids::<I, QT, S>);
|
||||
if self.use_hitcounts {
|
||||
hooks.emulator().set_exec_edge_hook(trace_edge_hitcount);
|
||||
hooks.edges_raw(
|
||||
Some(gen_unique_edge_ids::<I, QT, S>),
|
||||
Some(trace_edge_hitcount),
|
||||
);
|
||||
} else {
|
||||
hooks.emulator().set_exec_edge_hook(trace_edge_single);
|
||||
hooks.edges_raw(
|
||||
Some(gen_unique_edge_ids::<I, QT, S>),
|
||||
Some(trace_edge_single),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,15 +132,20 @@ where
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||
|
||||
fn init_hooks<'a, QT>(&self, hooks: Pin<&QemuHooks<'a, I, QT, S>>)
|
||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
hooks.edge_generation(gen_hashed_edge_ids::<I, QT, S>);
|
||||
if self.use_hitcounts {
|
||||
hooks.emulator().set_exec_edge_hook(trace_edge_hitcount_ptr);
|
||||
hooks.edges_raw(
|
||||
Some(gen_hashed_edge_ids::<I, QT, S>),
|
||||
Some(trace_edge_hitcount_ptr),
|
||||
);
|
||||
} else {
|
||||
hooks.emulator().set_exec_edge_hook(trace_edge_single_ptr);
|
||||
hooks.edges_raw(
|
||||
Some(gen_hashed_edge_ids::<I, QT, S>),
|
||||
Some(trace_edge_single_ptr),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -143,18 +153,17 @@ where
|
||||
thread_local!(static PREV_LOC : UnsafeCell<u64> = UnsafeCell::new(0));
|
||||
|
||||
pub fn gen_unique_edge_ids<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
state: Option<&mut S>,
|
||||
src: u64,
|
||||
dest: u64,
|
||||
src: GuestAddr,
|
||||
dest: GuestAddr,
|
||||
) -> Option<u64>
|
||||
where
|
||||
S: HasMetadata,
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
if let Some(h) = helpers.match_first_type::<QemuEdgeCoverageHelper>() {
|
||||
if let Some(h) = hooks.helpers().match_first_type::<QemuEdgeCoverageHelper>() {
|
||||
if !h.must_instrument(src) && !h.must_instrument(dest) {
|
||||
return None;
|
||||
}
|
||||
@ -189,45 +198,47 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn trace_edge_hitcount(id: u64) {
|
||||
pub extern "C" fn trace_edge_hitcount(id: u64, _data: u64) {
|
||||
unsafe {
|
||||
EDGES_MAP[id as usize] = EDGES_MAP[id as usize].wrapping_add(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn trace_edge_single(id: u64) {
|
||||
pub extern "C" fn trace_edge_single(id: u64, _data: u64) {
|
||||
unsafe {
|
||||
EDGES_MAP[id as usize] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_hashed_edge_ids<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
src: u64,
|
||||
dest: u64,
|
||||
src: GuestAddr,
|
||||
dest: GuestAddr,
|
||||
) -> Option<u64>
|
||||
where
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
if let Some(h) = helpers.match_first_type::<QemuEdgeCoverageChildHelper>() {
|
||||
if let Some(h) = hooks
|
||||
.helpers()
|
||||
.match_first_type::<QemuEdgeCoverageChildHelper>()
|
||||
{
|
||||
if !h.must_instrument(src) && !h.must_instrument(dest) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some((hash_me(src) ^ hash_me(dest)) & (unsafe { EDGES_MAP_PTR_SIZE } as u64 - 1))
|
||||
Some((hash_me(src as u64) ^ hash_me(dest as u64)) & (unsafe { EDGES_MAP_PTR_SIZE } as u64 - 1))
|
||||
}
|
||||
|
||||
pub extern "C" fn trace_edge_hitcount_ptr(id: u64) {
|
||||
pub extern "C" fn trace_edge_hitcount_ptr(id: u64, _data: u64) {
|
||||
unsafe {
|
||||
let ptr = EDGES_MAP_PTR.add(id as usize);
|
||||
*ptr = (*ptr).wrapping_add(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn trace_edge_single_ptr(id: u64) {
|
||||
pub extern "C" fn trace_edge_single_ptr(id: u64, _data: u64) {
|
||||
unsafe {
|
||||
let ptr = EDGES_MAP_PTR.add(id as usize);
|
||||
*ptr = 1;
|
||||
@ -235,24 +246,30 @@ pub extern "C" fn trace_edge_single_ptr(id: u64) {
|
||||
}
|
||||
|
||||
pub fn gen_addr_block_ids<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
_helpers: &mut QT,
|
||||
_hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: u64,
|
||||
) -> Option<u64> {
|
||||
Some(pc)
|
||||
pc: GuestAddr,
|
||||
) -> Option<u64>
|
||||
where
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
Some(pc as u64)
|
||||
}
|
||||
|
||||
pub fn gen_hashed_block_ids<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
_helpers: &mut QT,
|
||||
_hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: u64,
|
||||
) -> Option<u64> {
|
||||
Some(hash_me(pc))
|
||||
pc: GuestAddr,
|
||||
) -> Option<u64>
|
||||
where
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
Some(hash_me(pc as u64))
|
||||
}
|
||||
|
||||
pub extern "C" fn trace_block_transition_hitcount(id: u64) {
|
||||
pub extern "C" fn trace_block_transition_hitcount(id: u64, _data: u64) {
|
||||
unsafe {
|
||||
PREV_LOC.with(|prev_loc| {
|
||||
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_SIZE - 1);
|
||||
@ -263,7 +280,7 @@ pub extern "C" fn trace_block_transition_hitcount(id: u64) {
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn trace_block_transition_single(id: u64) {
|
||||
pub extern "C" fn trace_block_transition_single(id: u64, _data: u64) {
|
||||
unsafe {
|
||||
PREV_LOC.with(|prev_loc| {
|
||||
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_SIZE - 1);
|
||||
|
@ -189,8 +189,14 @@ extern "C" {
|
||||
fn libafl_qemu_set_breakpoint(addr: u64) -> i32;
|
||||
fn libafl_qemu_remove_breakpoint(addr: u64) -> i32;
|
||||
fn libafl_flush_jit();
|
||||
fn libafl_qemu_set_hook(addr: u64, callback: extern "C" fn(u64), val: u64) -> i32;
|
||||
fn libafl_qemu_remove_hook(addr: u64) -> i32;
|
||||
fn libafl_qemu_set_hook(
|
||||
addr: GuestAddr,
|
||||
callback: extern "C" fn(GuestAddr, u64),
|
||||
data: u64,
|
||||
invalidate_block: i32,
|
||||
) -> usize;
|
||||
// fn libafl_qemu_remove_hook(num: usize, invalidate_block: i32) -> i32;
|
||||
fn libafl_qemu_remove_hooks_at(addr: GuestAddr, invalidate_block: i32) -> usize;
|
||||
fn libafl_qemu_run() -> i32;
|
||||
fn libafl_load_addr() -> u64;
|
||||
fn libafl_get_brk() -> u64;
|
||||
@ -217,30 +223,68 @@ extern "C" {
|
||||
static guest_base: usize;
|
||||
static mut mmap_next_start: GuestAddr;
|
||||
|
||||
static mut libafl_exec_edge_hook: unsafe extern "C" fn(u64);
|
||||
static mut libafl_gen_edge_hook: unsafe extern "C" fn(u64, u64) -> u64;
|
||||
static mut libafl_exec_block_hook: unsafe extern "C" fn(u64);
|
||||
static mut libafl_gen_block_hook: unsafe extern "C" fn(u64) -> u64;
|
||||
// void libafl_add_edge_hook(uint64_t (*gen)(target_ulong src, target_ulong dst), void (*exec)(uint64_t id));
|
||||
fn libafl_add_edge_hook(
|
||||
gen: Option<extern "C" fn(GuestAddr, GuestAddr, u64) -> u64>,
|
||||
exec: Option<extern "C" fn(u64, u64)>,
|
||||
data: u64,
|
||||
);
|
||||
|
||||
static mut libafl_exec_read_hook1: unsafe extern "C" fn(u64, u64);
|
||||
static mut libafl_exec_read_hook2: unsafe extern "C" fn(u64, u64);
|
||||
static mut libafl_exec_read_hook4: unsafe extern "C" fn(u64, u64);
|
||||
static mut libafl_exec_read_hook8: unsafe extern "C" fn(u64, u64);
|
||||
static mut libafl_exec_read_hookN: unsafe extern "C" fn(u64, u64, u32);
|
||||
static mut libafl_gen_read_hook: unsafe extern "C" fn(u32) -> u64;
|
||||
// void libafl_add_block_hook(uint64_t (*gen)(target_ulong pc), void (*exec)(uint64_t id));
|
||||
fn libafl_add_block_hook(
|
||||
gen: Option<extern "C" fn(GuestAddr, u64) -> u64>,
|
||||
exec: Option<extern "C" fn(u64, u64)>,
|
||||
data: u64,
|
||||
);
|
||||
|
||||
static mut libafl_exec_write_hook1: unsafe extern "C" fn(u64, u64);
|
||||
static mut libafl_exec_write_hook2: unsafe extern "C" fn(u64, u64);
|
||||
static mut libafl_exec_write_hook4: unsafe extern "C" fn(u64, u64);
|
||||
static mut libafl_exec_write_hook8: unsafe extern "C" fn(u64, u64);
|
||||
static mut libafl_exec_write_hookN: unsafe extern "C" fn(u64, u64, u32);
|
||||
static mut libafl_gen_write_hook: unsafe extern "C" fn(u32) -> u64;
|
||||
// void libafl_add_read_hook(uint64_t (*gen)(target_ulong pc, size_t size, uint64_t data),
|
||||
// void (*exec1)(uint64_t id, target_ulong addr, uint64_t data),
|
||||
// void (*exec2)(uint64_t id, target_ulong addr, uint64_t data),
|
||||
// void (*exec4)(uint64_t id, target_ulong addr, uint64_t data),
|
||||
// void (*exec8)(uint64_t id, target_ulong addr, uint64_t data),
|
||||
// void (*exec_n)(uint64_t id, target_ulong addr, size_t size, uint64_t data),
|
||||
// uint64_t data);
|
||||
fn libafl_add_read_hook(
|
||||
gen: Option<extern "C" fn(GuestAddr, usize, u64) -> u64>,
|
||||
exec1: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec2: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec4: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec8: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec_n: Option<extern "C" fn(u64, GuestAddr, usize, u64)>,
|
||||
data: u64,
|
||||
);
|
||||
|
||||
static mut libafl_exec_cmp_hook1: unsafe extern "C" fn(u64, u8, u8);
|
||||
static mut libafl_exec_cmp_hook2: unsafe extern "C" fn(u64, u16, u16);
|
||||
static mut libafl_exec_cmp_hook4: unsafe extern "C" fn(u64, u32, u32);
|
||||
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;
|
||||
// void libafl_add_write_hook(uint64_t (*gen)(target_ulong pc, size_t size, uint64_t data),
|
||||
// void (*exec1)(uint64_t id, target_ulong addr, uint64_t data),
|
||||
// void (*exec2)(uint64_t id, target_ulong addr, uint64_t data),
|
||||
// void (*exec4)(uint64_t id, target_ulong addr, uint64_t data),
|
||||
// void (*exec8)(uint64_t id, target_ulong addr, uint64_t data),
|
||||
// void (*exec_n)(uint64_t id, target_ulong addr, size_t size, uint64_t data),
|
||||
// uint64_t data);
|
||||
fn libafl_add_write_hook(
|
||||
gen: Option<extern "C" fn(GuestAddr, usize, u64) -> u64>,
|
||||
exec1: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec2: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec4: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec8: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec_n: Option<extern "C" fn(u64, GuestAddr, usize, u64)>,
|
||||
data: u64,
|
||||
);
|
||||
|
||||
// void libafl_add_cmp_hook(uint64_t (*gen)(target_ulong pc, size_t size, uint64_t data),
|
||||
// void (*exec1)(uint64_t id, uint8_t v0, uint8_t v1, uint64_t data),
|
||||
// void (*exec2)(uint64_t id, uint16_t v0, uint16_t v1, uint64_t data),
|
||||
// void (*exec4)(uint64_t id, uint32_t v0, uint32_t v1, uint64_t data),
|
||||
// void (*exec8)(uint64_t id, uint64_t v0, uint64_t v1, uint64_t data),
|
||||
// uint64_t data);
|
||||
fn libafl_add_cmp_hook(
|
||||
gen: Option<extern "C" fn(GuestAddr, usize, u64) -> u64>,
|
||||
exec1: Option<extern "C" fn(u64, u8, u8, u64)>,
|
||||
exec2: Option<extern "C" fn(u64, u16, u16, u64)>,
|
||||
exec4: Option<extern "C" fn(u64, u32, u32, u64)>,
|
||||
exec8: Option<extern "C" fn(u64, u64, u64, u64)>,
|
||||
data: u64,
|
||||
);
|
||||
|
||||
static mut libafl_on_thread_hook: unsafe extern "C" fn(u32);
|
||||
|
||||
@ -323,10 +367,10 @@ static mut GDB_COMMANDS: Vec<FatPtr> = vec![];
|
||||
|
||||
extern "C" fn gdb_cmd(buf: *const u8, len: usize, data: *const ()) -> i32 {
|
||||
unsafe {
|
||||
let closure =
|
||||
&mut *(data as *mut std::boxed::Box<dyn for<'r> std::ops::FnMut(&'r str) -> bool>);
|
||||
let closure = &mut *(data as *mut Box<dyn for<'r> FnMut(&Emulator, &'r str) -> bool>);
|
||||
let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len));
|
||||
if closure(cmd) {
|
||||
let emu = Emulator::new_empty();
|
||||
if closure(&emu, cmd) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
@ -336,7 +380,7 @@ extern "C" fn gdb_cmd(buf: *const u8, len: usize, data: *const ()) -> i32 {
|
||||
|
||||
static mut EMULATOR_IS_INITIALIZED: bool = false;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Emulator {
|
||||
_private: (),
|
||||
}
|
||||
@ -453,16 +497,19 @@ impl Emulator {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_hook(&self, addr: GuestAddr, callback: extern "C" fn(u64), val: u64) {
|
||||
unsafe {
|
||||
libafl_qemu_set_hook(addr.into(), callback, val);
|
||||
}
|
||||
pub fn set_hook(
|
||||
&self,
|
||||
addr: GuestAddr,
|
||||
callback: extern "C" fn(GuestAddr, u64),
|
||||
data: u64,
|
||||
invalidate_block: bool,
|
||||
) -> usize {
|
||||
unsafe { libafl_qemu_set_hook(addr.into(), callback, data, i32::from(invalidate_block)) }
|
||||
}
|
||||
|
||||
pub fn remove_hook(&self, addr: GuestAddr) {
|
||||
unsafe {
|
||||
libafl_qemu_remove_hook(addr.into());
|
||||
}
|
||||
#[must_use]
|
||||
pub fn remove_hook(&self, addr: GuestAddr, invalidate_block: bool) -> usize {
|
||||
unsafe { libafl_qemu_remove_hooks_at(addr.into(), i32::from(invalidate_block)) }
|
||||
}
|
||||
|
||||
/// This function will run the emulator until the next breakpoint, or until finish.
|
||||
@ -577,133 +624,60 @@ impl Emulator {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add has_X_hook() and panic when setting a hook for the second time
|
||||
|
||||
pub fn set_exec_edge_hook(&self, hook: extern "C" fn(id: u64)) {
|
||||
unsafe {
|
||||
libafl_exec_edge_hook = hook;
|
||||
}
|
||||
pub fn add_edge_hooks(
|
||||
&self,
|
||||
gen: Option<extern "C" fn(GuestAddr, GuestAddr, u64) -> u64>,
|
||||
exec: Option<extern "C" fn(u64, u64)>,
|
||||
data: u64,
|
||||
) {
|
||||
unsafe { libafl_add_edge_hook(gen, exec, data) }
|
||||
}
|
||||
|
||||
pub fn set_gen_edge_hook(&self, hook: extern "C" fn(src: u64, dest: u64) -> u64) {
|
||||
unsafe {
|
||||
libafl_gen_edge_hook = hook;
|
||||
}
|
||||
pub fn add_block_hooks(
|
||||
&self,
|
||||
gen: Option<extern "C" fn(GuestAddr, u64) -> u64>,
|
||||
exec: Option<extern "C" fn(u64, u64)>,
|
||||
data: u64,
|
||||
) {
|
||||
unsafe { libafl_add_block_hook(gen, exec, data) }
|
||||
}
|
||||
|
||||
pub fn set_exec_block_hook(&self, hook: extern "C" fn(pc: u64)) {
|
||||
unsafe {
|
||||
libafl_exec_block_hook = hook;
|
||||
}
|
||||
pub fn add_read_hooks(
|
||||
&self,
|
||||
gen: Option<extern "C" fn(GuestAddr, usize, u64) -> u64>,
|
||||
exec1: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec2: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec4: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec8: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec_n: Option<extern "C" fn(u64, GuestAddr, usize, u64)>,
|
||||
data: u64,
|
||||
) {
|
||||
unsafe { libafl_add_read_hook(gen, exec1, exec2, exec4, exec8, exec_n, data) }
|
||||
}
|
||||
|
||||
pub fn set_gen_block_hook(&self, hook: extern "C" fn(pc: u64) -> u64) {
|
||||
unsafe {
|
||||
libafl_gen_block_hook = hook;
|
||||
}
|
||||
pub fn add_write_hooks(
|
||||
&self,
|
||||
gen: Option<extern "C" fn(GuestAddr, usize, u64) -> u64>,
|
||||
exec1: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec2: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec4: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec8: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
||||
exec_n: Option<extern "C" fn(u64, GuestAddr, usize, u64)>,
|
||||
data: u64,
|
||||
) {
|
||||
unsafe { libafl_add_write_hook(gen, exec1, exec2, exec4, exec8, exec_n, data) }
|
||||
}
|
||||
|
||||
pub fn set_exec_read1_hook(&self, hook: extern "C" fn(id: u64, addr: u64)) {
|
||||
unsafe {
|
||||
libafl_exec_read_hook1 = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_read2_hook(&self, hook: extern "C" fn(id: u64, addr: u64)) {
|
||||
unsafe {
|
||||
libafl_exec_read_hook2 = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_read4_hook(&self, hook: extern "C" fn(id: u64, addr: u64)) {
|
||||
unsafe {
|
||||
libafl_exec_read_hook4 = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_read8_hook(&self, hook: extern "C" fn(id: u64, addr: u64)) {
|
||||
unsafe {
|
||||
libafl_exec_read_hook8 = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_read_n_hook(&self, hook: extern "C" fn(id: u64, addr: u64, size: u32)) {
|
||||
unsafe {
|
||||
libafl_exec_read_hookN = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_gen_read_hook(&self, hook: extern "C" fn(size: u32) -> u64) {
|
||||
unsafe {
|
||||
libafl_gen_read_hook = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_write1_hook(&self, hook: extern "C" fn(id: u64, addr: u64)) {
|
||||
unsafe {
|
||||
libafl_exec_write_hook1 = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_write2_hook(&self, hook: extern "C" fn(id: u64, addr: u64)) {
|
||||
unsafe {
|
||||
libafl_exec_write_hook2 = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_write4_hook(&self, hook: extern "C" fn(id: u64, addr: u64)) {
|
||||
unsafe {
|
||||
libafl_exec_write_hook4 = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_write8_hook(&self, hook: extern "C" fn(id: u64, addr: u64)) {
|
||||
unsafe {
|
||||
libafl_exec_write_hook8 = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_write_n_hook(&self, hook: extern "C" fn(id: u64, addr: u64, size: u32)) {
|
||||
unsafe {
|
||||
libafl_exec_write_hookN = hook;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add pc arg
|
||||
pub fn set_gen_write_hook(&self, hook: extern "C" fn(size: u32) -> u64) {
|
||||
unsafe {
|
||||
libafl_gen_write_hook = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_cmp1_hook(&self, hook: extern "C" fn(id: u64, v0: u8, v1: u8)) {
|
||||
unsafe {
|
||||
libafl_exec_cmp_hook1 = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_cmp2_hook(&self, hook: extern "C" fn(id: u64, v0: u16, v1: u16)) {
|
||||
unsafe {
|
||||
libafl_exec_cmp_hook2 = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_cmp4_hook(&self, hook: extern "C" fn(id: u64, v0: u32, v1: u32)) {
|
||||
unsafe {
|
||||
libafl_exec_cmp_hook4 = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_exec_cmp8_hook(&self, hook: extern "C" fn(id: u64, v0: u64, v1: u64)) {
|
||||
unsafe {
|
||||
libafl_exec_cmp_hook8 = hook;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_gen_cmp_hook(&self, hook: extern "C" fn(pc: u64, size: u32) -> u64) {
|
||||
unsafe {
|
||||
libafl_gen_cmp_hook = hook;
|
||||
}
|
||||
pub fn add_cmp_hooks(
|
||||
&self,
|
||||
gen: Option<extern "C" fn(GuestAddr, usize, u64) -> u64>,
|
||||
exec1: Option<extern "C" fn(u64, u8, u8, u64)>,
|
||||
exec2: Option<extern "C" fn(u64, u16, u16, u64)>,
|
||||
exec4: Option<extern "C" fn(u64, u32, u32, u64)>,
|
||||
exec8: Option<extern "C" fn(u64, u64, u64, u64)>,
|
||||
data: u64,
|
||||
) {
|
||||
unsafe { libafl_add_cmp_hook(gen, exec1, exec2, exec4, exec8, data) }
|
||||
}
|
||||
|
||||
pub fn set_on_thread_hook(&self, hook: extern "C" fn(tid: u32)) {
|
||||
@ -730,7 +704,7 @@ impl Emulator {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_gdb_cmd(&self, callback: Box<dyn FnMut(&str) -> bool>) {
|
||||
pub fn add_gdb_cmd(&self, callback: Box<dyn FnMut(&Self, &str) -> bool>) {
|
||||
unsafe {
|
||||
GDB_COMMANDS.push(core::mem::transmute(callback));
|
||||
libafl_qemu_add_gdb_cmd(
|
||||
@ -791,7 +765,7 @@ pub mod pybind {
|
||||
)
|
||||
}
|
||||
|
||||
extern "C" fn py_generic_hook_wrapper(idx: u64) {
|
||||
extern "C" fn py_generic_hook_wrapper(_pc: GuestAddr, idx: u64) {
|
||||
let obj = unsafe { &PY_GENERIC_HOOKS[idx as usize].1 };
|
||||
Python::with_gil(|py| {
|
||||
obj.call0(py).expect("Error in the hook");
|
||||
@ -918,15 +892,16 @@ pub mod pybind {
|
||||
unsafe {
|
||||
let idx = PY_GENERIC_HOOKS.len();
|
||||
PY_GENERIC_HOOKS.push((addr, hook));
|
||||
self.emu.set_hook(addr, py_generic_hook_wrapper, idx as u64);
|
||||
self.emu
|
||||
.set_hook(addr, py_generic_hook_wrapper, idx as u64, true);
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_hook(&self, addr: GuestAddr) {
|
||||
fn remove_hook(&self, addr: GuestAddr) -> usize {
|
||||
unsafe {
|
||||
PY_GENERIC_HOOKS.retain(|(a, _)| *a != addr);
|
||||
}
|
||||
self.emu.remove_hook(addr);
|
||||
self.emu.remove_hook(addr, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,5 @@
|
||||
//! A `QEMU`-based executor for binary-only instrumentation in `LibAFL`
|
||||
use core::{
|
||||
fmt::{self, Debug, Formatter},
|
||||
pin::Pin,
|
||||
};
|
||||
use core::fmt::{self, Debug, Formatter};
|
||||
|
||||
use libafl::{
|
||||
bolts::shmem::ShMemProvider,
|
||||
@ -26,7 +23,7 @@ where
|
||||
OT: ObserversTuple<I, S>,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
hooks: Pin<Box<QemuHooks<'a, I, QT, S>>>,
|
||||
hooks: &'a mut QemuHooks<'a, I, QT, S>,
|
||||
inner: InProcessExecutor<'a, H, I, OT, S>,
|
||||
}
|
||||
|
||||
@ -53,7 +50,7 @@ where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
pub fn new<EM, OF, Z>(
|
||||
hooks: Pin<Box<QemuHooks<'a, I, QT, S>>>,
|
||||
hooks: &'a mut QemuHooks<'a, I, QT, S>,
|
||||
harness_fn: &'a mut H,
|
||||
observers: OT,
|
||||
fuzzer: &mut Z,
|
||||
@ -80,12 +77,12 @@ where
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn hooks(&self) -> &Pin<Box<QemuHooks<'a, I, QT, S>>> {
|
||||
&self.hooks
|
||||
pub fn hooks(&self) -> &QemuHooks<'a, I, QT, S> {
|
||||
self.hooks
|
||||
}
|
||||
|
||||
pub fn hooks_mut(&mut self) -> &mut Pin<Box<QemuHooks<'a, I, QT, S>>> {
|
||||
&mut self.hooks
|
||||
pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, I, QT, S> {
|
||||
self.hooks
|
||||
}
|
||||
|
||||
pub fn emulator(&self) -> &Emulator {
|
||||
@ -108,21 +105,9 @@ where
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
let emu = Emulator::new_empty();
|
||||
unsafe {
|
||||
self.hooks
|
||||
.as_mut()
|
||||
.get_unchecked_mut()
|
||||
.helpers_mut()
|
||||
.pre_exec_all(&emu, input);
|
||||
}
|
||||
self.hooks.helpers_mut().pre_exec_all(&emu, input);
|
||||
let r = self.inner.run_target(fuzzer, state, mgr, input);
|
||||
unsafe {
|
||||
self.hooks
|
||||
.as_mut()
|
||||
.get_unchecked_mut()
|
||||
.helpers_mut()
|
||||
.post_exec_all(&emu, input);
|
||||
}
|
||||
self.hooks.helpers_mut().post_exec_all(&emu, input);
|
||||
r
|
||||
}
|
||||
}
|
||||
@ -153,7 +138,7 @@ where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
hooks: Pin<Box<QemuHooks<'a, I, QT, S>>>,
|
||||
hooks: &'a mut QemuHooks<'a, I, QT, S>,
|
||||
inner: InProcessForkExecutor<'a, H, I, OT, S, SP>,
|
||||
}
|
||||
|
||||
@ -182,7 +167,7 @@ where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
pub fn new<EM, OF, Z>(
|
||||
hooks: Pin<Box<QemuHooks<'a, I, QT, S>>>,
|
||||
hooks: &'a mut QemuHooks<'a, I, QT, S>,
|
||||
harness_fn: &'a mut H,
|
||||
observers: OT,
|
||||
fuzzer: &mut Z,
|
||||
@ -219,12 +204,12 @@ where
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn hooks(&self) -> &Pin<Box<QemuHooks<'a, I, QT, S>>> {
|
||||
&self.hooks
|
||||
pub fn hooks(&self) -> &QemuHooks<'a, I, QT, S> {
|
||||
self.hooks
|
||||
}
|
||||
|
||||
pub fn hooks_mut(&mut self) -> &mut Pin<Box<QemuHooks<'a, I, QT, S>>> {
|
||||
&mut self.hooks
|
||||
pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, I, QT, S> {
|
||||
self.hooks
|
||||
}
|
||||
|
||||
pub fn emulator(&self) -> &Emulator {
|
||||
@ -249,21 +234,9 @@ where
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
let emu = Emulator::new_empty();
|
||||
unsafe {
|
||||
self.hooks
|
||||
.as_mut()
|
||||
.get_unchecked_mut()
|
||||
.helpers_mut()
|
||||
.pre_exec_all(&emu, input);
|
||||
}
|
||||
self.hooks.helpers_mut().pre_exec_all(&emu, input);
|
||||
let r = self.inner.run_target(fuzzer, state, mgr, input);
|
||||
unsafe {
|
||||
self.hooks
|
||||
.as_mut()
|
||||
.get_unchecked_mut()
|
||||
.helpers_mut()
|
||||
.post_exec_all(&emu, input);
|
||||
}
|
||||
self.hooks.helpers_mut().post_exec_all(&emu, input);
|
||||
r
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use core::{fmt::Debug, ops::Range, pin::Pin};
|
||||
use core::{fmt::Debug, ops::Range};
|
||||
use libafl::{bolts::tuples::MatchFirstType, inputs::Input};
|
||||
|
||||
use crate::{emu::Emulator, hooks::QemuHooks};
|
||||
@ -11,7 +11,7 @@ where
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool = true;
|
||||
|
||||
fn init_hooks<'a, QT>(&self, _hooks: Pin<&QemuHooks<'a, I, QT, S>>)
|
||||
fn init_hooks<QT>(&self, _hooks: &QemuHooks<'_, I, QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
@ -28,7 +28,7 @@ where
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool;
|
||||
|
||||
fn init_hooks_all<'a, QT>(&self, hooks: Pin<&QemuHooks<'a, I, QT, S>>)
|
||||
fn init_hooks_all<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<I, S>;
|
||||
|
||||
@ -43,7 +43,7 @@ where
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||
|
||||
fn init_hooks_all<'a, QT>(&self, _hooks: Pin<&QemuHooks<'a, I, QT, S>>)
|
||||
fn init_hooks_all<QT>(&self, _hooks: &QemuHooks<'_, I, QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
@ -62,7 +62,7 @@ where
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool = Head::HOOKS_DO_SIDE_EFFECTS || Tail::HOOKS_DO_SIDE_EFFECTS;
|
||||
|
||||
fn init_hooks_all<'a, QT>(&self, hooks: Pin<&QemuHooks<'a, I, QT, S>>)
|
||||
fn init_hooks_all<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,8 @@ pub use strum_macros::EnumIter;
|
||||
#[cfg(feature = "python")]
|
||||
use pyo3::prelude::*;
|
||||
|
||||
use capstone::arch::BuildsCapstone;
|
||||
|
||||
pub use syscall_numbers::x86::*;
|
||||
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||
@ -35,3 +37,10 @@ impl IntoPy<PyObject> for Regs {
|
||||
n.into_py(py)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an X86 ArchCapstoneBuilder
|
||||
pub fn capstone() -> capstone::arch::x86::ArchCapstoneBuilder {
|
||||
capstone::Capstone::new()
|
||||
.x86()
|
||||
.mode(capstone::arch::x86::ArchMode::Mode32)
|
||||
}
|
||||
|
@ -7,8 +7,12 @@
|
||||
allow(clippy::useless_conversion)
|
||||
)]
|
||||
#![allow(clippy::needless_pass_by_value)]
|
||||
#![allow(clippy::transmute_ptr_to_ptr)]
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
// Till they fix this buggy lint in clippy
|
||||
#![allow(clippy::borrow_deref_ref)]
|
||||
#![allow(clippy::borrow_as_ptr)]
|
||||
// Allow only ATM, it will be evetually removed
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
|
||||
use std::env;
|
||||
|
||||
@ -50,6 +54,8 @@ pub use snapshot::QemuSnapshotHelper;
|
||||
pub mod asan;
|
||||
pub use asan::{init_with_asan, QemuAsanHelper};
|
||||
|
||||
pub mod calls;
|
||||
|
||||
pub mod executor;
|
||||
pub use executor::{QemuExecutor, QemuForkExecutor};
|
||||
|
||||
|
@ -3,7 +3,6 @@ use libafl::{inputs::Input, state::HasMetadata};
|
||||
use std::{
|
||||
cell::UnsafeCell,
|
||||
collections::{HashMap, HashSet},
|
||||
pin::Pin,
|
||||
sync::Mutex,
|
||||
};
|
||||
use thread_local::ThreadLocal;
|
||||
@ -197,15 +196,18 @@ where
|
||||
I: Input,
|
||||
S: HasMetadata,
|
||||
{
|
||||
fn init_hooks<'a, QT>(&self, hooks: Pin<&QemuHooks<'a, I, QT, S>>)
|
||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
hooks.write8_execution(trace_write8_snapshot::<I, QT, S>);
|
||||
hooks.write4_execution(trace_write4_snapshot::<I, QT, S>);
|
||||
hooks.write2_execution(trace_write2_snapshot::<I, QT, S>);
|
||||
hooks.write1_execution(trace_write1_snapshot::<I, QT, S>);
|
||||
hooks.write_n_execution(trace_write_n_snapshot::<I, QT, S>);
|
||||
hooks.writes(
|
||||
None,
|
||||
Some(trace_write1_snapshot::<I, QT, S>),
|
||||
Some(trace_write2_snapshot::<I, QT, S>),
|
||||
Some(trace_write4_snapshot::<I, QT, S>),
|
||||
Some(trace_write8_snapshot::<I, QT, S>),
|
||||
Some(trace_write_n_snapshot::<I, QT, S>),
|
||||
);
|
||||
|
||||
hooks.after_syscalls(trace_mmap_snapshot::<I, QT, S>);
|
||||
}
|
||||
@ -220,8 +222,7 @@ where
|
||||
}
|
||||
|
||||
pub fn trace_write1_snapshot<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -229,15 +230,12 @@ pub fn trace_write1_snapshot<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(addr, 1);
|
||||
}
|
||||
|
||||
pub fn trace_write2_snapshot<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -245,15 +243,12 @@ pub fn trace_write2_snapshot<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(addr, 2);
|
||||
}
|
||||
|
||||
pub fn trace_write4_snapshot<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -261,15 +256,12 @@ pub fn trace_write4_snapshot<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(addr, 4);
|
||||
}
|
||||
|
||||
pub fn trace_write8_snapshot<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -277,15 +269,12 @@ pub fn trace_write8_snapshot<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(addr, 8);
|
||||
}
|
||||
|
||||
pub fn trace_write_n_snapshot<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -294,17 +283,14 @@ pub fn trace_write_n_snapshot<I, QT, S>(
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(addr, size);
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub fn trace_mmap_snapshot<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
hooks: &mut QemuHooks<'_, I, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
result: u64,
|
||||
sys_num: i32,
|
||||
@ -324,51 +310,37 @@ where
|
||||
// NOT A COMPLETE LIST OF MEMORY EFFECTS
|
||||
match i64::from(sys_num) {
|
||||
SYS_read | SYS_pread64 => {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(a1 as GuestAddr, a2 as usize);
|
||||
}
|
||||
SYS_readlinkat => {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(a2 as GuestAddr, a3 as usize);
|
||||
}
|
||||
SYS_futex => {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(a0 as GuestAddr, a3 as usize);
|
||||
}
|
||||
#[cfg(not(cpu_target = "arm"))]
|
||||
SYS_newfstatat => {
|
||||
if a2 != 0 {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(a2 as GuestAddr, 4096); // stat is not greater than a page
|
||||
}
|
||||
}
|
||||
#[cfg(cpu_target = "arm")]
|
||||
SYS_fstatat64 => {
|
||||
if a2 != 0 {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(a2 as GuestAddr, 4096); // stat is not greater than a page
|
||||
}
|
||||
}
|
||||
SYS_statfs | SYS_fstatfs | SYS_fstat => {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(a1 as GuestAddr, 4096); // stat is not greater than a page
|
||||
}
|
||||
SYS_getrandom => {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(a0 as GuestAddr, a1 as usize);
|
||||
}
|
||||
// mmap syscalls
|
||||
@ -382,9 +354,7 @@ where
|
||||
#[cfg(cpu_target = "arm")]
|
||||
if i64::from(sys_num) == SYS_mmap2 {
|
||||
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.add_mapped(result as GuestAddr, a1 as usize, Some(prot));
|
||||
}
|
||||
} else if i64::from(sys_num) == SYS_mremap {
|
||||
@ -394,9 +364,7 @@ where
|
||||
h.add_mapped(result as GuestAddr, a2 as usize, None);
|
||||
} else if i64::from(sys_num) == SYS_mprotect {
|
||||
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.add_mapped(a0 as GuestAddr, a2 as usize, Some(prot));
|
||||
}
|
||||
}
|
||||
@ -404,21 +372,15 @@ where
|
||||
#[cfg(not(cpu_target = "arm"))]
|
||||
if i64::from(sys_num) == SYS_mmap {
|
||||
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.add_mapped(result as GuestAddr, a1 as usize, Some(prot));
|
||||
}
|
||||
} else if i64::from(sys_num) == SYS_mremap {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.add_mapped(result as GuestAddr, a2 as usize, None);
|
||||
} else if i64::from(sys_num) == SYS_mprotect {
|
||||
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.add_mapped(a0 as GuestAddr, a2 as usize, Some(prot));
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ pub use strum_macros::EnumIter;
|
||||
#[cfg(feature = "python")]
|
||||
use pyo3::prelude::*;
|
||||
|
||||
use capstone::arch::BuildsCapstone;
|
||||
|
||||
pub use syscall_numbers::x86_64::*;
|
||||
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||
@ -43,3 +45,11 @@ impl IntoPy<PyObject> for Regs {
|
||||
n.into_py(py)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an X86 `ArchCapstoneBuilder`
|
||||
#[must_use]
|
||||
pub fn capstone() -> capstone::arch::x86::ArchCapstoneBuilder {
|
||||
capstone::Capstone::new()
|
||||
.x86()
|
||||
.mode(capstone::arch::x86::ArchMode::Mode64)
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ where
|
||||
};
|
||||
|
||||
if self.use_cmplog.unwrap_or(false) {
|
||||
let hooks = QemuHooks::new(
|
||||
let mut hooks = QemuHooks::new(
|
||||
emulator,
|
||||
tuple_list!(
|
||||
QemuEdgeCoverageHelper::default(),
|
||||
@ -216,7 +216,7 @@ where
|
||||
);
|
||||
|
||||
let executor = QemuExecutor::new(
|
||||
hooks,
|
||||
&mut hooks,
|
||||
&mut harness,
|
||||
tuple_list!(edges_observer, time_observer),
|
||||
&mut fuzzer,
|
||||
@ -316,11 +316,11 @@ where
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let hooks =
|
||||
let mut hooks =
|
||||
QemuHooks::new(emulator, tuple_list!(QemuEdgeCoverageHelper::default()));
|
||||
|
||||
let executor = QemuExecutor::new(
|
||||
hooks,
|
||||
&mut hooks,
|
||||
&mut harness,
|
||||
tuple_list!(edges_observer, time_observer),
|
||||
&mut fuzzer,
|
||||
|
Loading…
x
Reference in New Issue
Block a user