LibAFL is composed of different crates.
A crate is an individual library in Rust's Cargo build system, that you can use by adding it to your project's Cargo.toml
, like:
[dependencies]
libafl = { version = "*" }
For LibAFL, each crate has its self-contained purpose, and the user may not need to use all of them in their project. Following the naming convention of the folders in the project's root, they are:
This is the main crate that contains all the components needed to build a fuzzer.
This crate has a number of feature flags that enable and disable certain aspects of LibAFL.
The features can be found in LibAFL's Cargo.toml
under "[features]
", and are usually explained with comments there.
Some features worthy of remark are:
std
enables the parts of the code that use the Rust standard library. Without this flag, LibAFL isno_std
compatible. This disables a range of features, but allows us to use LibAFL in embedded environments, read theno_std
section for further details.derive
enables the usage of thederive(...)
macros defined in libafl_derive from libafl.rand_trait
allows you to use LibAFL's very fast (but insecure!) random number generator wherever compatibility with Rust'srand
crate is needed.llmp_bind_public
makes LibAFL's LLMP bind to a public TCP port, over which other fuzzers nodes can communicate with this instance.introspection
adds performance statistics to LibAFL.
You can choose the features by using features = ["feature1", "feature2", ...]
for LibAFL in your Cargo.toml
.
Out of this list, by default, std
, derive
, and rand_trait
are already set.
You can choose to disable them by setting default-features = false
in your Cargo.toml
.
The libafl_bolts
crate is a minimal tool shed filled with useful low-level rust features, not necessarily related to fuzzers.
In it, you'll find highlights like:
core_affinity
to bind the current process to coresSerdeAnyMap
a map that can store typed values in a serializable fashionminibsod
to dump the current process stateLLMP
, "low level message passing", a lock-free IPC mechanismRand
, different fast (non-cryptographically secure) RNG implementations like RomuRandShMem
, a platform independent shard memory implementationTuples
, a compiletime tuple implementation
... and much more.
The sugar crate abstracts away most of the complexity of LibAFL's API.
Instead of high flexibility, it aims to be high-level and easy-to-use.
It is not as flexible as stitching your fuzzer together from each individual component, but allows you to build a fuzzer with minimal lines of code.
To see it in action, take a look at the libfuzzer_stb_image_sugar
example fuzzer.
This a proc-macro crate paired with the libafl
crate.
At the moment, it just exposes the derive(SerdeAny)
macro that can be used to define Metadata structs, see the section about Metadata for details.
This crate exposes code to interact with, and to instrument, targets. To enable and disable features at compile-time, the features are enabled and disabled using feature flags.
Currently, the supported flags are:
pcguard_edges
defines the SanitizerCoverage trace-pc-guard hooks to track the executed edges in a map.pcguard_hitcounts
defines the SanitizerCoverage trace-pc-guard hooks to track the executed edges with the hitcounts (like AFL) in a map.libfuzzer
exposes a compatibility layer with libFuzzer style harnesses.value_profile
defines the SanitizerCoverage trace-cmp hooks to track the matching bits of each comparison in a map.
This is a library that provides utils to wrap compilers and create source-level fuzzers.
At the moment, only the Clang compiler is supported. To understand it deeper, look through the tutorials and examples.
This library bridges LibAFL with Frida as instrumentation backend. With this crate, you can instrument targets on Linux/macOS/Windows/Android for coverage collection. Additionally, it supports CmpLog, and AddressSanitizer instrumentation and runtimes for aarch64. See further information, as well as usage instructions, later in the book.
This library bridges LibAFL with QEMU user-mode to fuzz ELF cross-platform binaries.
It works on Linux and can collect edge coverage without collisions! It also supports a wide range of hooks and instrumentation options.
Nyx is a KVM-based snapshot fuzzer. libafl_nyx
adds these capabilities to LibAFL. There is a specific section explaining usage of libafl_nyx later in the book.
Concolic fuzzing is the combination of fuzzing and a symbolic execution engine. This can reach greater depth than normal fuzzing, and is exposed in this crate. There is a specific section explaining usage of libafl_concolic later in the book.