commit
bd22ea5268
28
README.md
28
README.md
@ -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.
|
||||
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 <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, ...)
|
||||
|
||||
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
|
||||
|
||||
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!*
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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<PathBuf>,
|
||||
modules_to_instrument: Vec<PathBuf>,
|
||||
corpus_dirs: &Vec<PathBuf>,
|
||||
objective_dir: PathBuf,
|
||||
broker_port: u16,
|
||||
) -> Result<(), Error> {
|
||||
|
@ -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
|
||||
|
@ -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" }
|
||||
|
@ -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
|
||||
|
||||
|
@ -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<I: Input + HasTargetBytes>(&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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user