diff --git a/README.md b/README.md index 523d388e81..cc16b5da95 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,12 @@ LibAFL is written and maintained by Andrea Fioraldi a LibAFL gives you many of the benefits of an off-the-shelf fuzzer, while being completely customizable. Some highlight features currently include: -- `multi platform`: LibAFL was confirmed to work on *Windows*, *MacOS*, *Linux*, and *Android* on *x86_64* and *aarch64*. -- `portable`: `LibAFL` can be built in `no_std` mode. Inject LibAFL in obscure targets like embedded devices and hypervisors. +- `fast`: We do everything we can at compile time, keeping runtime overhead minimal. Users reach 120k execs/sec in frida-mode on a phone (using all cores). +- `scalable`: `Low Level Message Passing`, `LLMP` for short, allows LibAFL to scale almost linearly over cores, and via TCP to multiple machines soon! - `adaptable`: You can replace each part of LibAFL. For example, `BytesInput` is just one potential form input: feel free to add an AST-based input for structured fuzzing, and more. -- `scalable`: `Low Level Message Passing`, `LLMP` for short, allows LibAFL to scale almost linearly over cores, and via TCP to multiple machines! -- `fast`: We do everything we can at compile time, keeping runtime overhead minimal. +- `multi platform`: LibAFL was confirmed to work on *Windows*, *MacOS*, *Linux*, and *Android* on *x86_64* and *aarch64*. `LibAFL` can be built in `no_std` mode to inject LibAFL into obscure targets like embedded devices and hypervisors. - `bring your own target`: We support binary-only modes, like Frida-Mode, as well as multiple compilation passes for sourced-based instrumentation. Of course it's easy to add custom instrumentation backends. -- `usable`: We hope. But we'll let you be the judge. Enjoy LibAFL. ## Overview @@ -26,26 +24,25 @@ It is fast, multi-platform, no_std compatible, and scales over cores and machine It offers a main crate that provide building blocks for custom fuzzers, [libafl](./libafl), a library containing common code that can be used for targets instrumentation, [libafl_targets](./libafl_targets), and a library providing facilities to wrap compilers, [libafl_cc](./libafl_cc). -LibAFL offers integrations with popular instrumemntation frameworks. At the moment, the supported backends are: +LibAFL offers integrations with popular instrumentation frameworks. At the moment, the supported backends are: + SanitizerCoverage, in [libafl_targets](./libafl_targets) + Frida, in [libafl_frida](./libafl_frida), by s1341 (Windows support is broken atm, it relies on [this upstream issue](https://github.com/meme/frida-rust/issues/9) to be fixed.) + More to come (QEMU-mode, ...) -LibAFL offers integrations with popular instrumemntation frameworks too. At the moment, the supported backends are: - -+ SanitizerCoverage, in [libafl_targets](./libafl_targets) -+ Frida, in [libafl_frida](./libafl_frida), by s1341 (Windows support will be added soon) - ## Getting started -Clone the LibAFL repository with +1. Install the Rust development language. We highly recommend *not* to use e.g. +your Linux distribution package as this is likely outdated. So rather install +Rust directly, instructions can be found [here](https://www.rust-lang.org/tools/install). + +2. Clone the LibAFL repository with ``` git clone https://github.com/AFLplusplus/LibAFL ``` -To get the latest and greatest features, +If you want to get the latest and greatest features, ``` git checkout dev ``` @@ -56,18 +53,19 @@ Build the library using cargo build --release ``` -Build the API documentation with +4. Build the API documentation with ``` cargo doc ``` -Browse the LibAFL book (WIP!) with (requires [mdbook](https://github.com/rust-lang/mdBook)) +5. Browse the LibAFL book (WIP!) with (requires [mdbook](https://github.com/rust-lang/mdBook)) ``` cd docs && mdbook serve ``` + We collect all example fuzzers in [`./fuzzers`](./fuzzers/). Be sure to read their documentation (and source), this is *the natural way to get started!* diff --git a/docs/src/design/architecture.md b/docs/src/design/architecture.md index b600ebdc75..321a612a1b 100644 --- a/docs/src/design/architecture.md +++ b/docs/src/design/architecture.md @@ -2,7 +2,7 @@ The LibAFL architecture is built around some entities to allow code reuse and low-cost abstractions. -Initially, we started thinking to implement LibAFL in an Object Oriented language, such C++. When we landed to Rust, we immediately changed our idea as we realized that, while Rust allow a sort of OOP pattern, we can build the library using a more sane approach like the one described in [this blogpost](https://kyren.github.io/2018/09/14/rustconf-talk.html) about game design in Rust. +Initially, we started thinking to implement LibAFL in an Object Oriented language, such C++. When we landed to Rust, we immediately changed our idea as we realized that, while Rust allows a sort of OOP pattern, we can build the library using a more sane approach like the one described in [this blogpost](https://kyren.github.io/2018/09/14/rustconf-talk.html) about game design in Rust. The LibAFL code reuse meachanism is so based on components rather than sub-classes, but there are still some OOP patterns in the library. diff --git a/docs/src/getting_started/setup.md b/docs/src/getting_started/setup.md index e57aca1f14..3734f90e3e 100644 --- a/docs/src/getting_started/setup.md +++ b/docs/src/getting_started/setup.md @@ -37,17 +37,17 @@ In addition, if you want to perform source-level fuzz testing of C/C++ applicati you will likely need Clang with its instrumentation options to compile the programs under test. -You can download and build the LLVM source tree, Clang included, following the steps -explained [here](https://clang.llvm.org/get_started.html). - -Alternatively, on Linux, you can use your distro's package manager to get Clang, +On Linux you can use your distro's package manager to get Clang, but these packages are not always updated, so we suggest you to use the Debian/Ubuntu prebuilt packages from LLVM that are available using their [official repository](https://apt.llvm.org/). -For Miscrosoft Windows, you can download the [installer package](https://llvm.org/builds/) that LLVM generates periodically. +For Microsoft Windows, you can download the [installer package](https://llvm.org/builds/) that LLVM generates periodically. Despite that Clang is the default C compiler on macOS, we discourage the use of the build shipped by Apple and encourage -the installation from `brew` or direclty a fresh build from the source code. +the installation from `brew` or directly a fresh build from the source code. + +Alternatively you can download and build the LLVM source tree - Clang included - following the steps +explained [here](https://clang.llvm.org/get_started.html). ## Rust installation diff --git a/docs/src/medatata/definition.md b/docs/src/medatata/definition.md index f78e552859..1f854ecc5a 100644 --- a/docs/src/medatata/definition.md +++ b/docs/src/medatata/definition.md @@ -14,6 +14,6 @@ pub struct MyMetadata { } ``` -The struct must be static, so it cannot holds references to borrowed objects. +The struct must be static, so it cannot hold references to borrowed objects. diff --git a/fuzzers/frida_libpng/harness.cc b/fuzzers/frida_libpng/harness.cc index 20a2070e16..b5e3e6eda8 100644 --- a/fuzzers/frida_libpng/harness.cc +++ b/fuzzers/frida_libpng/harness.cc @@ -88,7 +88,7 @@ static char * allocation = NULL; __attribute__((noinline)) void func3( char * alloc) { printf("func3\n"); - if (random() % 5 == 0) { + if (random() == 0) { alloc[0xff] = 0xde; } } diff --git a/fuzzers/frida_libpng/src/fuzzer.rs b/fuzzers/frida_libpng/src/fuzzer.rs index d7df2525cb..d7b0c8cde4 100644 --- a/fuzzers/frida_libpng/src/fuzzer.rs +++ b/fuzzers/frida_libpng/src/fuzzer.rs @@ -197,9 +197,10 @@ pub fn main() { env::args() .nth(3) .expect("no modules to instrument specified") - .split(":") + .split(':') + .map(|module_name| std::fs::canonicalize(module_name).unwrap()) .collect(), - vec![PathBuf::from("./corpus")], + &vec![PathBuf::from("./corpus")], PathBuf::from("./crashes"), 1337, ) @@ -224,8 +225,8 @@ fn fuzz( unsafe fn fuzz( module_name: &str, symbol_name: &str, - modules_to_instrument: Vec<&str>, - corpus_dirs: Vec, + modules_to_instrument: Vec, + corpus_dirs: &Vec, objective_dir: PathBuf, broker_port: u16, ) -> Result<(), Error> { diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 9d0466b2d5..bfa8cd5a3c 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -61,7 +61,6 @@ libafl_derive = { version = "*", optional = true, path = "../libafl_derive" } serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc"] } # an easy way to debug print SerdeAnyMap compression = { version = "0.1.5" } num_enum = "0.5.1" -spin = "0.9.0" [target.'cfg(target_os = "android")'.dependencies] backtrace = { version = "0.3", optional = true, default-features = false, features = ["std", "libbacktrace"] } # for llmp_debug diff --git a/libafl_frida/Cargo.toml b/libafl_frida/Cargo.toml index 92a082e53a..26dc39bbd3 100644 --- a/libafl_frida/Cargo.toml +++ b/libafl_frida/Cargo.toml @@ -27,7 +27,7 @@ termcolor = "1.1.2" serde = "1.0" backtrace = { version = "0.3.58", default-features = false, features = ["std", "serde"] } num-traits = "0.2.14" -seahash = "4.1.0" +ahash = "0.7" [target.'cfg(unix)'.dependencies] gothook = { version = "0.1" } diff --git a/libafl_frida/src/asan_rt.rs b/libafl_frida/src/asan_rt.rs index 80d243f50f..5f3a42a582 100644 --- a/libafl_frida/src/asan_rt.rs +++ b/libafl_frida/src/asan_rt.rs @@ -31,6 +31,7 @@ use std::{ cell::{RefCell, RefMut}, ffi::c_void, io::{self, Write}, + path::PathBuf, rc::Rc, }; use termcolor::{Color, ColorSpec, WriteColor}; @@ -697,7 +698,7 @@ impl AsanRuntime { /// Initialize the runtime so that it is read for action. Take care not to move the runtime /// instance after this function has been called, as the generated blobs would become /// invalid! - pub fn init(&mut self, modules_to_instrument: &[&str]) { + pub fn init(&mut self, modules_to_instrument: &[PathBuf]) { // workaround frida's frida-gum-allocate-near bug: unsafe { for _ in 0..512 { @@ -730,7 +731,7 @@ impl AsanRuntime { self.unpoison_all_existing_memory(); for module_name in modules_to_instrument { #[cfg(unix)] - self.hook_library(module_name); + self.hook_library(module_name.to_str().unwrap()); } } @@ -786,15 +787,14 @@ impl AsanRuntime { pub fn register_thread(&self) { let mut allocator = Allocator::get(); let (stack_start, stack_end) = Self::current_stack(); - println!("current stack: {:#016x}-{:#016x}", stack_start, stack_end); allocator.map_shadow_for_region(stack_start, stack_end, true); - //let (tls_start, tls_end) = Self::current_tls(); - //allocator.map_shadow_for_region(tls_start, tls_end, true); - //println!( - //"registering thread with stack {:x}:{:x} and tls {:x}:{:x}", - //stack_start as usize, stack_end as usize, tls_start as usize, tls_end as usize - //); + let (tls_start, tls_end) = Self::current_tls(); + allocator.map_shadow_for_region(tls_start, tls_end, true); + println!( + "registering thread with stack {:x}:{:x} and tls {:x}:{:x}", + stack_start as usize, stack_end as usize, tls_start as usize, tls_end as usize + ); } /// Determine the stack start, end for the currently running thread @@ -829,6 +829,9 @@ impl AsanRuntime { /// Determine the tls start, end for the currently running thread fn current_tls() -> (usize, usize) { let tls_address = unsafe { get_tls_ptr() } as usize; + // we need to mask off the highest byte, due to 'High Byte Ignore" + #[cfg(target_os = "android")] + let tls_address = tls_address & 0xffffffffffffff; let (start, end, _, _) = find_mapping_for_address(tls_address).unwrap(); (start, end) @@ -1421,7 +1424,6 @@ impl AsanRuntime { ; b >skip_report ; report: - ; brk 0x11 ; stp x29, x30, [sp, #-0x10]! ; mov x29, sp @@ -1541,7 +1543,6 @@ impl AsanRuntime { ; b >skip_report ; report: - ; brk 0x22 ; stp x29, x30, [sp, #-0x10]! ; mov x29, sp diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index 589f270b40..d53308f192 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -1,3 +1,6 @@ +use ahash::AHasher; +use std::hash::Hasher; + use libafl::inputs::{HasTargetBytes, Input}; #[cfg(any(target_os = "linux", target_os = "android"))] @@ -26,7 +29,7 @@ use frida_gum::{Gum, Module, PageProtection}; use num_traits::cast::FromPrimitive; use rangemap::RangeMap; -use std::rc::Rc; +use std::{path::PathBuf, rc::Rc}; use crate::{asan_rt::AsanRuntime, FridaOptions}; @@ -82,9 +85,12 @@ impl<'a> FridaHelper<'a> for FridaInstrumentationHelper<'a> { fn post_exec(&mut self, input: &I) { if self.options.drcov_enabled() { + let mut hasher = AHasher::new_with_keys(0, 0); + hasher.write(input.target_bytes().as_slice()); + let filename = format!( "./coverage/{:016x}.drcov", - seahash::hash(input.target_bytes().as_slice()) + hasher.finish(), ); DrCovWriter::new(&filename, &self.ranges, &mut self.drcov_basic_blocks).write(); } @@ -193,7 +199,7 @@ impl<'a> FridaInstrumentationHelper<'a> { gum: &'a Gum, options: FridaOptions, _harness_module_name: &str, - modules_to_instrument: &'a [&str], + modules_to_instrument: &'a [PathBuf], ) -> Self { let mut helper = Self { map: [0u8; MAP_SIZE], @@ -214,11 +220,11 @@ impl<'a> FridaInstrumentationHelper<'a> { if options.stalker_enabled() { for (id, module_name) in modules_to_instrument.iter().enumerate() { - let (lib_start, lib_end) = find_mapping_for_path(module_name); - println!("including range {:x}-{:x} for {}", lib_start, lib_end, module_name); + let (lib_start, lib_end) = find_mapping_for_path(module_name.to_str().unwrap()); + println!("including range {:x}-{:x} for {:?}", lib_start, lib_end, module_name); helper .ranges - .insert(lib_start..lib_end, (id as u16, module_name)); + .insert(lib_start..lib_end, (id as u16, module_name.to_str().unwrap())); } if helper.options.drcov_enabled() {