Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/AFLplusplus/AFLplusplus/llms.txt

Use this file to discover all available pages before exploring further.

When source code isn’t available, AFL++ offers multiple solutions for fuzzing binary-only targets. This guide covers the fastest and most effective techniques.

Quick Recommendations

Fastest options (if persistent mode is possible):
  • FRIDA mode with persistent mode
  • QEMU mode with persistent mode
Best fallback options:
  1. ZAFL (binary rewriter) - 90-95% speed of source instrumentation
  2. RetroWrite (binary rewriter) - close to source speed
  3. QEMU mode with AFL_ENTRYPOINT/AFL_EXITPOINT
  4. FRIDA mode
For non-Linux targets:
  • Unicorn mode (any architecture, any OS)
  • WINE+QEMU (Windows PE binaries)

QEMU Mode

QEMU mode is the native AFL++ solution for binary-only fuzzing using user-space emulation.

Building QEMU Mode

cd qemu_mode
./build_qemu_support.sh
cd ..

Basic Usage

# Simple QEMU fuzzing
afl-fuzz -Q -i input -o output -- ./target @@

# For stdin-based targets
afl-fuzz -Q -i input -o output -- ./target
For production fuzzing, run these instances:
# Instance 1: QEMU with CMPLOG
AFL_COMPCOV_LEVEL=2 afl-fuzz -Q -c 0 -S qemu-cmplog -i input -o output -- ./target @@

# Instance 2: QEMU with QASAN (sanitizer)
AFL_USE_QASAN=1 afl-fuzz -Q -S qemu-asan -i input -o output -- ./target @@

# Instance 3: QEMU with LAF-Intel
AFL_PRELOAD=libcmpcov.so AFL_COMPCOV_LEVEL=2 afl-fuzz -Q -S qemu-laf -i input -o output -- ./target @@

# Remaining instances: standard QEMU mode
afl-fuzz -Q -S qemu-1 -i input -o output -- ./target @@
afl-fuzz -Q -S qemu-2 -i input -o output -- ./target @@

Performance Optimization

QEMU mode has approximately 50% speed reduction compared to source instrumentation. Optimize it:
1

Use AFL_ENTRYPOINT

Move the forkserver to a later point in execution:
# Find a good entry point after initialization
export AFL_ENTRYPOINT=0x400a80
afl-fuzz -Q -i input -o output -- ./target @@
Provides 5-10% speed increase.
2

Use Persistent Mode

Achieve 3-8x speed improvement with persistent mode:
# Set persistent address and loop count
export AFL_QEMU_PERSISTENT_ADDR=0x400b20
export AFL_QEMU_PERSISTENT_CNT=10000
export AFL_QEMU_PERSISTENT_HOOK=/path/to/hook.so

afl-fuzz -Q -i input -o output -- ./target @@
See QEMU Persistent Mode for implementation details.
3

Limit Instrumentation Range

Instrument only specific code sections:
export AFL_CODE_START=0x400000
export AFL_CODE_END=0x450000

afl-fuzz -Q -i input -o output -- ./target @@
QEMU persistent mode can achieve 150-300% overall speed increase, making it faster than standard source instrumentation!

QEMU Mode Resources

FRIDA Mode

FRIDA mode offers similar functionality to QEMU with some advantages:
  • Often slightly faster than QEMU
  • Works on macOS (Intel and M1)
  • Excellent for mobile fuzzing (iOS/Android)

Building FRIDA Mode

cd frida_mode
gmake
cd ..

Basic Usage

# Basic FRIDA fuzzing
afl-fuzz -O -i input -o output -- ./target @@

# With persistent mode (if available)
AFL_FRIDA_PERSISTENT_ADDR=0x400b20 afl-fuzz -O -i input -o output -- ./target @@

Remote Fuzzing

FRIDA excels at fuzzing on remote devices:
# Connect to remote device (iOS/Android)
export AFL_FRIDA_REMOTE_ADDR=192.168.1.100:27042
afl-fuzz -O -i input -o output -- ./target @@
For advanced remote fuzzing, use fpicker as an intermediate.

FRIDA Mode Resources

Binary Rewriters

Binary rewriters statically instrument binaries, achieving near-source-code speeds. ZAFL provides the best performance among binary rewriters. Features:
  • Supports x86-64 C/C++
  • Handles stripped/unstripped binaries
  • Works with PIE and non-PIE
  • 90-95% speed of afl-clang-fast
  • Supports advanced transformations (LAF-Intel, context sensitivity)
Installation:
git clone https://git.zephyr-software.com/opensrc/zafl
cd zafl
# Follow ZAFL build instructions
Usage:
# Rewrite binary
zafl-rewrite ./target ./target-instrumented

# Fuzz normally
afl-fuzz -i input -o output -- ./target-instrumented @@

RetroWrite

RetroWrite decompiles binaries to assembly for instrumentation. Requirements:
  • x86_64 or ARM64 binaries
  • Must have symbols (not stripped)
  • Must be compiled with PIE/PIC
  • No C++ exceptions
Installation:
pip3 install retrowrite
Usage:
# Decompile to assembly
retrowrite --asan ./target ./target.s

# Compile with afl-gcc (AFL++ v4.21c or earlier)
afl-gcc ./target.s -o target-instrumented

# Fuzz
afl-fuzz -i input -o output -- ./target-instrumented @@
RetroWrite requires afl-gcc, which was removed in AFL++ v4.22c. Use ZAFL instead for newer AFL++ versions.

Dyninst

Dyninst instruments binaries at load time. Advantages:
  • Works on many binary types
  • 15-35% speed reduction (better than QEMU)
Disadvantages:
  • Often causes crashes due to code relocation issues
  • Can be unstable
Installation:
git clone https://github.com/vanhauser-thc/afl-dyninst
cd afl-dyninst
make
Usage:
# Instrument binary
./afl-dyninst -i ./target -o ./target-instrumented -e main -s 100

# Fuzz
afl-fuzz -i input -o output -- ./target-instrumented @@

Specialized Modes

WINE+QEMU (Windows Binaries)

Fuzz Windows PE binaries on Linux: Requirements:
  • Wine
  • Python 3
  • pefile package: pip3 install pefile
Usage:
# Build WINE+QEMU support
cd qemu_mode
./build_qemu_support.sh
cd ..

# Fuzz Windows binary
AFL_WINE=1 afl-fuzz -Q -i input -o output -- wine ./target.exe @@
See WINE Mode Documentation for details.

Unicorn Mode (Any Architecture)

Unicorn mode emulates any CPU architecture but requires custom scripts. Use cases:
  • Embedded firmware
  • Non-x86 architectures
  • Partial binary emulation
  • Specialized environments
Building:
cd unicorn_mode
./build_unicorn_support.py
Usage: Write a Python harness:
from unicornafl import *

# Your emulation setup
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
# ... configure memory, load binary, etc.

# Start fuzzing
uc.afl_fuzz(input_file, place_input_callback, exits)
See Unicorn Mode Documentation for complete examples.

Nyx Mode (Full System Fuzzing)

Nyx provides full system emulation with snapshot support. Features:
  • KVM-based (very fast)
  • Full system snapshots
  • x86_64 Linux only
Use cases:
  • Kernel fuzzing
  • Driver fuzzing
  • Complex multi-process targets
Requirements:
  • Linux host
  • KVM support
  • Special 5.10 kernel for fuzzing
Building:
cd nyx_mode
./build_nyx_support.sh
See Nyx Mode Documentation for setup.

Coresight (ARM Hardware Tracing)

Coresight uses ARM’s hardware tracing (like Intel PT). Features:
  • Faster than QEMU for ARM
  • Hardware-assisted coverage
Limitations:
  • Only one process can be traced at a time (WIP)
  • Cannot run parallel instances
  • ARM only
Building:
cd coresight_mode
./build_coresight_support.sh
See Coresight Mode Documentation.

Fuzzing Shared Libraries

To fuzz a shared library without source:
1

Write a Harness

Create a small program that loads and calls the library:
#include <dlfcn.h>

int main(int argc, char **argv) {
  void *handle = dlopen("./libtarget.so", RTLD_NOW);
  void (*fuzz_func)(char *) = dlsym(handle, "process_input");
  
  fuzz_func(argv[1]);
  return 0;
}
2

Fuzz with QEMU or FRIDA

# QEMU mode with library instrumentation
AFL_INST_LIBS=1 afl-fuzz -Q -i input -o output -- ./harness @@

# Or FRIDA mode with specific ranges
AFL_FRIDA_INST_RANGES=libtarget.so afl-fuzz -O -i input -o output -- ./harness @@

Performance Comparison

MethodSpeed vs SourceProsCons
QEMU (basic)50%Easy to use, cross-platformSlower
QEMU (persistent)150-300%Very fast, no modificationsRequires setup
FRIDA (basic)55%macOS support, remote fuzzingSlightly slower
FRIDA (persistent)150-300%Very fast, mobile supportRequires setup
ZAFL90-95%Near-native speed, easyx86-64 only
RetroWrite85-95%Good speedRequires symbols, PIE
Dyninst65-85%FlexibleOften crashes
Unicorn10-30%Any architectureVery slow, requires scripting
DynamoRIO1-2%Cross-platformExtremely slow
Intel PT10-30%Hardware-assistedComplex setup, Intel only

Common Configurations

Desktop Application (x86-64 Linux)

# Try binary rewriters first
zafl-rewrite ./app ./app-instrumented
afl-fuzz -i input -o output -- ./app-instrumented @@

# Fallback: QEMU with persistence
export AFL_QEMU_PERSISTENT_ADDR=0x401234
afl-fuzz -Q -i input -o output -- ./app @@

Mobile App (Android/iOS)

# Use FRIDA remote mode
export AFL_FRIDA_REMOTE_ADDR=device-ip:27042
AFL_FRIDA_PERSISTENT_ADDR=0x12345 afl-fuzz -O -i input -o output -- ./app

Embedded Firmware (ARM)

# Use Unicorn mode with custom harness
cd unicorn_mode
python3 fuzz_firmware.py

Windows Application

# Use WINE+QEMU
AFL_WINE=1 afl-fuzz -Q -i input -o output -- wine ./app.exe @@

Troubleshooting

Binary Crashes Immediately

# Check if target runs normally
./target test_input

# Try without AFL
AFL_DEBUG=1 afl-fuzz -Q -i input -o output -- ./target @@

# Set AFL_ENTRYPOINT after initialization
export AFL_ENTRYPOINT=0x400a00

Low Stability

# Use AFL_ENTRYPOINT to skip variable initialization
export AFL_ENTRYPOINT=0x401000

# Increase timeout
afl-fuzz -Q -t 1000 -i input -o output -- ./target @@

Can’t Find Instrumentation Libraries

# Set LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/path/to/afl++:$LD_LIBRARY_PATH

# Or use AFL_PRELOAD
export AFL_PRELOAD=/path/to/libcmpcov.so

Best Practices

Always try binary rewriters first - ZAFL provides 90-95% source code speed without any setup complexity.
Use persistent mode when possible - The 3-8x speed improvement makes binary fuzzing competitive with source fuzzing.
Binary fuzzing uses more CPU and RAM than source fuzzing. Reduce the number of parallel instances accordingly.

Next Steps