diff options
author | Andrea Fioraldi <andreafioraldi@gmail.com> | 2022-01-26 21:45:30 +0100 |
---|---|---|
committer | Andrea Fioraldi <andreafioraldi@gmail.com> | 2022-01-26 21:45:30 +0100 |
commit | aa5f59b50196360e4d68178064120100c8ece4dd (patch) | |
tree | 2001b9dbbf3bfb08bc0f81a10b02a4d7c22f02a9 | |
parent | 08c39c15522fc1765ab6fcff03a02bb5f9d4f230 (diff) | |
download | afl++-aa5f59b50196360e4d68178064120100c8ece4dd.tar.gz |
libafl_base custom mutator
-rw-r--r-- | custom_mutators/libafl_base/.gitignore | 10 | ||||
-rw-r--r-- | custom_mutators/libafl_base/Cargo.toml | 14 | ||||
-rw-r--r-- | custom_mutators/libafl_base/Makefile | 9 | ||||
-rw-r--r-- | custom_mutators/libafl_base/src/lib.rs | 238 | ||||
-rw-r--r-- | custom_mutators/rust/custom_mutator/src/lib.rs | 4 |
5 files changed, 273 insertions, 2 deletions
diff --git a/custom_mutators/libafl_base/.gitignore b/custom_mutators/libafl_base/.gitignore new file mode 100644 index 00000000..088ba6ba --- /dev/null +++ b/custom_mutators/libafl_base/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/custom_mutators/libafl_base/Cargo.toml b/custom_mutators/libafl_base/Cargo.toml new file mode 100644 index 00000000..6e40fc39 --- /dev/null +++ b/custom_mutators/libafl_base/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "libafl_base" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "62614ce1016c86e3f00f35b56399292ceabd486b" } +custom_mutator = { path = "../rust/custom_mutator", features = ["afl_internals"] } +serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib + +[lib] +crate-type = ["cdylib"] diff --git a/custom_mutators/libafl_base/Makefile b/custom_mutators/libafl_base/Makefile new file mode 100644 index 00000000..a1fd6b6c --- /dev/null +++ b/custom_mutators/libafl_base/Makefile @@ -0,0 +1,9 @@ +all: target/release/liblibafl_base.so + cp target/release/liblibafl_base.so libafl_base.so + +target/release/liblibafl_base.so: src/lib.rs + cargo build --release + +clean: + cargo clean + rm -f libafl_base.so diff --git a/custom_mutators/libafl_base/src/lib.rs b/custom_mutators/libafl_base/src/lib.rs new file mode 100644 index 00000000..6f2db8ca --- /dev/null +++ b/custom_mutators/libafl_base/src/lib.rs @@ -0,0 +1,238 @@ +#![cfg(unix)] +#![allow(unused_variables)] + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::{ + cell::{RefCell, UnsafeCell}, + collections::HashMap, + ffi::CStr, +}; + +use custom_mutator::{afl_state, export_mutator, CustomMutator}; + +use libafl::{ + bolts::{rands::StdRand, serdeany::SerdeAnyMap, tuples::Merge}, + corpus::{Corpus, Testcase}, + inputs::{BytesInput, HasBytesVec}, + mutators::{ + scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens}, + Mutator, + }, + state::{HasCorpus, HasMaxSize, HasMetadata, HasRand, State}, + Error, +}; + +const MAX_FILE: usize = 1 * 1024 * 1024; + +static mut AFL: Option<&'static afl_state> = None; +static mut CURRENT_ENTRY: Option<usize> = None; + +fn afl() -> &'static afl_state { + unsafe { AFL.unwrap() } +} + +#[derive(Default, Debug)] +pub struct AFLCorpus { + entries: UnsafeCell<HashMap<usize, RefCell<Testcase<BytesInput>>>>, +} + +impl Clone for AFLCorpus { + fn clone(&self) -> Self { + unsafe { + Self { + entries: UnsafeCell::new(self.entries.get().as_ref().unwrap().clone()), + } + } + } +} + +impl Serialize for AFLCorpus { + fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + unimplemented!(); + } +} + +impl<'de> Deserialize<'de> for AFLCorpus { + fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + unimplemented!(); + } +} + +impl Corpus<BytesInput> for AFLCorpus { + #[inline] + fn count(&self) -> usize { + afl().queued_items as usize + } + + #[inline] + fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<usize, Error> { + unimplemented!(); + } + + #[inline] + fn replace(&mut self, idx: usize, testcase: Testcase<BytesInput>) -> Result<(), Error> { + unimplemented!(); + } + + #[inline] + fn remove(&mut self, idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> { + unimplemented!(); + } + + #[inline] + fn get(&self, idx: usize) -> Result<&RefCell<Testcase<BytesInput>>, Error> { + unsafe { + let entries = self.entries.get().as_mut().unwrap(); + entries.entry(idx).or_insert_with(|| { + let queue_buf = std::slice::from_raw_parts_mut(afl().queue_buf, self.count()); + let entry = queue_buf[idx].as_mut().unwrap(); + let fname = CStr::from_ptr((entry.fname as *mut i8).as_ref().unwrap()) + .to_str() + .unwrap() + .to_owned(); + let mut testcase = Testcase::with_filename(BytesInput::new(vec![]), fname); + *testcase.input_mut() = None; + RefCell::new(testcase) + }); + Ok(&self.entries.get().as_ref().unwrap()[&idx]) + } + } + + #[inline] + fn current(&self) -> &Option<usize> { + unsafe { + CURRENT_ENTRY = Some(afl().current_entry as usize); + &CURRENT_ENTRY + } + } + + #[inline] + fn current_mut(&mut self) -> &mut Option<usize> { + unimplemented!(); + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct AFLState { + rand: StdRand, + corpus: AFLCorpus, + metadata: SerdeAnyMap, + max_size: usize, +} + +impl AFLState { + pub fn new(seed: u32) -> Self { + Self { + rand: StdRand::with_seed(seed as u64), + corpus: AFLCorpus::default(), + metadata: SerdeAnyMap::new(), + max_size: MAX_FILE, + } + } +} + +impl State for AFLState {} + +impl HasRand for AFLState { + type Rand = StdRand; + + #[inline] + fn rand(&self) -> &Self::Rand { + &self.rand + } + + #[inline] + fn rand_mut(&mut self) -> &mut Self::Rand { + &mut self.rand + } +} + +impl HasCorpus<BytesInput> for AFLState { + type Corpus = AFLCorpus; + + #[inline] + fn corpus(&self) -> &Self::Corpus { + &self.corpus + } + + #[inline] + fn corpus_mut(&mut self) -> &mut Self::Corpus { + &mut self.corpus + } +} + +impl HasMetadata for AFLState { + #[inline] + fn metadata(&self) -> &SerdeAnyMap { + &self.metadata + } + + #[inline] + fn metadata_mut(&mut self) -> &mut SerdeAnyMap { + &mut self.metadata + } +} + +impl HasMaxSize for AFLState { + fn max_size(&self) -> usize { + self.max_size + } + + fn set_max_size(&mut self, max_size: usize) { + self.max_size = max_size; + } +} + +struct LibAFLBaseCustomMutator { + state: AFLState, + input: BytesInput, +} + +impl CustomMutator for LibAFLBaseCustomMutator { + type Error = libafl::Error; + + fn init(afl: &'static afl_state, seed: u32) -> Result<Self, Self::Error> { + unsafe { + AFL = Some(afl); + let mut state = AFLState::new(seed); + let extras = std::slice::from_raw_parts(afl.extras, afl.extras_cnt as usize); + let mut tokens = vec![]; + for extra in extras { + let data = std::slice::from_raw_parts(extra.data, extra.len as usize); + tokens.push(data.to_vec()); + } + if !tokens.is_empty() { + state.add_metadata(Tokens::new(tokens)); + } + Ok(Self { + state, + input: BytesInput::new(vec![]), + }) + } + } + + fn fuzz<'b, 's: 'b>( + &'s mut self, + buffer: &'b mut [u8], + add_buff: Option<&[u8]>, + max_size: usize, + ) -> Result<Option<&'b [u8]>, Self::Error> { + self.state.set_max_size(max_size); + + // TODO avoid copy + self.input.bytes_mut().clear(); + self.input.bytes_mut().extend_from_slice(buffer); + + let mut mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); + mutator.mutate(&mut self.state, &mut self.input, 0)?; + Ok(Some(self.input.bytes())) + } +} + +export_mutator!(LibAFLBaseCustomMutator); diff --git a/custom_mutators/rust/custom_mutator/src/lib.rs b/custom_mutators/rust/custom_mutator/src/lib.rs index 83ecbd9a..f872241e 100644 --- a/custom_mutators/rust/custom_mutator/src/lib.rs +++ b/custom_mutators/rust/custom_mutator/src/lib.rs @@ -370,7 +370,7 @@ macro_rules! _define_afl_custom_init { ) -> *const ::std::os::raw::c_void { $crate::wrappers::afl_custom_init_::<$mutator_type>(afl, seed as u32) } - } + }; } /// An exported macro to defined afl_custom_init meant for insternal usage @@ -385,7 +385,7 @@ macro_rules! _define_afl_custom_init { ) -> *const ::std::os::raw::c_void { $crate::wrappers::afl_custom_init_::<$mutator_type>(seed as u32) } - } + }; } /// exports the given Mutator as a custom mutator as the C interface that AFL++ expects. |