afl-cov-fast is a tool to generate code coverage from AFL test cases. It aims to efficiently generate a "zero coverage" report of functions and lines never covered by a fuzzing campaign, both when code is available and in binary-only mode.
It is a reimplementation of afl-cov's "cover-corpus" mode with additional support for binary-only targets (via the QEMU and Frida backends), multiprocessing, and reduced Python overhead.
Start by cloning this repository and its submodules:
$ git clone --recursive https://github.com/airbus-seclab/afl-cov-fast.git
- Python 3.6 or newer;
- The Python
tqdm
package; lcov
(for thelcov
andgenhtml
commands);llvm
(for thellvm-profdata
command);llvm-tools
(for thellvm-cov
command).
A Dockerfile
is provided with pre-installed dependencies. To use it, the
following commands can be used:
$ docker build -t afl-cov-fast .
$ docker run --rm -it -v "${PWD}:/workdir" -v "<path-to-your-fuzzed-project>:<absolute-path-to-your-fuzzed-project>" -u `id -u`:`id -g` --name afl-cov-fast afl-cov-fast
Notes:
- You have to mount your project with the same path in the docker container when
in GCC mode so that paths to coverage files are properly resolved. In other
cases, you can use an arbitrary folder (e.g.
/project
); - AFL++ is purposefully not included in the Docker image so you can use your exact version when relying on the QEMU or Frida backend. This means that you will have to build the QEMU TCG plugin yourself (see below) if necessary.
When using Debian, dependencies can be installed with the following commands:
$ sudo apt update
$ sudo apt install python3 python3-tqdm lcov llvm-16 llvm-16-tools
Notes:
- The
lcov
dependency is only required for the GCC and LLVM backend; - The
llvm-*
dependencies are only required for the LLVM backend.
Alternatively, Python dependencies could be installed using pip
in a virtual
environment like so:
$ python3 -m venv .env
$ source .env/bin/activate
$ pip3 install -r requirements.txt
For the QEMU backend, coverage is obtained using a QEMU TCG plugin. This is supported natively by AFL++ since this commit present in v4.10c.
The QEMU plugins simply need to be compiled in AFL++:
$ cd <afl++-path>/qemu_mode
$ make -C qemuafl plugins
A custom utility is used to merge drcov files into a single "full" coverage file (for the QEMU and Frida backend), which is included as a submodule of this repository and must be built separately:
$ cargo install --path drcov-merge
When source code is available (for the GCC or LLVM backend), the binary is instrumented at compile time. Specific options must be added for coverage to be exported when the target is run. These options are described below.
Compile the target with the --coverage
option (equivalent to
-fprofile-arcs -ftest-coverage
).
When run, the output binary will then output coverage information in gcno
and
gcda
files.
Compile the target with the -fprofile-instr-generate -fcoverage-mapping
options.
When run, the output binary will then output coverage information in a profraw
file.
When running, the coverage-command
is used to run the target binary and obtain
coverage. The @@
and AFL_FILE
strings in this command will be replaced with
the path to the input file. If none of them is present, the content of the input
file will be written to stdin
instead.
Example usage:
$ afl-cov-fast.py -m gcc --code-dir 'src' --afl-fuzzing-dir 'output' --coverage-cmd './a.out @@' -j8
Then, simply open the output/cov/web/index.html
file.
Example usage:
$ afl-cov-fast.py -m llvm --code-dir 'src' --afl-fuzzing-dir 'output' --coverage-cmd './a.out @@' --binary-path 'a.out' -j8
Then, simply open the output/cov/web/index.html
file.
Example usage:
$ afl-cov-fast.py -m qemu --afl-fuzzing-dir 'output' --afl-path './AFLplusplus' --coverage-cmd './a.out @@' -j8
Then, load the aggregated coverage file in output/cov/drcov/full.drcov.trace
using lighthouse,
Cartographer,
lightkeeper, or
CutterDRcov.
Example usage:
$ afl-cov-fast.py -m frida --afl-fuzzing-dir 'output' --afl-path './AFLplusplus' --coverage-cmd './a.out @@' -j8
Then, load the aggregated coverage file in output/cov/drcov/full.drcov.trace
using lighthouse,
Cartographer,
lightkeeper, or
CutterDRcov.
Practical usage examples are also provided in the examples directory.
Issues and pull requests are welcome!
Notably, the following features could be added:
- Support for other backends (e.g. Nyx, Unicorn),
- Support for in-memory fuzzing instead of providing inputs from a file or stdin,
- Any other feature you might find useful.
- https://github.com/vanhauser-thc/afl-cov
- https://github.com/eqv/aflq_fast_cov
- https://github.com/novafacing/pyafl_qemu_trace
This project is licensed under the GPLv3 License. See the LICENSE file for details.