diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index cb90ac6793..0f8e723c25 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -402,7 +402,7 @@ mod tests { use crate::executors::inmemory::InMemoryExecutor; use crate::executors::{Executor, ExitKind}; use crate::inputs::bytes::BytesInput; - use crate::mutators::scheduled::{mutation_bitflip, ComposedByMutations, StdScheduledMutator}; + use crate::mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator}; use crate::stages::mutational::StdMutationalStage; use crate::utils::StdRand; diff --git a/afl/src/events/mod.rs b/afl/src/events/mod.rs index 8df9f0a849..49b46fede9 100644 --- a/afl/src/events/mod.rs +++ b/afl/src/events/mod.rs @@ -8,7 +8,7 @@ pub mod shmem_translated; #[cfg(feature = "std")] pub use crate::events::llmp::LLMP; -//use core::any::TypeId; +use core::fmt::Formatter; #[cfg(feature = "std")] use std::io::Write; @@ -19,8 +19,43 @@ use crate::inputs::Input; use crate::utils::Rand; use crate::AflError; +pub enum EventDestination { + Main, + Broker, + Clients, +} + pub trait Event { - fn name(&self) -> &'static str; + fn name() -> &'static str; + + fn destination() -> EventDestination; + + fn log(&self, formatter: &mut Formatter, _state: &S) -> Result<(), AflError> + where + S: State, + C: Corpus, + E: Executor, + I: Input, + R: Rand, + { + match write!(formatter, "[{}]", Self::name()) { + Ok(_) => Ok(()), + Err(_) => Err(AflError::Unknown("write error".to_string())), + } + } + + fn on_recv(&self, _state: &mut S) -> Result<(), AflError> + where + S: State, + C: Corpus, + E: Executor, + I: Input, + R: Rand, + { + Ok(()) + } + + // TODO serialize and deserialize, defaults to serde } pub trait EventManager @@ -32,6 +67,7 @@ where R: Rand, { /// Check if this EventaManager support a given Event type + /// To compare events, use Event::name().as_ptr() fn enabled(&self) -> bool where T: Event; @@ -71,9 +107,13 @@ macro_rules! fire_event { pub struct LoadInitialEvent {} impl Event for LoadInitialEvent { - fn name(&self) -> &'static str { + fn name() -> &'static str { "LOAD" } + + fn destination() -> EventDestination { + EventDestination::Broker + } } impl LoadInitialEvent { pub fn new() -> Self { @@ -92,9 +132,13 @@ impl Event for NewTestcaseEvent where I: Input, { - fn name(&self) -> &'static str { + fn name() -> &'static str { "NEW" } + + fn destination() -> EventDestination { + EventDestination::Clients + } } impl NewTestcaseEvent @@ -112,9 +156,13 @@ where pub struct UpdateStatsEvent {} impl Event for UpdateStatsEvent { - fn name(&self) -> &'static str { + fn name() -> &'static str { "STATS" } + + fn destination() -> EventDestination { + EventDestination::Broker + } } impl UpdateStatsEvent { pub fn new() -> Self { @@ -122,6 +170,22 @@ impl UpdateStatsEvent { } } +pub struct CrashEvent {} +impl Event for CrashEvent { + fn name() -> &'static str { + "CRASH" + } + + fn destination() -> EventDestination { + EventDestination::Broker + } +} +impl CrashEvent { + pub fn new() -> Self { + CrashEvent {} + } +} + #[cfg(feature = "std")] pub struct LoggerEventManager where @@ -146,20 +210,13 @@ where T: Event, { true - /*let _load = TypeId::of::(); - let _new = TypeId::of::(); - match TypeId::of::() { - _load => true, - _new => true, - _ => false, - }*/ } - fn fire(&mut self, event: T) -> Result<(), AflError> + fn fire(&mut self, _event: T) -> Result<(), AflError> where T: Event, { - self.events.push(event.name().to_string()); + self.events.push(T::name().to_string()); Ok(()) } diff --git a/afl/src/mutators/mod.rs b/afl/src/mutators/mod.rs index 9067e7f8b0..2b32fc740a 100644 --- a/afl/src/mutators/mod.rs +++ b/afl/src/mutators/mod.rs @@ -1,8 +1,7 @@ pub mod scheduled; -pub use scheduled::ComposedByMutations; -pub use scheduled::HavocBytesMutator; -pub use scheduled::ScheduledMutator; -pub use scheduled::StdScheduledMutator; +pub use scheduled::*; +pub mod mutations; +pub use mutations::*; use crate::corpus::Corpus; use crate::inputs::Input; @@ -34,3 +33,10 @@ where Ok(()) } } + +pub const DEFAULT_MAX_SIZE: usize = 1048576; + +pub trait HasMaxSize { + fn max_size(&self) -> usize; + fn set_max_size(&mut self, max_size: usize); +} diff --git a/afl/src/mutators/mutations.rs b/afl/src/mutators/mutations.rs new file mode 100644 index 0000000000..4fb1dc1d87 --- /dev/null +++ b/afl/src/mutators/mutations.rs @@ -0,0 +1,260 @@ +use crate::inputs::{HasBytesVec, Input}; +use crate::mutators::Corpus; +use crate::mutators::*; +use crate::utils::Rand; +use crate::AflError; + +pub enum MutationResult { + Mutated, + Skipped, +} + +// TODO maybe the mutator arg is not needed +/// The generic function type that identifies mutations +pub type MutationFunction = + fn(&mut M, &mut R, &C, &mut I) -> Result; + +pub trait ComposedByMutations +where + C: Corpus, + I: Input, + R: Rand, +{ + /// Get a mutation by index + fn mutation_by_idx(&self, index: usize) -> MutationFunction; + + /// Get the number of mutations + fn mutations_count(&self) -> usize; + + /// Add a mutation + fn add_mutation(&mut self, mutation: MutationFunction); +} + +/// Bitflip mutation for inputs with a bytes vector +pub fn mutation_bitflip( + _mutator: &mut M, + rand: &mut R, + _corpus: &C, + input: &mut I, +) -> Result +where + M: Mutator, + C: Corpus, + I: Input + HasBytesVec, + R: Rand, +{ + if input.bytes().len() == 0 { + Ok(MutationResult::Skipped) + } else { + let bit = rand.below((input.bytes().len() << 3) as u64) as usize; + unsafe { + // moar speed, no bound check + *input.bytes_mut().get_unchecked_mut(bit >> 3) ^= (128 >> (bit & 7)) as u8; + } + Ok(MutationResult::Mutated) + } +} + +pub fn mutation_byteflip( + _mutator: &mut M, + rand: &mut R, + _corpus: &C, + input: &mut I, +) -> Result +where + M: Mutator, + C: Corpus, + I: Input + HasBytesVec, + R: Rand, +{ + if input.bytes().len() == 0 { + Ok(MutationResult::Skipped) + } else { + let idx = rand.below(input.bytes().len() as u64) as usize; + unsafe { + // moar speed, no bound check + *input.bytes_mut().get_unchecked_mut(idx) ^= 0xff; + } + Ok(MutationResult::Mutated) + } +} + +pub fn mutation_byteinc( + _mutator: &mut M, + rand: &mut R, + _corpus: &C, + input: &mut I, +) -> Result +where + M: Mutator, + C: Corpus, + I: Input + HasBytesVec, + R: Rand, +{ + if input.bytes().len() == 0 { + Ok(MutationResult::Skipped) + } else { + let idx = rand.below(input.bytes().len() as u64) as usize; + unsafe { + // moar speed, no bound check + *input.bytes_mut().get_unchecked_mut(idx) += 1; + } + Ok(MutationResult::Mutated) + } +} + +pub fn mutation_bytedec( + _mutator: &mut M, + rand: &mut R, + _corpus: &C, + input: &mut I, +) -> Result +where + M: Mutator, + C: Corpus, + I: Input + HasBytesVec, + R: Rand, +{ + if input.bytes().len() == 0 { + Ok(MutationResult::Skipped) + } else { + let idx = rand.below(input.bytes().len() as u64) as usize; + unsafe { + // moar speed, no bound check + *input.bytes_mut().get_unchecked_mut(idx) -= 1; + } + Ok(MutationResult::Mutated) + } +} + +pub fn mutation_byteneg( + _mutator: &mut M, + rand: &mut R, + _corpus: &C, + input: &mut I, +) -> Result +where + M: Mutator, + C: Corpus, + I: Input + HasBytesVec, + R: Rand, +{ + if input.bytes().len() == 0 { + Ok(MutationResult::Skipped) + } else { + let idx = rand.below(input.bytes().len() as u64) as usize; + unsafe { + // moar speed, no bound check + *input.bytes_mut().get_unchecked_mut(idx) = !(*input.bytes().get_unchecked(idx)); + } + Ok(MutationResult::Mutated) + } +} + +/* +pub fn mutation_bytesexpand( + mutator: &mut M, + rand: &mut R, + _corpus: &C, + input: &mut I, +) -> Result +where + M: Mutator + HasMaxSize, + C: Corpus, + I: Input + HasBytesVec, + R: Rand, +{ + let len = rand.below(mutator.max_size() as u64) as usize; + + + Ok(MutationResult::Mutated) +} +*/ + +pub fn mutation_bytesdelete( + _mutator: &mut M, + rand: &mut R, + _corpus: & C, + input: &mut I, +) -> Result +where + M: Mutator, + C: Corpus, + I: Input + HasBytesVec, + R: Rand, +{ + let size = input.bytes().len(); + if size <= 2 { + return Ok(MutationResult::Skipped); + } + + let off = rand.below(size as u64) as usize; + let len = rand.below((size - off) as u64) as usize; + input.bytes_mut().drain(off..len); + + Ok(MutationResult::Mutated) +} + +/// Returns the first and last diff position between the given vectors, stopping at the min len +fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { + let mut first_diff: i64 = -1; + let mut last_diff: i64 = -1; + for (i, (this_el, other_el)) in this.iter().zip(other.iter()).enumerate() { + if this_el != other_el { + if first_diff < 0 { + first_diff = i as i64; + } + last_diff = i as i64; + } + } + + (first_diff, last_diff) +} + +/// Splicing mutator +pub fn mutation_splice( + _mutator: &mut M, + rand: &mut R, + corpus: & C, + input: &mut I, +) -> Result +where + M: Mutator, + C: Corpus, + I: Input + HasBytesVec, + R: Rand, +{ + // We don't want to use the testcase we're already using for splicing + let (other_testcase, _) = corpus.random_entry(rand)?.clone(); + // TODO: Load let other = Testcase::load_from_disk(other_test)?; + // println!("Input: {:?}, other input: {:?}", input.bytes(), other.bytes()); + let other = match other_testcase.input() { + Some(i) => i, + None => return Ok(MutationResult::Skipped), //TODO + }; + + let mut counter = 0; + let (first_diff, last_diff) = loop { + let (f, l) = locate_diffs(input.bytes(), other.bytes()); + // println!("Diffs were between {} and {}", f, l); + if f != l && f >= 0 && l >= 2 { + break (f, l); + } + if counter == 3 { + return Ok(MutationResult::Skipped); + } + counter += 1; + }; + + let split_at = rand.between(first_diff as u64, last_diff as u64) as usize; + + // println!("Splicing at {}", split_at); + + input + .bytes_mut() + .splice(split_at.., other.bytes()[split_at..].iter().cloned()); + + // println!("Splice result: {:?}, input is now: {:?}", split_result, input.bytes()); + + Ok(MutationResult::Mutated) +} diff --git a/afl/src/mutators/scheduled.rs b/afl/src/mutators/scheduled.rs index 45a85f12d2..c9b296ab93 100644 --- a/afl/src/mutators/scheduled.rs +++ b/afl/src/mutators/scheduled.rs @@ -3,36 +3,10 @@ use core::marker::PhantomData; use crate::inputs::{HasBytesVec, Input}; use crate::mutators::Corpus; -use crate::mutators::Mutator; +use crate::mutators::*; use crate::utils::Rand; use crate::AflError; -pub enum MutationResult { - Mutated, - Skipped, -} - -// TODO maybe the mutator arg is not needed -/// The generic function type that identifies mutations -type MutationFunction = - fn(&mut M, &mut R, &C, &mut I) -> Result; - -pub trait ComposedByMutations -where - C: Corpus, - I: Input, - R: Rand, -{ - /// Get a mutation by index - fn mutation_by_idx(&self, index: usize) -> MutationFunction; - - /// Get the number of mutations - fn mutations_count(&self) -> usize; - - /// Add a mutation - fn add_mutation(&mut self, mutation: MutationFunction); -} - pub trait ScheduledMutator: Mutator + ComposedByMutations where C: Corpus, @@ -85,6 +59,7 @@ where R: Rand, { mutations: Vec>, + max_size: usize, } impl Mutator for StdScheduledMutator @@ -132,6 +107,20 @@ where // Just use the default methods } +impl HasMaxSize for StdScheduledMutator +where + C: Corpus, + I: Input, + R: Rand, +{ + fn max_size(&self) -> usize { + self.max_size + } + fn set_max_size(&mut self, max_size: usize) { + self.max_size = max_size; + } +} + impl StdScheduledMutator where C: Corpus, @@ -140,203 +129,21 @@ where { /// Create a new StdScheduledMutator instance without mutations and corpus pub fn new() -> Self { - StdScheduledMutator { mutations: vec![] } + StdScheduledMutator { + mutations: vec![], + max_size: DEFAULT_MAX_SIZE, + } } /// Create a new StdScheduledMutator instance specifying mutations pub fn with_mutations(mutations: Vec>) -> Self { StdScheduledMutator { mutations: mutations, + max_size: DEFAULT_MAX_SIZE, } } } -/// Bitflip mutation for inputs with a bytes vector -pub fn mutation_bitflip( - _mutator: &mut M, - rand: &mut R, - _corpus: &C, - input: &mut I, -) -> Result -where - M: Mutator, - C: Corpus, - I: Input + HasBytesVec, - R: Rand, -{ - if input.bytes().len() == 0 { - Ok(MutationResult::Skipped) - } else { - let bit = rand.below((input.bytes().len() << 3) as u64) as usize; - unsafe { - // moar speed, no bound check - *input.bytes_mut().get_unchecked_mut(bit >> 3) ^= (128 >> (bit & 7)) as u8; - } - Ok(MutationResult::Mutated) - } -} - -pub fn mutation_byteflip( - _mutator: &mut M, - rand: &mut R, - _corpus: &C, - input: &mut I, -) -> Result -where - M: Mutator, - C: Corpus, - I: Input + HasBytesVec, - R: Rand, -{ - if input.bytes().len() == 0 { - Ok(MutationResult::Skipped) - } else { - let idx = rand.below(input.bytes().len() as u64) as usize; - unsafe { - // moar speed, no bound check - *input.bytes_mut().get_unchecked_mut(idx) ^= 0xff; - } - Ok(MutationResult::Mutated) - } -} - -pub fn mutation_byteinc( - _mutator: &mut M, - rand: &mut R, - _corpus: &C, - input: &mut I, -) -> Result -where - M: Mutator, - C: Corpus, - I: Input + HasBytesVec, - R: Rand, -{ - if input.bytes().len() == 0 { - Ok(MutationResult::Skipped) - } else { - let idx = rand.below(input.bytes().len() as u64) as usize; - unsafe { - // moar speed, no bound check - *input.bytes_mut().get_unchecked_mut(idx) += 1; - } - Ok(MutationResult::Mutated) - } -} - -pub fn mutation_bytedec( - _mutator: &mut M, - rand: &mut R, - _corpus: &C, - input: &mut I, -) -> Result -where - M: Mutator, - C: Corpus, - I: Input + HasBytesVec, - R: Rand, -{ - if input.bytes().len() == 0 { - Ok(MutationResult::Skipped) - } else { - let idx = rand.below(input.bytes().len() as u64) as usize; - unsafe { - // moar speed, no bound check - *input.bytes_mut().get_unchecked_mut(idx) -= 1; - } - Ok(MutationResult::Mutated) - } -} - -pub fn mutation_byteneg( - _mutator: &mut M, - rand: &mut R, - _corpus: &C, - input: &mut I, -) -> Result -where - M: Mutator, - C: Corpus, - I: Input + HasBytesVec, - R: Rand, -{ - if input.bytes().len() == 0 { - Ok(MutationResult::Skipped) - } else { - let idx = rand.below(input.bytes().len() as u64) as usize; - unsafe { - // moar speed, no bound check - *input.bytes_mut().get_unchecked_mut(idx) = !(*input.bytes().get_unchecked(idx)); - } - Ok(MutationResult::Mutated) - } -} - -/// Returns the first and last diff position between the given vectors, stopping at the min len -fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { - let mut first_diff: i64 = -1; - let mut last_diff: i64 = -1; - for (i, (this_el, other_el)) in this.iter().zip(other.iter()).enumerate() { - if this_el != other_el { - if first_diff < 0 { - first_diff = i as i64; - } - last_diff = i as i64; - } - } - - (first_diff, last_diff) -} - -/// Splicing mutator -pub fn mutation_splice( - _mutator: &mut M, - rand: &mut R, - corpus: &C, - input: &mut I, -) -> Result -where - M: Mutator, - C: Corpus, - I: Input + HasBytesVec, - R: Rand, -{ - // TODO: Don't reuse the current testcase! - // (We don't want to use the testcase we're already using for splicing) - let (other_testcase, _) = corpus.random_entry(rand)?; - // TODO: let other = other_testcase.load_input()?; - // println!("Input: {:?}, other input: {:?}", input.bytes(), other.bytes()); - let other = match other_testcase.input() { - Some(i) => i, - None => return Ok(MutationResult::Skipped), // TODO!! - }; - - let mut counter = 0; - let (first_diff, last_diff) = loop { - let (f, l) = locate_diffs(input.bytes(), other.bytes()); - // println!("Diffs were between {} and {}", f, l); - if f != l && f >= 0 && l >= 2 { - break (f, l); - } - if counter == 3 { - return Ok(MutationResult::Skipped); - } - counter += 1; - }; - - let split_at = rand.between(first_diff as u64, last_diff as u64) as usize; - - // println!("Splicing at {}", split_at); - - input - .bytes_mut() - .splice(split_at.., other.bytes()[split_at..].iter().cloned()); - - // println!("Splice result: {:?}, input is now: {:?}", split_result, input.bytes()); - - Ok(MutationResult::Mutated) -} - /// Schedule some selected byte level mutations given a ScheduledMutator type pub struct HavocBytesMutator where @@ -401,11 +208,12 @@ where scheduled.add_mutation(mutation_bytedec); scheduled.add_mutation(mutation_byteneg); - scheduled.add_mutation(mutation_bitflip); - scheduled.add_mutation(mutation_bitflip); - scheduled.add_mutation(mutation_bitflip); - scheduled.add_mutation(mutation_bitflip); - scheduled.add_mutation(mutation_bitflip); + //scheduled.add_mutation(mutation_bytesexpand); + scheduled.add_mutation(mutation_bytesdelete); + scheduled.add_mutation(mutation_bytesdelete); + scheduled.add_mutation(mutation_bytesdelete); + scheduled.add_mutation(mutation_bytesdelete); + scheduled.add_mutation(mutation_bitflip); scheduled.add_mutation(mutation_bitflip); scheduled.add_mutation(mutation_bitflip);