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:
Andrea Fioraldi 2022-06-16 11:09:07 +02:00 committed by GitHub
parent 93048f6270
commit 7147170240
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1547 additions and 1525 deletions

View File

@ -332,7 +332,7 @@ fn fuzz(
ExitKind::Ok ExitKind::Ok
}; };
let hooks = QemuHooks::new( let mut hooks = QemuHooks::new(
&emu, &emu,
tuple_list!( tuple_list!(
QemuEdgeCoverageHelper::default(), QemuEdgeCoverageHelper::default(),
@ -343,7 +343,7 @@ fn fuzz(
); );
let executor = QemuExecutor::new( let executor = QemuExecutor::new(
hooks, &mut hooks,
&mut harness, &mut harness,
tuple_list!(edges_observer, time_observer), tuple_list!(edges_observer, time_observer),
&mut fuzzer, &mut fuzzer,

View File

@ -157,11 +157,11 @@ pub fn fuzz() {
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); 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 // Create a QEMU in-process executor
let executor = QemuExecutor::new( let executor = QemuExecutor::new(
hooks, &mut hooks,
&mut harness, &mut harness,
tuple_list!(edges_observer, time_observer), tuple_list!(edges_observer, time_observer),
&mut fuzzer, &mut fuzzer,

View File

@ -12,7 +12,7 @@ edition = "2021"
categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"] categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"]
[features] [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 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. 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). 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).

View File

@ -71,6 +71,7 @@ Welcome to `LibAFL`
) )
)] )]
// Till they fix this buggy lint in clippy // Till they fix this buggy lint in clippy
#![allow(clippy::borrow_as_ptr)]
#![allow(clippy::borrow_deref_ref)] #![allow(clippy::borrow_deref_ref)]
#[cfg(feature = "std")] #[cfg(feature = "std")]

View File

@ -132,12 +132,14 @@ impl TuiUI {
let tabs = Tabs::new(titles) let tabs = Tabs::new(titles)
.block( .block(
Block::default() Block::default()
.title(Span::styled( .title(
"charts (`g` switch)", Span::styled(
Style::default() "charts (`g` switch)",
.fg(Color::LightCyan) Style::default()
.add_modifier(Modifier::BOLD), .fg(Color::LightCyan)
)) .add_modifier(Modifier::BOLD),
),
)
.borders(Borders::ALL), .borders(Borders::ALL),
) )
.highlight_style(Style::default().fg(Color::LightYellow)) .highlight_style(Style::default().fg(Color::LightYellow))
@ -275,12 +277,14 @@ impl TuiUI {
let chart = Chart::new(datasets) let chart = Chart::new(datasets)
.block( .block(
Block::default() Block::default()
.title(Span::styled( .title(
title, Span::styled(
Style::default() title,
.fg(Color::LightCyan) Style::default()
.add_modifier(Modifier::BOLD), .fg(Color::LightCyan)
)) .add_modifier(Modifier::BOLD),
),
)
.borders(Borders::ALL), .borders(Borders::ALL),
) )
.x_axis( .x_axis(
@ -357,12 +361,14 @@ impl TuiUI {
let table = Table::new(items) let table = Table::new(items)
.block( .block(
Block::default() Block::default()
.title(Span::styled( .title(
"generic", Span::styled(
Style::default() "generic",
.fg(Color::LightCyan) Style::default()
.add_modifier(Modifier::BOLD), .fg(Color::LightCyan)
)) .add_modifier(Modifier::BOLD),
),
)
.borders(Borders::ALL), .borders(Borders::ALL),
) )
.widths(&[Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]); .widths(&[Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]);
@ -468,18 +474,19 @@ impl TuiUI {
}; };
} }
let table = Table::new(items) let table =
.block( Table::new(items)
Block::default() .block(
.title(Span::styled( Block::default()
"introspection", .title(Span::styled(
Style::default() "introspection",
.fg(Color::LightCyan) Style::default()
.add_modifier(Modifier::BOLD), .fg(Color::LightCyan)
)) .add_modifier(Modifier::BOLD),
.borders(Borders::ALL), ))
) .borders(Borders::ALL),
.widths(&[Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]); )
.widths(&[Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]);
f.render_widget(table, client_chunks[1]); f.render_widget(table, client_chunks[1]);
} }
} }
@ -496,12 +503,14 @@ impl TuiUI {
.map(|msg| ListItem::new(Span::raw(msg))) .map(|msg| ListItem::new(Span::raw(msg)))
.collect(); .collect();
let logs = List::new(logs).block( let logs = List::new(logs).block(
Block::default().borders(Borders::ALL).title(Span::styled( Block::default().borders(Borders::ALL).title(
"clients logs (`t` to show/hide)", Span::styled(
Style::default() "clients logs (`t` to show/hide)",
.fg(Color::LightCyan) Style::default()
.add_modifier(Modifier::BOLD), .fg(Color::LightCyan)
)), .add_modifier(Modifier::BOLD),
),
),
); );
f.render_widget(logs, area); f.render_widget(logs, area);
} }

View File

@ -38,6 +38,7 @@ strum_macros = "0.21"
syscall-numbers = "2.0" syscall-numbers = "2.0"
bio = "0.39" bio = "0.39"
thread_local = "1.1.3" thread_local = "1.1.3"
capstone = "0.10"
#pyo3 = { version = "0.15", features = ["extension-module"], optional = true } #pyo3 = { version = "0.15", features = ["extension-module"], optional = true }
pyo3 = { version = "0.15", optional = true } pyo3 = { version = "0.15", optional = true }

View File

@ -3,7 +3,7 @@ use which::which;
const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
const QEMU_DIRNAME: &str = "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]) { fn build_dep_check(tools: &[&str]) {
for tool in tools { for tool in tools {

View File

@ -59,3 +59,8 @@ impl IntoPy<PyObject> for Regs {
n.into_py(py) n.into_py(py)
} }
} }
/// Return an ARM64 ArchCapstoneBuilder
pub fn capstone() -> capstone::arch::arm64::ArchCapstoneBuilder {
capstone::Capstone::new().arm()
}

View File

@ -47,3 +47,8 @@ impl IntoPy<PyObject> for Regs {
n.into_py(py) n.into_py(py)
} }
} }
/// Return an ARM ArchCapstoneBuilder
pub fn capstone() -> capstone::arch::arm::ArchCapstoneBuilder {
capstone::Capstone::new().arm()
}

View File

@ -1,6 +1,6 @@
use libafl::{inputs::Input, state::HasMetadata}; use libafl::{inputs::Input, state::HasMetadata};
use num_enum::{IntoPrimitive, TryFromPrimitive}; use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::{env, fs, pin::Pin, ptr}; use std::{env, fs, ptr};
use crate::{ use crate::{
emu::{Emulator, SyscallHookResult}, emu::{Emulator, SyscallHookResult},
@ -413,23 +413,27 @@ where
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = false; 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 where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
//hooks.read_generation(gen_readwrite_asan::<I, QT, S>); hooks.reads(
hooks.read8_execution(trace_read8_asan::<I, QT, S>); Some(gen_readwrite_asan::<I, QT, S>),
hooks.read4_execution(trace_read4_asan::<I, QT, S>); Some(trace_read1_asan::<I, QT, S>),
hooks.read2_execution(trace_read2_asan::<I, QT, S>); Some(trace_read2_asan::<I, QT, S>),
hooks.read1_execution(trace_read1_asan::<I, QT, S>); Some(trace_read4_asan::<I, QT, S>),
hooks.read_n_execution(trace_read_n_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.writes(
hooks.write8_execution(trace_write8_asan::<I, QT, S>); Some(gen_readwrite_asan::<I, QT, S>),
hooks.write4_execution(trace_write4_asan::<I, QT, S>); Some(trace_write1_asan::<I, QT, S>),
hooks.write2_execution(trace_write2_asan::<I, QT, S>); Some(trace_write2_asan::<I, QT, S>),
hooks.write1_execution(trace_write1_asan::<I, QT, S>); Some(trace_write4_asan::<I, QT, S>),
hooks.write_n_execution(trace_write_n_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>); 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>( pub fn gen_readwrite_asan<I, QT, S>(
_emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
pc: u64, pc: u64,
_size: usize, _size: usize,
@ -452,18 +453,16 @@ where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, 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) { if h.must_instrument(pc) {
Some(pc) Some(pc)
} else { } else {
None None
} }
} }
*/
pub fn trace_read1_asan<I, QT, S>( pub fn trace_read1_asan<I, QT, S>(
emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -471,13 +470,13 @@ pub fn trace_read1_asan<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap(); let emulator = hooks.emulator().clone();
h.read_1(emulator, addr); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.read_1(&emulator, addr);
} }
pub fn trace_read2_asan<I, QT, S>( pub fn trace_read2_asan<I, QT, S>(
emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -485,13 +484,13 @@ pub fn trace_read2_asan<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap(); let emulator = hooks.emulator().clone();
h.read_2(emulator, addr); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.read_2(&emulator, addr);
} }
pub fn trace_read4_asan<I, QT, S>( pub fn trace_read4_asan<I, QT, S>(
emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -499,13 +498,13 @@ pub fn trace_read4_asan<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap(); let emulator = hooks.emulator().clone();
h.read_4(emulator, addr); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.read_4(&emulator, addr);
} }
pub fn trace_read8_asan<I, QT, S>( pub fn trace_read8_asan<I, QT, S>(
emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -513,13 +512,13 @@ pub fn trace_read8_asan<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap(); let emulator = hooks.emulator().clone();
h.read_8(emulator, addr); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.read_8(&emulator, addr);
} }
pub fn trace_read_n_asan<I, QT, S>( pub fn trace_read_n_asan<I, QT, S>(
emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -528,13 +527,13 @@ pub fn trace_read_n_asan<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap(); let emulator = hooks.emulator().clone();
h.read_n(emulator, addr, size); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.read_n(&emulator, addr, size);
} }
pub fn trace_write1_asan<I, QT, S>( pub fn trace_write1_asan<I, QT, S>(
emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -542,13 +541,13 @@ pub fn trace_write1_asan<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap(); let emulator = hooks.emulator().clone();
h.write_1(emulator, addr); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.write_1(&emulator, addr);
} }
pub fn trace_write2_asan<I, QT, S>( pub fn trace_write2_asan<I, QT, S>(
emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -556,13 +555,13 @@ pub fn trace_write2_asan<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap(); let emulator = hooks.emulator().clone();
h.write_2(emulator, addr); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.write_2(&emulator, addr);
} }
pub fn trace_write4_asan<I, QT, S>( pub fn trace_write4_asan<I, QT, S>(
emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -570,13 +569,13 @@ pub fn trace_write4_asan<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap(); let emulator = hooks.emulator().clone();
h.write_4(emulator, addr); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.write_4(&emulator, addr);
} }
pub fn trace_write8_asan<I, QT, S>( pub fn trace_write8_asan<I, QT, S>(
emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -584,13 +583,13 @@ pub fn trace_write8_asan<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap(); let emulator = hooks.emulator().clone();
h.write_8(emulator, addr); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.write_8(&emulator, addr);
} }
pub fn trace_write_n_asan<I, QT, S>( pub fn trace_write_n_asan<I, QT, S>(
emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -599,14 +598,14 @@ pub fn trace_write_n_asan<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers.match_first_type_mut::<QemuAsanHelper>().unwrap(); let emulator = hooks.emulator().clone();
h.read_n(emulator, addr, size); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.read_n(&emulator, addr, size);
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn qasan_fake_syscall<I, QT, S>( pub fn qasan_fake_syscall<I, QT, S>(
emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
sys_num: i32, sys_num: i32,
a0: u64, a0: u64,
@ -623,39 +622,40 @@ where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
if sys_num == QASAN_FAKESYS_NR { 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; let mut r = 0;
match QasanAction::try_from(a0).expect("Invalid QASan action number") { match QasanAction::try_from(a0).expect("Invalid QASan action number") {
QasanAction::CheckLoad => { QasanAction::CheckLoad => {
h.read_n(emulator, a1 as GuestAddr, a2 as usize); h.read_n(&emulator, a1 as GuestAddr, a2 as usize);
} }
QasanAction::CheckStore => { QasanAction::CheckStore => {
h.write_n(emulator, a1 as GuestAddr, a2 as usize); h.write_n(&emulator, a1 as GuestAddr, a2 as usize);
} }
QasanAction::Poison => { QasanAction::Poison => {
h.poison( h.poison(
emulator, &emulator,
a1 as GuestAddr, a1 as GuestAddr,
a2 as usize, a2 as usize,
PoisonKind::try_from(a3 as u8).unwrap(), PoisonKind::try_from(a3 as u8).unwrap(),
); );
} }
QasanAction::UserPoison => { 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 => { QasanAction::UnPoison => {
h.unpoison(emulator, a1 as GuestAddr, a2 as usize); h.unpoison(&emulator, a1 as GuestAddr, a2 as usize);
} }
QasanAction::IsPoison => { 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; r = 1;
} }
} }
QasanAction::Alloc => { QasanAction::Alloc => {
h.alloc(emulator, a1, a2); h.alloc(&emulator, a1, a2);
} }
QasanAction::Dealloc => { QasanAction::Dealloc => {
h.dealloc(emulator, a1); h.dealloc(&emulator, a1);
} }
QasanAction::Enable => { QasanAction::Enable => {
h.set_enabled(true); h.set_enabled(true);

182
libafl_qemu/src/calls.rs Normal file
View 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
}

View File

@ -1,4 +1,3 @@
use core::pin::Pin;
use hashbrown::HashMap; use hashbrown::HashMap;
use libafl::{inputs::Input, state::HasMetadata}; use libafl::{inputs::Input, state::HasMetadata};
pub use libafl_targets::{ pub use libafl_targets::{
@ -8,7 +7,6 @@ pub use libafl_targets::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
emu::Emulator,
helper::{hash_me, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, helper::{hash_me, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
hooks::QemuHooks, hooks::QemuHooks,
}; };
@ -59,15 +57,17 @@ where
I: Input, I: Input,
S: HasMetadata, 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 where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
hooks.cmp_generation(gen_unique_cmp_ids::<I, QT, S>); hooks.cmps_raw(
hooks.emulator().set_exec_cmp8_hook(trace_cmp8_cmplog); Some(gen_unique_cmp_ids::<I, QT, S>),
hooks.emulator().set_exec_cmp4_hook(trace_cmp4_cmplog); Some(trace_cmp1_cmplog),
hooks.emulator().set_exec_cmp2_hook(trace_cmp2_cmplog); Some(trace_cmp2_cmplog),
hooks.emulator().set_exec_cmp1_hook(trace_cmp1_cmplog); Some(trace_cmp4_cmplog),
Some(trace_cmp8_cmplog),
);
} }
} }
@ -101,21 +101,22 @@ where
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = false; 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 where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
hooks.cmp_generation(gen_hashed_cmp_ids::<I, QT, S>); hooks.cmps_raw(
hooks.emulator().set_exec_cmp8_hook(trace_cmp8_cmplog); Some(gen_hashed_cmp_ids::<I, QT, S>),
hooks.emulator().set_exec_cmp4_hook(trace_cmp4_cmplog); Some(trace_cmp1_cmplog),
hooks.emulator().set_exec_cmp2_hook(trace_cmp2_cmplog); Some(trace_cmp2_cmplog),
hooks.emulator().set_exec_cmp1_hook(trace_cmp1_cmplog); Some(trace_cmp4_cmplog),
Some(trace_cmp8_cmplog),
);
} }
} }
pub fn gen_unique_cmp_ids<I, QT, S>( pub fn gen_unique_cmp_ids<I, QT, S>(
_emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
state: Option<&mut S>, state: Option<&mut S>,
pc: u64, pc: u64,
_size: usize, _size: usize,
@ -125,7 +126,7 @@ where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, 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) { if !h.must_instrument(pc) {
return None; return None;
} }
@ -147,8 +148,7 @@ where
} }
pub fn gen_hashed_cmp_ids<I, QT, S>( pub fn gen_hashed_cmp_ids<I, QT, S>(
_emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
pc: u64, pc: u64,
_size: usize, _size: usize,
@ -158,7 +158,7 @@ where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, 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) { if !h.must_instrument(pc) {
return None; return None;
} }
@ -166,25 +166,25 @@ where
Some(hash_me(pc) & (CMPLOG_MAP_W as u64 - 1)) 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 { unsafe {
__libafl_targets_cmplog_instructions(id as usize, 1, u64::from(v0), u64::from(v1)); __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 { unsafe {
__libafl_targets_cmplog_instructions(id as usize, 2, u64::from(v0), u64::from(v1)); __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 { unsafe {
__libafl_targets_cmplog_instructions(id as usize, 4, u64::from(v0), u64::from(v1)); __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 { unsafe {
__libafl_targets_cmplog_instructions(id as usize, 8, v0, v1); __libafl_targets_cmplog_instructions(id as usize, 8, v0, v1);
} }

View File

@ -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, edges_max_num, EDGES_MAP, EDGES_MAP_PTR, EDGES_MAP_PTR_SIZE, EDGES_MAP_SIZE, MAX_EDGES_NUM,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{cell::UnsafeCell, cmp::max, pin::Pin}; use std::{cell::UnsafeCell, cmp::max};
use crate::{ use crate::{
emu::Emulator, emu::GuestAddr,
helper::{hash_me, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, helper::{hash_me, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
hooks::QemuHooks, hooks::QemuHooks,
}; };
#[derive(Debug, Default, Serialize, Deserialize)] #[derive(Debug, Default, Serialize, Deserialize)]
pub struct QemuEdgesMapMetadata { pub struct QemuEdgesMapMetadata {
pub map: HashMap<(u64, u64), u64>, pub map: HashMap<(GuestAddr, GuestAddr), u64>,
pub current_id: u64, pub current_id: u64,
} }
@ -70,15 +70,20 @@ where
I: Input, I: Input,
S: HasMetadata, 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 where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
hooks.edge_generation(gen_unique_edge_ids::<I, QT, S>);
if self.use_hitcounts { 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 { } 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; 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 where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
hooks.edge_generation(gen_hashed_edge_ids::<I, QT, S>);
if self.use_hitcounts { 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 { } 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)); thread_local!(static PREV_LOC : UnsafeCell<u64> = UnsafeCell::new(0));
pub fn gen_unique_edge_ids<I, QT, S>( pub fn gen_unique_edge_ids<I, QT, S>(
_emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
state: Option<&mut S>, state: Option<&mut S>,
src: u64, src: GuestAddr,
dest: u64, dest: GuestAddr,
) -> Option<u64> ) -> Option<u64>
where where
S: HasMetadata, S: HasMetadata,
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, 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) { if !h.must_instrument(src) && !h.must_instrument(dest) {
return None; 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 { unsafe {
EDGES_MAP[id as usize] = EDGES_MAP[id as usize].wrapping_add(1); 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 { unsafe {
EDGES_MAP[id as usize] = 1; EDGES_MAP[id as usize] = 1;
} }
} }
pub fn gen_hashed_edge_ids<I, QT, S>( pub fn gen_hashed_edge_ids<I, QT, S>(
_emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
src: u64, src: GuestAddr,
dest: u64, dest: GuestAddr,
) -> Option<u64> ) -> Option<u64>
where where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, 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) { if !h.must_instrument(src) && !h.must_instrument(dest) {
return None; 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 { unsafe {
let ptr = EDGES_MAP_PTR.add(id as usize); let ptr = EDGES_MAP_PTR.add(id as usize);
*ptr = (*ptr).wrapping_add(1); *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 { unsafe {
let ptr = EDGES_MAP_PTR.add(id as usize); let ptr = EDGES_MAP_PTR.add(id as usize);
*ptr = 1; *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>( pub fn gen_addr_block_ids<I, QT, S>(
_emulator: &Emulator, _hooks: &mut QemuHooks<'_, I, QT, S>,
_helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
pc: u64, pc: GuestAddr,
) -> Option<u64> { ) -> Option<u64>
Some(pc) where
I: Input,
QT: QemuHelperTuple<I, S>,
{
Some(pc as u64)
} }
pub fn gen_hashed_block_ids<I, QT, S>( pub fn gen_hashed_block_ids<I, QT, S>(
_emulator: &Emulator, _hooks: &mut QemuHooks<'_, I, QT, S>,
_helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
pc: u64, pc: GuestAddr,
) -> Option<u64> { ) -> Option<u64>
Some(hash_me(pc)) 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 { unsafe {
PREV_LOC.with(|prev_loc| { PREV_LOC.with(|prev_loc| {
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_SIZE - 1); 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 { unsafe {
PREV_LOC.with(|prev_loc| { PREV_LOC.with(|prev_loc| {
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_SIZE - 1); let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_SIZE - 1);

View File

@ -189,8 +189,14 @@ extern "C" {
fn libafl_qemu_set_breakpoint(addr: u64) -> i32; fn libafl_qemu_set_breakpoint(addr: u64) -> i32;
fn libafl_qemu_remove_breakpoint(addr: u64) -> i32; fn libafl_qemu_remove_breakpoint(addr: u64) -> i32;
fn libafl_flush_jit(); fn libafl_flush_jit();
fn libafl_qemu_set_hook(addr: u64, callback: extern "C" fn(u64), val: u64) -> i32; fn libafl_qemu_set_hook(
fn libafl_qemu_remove_hook(addr: u64) -> i32; 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_qemu_run() -> i32;
fn libafl_load_addr() -> u64; fn libafl_load_addr() -> u64;
fn libafl_get_brk() -> u64; fn libafl_get_brk() -> u64;
@ -217,30 +223,68 @@ extern "C" {
static guest_base: usize; static guest_base: usize;
static mut mmap_next_start: GuestAddr; static mut mmap_next_start: GuestAddr;
static mut libafl_exec_edge_hook: unsafe extern "C" fn(u64); // void libafl_add_edge_hook(uint64_t (*gen)(target_ulong src, target_ulong dst), void (*exec)(uint64_t id));
static mut libafl_gen_edge_hook: unsafe extern "C" fn(u64, u64) -> u64; fn libafl_add_edge_hook(
static mut libafl_exec_block_hook: unsafe extern "C" fn(u64); gen: Option<extern "C" fn(GuestAddr, GuestAddr, u64) -> u64>,
static mut libafl_gen_block_hook: unsafe extern "C" fn(u64) -> u64; exec: Option<extern "C" fn(u64, u64)>,
data: u64,
);
static mut libafl_exec_read_hook1: unsafe extern "C" fn(u64, u64); // void libafl_add_block_hook(uint64_t (*gen)(target_ulong pc), void (*exec)(uint64_t id));
static mut libafl_exec_read_hook2: unsafe extern "C" fn(u64, u64); fn libafl_add_block_hook(
static mut libafl_exec_read_hook4: unsafe extern "C" fn(u64, u64); gen: Option<extern "C" fn(GuestAddr, u64) -> u64>,
static mut libafl_exec_read_hook8: unsafe extern "C" fn(u64, u64); exec: Option<extern "C" fn(u64, u64)>,
static mut libafl_exec_read_hookN: unsafe extern "C" fn(u64, u64, u32); data: u64,
static mut libafl_gen_read_hook: unsafe extern "C" fn(u32) -> u64; );
static mut libafl_exec_write_hook1: unsafe extern "C" fn(u64, u64); // void libafl_add_read_hook(uint64_t (*gen)(target_ulong pc, size_t size, uint64_t data),
static mut libafl_exec_write_hook2: unsafe extern "C" fn(u64, u64); // void (*exec1)(uint64_t id, target_ulong addr, uint64_t data),
static mut libafl_exec_write_hook4: unsafe extern "C" fn(u64, u64); // void (*exec2)(uint64_t id, target_ulong addr, uint64_t data),
static mut libafl_exec_write_hook8: unsafe extern "C" fn(u64, u64); // void (*exec4)(uint64_t id, target_ulong addr, uint64_t data),
static mut libafl_exec_write_hookN: unsafe extern "C" fn(u64, u64, u32); // void (*exec8)(uint64_t id, target_ulong addr, uint64_t data),
static mut libafl_gen_write_hook: unsafe extern "C" fn(u32) -> u64; // 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); // void libafl_add_write_hook(uint64_t (*gen)(target_ulong pc, size_t size, uint64_t data),
static mut libafl_exec_cmp_hook2: unsafe extern "C" fn(u64, u16, u16); // void (*exec1)(uint64_t id, target_ulong addr, uint64_t data),
static mut libafl_exec_cmp_hook4: unsafe extern "C" fn(u64, u32, u32); // void (*exec2)(uint64_t id, target_ulong addr, uint64_t data),
static mut libafl_exec_cmp_hook8: unsafe extern "C" fn(u64, u64, u64); // void (*exec4)(uint64_t id, target_ulong addr, uint64_t data),
static mut libafl_gen_cmp_hook: unsafe extern "C" fn(u64, u32) -> u64; // 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); 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 { extern "C" fn gdb_cmd(buf: *const u8, len: usize, data: *const ()) -> i32 {
unsafe { unsafe {
let closure = let closure = &mut *(data as *mut Box<dyn for<'r> FnMut(&Emulator, &'r str) -> bool>);
&mut *(data as *mut std::boxed::Box<dyn for<'r> std::ops::FnMut(&'r str) -> bool>);
let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len)); 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 1
} else { } else {
0 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; static mut EMULATOR_IS_INITIALIZED: bool = false;
#[derive(Debug)] #[derive(Clone, Debug)]
pub struct Emulator { pub struct Emulator {
_private: (), _private: (),
} }
@ -453,16 +497,19 @@ impl Emulator {
} }
} }
pub fn set_hook(&self, addr: GuestAddr, callback: extern "C" fn(u64), val: u64) { pub fn set_hook(
unsafe { &self,
libafl_qemu_set_hook(addr.into(), callback, val); 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) { #[must_use]
unsafe { pub fn remove_hook(&self, addr: GuestAddr, invalidate_block: bool) -> usize {
libafl_qemu_remove_hook(addr.into()); 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. /// 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 add_edge_hooks(
&self,
pub fn set_exec_edge_hook(&self, hook: extern "C" fn(id: u64)) { gen: Option<extern "C" fn(GuestAddr, GuestAddr, u64) -> u64>,
unsafe { exec: Option<extern "C" fn(u64, u64)>,
libafl_exec_edge_hook = hook; 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) { pub fn add_block_hooks(
unsafe { &self,
libafl_gen_edge_hook = hook; 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)) { pub fn add_read_hooks(
unsafe { &self,
libafl_exec_block_hook = 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,
) {
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) { pub fn add_write_hooks(
unsafe { &self,
libafl_gen_block_hook = 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,
) {
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)) { pub fn add_cmp_hooks(
unsafe { &self,
libafl_exec_read_hook1 = 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)>,
pub fn set_exec_read2_hook(&self, hook: extern "C" fn(id: u64, addr: u64)) { exec8: Option<extern "C" fn(u64, u64, u64, u64)>,
unsafe { data: u64,
libafl_exec_read_hook2 = hook; ) {
} unsafe { libafl_add_cmp_hook(gen, exec1, exec2, exec4, exec8, data) }
}
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 set_on_thread_hook(&self, hook: extern "C" fn(tid: u32)) { 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 { unsafe {
GDB_COMMANDS.push(core::mem::transmute(callback)); GDB_COMMANDS.push(core::mem::transmute(callback));
libafl_qemu_add_gdb_cmd( 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 }; let obj = unsafe { &PY_GENERIC_HOOKS[idx as usize].1 };
Python::with_gil(|py| { Python::with_gil(|py| {
obj.call0(py).expect("Error in the hook"); obj.call0(py).expect("Error in the hook");
@ -918,15 +892,16 @@ pub mod pybind {
unsafe { unsafe {
let idx = PY_GENERIC_HOOKS.len(); let idx = PY_GENERIC_HOOKS.len();
PY_GENERIC_HOOKS.push((addr, hook)); 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 { unsafe {
PY_GENERIC_HOOKS.retain(|(a, _)| *a != addr); PY_GENERIC_HOOKS.retain(|(a, _)| *a != addr);
} }
self.emu.remove_hook(addr); self.emu.remove_hook(addr, true)
} }
} }
} }

View File

@ -1,8 +1,5 @@
//! A `QEMU`-based executor for binary-only instrumentation in `LibAFL` //! A `QEMU`-based executor for binary-only instrumentation in `LibAFL`
use core::{ use core::fmt::{self, Debug, Formatter};
fmt::{self, Debug, Formatter},
pin::Pin,
};
use libafl::{ use libafl::{
bolts::shmem::ShMemProvider, bolts::shmem::ShMemProvider,
@ -26,7 +23,7 @@ where
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
QT: QemuHelperTuple<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>, inner: InProcessExecutor<'a, H, I, OT, S>,
} }
@ -53,7 +50,7 @@ where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
pub fn new<EM, OF, Z>( 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, harness_fn: &'a mut H,
observers: OT, observers: OT,
fuzzer: &mut Z, fuzzer: &mut Z,
@ -80,12 +77,12 @@ where
&mut self.inner &mut self.inner
} }
pub fn hooks(&self) -> &Pin<Box<QemuHooks<'a, I, QT, S>>> { pub fn hooks(&self) -> &QemuHooks<'a, I, QT, S> {
&self.hooks self.hooks
} }
pub fn hooks_mut(&mut self) -> &mut Pin<Box<QemuHooks<'a, I, QT, S>>> { pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, I, QT, S> {
&mut self.hooks self.hooks
} }
pub fn emulator(&self) -> &Emulator { pub fn emulator(&self) -> &Emulator {
@ -108,21 +105,9 @@ where
input: &I, input: &I,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
let emu = Emulator::new_empty(); let emu = Emulator::new_empty();
unsafe { self.hooks.helpers_mut().pre_exec_all(&emu, input);
self.hooks
.as_mut()
.get_unchecked_mut()
.helpers_mut()
.pre_exec_all(&emu, input);
}
let r = self.inner.run_target(fuzzer, state, mgr, input); let r = self.inner.run_target(fuzzer, state, mgr, input);
unsafe { self.hooks.helpers_mut().post_exec_all(&emu, input);
self.hooks
.as_mut()
.get_unchecked_mut()
.helpers_mut()
.post_exec_all(&emu, input);
}
r r
} }
} }
@ -153,7 +138,7 @@ where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
SP: ShMemProvider, 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>, inner: InProcessForkExecutor<'a, H, I, OT, S, SP>,
} }
@ -182,7 +167,7 @@ where
SP: ShMemProvider, SP: ShMemProvider,
{ {
pub fn new<EM, OF, Z>( 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, harness_fn: &'a mut H,
observers: OT, observers: OT,
fuzzer: &mut Z, fuzzer: &mut Z,
@ -219,12 +204,12 @@ where
&mut self.inner &mut self.inner
} }
pub fn hooks(&self) -> &Pin<Box<QemuHooks<'a, I, QT, S>>> { pub fn hooks(&self) -> &QemuHooks<'a, I, QT, S> {
&self.hooks self.hooks
} }
pub fn hooks_mut(&mut self) -> &mut Pin<Box<QemuHooks<'a, I, QT, S>>> { pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, I, QT, S> {
&mut self.hooks self.hooks
} }
pub fn emulator(&self) -> &Emulator { pub fn emulator(&self) -> &Emulator {
@ -249,21 +234,9 @@ where
input: &I, input: &I,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
let emu = Emulator::new_empty(); let emu = Emulator::new_empty();
unsafe { self.hooks.helpers_mut().pre_exec_all(&emu, input);
self.hooks
.as_mut()
.get_unchecked_mut()
.helpers_mut()
.pre_exec_all(&emu, input);
}
let r = self.inner.run_target(fuzzer, state, mgr, input); let r = self.inner.run_target(fuzzer, state, mgr, input);
unsafe { self.hooks.helpers_mut().post_exec_all(&emu, input);
self.hooks
.as_mut()
.get_unchecked_mut()
.helpers_mut()
.post_exec_all(&emu, input);
}
r r
} }
} }

View File

@ -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 libafl::{bolts::tuples::MatchFirstType, inputs::Input};
use crate::{emu::Emulator, hooks::QemuHooks}; use crate::{emu::Emulator, hooks::QemuHooks};
@ -11,7 +11,7 @@ where
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = true; 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 where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
@ -28,7 +28,7 @@ where
{ {
const HOOKS_DO_SIDE_EFFECTS: bool; 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 where
QT: QemuHelperTuple<I, S>; QT: QemuHelperTuple<I, S>;
@ -43,7 +43,7 @@ where
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = false; 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 where
QT: QemuHelperTuple<I, S>, 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; 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 where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,8 @@ pub use strum_macros::EnumIter;
#[cfg(feature = "python")] #[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
use capstone::arch::BuildsCapstone;
pub use syscall_numbers::x86::*; pub use syscall_numbers::x86::*;
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)] #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
@ -35,3 +37,10 @@ impl IntoPy<PyObject> for Regs {
n.into_py(py) 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)
}

View File

@ -7,8 +7,12 @@
allow(clippy::useless_conversion) allow(clippy::useless_conversion)
)] )]
#![allow(clippy::needless_pass_by_value)] #![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 // 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; use std::env;
@ -50,6 +54,8 @@ pub use snapshot::QemuSnapshotHelper;
pub mod asan; pub mod asan;
pub use asan::{init_with_asan, QemuAsanHelper}; pub use asan::{init_with_asan, QemuAsanHelper};
pub mod calls;
pub mod executor; pub mod executor;
pub use executor::{QemuExecutor, QemuForkExecutor}; pub use executor::{QemuExecutor, QemuForkExecutor};

View File

@ -3,7 +3,6 @@ use libafl::{inputs::Input, state::HasMetadata};
use std::{ use std::{
cell::UnsafeCell, cell::UnsafeCell,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
pin::Pin,
sync::Mutex, sync::Mutex,
}; };
use thread_local::ThreadLocal; use thread_local::ThreadLocal;
@ -197,15 +196,18 @@ where
I: Input, I: Input,
S: HasMetadata, 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 where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
hooks.write8_execution(trace_write8_snapshot::<I, QT, S>); hooks.writes(
hooks.write4_execution(trace_write4_snapshot::<I, QT, S>); None,
hooks.write2_execution(trace_write2_snapshot::<I, QT, S>); Some(trace_write1_snapshot::<I, QT, S>),
hooks.write1_execution(trace_write1_snapshot::<I, QT, S>); Some(trace_write2_snapshot::<I, QT, S>),
hooks.write_n_execution(trace_write_n_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>); hooks.after_syscalls(trace_mmap_snapshot::<I, QT, S>);
} }
@ -220,8 +222,7 @@ where
} }
pub fn trace_write1_snapshot<I, QT, S>( pub fn trace_write1_snapshot<I, QT, S>(
_emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -229,15 +230,12 @@ pub fn trace_write1_snapshot<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(addr, 1); h.access(addr, 1);
} }
pub fn trace_write2_snapshot<I, QT, S>( pub fn trace_write2_snapshot<I, QT, S>(
_emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -245,15 +243,12 @@ pub fn trace_write2_snapshot<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(addr, 2); h.access(addr, 2);
} }
pub fn trace_write4_snapshot<I, QT, S>( pub fn trace_write4_snapshot<I, QT, S>(
_emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -261,15 +256,12 @@ pub fn trace_write4_snapshot<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(addr, 4); h.access(addr, 4);
} }
pub fn trace_write8_snapshot<I, QT, S>( pub fn trace_write8_snapshot<I, QT, S>(
_emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -277,15 +269,12 @@ pub fn trace_write8_snapshot<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(addr, 8); h.access(addr, 8);
} }
pub fn trace_write_n_snapshot<I, QT, S>( pub fn trace_write_n_snapshot<I, QT, S>(
_emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
@ -294,17 +283,14 @@ pub fn trace_write_n_snapshot<I, QT, S>(
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(addr, size); h.access(addr, size);
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
pub fn trace_mmap_snapshot<I, QT, S>( pub fn trace_mmap_snapshot<I, QT, S>(
_emulator: &Emulator, hooks: &mut QemuHooks<'_, I, QT, S>,
helpers: &mut QT,
_state: Option<&mut S>, _state: Option<&mut S>,
result: u64, result: u64,
sys_num: i32, sys_num: i32,
@ -324,51 +310,37 @@ where
// NOT A COMPLETE LIST OF MEMORY EFFECTS // NOT A COMPLETE LIST OF MEMORY EFFECTS
match i64::from(sys_num) { match i64::from(sys_num) {
SYS_read | SYS_pread64 => { SYS_read | SYS_pread64 => {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(a1 as GuestAddr, a2 as usize); h.access(a1 as GuestAddr, a2 as usize);
} }
SYS_readlinkat => { SYS_readlinkat => {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(a2 as GuestAddr, a3 as usize); h.access(a2 as GuestAddr, a3 as usize);
} }
SYS_futex => { SYS_futex => {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(a0 as GuestAddr, a3 as usize); h.access(a0 as GuestAddr, a3 as usize);
} }
#[cfg(not(cpu_target = "arm"))] #[cfg(not(cpu_target = "arm"))]
SYS_newfstatat => { SYS_newfstatat => {
if a2 != 0 { if a2 != 0 {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(a2 as GuestAddr, 4096); // stat is not greater than a page h.access(a2 as GuestAddr, 4096); // stat is not greater than a page
} }
} }
#[cfg(cpu_target = "arm")] #[cfg(cpu_target = "arm")]
SYS_fstatat64 => { SYS_fstatat64 => {
if a2 != 0 { if a2 != 0 {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(a2 as GuestAddr, 4096); // stat is not greater than a page h.access(a2 as GuestAddr, 4096); // stat is not greater than a page
} }
} }
SYS_statfs | SYS_fstatfs | SYS_fstat => { SYS_statfs | SYS_fstatfs | SYS_fstat => {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(a1 as GuestAddr, 4096); // stat is not greater than a page h.access(a1 as GuestAddr, 4096); // stat is not greater than a page
} }
SYS_getrandom => { SYS_getrandom => {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(a0 as GuestAddr, a1 as usize); h.access(a0 as GuestAddr, a1 as usize);
} }
// mmap syscalls // mmap syscalls
@ -382,9 +354,7 @@ where
#[cfg(cpu_target = "arm")] #[cfg(cpu_target = "arm")]
if i64::from(sys_num) == SYS_mmap2 { if i64::from(sys_num) == SYS_mmap2 {
if let Ok(prot) = MmapPerms::try_from(a2 as i32) { if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.add_mapped(result as GuestAddr, a1 as usize, Some(prot)); h.add_mapped(result as GuestAddr, a1 as usize, Some(prot));
} }
} else if i64::from(sys_num) == SYS_mremap { } else if i64::from(sys_num) == SYS_mremap {
@ -394,9 +364,7 @@ where
h.add_mapped(result as GuestAddr, a2 as usize, None); h.add_mapped(result as GuestAddr, a2 as usize, None);
} else if i64::from(sys_num) == SYS_mprotect { } else if i64::from(sys_num) == SYS_mprotect {
if let Ok(prot) = MmapPerms::try_from(a2 as i32) { if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.add_mapped(a0 as GuestAddr, a2 as usize, Some(prot)); h.add_mapped(a0 as GuestAddr, a2 as usize, Some(prot));
} }
} }
@ -404,21 +372,15 @@ where
#[cfg(not(cpu_target = "arm"))] #[cfg(not(cpu_target = "arm"))]
if i64::from(sys_num) == SYS_mmap { if i64::from(sys_num) == SYS_mmap {
if let Ok(prot) = MmapPerms::try_from(a2 as i32) { if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.add_mapped(result as GuestAddr, a1 as usize, Some(prot)); h.add_mapped(result as GuestAddr, a1 as usize, Some(prot));
} }
} else if i64::from(sys_num) == SYS_mremap { } else if i64::from(sys_num) == SYS_mremap {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.add_mapped(result as GuestAddr, a2 as usize, None); h.add_mapped(result as GuestAddr, a2 as usize, None);
} else if i64::from(sys_num) == SYS_mprotect { } else if i64::from(sys_num) == SYS_mprotect {
if let Ok(prot) = MmapPerms::try_from(a2 as i32) { if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
let h = helpers let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.add_mapped(a0 as GuestAddr, a2 as usize, Some(prot)); h.add_mapped(a0 as GuestAddr, a2 as usize, Some(prot));
} }
} }

View File

@ -4,6 +4,8 @@ pub use strum_macros::EnumIter;
#[cfg(feature = "python")] #[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
use capstone::arch::BuildsCapstone;
pub use syscall_numbers::x86_64::*; pub use syscall_numbers::x86_64::*;
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)] #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
@ -43,3 +45,11 @@ impl IntoPy<PyObject> for Regs {
n.into_py(py) 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)
}

View File

@ -207,7 +207,7 @@ where
}; };
if self.use_cmplog.unwrap_or(false) { if self.use_cmplog.unwrap_or(false) {
let hooks = QemuHooks::new( let mut hooks = QemuHooks::new(
emulator, emulator,
tuple_list!( tuple_list!(
QemuEdgeCoverageHelper::default(), QemuEdgeCoverageHelper::default(),
@ -216,7 +216,7 @@ where
); );
let executor = QemuExecutor::new( let executor = QemuExecutor::new(
hooks, &mut hooks,
&mut harness, &mut harness,
tuple_list!(edges_observer, time_observer), tuple_list!(edges_observer, time_observer),
&mut fuzzer, &mut fuzzer,
@ -316,11 +316,11 @@ where
} }
} }
} else { } else {
let hooks = let mut hooks =
QemuHooks::new(emulator, tuple_list!(QemuEdgeCoverageHelper::default())); QemuHooks::new(emulator, tuple_list!(QemuEdgeCoverageHelper::default()));
let executor = QemuExecutor::new( let executor = QemuExecutor::new(
hooks, &mut hooks,
&mut harness, &mut harness,
tuple_list!(edges_observer, time_observer), tuple_list!(edges_observer, time_observer),
&mut fuzzer, &mut fuzzer,