Merge pull request #78 from AFLplusplus/dev

Dev
This commit is contained in:
Andrea Fioraldi 2021-04-30 15:07:30 +02:00 committed by GitHub
commit bd22ea5268
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 52 additions and 47 deletions

View File

@ -10,14 +10,12 @@ LibAFL is written and maintained by Andrea Fioraldi <andreafioraldi@gmail.com> a
LibAFL gives you many of the benefits of an off-the-shelf fuzzer, while being completely customizable. LibAFL gives you many of the benefits of an off-the-shelf fuzzer, while being completely customizable.
Some highlight features currently include: Some highlight features currently include:
- `multi platform`: LibAFL was confirmed to work on *Windows*, *MacOS*, *Linux*, and *Android* on *x86_64* and *aarch64*. - `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).
- `portable`: `LibAFL` can be built in `no_std` mode. Inject LibAFL in obscure targets like embedded devices and hypervisors. - `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: - `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. 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! - `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.
- `fast`: We do everything we can at compile time, keeping runtime overhead minimal.
- `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. - `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 ## 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). 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) + SanitizerCoverage, in [libafl_targets](./libafl_targets)
+ Frida, in [libafl_frida](./libafl_frida), by s1341 <github@shmarya.net> (Windows support is broken atm, it relies on [this upstream issue](https://github.com/meme/frida-rust/issues/9) to be fixed.) + Frida, in [libafl_frida](./libafl_frida), by s1341 <github@shmarya.net> (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, ...) + 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 <github@shmarya.net> (Windows support will be added soon)
## Getting started ## 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 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 git checkout dev
``` ```
@ -56,18 +53,19 @@ Build the library using
cargo build --release cargo build --release
``` ```
Build the API documentation with 4. Build the API documentation with
``` ```
cargo doc 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 cd docs && mdbook serve
``` ```
We collect all example fuzzers in [`./fuzzers`](./fuzzers/). We collect all example fuzzers in [`./fuzzers`](./fuzzers/).
Be sure to read their documentation (and source), this is *the natural way to get started!* Be sure to read their documentation (and source), this is *the natural way to get started!*

View File

@ -2,7 +2,7 @@
The LibAFL architecture is built around some entities to allow code reuse and low-cost abstractions. 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. The LibAFL code reuse meachanism is so based on components rather than sub-classes, but there are still some OOP patterns in the library.

View File

@ -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 you will likely need Clang with its instrumentation options to compile the programs
under test. under test.
You can download and build the LLVM source tree, Clang included, following the steps On Linux you can use your distro's package manager to get Clang,
explained [here](https://clang.llvm.org/get_started.html).
Alternatively, 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 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/). 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 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 ## Rust installation

View File

@ -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.

View File

@ -88,7 +88,7 @@ static char * allocation = NULL;
__attribute__((noinline)) __attribute__((noinline))
void func3( char * alloc) { void func3( char * alloc) {
printf("func3\n"); printf("func3\n");
if (random() % 5 == 0) { if (random() == 0) {
alloc[0xff] = 0xde; alloc[0xff] = 0xde;
} }
} }

View File

@ -197,9 +197,10 @@ pub fn main() {
env::args() env::args()
.nth(3) .nth(3)
.expect("no modules to instrument specified") .expect("no modules to instrument specified")
.split(":") .split(':')
.map(|module_name| std::fs::canonicalize(module_name).unwrap())
.collect(), .collect(),
vec![PathBuf::from("./corpus")], &vec![PathBuf::from("./corpus")],
PathBuf::from("./crashes"), PathBuf::from("./crashes"),
1337, 1337,
) )
@ -224,8 +225,8 @@ fn fuzz(
unsafe fn fuzz( unsafe fn fuzz(
module_name: &str, module_name: &str,
symbol_name: &str, symbol_name: &str,
modules_to_instrument: Vec<&str>, modules_to_instrument: Vec<PathBuf>,
corpus_dirs: Vec<PathBuf>, corpus_dirs: &Vec<PathBuf>,
objective_dir: PathBuf, objective_dir: PathBuf,
broker_port: u16, broker_port: u16,
) -> Result<(), Error> { ) -> Result<(), Error> {

View File

@ -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 serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc"] } # an easy way to debug print SerdeAnyMap
compression = { version = "0.1.5" } compression = { version = "0.1.5" }
num_enum = "0.5.1" num_enum = "0.5.1"
spin = "0.9.0"
[target.'cfg(target_os = "android")'.dependencies] [target.'cfg(target_os = "android")'.dependencies]
backtrace = { version = "0.3", optional = true, default-features = false, features = ["std", "libbacktrace"] } # for llmp_debug backtrace = { version = "0.3", optional = true, default-features = false, features = ["std", "libbacktrace"] } # for llmp_debug

View File

@ -27,7 +27,7 @@ termcolor = "1.1.2"
serde = "1.0" serde = "1.0"
backtrace = { version = "0.3.58", default-features = false, features = ["std", "serde"] } backtrace = { version = "0.3.58", default-features = false, features = ["std", "serde"] }
num-traits = "0.2.14" num-traits = "0.2.14"
seahash = "4.1.0" ahash = "0.7"
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
gothook = { version = "0.1" } gothook = { version = "0.1" }

View File

@ -31,6 +31,7 @@ use std::{
cell::{RefCell, RefMut}, cell::{RefCell, RefMut},
ffi::c_void, ffi::c_void,
io::{self, Write}, io::{self, Write},
path::PathBuf,
rc::Rc, rc::Rc,
}; };
use termcolor::{Color, ColorSpec, WriteColor}; 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 /// 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 /// instance after this function has been called, as the generated blobs would become
/// invalid! /// 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: // workaround frida's frida-gum-allocate-near bug:
unsafe { unsafe {
for _ in 0..512 { for _ in 0..512 {
@ -730,7 +731,7 @@ impl AsanRuntime {
self.unpoison_all_existing_memory(); self.unpoison_all_existing_memory();
for module_name in modules_to_instrument { for module_name in modules_to_instrument {
#[cfg(unix)] #[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) { pub fn register_thread(&self) {
let mut allocator = Allocator::get(); let mut allocator = Allocator::get();
let (stack_start, stack_end) = Self::current_stack(); 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); allocator.map_shadow_for_region(stack_start, stack_end, true);
//let (tls_start, tls_end) = Self::current_tls(); let (tls_start, tls_end) = Self::current_tls();
//allocator.map_shadow_for_region(tls_start, tls_end, true); allocator.map_shadow_for_region(tls_start, tls_end, true);
//println!( println!(
//"registering thread with stack {:x}:{:x} and tls {:x}:{:x}", "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 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 /// 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 /// Determine the tls start, end for the currently running thread
fn current_tls() -> (usize, usize) { fn current_tls() -> (usize, usize) {
let tls_address = unsafe { get_tls_ptr() } as 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(); let (start, end, _, _) = find_mapping_for_address(tls_address).unwrap();
(start, end) (start, end)
@ -1421,7 +1424,6 @@ impl AsanRuntime {
; b >skip_report ; b >skip_report
; report: ; report:
; brk 0x11
; stp x29, x30, [sp, #-0x10]! ; stp x29, x30, [sp, #-0x10]!
; mov x29, sp ; mov x29, sp
@ -1541,7 +1543,6 @@ impl AsanRuntime {
; b >skip_report ; b >skip_report
; report: ; report:
; brk 0x22
; stp x29, x30, [sp, #-0x10]! ; stp x29, x30, [sp, #-0x10]!
; mov x29, sp ; mov x29, sp

View File

@ -1,3 +1,6 @@
use ahash::AHasher;
use std::hash::Hasher;
use libafl::inputs::{HasTargetBytes, Input}; use libafl::inputs::{HasTargetBytes, Input};
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
@ -26,7 +29,7 @@ use frida_gum::{Gum, Module, PageProtection};
use num_traits::cast::FromPrimitive; use num_traits::cast::FromPrimitive;
use rangemap::RangeMap; use rangemap::RangeMap;
use std::rc::Rc; use std::{path::PathBuf, rc::Rc};
use crate::{asan_rt::AsanRuntime, FridaOptions}; use crate::{asan_rt::AsanRuntime, FridaOptions};
@ -82,9 +85,12 @@ impl<'a> FridaHelper<'a> for FridaInstrumentationHelper<'a> {
fn post_exec<I: Input + HasTargetBytes>(&mut self, input: &I) { fn post_exec<I: Input + HasTargetBytes>(&mut self, input: &I) {
if self.options.drcov_enabled() { if self.options.drcov_enabled() {
let mut hasher = AHasher::new_with_keys(0, 0);
hasher.write(input.target_bytes().as_slice());
let filename = format!( let filename = format!(
"./coverage/{:016x}.drcov", "./coverage/{:016x}.drcov",
seahash::hash(input.target_bytes().as_slice()) hasher.finish(),
); );
DrCovWriter::new(&filename, &self.ranges, &mut self.drcov_basic_blocks).write(); DrCovWriter::new(&filename, &self.ranges, &mut self.drcov_basic_blocks).write();
} }
@ -193,7 +199,7 @@ impl<'a> FridaInstrumentationHelper<'a> {
gum: &'a Gum, gum: &'a Gum,
options: FridaOptions, options: FridaOptions,
_harness_module_name: &str, _harness_module_name: &str,
modules_to_instrument: &'a [&str], modules_to_instrument: &'a [PathBuf],
) -> Self { ) -> Self {
let mut helper = Self { let mut helper = Self {
map: [0u8; MAP_SIZE], map: [0u8; MAP_SIZE],
@ -214,11 +220,11 @@ impl<'a> FridaInstrumentationHelper<'a> {
if options.stalker_enabled() { if options.stalker_enabled() {
for (id, module_name) in modules_to_instrument.iter().enumerate() { for (id, module_name) in modules_to_instrument.iter().enumerate() {
let (lib_start, lib_end) = find_mapping_for_path(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); println!("including range {:x}-{:x} for {:?}", lib_start, lib_end, module_name);
helper helper
.ranges .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() { if helper.options.drcov_enabled() {