Overview
QEMU mode uses a patched version of QEMU (qemuafl) to instrument binary-only targets. The usual performance cost is 2-5x, which is considerably better than tools like DynamoRIO and PIN. Performance: 2-5x slowdown compared to native instrumentation Platform Support: Linux only (BSD support may be possible but not currently implemented) Architectures: x86, x86_64, arm, aarch64, i386 (and others via CPU_TARGET)Building QEMU Mode
This will download, configure, and compile the QEMU binary. Note that QEMU is a large project, so this may take a while.
# For ARM binaries
CPU_TARGET=arm ./build_qemu_support.sh
# For 32-bit binaries on 64-bit systems
CPU_TARGET=i386 ./build_qemu_support.sh
# For ARM64
CPU_TARGET=aarch64 ./build_qemu_support.sh
Basic Usage
Once QEMU mode is built, use the-Q flag with afl-fuzz:
i386 Architecture Note
When targeting i386, the forkserver handshake may fail due to lack of reserved memory. Fix with:Custom Library Paths
To specify a different library path (e.g., for cross-architecture fuzzing):Advanced Features
Deferred Initialization
Move the forkserver to a specific point in execution for significant speed improvements:AFL_EXITPOINT triggers when the block containing the address is reached.
Persistent Mode
QEMU mode supports persistent mode for x86, x86_64, arm, and aarch64, providing significant speed improvements. For details, see the persistent mode documentation.Snapshot Mode
As an extension to persistent mode, qemuafl can snapshot and restore memory state:Partial Instrumentation
Instrument only specific address ranges or modules:CompareCoverage
Enables sub-instrumentation with effects similar to laf-intel:AFL_COMPCOV_LEVEL=1: Instrument comparisons with immediate values/read-only memoryAFL_COMPCOV_LEVEL=2: Instrument all comparisons and memory comparison functionsAFL_COMPCOV_LEVEL=3: Additionally instrument floating-point comparisons (experimental)
CMPLOG mode (below) is recommended over CompareCoverage in most cases.
CMPLOG Mode
Based on the Redqueen project, CMPLOG learns immediates from CMP instructions and applies them to relevant input locations:Ijon Mode
Transmit information about variable changes to AFL++. Enable with:ijon_max, ijon_min, ijon_set, ijon_inc
Debugging:
Wine Mode
Fuzz Win32 PE binaries using Wine:Coverage Information
Generate coverage information using the drcov plugin:afl-qemu-trace -plugin qemuafl/build/contrib/plugins/libdrcov.so,arg=filename=/tmp/coverage.drcov.trace <target> <args>
Environment Variables Reference
| Variable | Description |
|---|---|
AFL_ENTRYPOINT | Address to move forkserver to (deferred init) |
AFL_EXITPOINT | Address to trigger instance termination |
AFL_QEMU_SNAPSHOT | Enable snapshot mode at specified address |
AFL_QEMU_INST_RANGES | Comma-separated list of ranges/modules to instrument |
AFL_QEMU_EXCLUDE_RANGES | Comma-separated list of ranges/modules to exclude |
AFL_COMPCOV_LEVEL | Enable CompareCoverage (1-3) |
AFL_QEMU_IJON | Path to Ijon configuration file |
AFL_QEMU_FORCE_DFL | Force QEMU to ignore target signal handlers |
AFL_QEMU_DEBUG_MAPS | Display memory layout |
AFL_INST_LIBS | Instrument all basic blocks (not just .text) |
QEMU_RESERVED_VA | Reserved memory for i386 targets |
QEMU_LD_PREFIX | Custom library path |
QEMU_PLUGIN | Load QEMU plugin |
Limitations and Gotchas
Workarounds
For CPU feature issues, try:- Using binaries built for older CPUs
- Recompiling with
-march=core2
Checksums and Post-Processing
For checksum fixes or test case cleanup, seeafl_custom_post_process in the custom mutators examples.
Benchmarking
To fairly compare QEMU instrumentation with afl-clang-fast:Linking Considerations
- Static linking required: Libraries you want to analyze must be statically linked
- Dynamic linking for standard libs: Standard C libraries should be dynamically linked to avoid wasteful instrumentation
- The instrumentation follows only the
.textsection of the first ELF binary encountered - Use
AFL_INST_LIBS=1to instrument every basic block (not recommended for most cases)

