131 lines
4.8 KiB
Rust
131 lines
4.8 KiB
Rust
use std::path::PathBuf;
|
|
#[cfg(windows)]
|
|
use std::ptr::write_volatile;
|
|
|
|
#[cfg(feature = "tui")]
|
|
use libafl::monitors::tui::TuiMonitor;
|
|
#[cfg(not(feature = "tui"))]
|
|
use libafl::monitors::SimpleMonitor;
|
|
use libafl::{
|
|
bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
|
|
corpus::{InMemoryCorpus, OnDiskCorpus},
|
|
events::SimpleEventManager,
|
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
|
feedbacks::{CrashFeedback, MaxMapFeedback},
|
|
fuzzer::{Fuzzer, StdFuzzer},
|
|
generators::RandPrintablesGenerator,
|
|
inputs::{BytesInput, HasTargetBytes},
|
|
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
|
observers::StdMapObserver,
|
|
schedulers::QueueScheduler,
|
|
stages::mutational::StdMutationalStage,
|
|
state::StdState,
|
|
};
|
|
|
|
/// Coverage map with explicit assignments due to the lack of instrumentation
|
|
static mut SIGNALS: [u8; 16] = [0; 16];
|
|
|
|
/// Assign a signal to the signals map
|
|
fn signals_set(idx: usize) {
|
|
unsafe { SIGNALS[idx] = 1 };
|
|
}
|
|
|
|
#[allow(clippy::similar_names)]
|
|
pub fn main() {
|
|
// The closure that we want to fuzz
|
|
let mut harness = |input: &BytesInput| {
|
|
let target = input.target_bytes();
|
|
let buf = target.as_slice();
|
|
signals_set(0);
|
|
if !buf.is_empty() && buf[0] == b'a' {
|
|
signals_set(1);
|
|
if buf.len() > 1 && buf[1] == b'b' {
|
|
signals_set(2);
|
|
if buf.len() > 2 && buf[2] == b'c' {
|
|
#[cfg(unix)]
|
|
panic!("Artificial bug triggered =)");
|
|
|
|
// panic!() raises a STATUS_STACK_BUFFER_OVERRUN exception which cannot be caught by the exception handler.
|
|
// Here we make it raise STATUS_ACCESS_VIOLATION instead.
|
|
// Extending the windows exception handler is a TODO. Maybe we can refer to what winafl code does.
|
|
// https://github.com/googleprojectzero/winafl/blob/ea5f6b85572980bb2cf636910f622f36906940aa/winafl.c#L728
|
|
#[cfg(windows)]
|
|
unsafe {
|
|
write_volatile(0 as *mut u32, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ExitKind::Ok
|
|
};
|
|
|
|
// Create an observation channel using the signals map
|
|
let observer =
|
|
unsafe { StdMapObserver::new_from_ptr("signals", SIGNALS.as_mut_ptr(), SIGNALS.len()) };
|
|
|
|
// Feedback to rate the interestingness of an input
|
|
let mut feedback = MaxMapFeedback::new(&observer);
|
|
|
|
// A feedback to choose if an input is a solution or not
|
|
let mut objective = CrashFeedback::new();
|
|
|
|
// create a State from scratch
|
|
let mut state = StdState::new(
|
|
// RNG
|
|
StdRand::with_seed(current_nanos()),
|
|
// Corpus that will be evolved, we keep it in memory for performance
|
|
InMemoryCorpus::new(),
|
|
// Corpus in which we store solutions (crashes in this example),
|
|
// on disk so the user can get them after stopping the fuzzer
|
|
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
|
|
// States of the feedbacks.
|
|
// The feedbacks can report the data that should persist in the State.
|
|
&mut feedback,
|
|
// Same for objective feedbacks
|
|
&mut objective,
|
|
)
|
|
.unwrap();
|
|
|
|
// The Monitor trait define how the fuzzer stats are displayed to the user
|
|
#[cfg(not(feature = "tui"))]
|
|
let mon = SimpleMonitor::new(|s| println!("{}", s));
|
|
#[cfg(feature = "tui")]
|
|
let mon = TuiMonitor::new(String::from("Baby Fuzzer"), false);
|
|
|
|
// The event manager handle the various events generated during the fuzzing loop
|
|
// such as the notification of the addition of a new item to the corpus
|
|
let mut mgr = SimpleEventManager::new(mon);
|
|
|
|
// A queue policy to get testcasess from the corpus
|
|
let scheduler = QueueScheduler::new();
|
|
|
|
// A fuzzer with feedbacks and a corpus scheduler
|
|
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
|
|
|
// Create the executor for an in-process function with just one observer
|
|
let mut executor = InProcessExecutor::new(
|
|
&mut harness,
|
|
tuple_list!(observer),
|
|
&mut fuzzer,
|
|
&mut state,
|
|
&mut mgr,
|
|
)
|
|
.expect("Failed to create the Executor");
|
|
|
|
// Generator of printable bytearrays of max size 32
|
|
let mut generator = RandPrintablesGenerator::new(32);
|
|
|
|
// Generate 8 initial inputs
|
|
state
|
|
.generate_initial_inputs(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 8)
|
|
.expect("Failed to generate the initial corpus");
|
|
|
|
// Setup a mutational stage with a basic bytes mutator
|
|
let mutator = StdScheduledMutator::new(havoc_mutations());
|
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
|
|
|
fuzzer
|
|
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
|
|
.expect("Error in the fuzzing loop");
|
|
}
|