diff --git a/.gitignore b/.gitignore index 96ef6c0b94..aaacb75743 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target Cargo.lock + +.vscode \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 618ab432cd..486e4da11e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +xxhrs = { version = "2.0.0", features = [] } #"random_entropy"] } diff --git a/src/engines/engine.rs b/src/engines/aflengine.rs similarity index 50% rename from src/engines/engine.rs rename to src/engines/aflengine.rs index c12814c011..f035008e98 100644 --- a/src/engines/engine.rs +++ b/src/engines/aflengine.rs @@ -1,16 +1,16 @@ use std::time; -pub trait RandState {} -pub trait Executor {} -pub trait Feedback {} -pub trait Stage {} +use crate::utils::Rand; +use crate::feedbacks::Feedback; +use crate::stages::Stage; +use crate::executors::Executor; +use crate::engines::Engine; +use crate::monitors::Monitor; -pub trait Monitor {} +pub struct AflEngine { -pub struct DefaultEngine { - - pub rand: Box, - pub feedback: Vec>, + //pub rand: Box, + //pub feedback: Vec>, pub stages: Vec>, pub current_stage: Box, @@ -25,4 +25,8 @@ pub struct DefaultEngine { // TODO: Map pub monitors: Vec>, +} + +impl Engine for AflEngine { + } \ No newline at end of file diff --git a/src/engines/mod.rs b/src/engines/mod.rs index a2ed982457..be929fe9b2 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -1,4 +1,4 @@ -pub mod engine; +pub mod aflengine; pub trait Engine { diff --git a/src/engines/monitor.rs b/src/engines/monitor.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/executors/mod.rs b/src/executors/mod.rs new file mode 100644 index 0000000000..0605ed68d8 --- /dev/null +++ b/src/executors/mod.rs @@ -0,0 +1,2 @@ + +pub trait Executor {} \ No newline at end of file diff --git a/src/feedbacks/mod.rs b/src/feedbacks/mod.rs new file mode 100644 index 0000000000..8bbb8bfd44 --- /dev/null +++ b/src/feedbacks/mod.rs @@ -0,0 +1 @@ +pub trait Feedback {} diff --git a/src/inputs/bytes.rs b/src/inputs/bytes.rs index eba6fd8048..6bdd19456e 100644 --- a/src/inputs/bytes.rs +++ b/src/inputs/bytes.rs @@ -2,7 +2,7 @@ use crate::inputs::Input; use std::io::Error; -#[derive(Debug)] +#[derive(Clone, Debug, Default)] pub struct BytesInput { bytes: Vec, } diff --git a/src/lib.rs b/src/lib.rs index 105655b79d..11e96aff18 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,11 @@ pub mod engines; +pub mod executors; +pub mod feedbacks; pub mod inputs; +pub mod monitors; +pub mod mutators; +pub mod stages; +pub mod utils; #[cfg(test)] mod tests { diff --git a/src/main.rs b/src/main.rs index 7da3a48059..e50d703d48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,11 @@ +pub mod engines; +pub mod executors; +pub mod feedbacks; +pub mod inputs; +pub mod monitors; +pub mod mutators; +pub mod stages; +pub mod utils; fn main() { println!("Hello, world!"); diff --git a/src/monitors/mod.rs b/src/monitors/mod.rs new file mode 100644 index 0000000000..ddf1ee9a52 --- /dev/null +++ b/src/monitors/mod.rs @@ -0,0 +1 @@ +pub trait Monitor {} diff --git a/src/mutators/mod.rs b/src/mutators/mod.rs new file mode 100644 index 0000000000..8650b9904f --- /dev/null +++ b/src/mutators/mod.rs @@ -0,0 +1,24 @@ +use std::io::Error; +use crate::inputs::Input; +use crate::utils::Rand; + +pub mod scheduled; + +pub trait Mutator { + + //fn rand(&self) -> &Box; + //fn rand_mut(&self) -> &mut Box; + + fn mutate(&mut self, input: &mut dyn Input) -> Result<(), Error> { + self.mutate_at((-1) as i32, input) + } + + fn mutate_at(&mut self, stage_idx: i32, input: &mut dyn Input) -> Result<(), Error>; + + fn post_exec(&mut self, is_interesting: bool) -> Result<(), Error> { + self.post_exec_at((-1) as i32, is_interesting) + } + + fn post_exec_at(&mut self, stage_idx: i32, is_interesting: bool) -> Result<(), Error>; + +} \ No newline at end of file diff --git a/src/mutators/scheduled.rs b/src/mutators/scheduled.rs new file mode 100644 index 0000000000..0f7d7ed452 --- /dev/null +++ b/src/mutators/scheduled.rs @@ -0,0 +1,12 @@ +use crate::mutators::Mutator; + +pub trait ScheduledMutator: Mutator { + + fn iterations(&self) -> u64 { + + //1 << (1 + self.rand_mut().below(7)) + return 0; + + } + +} \ No newline at end of file diff --git a/src/stages/mod.rs b/src/stages/mod.rs new file mode 100644 index 0000000000..5e219a7374 --- /dev/null +++ b/src/stages/mod.rs @@ -0,0 +1,2 @@ +//! Stages +pub trait Stage {} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000000..8f754e66f0 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,129 @@ +//! Utility functions for AFL + +use std::debug_assert; +use xxhrs::{XXH3_64}; + +/// Ways to get random around here +pub trait Rand { + + // Returns a new, randomly seeded, rand + fn new() -> Self; + // Sets the seed of this Rand + fn set_seed(&mut self, seed: u64); + // Gets the next 64 bit value + fn next(&mut self) -> u64; + // Gets a value below the given 64 bit val (inclusive) + fn below(&mut self, upper_bound_excl: u64) -> u64 { + if upper_bound_excl <= 1 { + return 0; + } + + /* + Modulo is biased - we don't want our fuzzing to be biased so let's do it + right. See + https://stackoverflow.com/questions/10984974/why-do-people-say-there-is-modulo-bias-when-using-a-random-number-generator + */ + let mut unbiased_rnd: u64; + loop { + unbiased_rnd = self.next(); + if unbiased_rnd < (u64::MAX - (u64::MAX % upper_bound_excl)) { + break; + } + } + + unbiased_rnd % upper_bound_excl + + } + + // Gets a value between the given lower bound (inclusive) and upper bound (inclusive) + fn between(&mut self, lower_bound_incl: u64, upper_bound_incl: u64) -> u64 { + debug_assert!(lower_bound_incl < upper_bound_incl); + lower_bound_incl + self.below(upper_bound_incl - lower_bound_incl + 1) + } + +} + +const HASH_CONST: u64 = 0xa5b35705; + +/// XXH3 Based, hopefully speedy, rnd implementation +/// +#[derive(Copy, Clone, Debug, Default)] +struct AflRand { + + + rand_seed: [u64; 4], + seeded: bool, + +} + +impl Rand for AflRand { + + fn new() -> AflRand { + + let mut ret: AflRand = Default::default(); + ret.set_seed(0); // TODO: Proper random seed? + ret + } + + fn set_seed(&mut self, seed: u64) { + self.rand_seed[0] = XXH3_64::hash_with_seed(HASH_CONST, &seed.to_le_bytes()); + self.rand_seed[1] = self.rand_seed[0] ^ 0x1234567890abcdef; + self.rand_seed[2] = self.rand_seed[0] & 0x0123456789abcdef; + self.rand_seed[3] = self.rand_seed[0] | 0x01abcde43f567908; + + self.seeded = true; + } + + fn next(&mut self) -> u64 { + + let ret: u64 = self.rand_seed[0].wrapping_add(self.rand_seed[3]).rotate_left(23).wrapping_add(self.rand_seed[0]); + let t: u64 = self.rand_seed[1] << 17; + + self.rand_seed[2] ^= self.rand_seed[0]; + self.rand_seed[3] ^= self.rand_seed[1]; + self.rand_seed[1] ^= self.rand_seed[2]; + self.rand_seed[0] ^= self.rand_seed[3]; + + self.rand_seed[2] ^= t; + + self.rand_seed[3] = self.rand_seed[3].rotate_left(45); + + return ret; + + } + +} + +/// Get the next higher power of two +fn next_pow2(val: u64) -> u64 { + // Early exit so we don't have to do a wrapping subtract; + if val <= 2 { + return val; + } + let mut out: u64 = val - 1; + out |= out >> 1; + out |= out >> 2; + out |= out >> 4; + out |= out >> 8; + out |= out >> 16; + return out + 1; +} + +#[cfg(test)] +mod tests { + use crate::utils::{AflRand, next_pow2}; + + #[test] + fn test_rand() { + //let rand: AflRand = AflRand::new(); + } + + #[test] + fn test_next_pow2() { + assert_eq!(next_pow2(0), 0); + assert_eq!(next_pow2(1), 1); + assert_eq!(next_pow2(2), 2); + assert_eq!(next_pow2(3), 4); + assert_eq!(next_pow2(1000), 1024); + } +}