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
|
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,
|
||||||
|
@ -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,
|
||||||
|
@ -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).
|
||||||
|
@ -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")]
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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 }
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
@ -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
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 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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
@ -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)
|
||||||
|
}
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user