libafl

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

LibAFL

LibAFL

LibAFL is a modular fuzzing library that implements features from AFL-based fuzzers like AFL++. Unlike traditional fuzzers, LibAFL provides all functionality in a modular and customizable way as a Rust library. It can be used as a drop-in replacement for libFuzzer or as a library to build custom fuzzers from scratch.
LibAFL 是一个模块化的模糊测试库,实现了基于AFL的模糊测试器(如AFL++)的功能。与传统模糊测试器不同,LibAFL 作为Rust库以模块化、可定制的方式提供所有功能。它可以作为libFuzzer的直接替代品,也可以作为从头构建自定义模糊测试器的库。

When to Use

适用场景

FuzzerBest ForComplexity
libFuzzerQuick setup, single-threadedLow
AFL++Multi-core, general purposeMedium
LibAFLCustom fuzzers, advanced features, researchHigh
Choose LibAFL when:
  • You need custom mutation strategies or feedback mechanisms
  • Standard fuzzers don't support your target architecture
  • You want to implement novel fuzzing techniques
  • You need fine-grained control over fuzzing components
  • You're conducting fuzzing research
模糊测试器适用场景复杂度
libFuzzer快速搭建、单线程
AFL++多核、通用场景
LibAFL自定义模糊测试器、高级功能、研究
选择LibAFL的场景:
  • 你需要自定义变异策略或反馈机制
  • 标准模糊测试器不支持你的目标架构
  • 你想要实现新颖的模糊测试技术
  • 你需要对模糊测试组件进行细粒度控制
  • 你正在进行模糊测试研究

Quick Start

快速开始

LibAFL can be used as a drop-in replacement for libFuzzer with minimal setup:
c
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Call your code with fuzzer-provided data
    my_function(data, size);
    return 0;
}
Build LibAFL's libFuzzer compatibility layer:
bash
git clone https://github.com/AFLplusplus/LibAFL
cd LibAFL/libafl_libfuzzer_runtime
./build.sh
Compile and run:
bash
clang++ -DNO_MAIN -g -O2 -fsanitize=fuzzer-no-link libFuzzer.a harness.cc main.cc -o fuzz
./fuzz corpus/
LibAFL 可以作为libFuzzer的直接替代品,只需极少的配置:
c
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Call your code with fuzzer-provided data
    my_function(data, size);
    return 0;
}
构建LibAFL的libFuzzer兼容层:
bash
git clone https://github.com/AFLplusplus/LibAFL
cd LibAFL/libafl_libfuzzer_runtime
./build.sh
编译并运行:
bash
clang++ -DNO_MAIN -g -O2 -fsanitize=fuzzer-no-link libFuzzer.a harness.cc main.cc -o fuzz
./fuzz corpus/

Installation

安装

Prerequisites

前置依赖

  • Clang/LLVM 15-18
  • Rust (via rustup)
  • Additional system dependencies
  • Clang/LLVM 15-18
  • Rust(通过rustup安装)
  • 其他系统依赖

Linux/macOS

Linux/macOS

Install Clang:
bash
apt install clang
Or install a specific version via apt.llvm.org:
bash
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 15
Configure environment for Rust:
bash
export RUSTFLAGS="-C linker=/usr/bin/clang-15"
export CC="clang-15"
export CXX="clang++-15"
Install Rust:
bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Install additional dependencies:
bash
apt install libssl-dev pkg-config
For libFuzzer compatibility mode, install nightly Rust:
bash
rustup toolchain install nightly --component llvm-tools
安装Clang:
bash
apt install clang
或者通过apt.llvm.org安装特定版本:
bash
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 15
配置Rust环境:
bash
export RUSTFLAGS="-C linker=/usr/bin/clang-15"
export CC="clang-15"
export CXX="clang++-15"
安装Rust:
bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
安装额外依赖:
bash
apt install libssl-dev pkg-config
若要使用libFuzzer兼容模式,安装nightly版本的Rust:
bash
rustup toolchain install nightly --component llvm-tools

Verification

验证安装

Build LibAFL to verify installation:
bash
cd LibAFL/libafl_libfuzzer_runtime
./build.sh
构建LibAFL以验证安装:
bash
cd LibAFL/libafl_libfuzzer_runtime
./build.sh

Should produce libFuzzer.a

Should produce libFuzzer.a

undefined
undefined

Writing a Harness

编写测试套(Harness)

LibAFL harnesses follow the same pattern as libFuzzer when using drop-in replacement mode:
c
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Your fuzzing target code here
    return 0;
}
When building custom fuzzers with LibAFL as a Rust library, harness logic is integrated directly into the fuzzer. See the "Writing a Custom Fuzzer" section below for the full pattern.
See Also: For detailed harness writing techniques, see the harness-writing technique skill.
当使用直接替换模式时,LibAFL的测试套遵循与libFuzzer相同的模式:
c
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Your fuzzing target code here
    return 0;
}
当将LibAFL作为Rust库构建自定义模糊测试器时,测试套逻辑直接集成到模糊测试器中。有关完整模式,请参阅下面的"编写自定义模糊测试器"部分。
另请参阅: 有关详细的测试套编写技术,请查看 harness-writing 技术文档。

Usage Modes

使用模式

LibAFL supports two primary usage modes:
LibAFL支持两种主要使用模式:

1. libFuzzer Drop-in Replacement

1. libFuzzer直接替换

Use LibAFL as a replacement for libFuzzer with existing harnesses.
Compilation:
bash
clang++ -DNO_MAIN -g -O2 -fsanitize=fuzzer-no-link libFuzzer.a harness.cc main.cc -o fuzz
Running:
bash
./fuzz corpus/
Recommended for long campaigns:
bash
./fuzz -fork=1 -ignore_crashes=1 corpus/
将LibAFL作为现有测试套的libFuzzer替代品使用。
编译:
bash
clang++ -DNO_MAIN -g -O2 -fsanitize=fuzzer-no-link libFuzzer.a harness.cc main.cc -o fuzz
运行:
bash
./fuzz corpus/
推荐用于长期测试任务:
bash
./fuzz -fork=1 -ignore_crashes=1 corpus/

2. Custom Fuzzer as Rust Library

2. 作为Rust库构建自定义模糊测试器

Build a fully customized fuzzer using LibAFL components.
Create project:
bash
cargo init --lib my_fuzzer
cd my_fuzzer
cargo add libafl@0.13 libafl_targets@0.13 libafl_bolts@0.13 libafl_cc@0.13 \
  --features "libafl_targets@0.13/libfuzzer,libafl_targets@0.13/sancov_pcguard_hitcounts"
Configure Cargo.toml:
toml
[lib]
crate-type = ["staticlib"]
使用LibAFL组件构建完全自定义的模糊测试器。
创建项目:
bash
cargo init --lib my_fuzzer
cd my_fuzzer
cargo add libafl@0.13 libafl_targets@0.13 libafl_bolts@0.13 libafl_cc@0.13 \
  --features "libafl_targets@0.13/libfuzzer,libafl_targets@0.13/sancov_pcguard_hitcounts"
配置Cargo.toml:
toml
[lib]
crate-type = ["staticlib"]

Writing a Custom Fuzzer

编写自定义模糊测试器

See Also: For detailed harness writing techniques, patterns for handling complex inputs, and advanced strategies, see the fuzz-harness-writing technique skill.
另请参阅: 有关详细的测试套编写技术、处理复杂输入的模式以及高级策略,请查看 fuzz-harness-writing 技术文档。

Fuzzer Components

模糊测试器组件

A LibAFL fuzzer consists of modular components:
  1. Observers - Collect execution feedback (coverage, timing)
  2. Feedback - Determine if inputs are interesting
  3. Objective - Define fuzzing goals (crashes, timeouts)
  4. State - Maintain corpus and metadata
  5. Mutators - Generate new inputs
  6. Scheduler - Select which inputs to mutate
  7. Executor - Run the target with inputs
LibAFL模糊测试器由模块化组件组成:
  1. 观测器(Observers) - 收集执行反馈(覆盖率、耗时)
  2. 反馈(Feedback) - 判断输入是否有价值
  3. 目标(Objective) - 定义模糊测试目标(崩溃、超时)
  4. 状态(State) - 维护测试语料库和元数据
  5. 变异器(Mutators) - 生成新输入
  6. 调度器(Scheduler) - 选择要变异的输入
  7. 执行器(Executor) - 使用输入运行目标程序

Basic Fuzzer Structure

基础模糊测试器结构

rust
use libafl::prelude::*;
use libafl_bolts::prelude::*;
use libafl_targets::{libfuzzer_test_one_input, std_edges_map_observer};

#[no_mangle]
pub extern "C" fn libafl_main() {
    let mut run_client = |state: Option<_>, mut restarting_mgr, _core_id| {
        // 1. Setup observers
        let edges_observer = HitcountsMapObserver::new(
            unsafe { std_edges_map_observer("edges") }
        ).track_indices();
        let time_observer = TimeObserver::new("time");

        // 2. Define feedback
        let mut feedback = feedback_or!(
            MaxMapFeedback::new(&edges_observer),
            TimeFeedback::new(&time_observer)
        );

        // 3. Define objective
        let mut objective = feedback_or_fast!(
            CrashFeedback::new(),
            TimeoutFeedback::new()
        );

        // 4. Create or restore state
        let mut state = state.unwrap_or_else(|| {
            StdState::new(
                StdRand::new(),
                InMemoryCorpus::new(),
                OnDiskCorpus::new(&output_dir).unwrap(),
                &mut feedback,
                &mut objective,
            ).unwrap()
        });

        // 5. Setup mutator
        let mutator = StdScheduledMutator::new(havoc_mutations());
        let mut stages = tuple_list!(StdMutationalStage::new(mutator));

        // 6. Setup scheduler
        let scheduler = IndexesLenTimeMinimizerScheduler::new(
            &edges_observer,
            QueueScheduler::new()
        );

        // 7. Create fuzzer
        let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

        // 8. Define harness
        let mut harness = |input: &BytesInput| {
            let buf = input.target_bytes().as_slice();
            libfuzzer_test_one_input(buf);
            ExitKind::Ok
        };

        // 9. Setup executor
        let mut executor = InProcessExecutor::with_timeout(
            &mut harness,
            tuple_list!(edges_observer, time_observer),
            &mut fuzzer,
            &mut state,
            &mut restarting_mgr,
            timeout,
        )?;

        // 10. Load initial inputs
        if state.must_load_initial_inputs() {
            state.load_initial_inputs(
                &mut fuzzer,
                &mut executor,
                &mut restarting_mgr,
                &input_dir
            )?;
        }

        // 11. Start fuzzing
        fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut restarting_mgr)?;
        Ok(())
    };

    // Launch fuzzer
    Launcher::builder()
        .run_client(&mut run_client)
        .cores(&cores)
        .build()
        .launch()
        .unwrap();
}
rust
use libafl::prelude::*;
use libafl_bolts::prelude::*;
use libafl_targets::{libfuzzer_test_one_input, std_edges_map_observer};

#[no_mangle]
pub extern "C" fn libafl_main() {
    let mut run_client = |state: Option<_>, mut restarting_mgr, _core_id| {
        // 1. Setup observers
        let edges_observer = HitcountsMapObserver::new(
            unsafe { std_edges_map_observer("edges") }
        ).track_indices();
        let time_observer = TimeObserver::new("time");

        // 2. Define feedback
        let mut feedback = feedback_or!(
            MaxMapFeedback::new(&edges_observer),
            TimeFeedback::new(&time_observer)
        );

        // 3. Define objective
        let mut objective = feedback_or_fast!(
            CrashFeedback::new(),
            TimeoutFeedback::new()
        );

        // 4. Create or restore state
        let mut state = state.unwrap_or_else(|| {
            StdState::new(
                StdRand::new(),
                InMemoryCorpus::new(),
                OnDiskCorpus::new(&output_dir).unwrap(),
                &mut feedback,
                &mut objective,
            ).unwrap()
        });

        // 5. Setup mutator
        let mutator = StdScheduledMutator::new(havoc_mutations());
        let mut stages = tuple_list!(StdMutationalStage::new(mutator));

        // 6. Setup scheduler
        let scheduler = IndexesLenTimeMinimizerScheduler::new(
            &edges_observer,
            QueueScheduler::new()
        );

        // 7. Create fuzzer
        let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

        // 8. Define harness
        let mut harness = |input: &BytesInput| {
            let buf = input.target_bytes().as_slice();
            libfuzzer_test_one_input(buf);
            ExitKind::Ok
        };

        // 9. Setup executor
        let mut executor = InProcessExecutor::with_timeout(
            &mut harness,
            tuple_list!(edges_observer, time_observer),
            &mut fuzzer,
            &mut state,
            &mut restarting_mgr,
            timeout,
        )?;

        // 10. Load initial inputs
        if state.must_load_initial_inputs() {
            state.load_initial_inputs(
                &mut fuzzer,
                &mut executor,
                &mut restarting_mgr,
                &input_dir
            )?;
        }

        // 11. Start fuzzing
        fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut restarting_mgr)?;
        Ok(())
    };

    // Launch fuzzer
    Launcher::builder()
        .run_client(&mut run_client)
        .cores(&cores)
        .build()
        .launch()
        .unwrap();
}

Compilation

编译

Verbose Mode

详细模式

Manually specify all instrumentation flags:
bash
clang++-15 -DNO_MAIN -g -O2 \
  -fsanitize-coverage=trace-pc-guard \
  -fsanitize=address \
  -Wl,--whole-archive target/release/libmy_fuzzer.a -Wl,--no-whole-archive \
  main.cc harness.cc -o fuzz
手动指定所有插桩标志:
bash
clang++-15 -DNO_MAIN -g -O2 \
  -fsanitize-coverage=trace-pc-guard \
  -fsanitize=address \
  -Wl,--whole-archive target/release/libmy_fuzzer.a -Wl,--no-whole-archive \
  main.cc harness.cc -o fuzz

Compiler Wrapper (Recommended)

编译器包装器(推荐)

Create a LibAFL compiler wrapper to handle instrumentation automatically.
Create
src/bin/libafl_cc.rs
:
rust
use libafl_cc::{ClangWrapper, CompilerWrapper, Configuration, ToolWrapper};

pub fn main() {
    let args: Vec<String> = env::args().collect();
    let mut cc = ClangWrapper::new();
    cc.cpp(is_cpp)
      .parse_args(&args)
      .link_staticlib(&dir, "my_fuzzer")
      .add_args(&Configuration::GenerateCoverageMap.to_flags().unwrap())
      .add_args(&Configuration::AddressSanitizer.to_flags().unwrap())
      .run()
      .unwrap();
}
Compile and use:
bash
cargo build --release
target/release/libafl_cxx -DNO_MAIN -g -O2 main.cc harness.cc -o fuzz
See Also: For detailed sanitizer configuration, common issues, and advanced flags, see the address-sanitizer and undefined-behavior-sanitizer technique skills.
创建LibAFL编译器包装器以自动处理插桩。
创建
src/bin/libafl_cc.rs
rust
use libafl_cc::{ClangWrapper, CompilerWrapper, Configuration, ToolWrapper};

pub fn main() {
    let args: Vec<String> = env::args().collect();
    let mut cc = ClangWrapper::new();
    cc.cpp(is_cpp)
      .parse_args(&args)
      .link_staticlib(&dir, "my_fuzzer")
      .add_args(&Configuration::GenerateCoverageMap.to_flags().unwrap())
      .add_args(&Configuration::AddressSanitizer.to_flags().unwrap())
      .run()
      .unwrap();
}
编译并使用:
bash
cargo build --release
target/release/libafl_cxx -DNO_MAIN -g -O2 main.cc harness.cc -o fuzz
另请参阅: 有关详细的 sanitizer 配置、常见问题和高级标志,请查看 address-sanitizerundefined-behavior-sanitizer 技术文档。

Running Campaigns

运行测试任务

Basic Run

基础运行

bash
./fuzz --cores 0 --input corpus/
bash
./fuzz --cores 0 --input corpus/

Multi-Core Fuzzing

多核模糊测试

bash
./fuzz --cores 0,8-15 --input corpus/
This runs 9 clients: one on core 0, and 8 on cores 8-15.
bash
./fuzz --cores 0,8-15 --input corpus/
此命令将运行9个客户端:1个在核心0上,8个在核心8-15上。

With Options

带参数运行

bash
./fuzz --cores 0-7 --input corpus/ --output crashes/ --timeout 1000
bash
./fuzz --cores 0-7 --input corpus/ --output crashes/ --timeout 1000

Text User Interface (TUI)

文本用户界面(TUI)

Enable graphical statistics view:
bash
./fuzz -tui=1 corpus/
启用图形化统计视图:
bash
./fuzz -tui=1 corpus/

Interpreting Output

输出解读

OutputMeaning
corpus: N
Number of interesting test cases found
objectives: N
Number of crashes/timeouts found
executions: N
Total number of target invocations
exec/sec: N
Current execution throughput
edges: X%
Code coverage percentage
clients: N
Number of parallel fuzzing processes
The fuzzer emits two main event types:
  • UserStats - Regular heartbeat with current statistics
  • Testcase - New interesting input discovered
输出内容含义
corpus: N
发现的有价值测试用例数量
objectives: N
发现的崩溃/超时数量
executions: N
目标程序的总调用次数
exec/sec: N
当前执行吞吐量
edges: X%
代码覆盖率百分比
clients: N
并行模糊测试进程数量
模糊测试器会输出两种主要事件类型:
  • UserStats - 包含当前统计信息的定期心跳
  • Testcase - 发现新的有价值输入

Advanced Usage

高级用法

Tips and Tricks

技巧与窍门

TipWhy It Helps
Use
-fork=1 -ignore_crashes=1
Continue fuzzing after first crash
Use
InMemoryOnDiskCorpus
Persist corpus across restarts
Enable TUI with
-tui=1
Better visualization of progress
Use specific LLVM versionAvoid compatibility issues
Set
RUSTFLAGS
correctly
Prevent linking errors
技巧优势
使用
-fork=1 -ignore_crashes=1
首次崩溃后继续模糊测试
使用
InMemoryOnDiskCorpus
重启后保留测试语料库
使用
-tui=1
启用TUI
更好地可视化测试进度
使用特定LLVM版本避免兼容性问题
正确设置
RUSTFLAGS
防止链接错误

Crash Deduplication

崩溃去重

Avoid storing duplicate crashes from the same bug:
Add backtrace observer:
rust
let backtrace_observer = BacktraceObserver::owned(
    "BacktraceObserver",
    libafl::observers::HarnessType::InProcess
);
Update executor:
rust
let mut executor = InProcessExecutor::with_timeout(
    &mut harness,
    tuple_list!(edges_observer, time_observer, backtrace_observer),
    &mut fuzzer,
    &mut state,
    &mut restarting_mgr,
    timeout,
)?;
Update objective with hash feedback:
rust
let mut objective = feedback_and!(
    feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()),
    NewHashFeedback::new(&backtrace_observer)
);
This ensures only crashes with unique backtraces are saved.
避免存储同一bug导致的重复崩溃:
添加回溯观测器:
rust
let backtrace_observer = BacktraceObserver::owned(
    "BacktraceObserver",
    libafl::observers::HarnessType::InProcess
);
更新执行器:
rust
let mut executor = InProcessExecutor::with_timeout(
    &mut harness,
    tuple_list!(edges_observer, time_observer, backtrace_observer),
    &mut fuzzer,
    &mut state,
    &mut restarting_mgr,
    timeout,
)?;
使用哈希反馈更新目标:
rust
let mut objective = feedback_and!(
    feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()),
    NewHashFeedback::new(&backtrace_observer)
);
这样可以确保只保存具有唯一回溯信息的崩溃。

Dictionary Fuzzing

字典模糊测试

Use dictionaries to guide fuzzing toward specific tokens:
Add tokens from file:
rust
let mut tokens = Tokens::new();
if let Some(tokenfile) = &tokenfile {
    tokens.add_from_file(tokenfile)?;
}
state.add_metadata(tokens);
Update mutator:
rust
let mutator = StdScheduledMutator::new(
    havoc_mutations().merge(tokens_mutations())
);
Hard-coded tokens example (PNG):
rust
state.add_metadata(Tokens::from([
    vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header
    "IHDR".as_bytes().to_vec(),
    "IDAT".as_bytes().to_vec(),
    "PLTE".as_bytes().to_vec(),
    "IEND".as_bytes().to_vec(),
]));
See Also: For detailed dictionary creation strategies and format-specific dictionaries, see the fuzzing-dictionaries technique skill.
使用字典引导模糊测试朝向特定令牌:
从文件添加令牌:
rust
let mut tokens = Tokens::new();
if let Some(tokenfile) = &tokenfile {
    tokens.add_from_file(tokenfile)?;
}
state.add_metadata(tokens);
更新变异器:
rust
let mutator = StdScheduledMutator::new(
    havoc_mutations().merge(tokens_mutations())
);
硬编码令牌示例(PNG):
rust
state.add_metadata(Tokens::from([
    vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header
    "IHDR".as_bytes().to_vec(),
    "IDAT".as_bytes().to_vec(),
    "PLTE".as_bytes().to_vec(),
    "IEND".as_bytes().to_vec(),
]));
另请参阅: 有关详细的字典创建策略和特定格式的字典,请查看 fuzzing-dictionaries 技术文档。

Auto Tokens

自动令牌

Automatically extract magic values and checksums from the program:
Enable in compiler wrapper:
rust
cc.add_pass(LLVMPasses::AutoTokens)
Load auto tokens in fuzzer:
rust
tokens += libafl_targets::autotokens()?;
Verify tokens section:
bash
echo "p (uint8_t *)__token_start" | gdb fuzz
从程序中自动提取魔术值和校验和:
在编译器包装器中启用:
rust
cc.add_pass(LLVMPasses::AutoTokens)
在模糊测试器中加载自动令牌:
rust
tokens += libafl_targets::autotokens()?;
验证令牌部分:
bash
echo "p (uint8_t *)__token_start" | gdb fuzz

Performance Tuning

性能调优

SettingImpact
Multi-core fuzzingLinear speedup with cores
InMemoryCorpus
Faster but non-persistent
InMemoryOnDiskCorpus
Balanced speed and persistence
Sanitizers2-5x slowdown, essential for bugs
Optimization level
-O2
Balance between speed and coverage
设置影响
多核模糊测试随核心数量线性提升速度
InMemoryCorpus
速度更快但不持久
InMemoryOnDiskCorpus
平衡速度和持久性
启用Sanitizers速度下降2-5倍,但对发现bug至关重要
优化级别
-O2
在速度和覆盖率之间取得平衡

Debugging Fuzzer

调试模糊测试器

Run fuzzer in single-process mode for easier debugging:
rust
// Replace launcher with direct call
run_client(None, SimpleEventManager::new(monitor), 0).unwrap();

// Comment out:
// Launcher::builder()
//     .run_client(&mut run_client)
//     ...
//     .launch()
Then debug with GDB:
bash
gdb --args ./fuzz --cores 0 --input corpus/
在单进程模式下运行模糊测试器以便于调试:
rust
// Replace launcher with direct call
run_client(None, SimpleEventManager::new(monitor), 0).unwrap();

// Comment out:
// Launcher::builder()
//     .run_client(&mut run_client)
//     ...
//     .launch()
然后使用GDB调试:
bash
gdb --args ./fuzz --cores 0 --input corpus/

Real-World Examples

实际示例

Example: libpng

示例:libpng

Fuzzing libpng using LibAFL:
1. Get source code:
bash
curl -L -O https://downloads.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
tar xf libpng-1.6.37.tar.xz
cd libpng-1.6.37/
apt install zlib1g-dev
2. Set compiler wrapper:
bash
export FUZZER_CARGO_DIR="/path/to/libafl/project"
export CC=$FUZZER_CARGO_DIR/target/release/libafl_cc
export CXX=$FUZZER_CARGO_DIR/target/release/libafl_cxx
3. Build static library:
bash
./configure --enable-shared=no
make
4. Get harness:
bash
curl -O https://raw.githubusercontent.com/glennrp/libpng/f8e5fa92b0e37ab597616f554bee254157998227/contrib/oss-fuzz/libpng_read_fuzzer.cc
5. Link fuzzer:
bash
$CXX libpng_read_fuzzer.cc .libs/libpng16.a -lz -o fuzz
6. Prepare seeds:
bash
mkdir seeds/
curl -o seeds/input.png https://raw.githubusercontent.com/glennrp/libpng/acfd50ae0ba3198ad734e5d4dec2b05341e50924/contrib/pngsuite/iftp1n3p08.png
7. Get dictionary (optional):
bash
curl -O https://raw.githubusercontent.com/glennrp/libpng/2fff013a6935967960a5ae626fc21432807933dd/contrib/oss-fuzz/png.dict
8. Start fuzzing:
bash
./fuzz --input seeds/ --cores 0 -x png.dict
使用LibAFL对libpng进行模糊测试:
1. 获取源代码:
bash
curl -L -O https://downloads.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
tar xf libpng-1.6.37.tar.xz
cd libpng-1.6.37/
apt install zlib1g-dev
2. 设置编译器包装器:
bash
export FUZZER_CARGO_DIR="/path/to/libafl/project"
export CC=$FUZZER_CARGO_DIR/target/release/libafl_cc
export CXX=$FUZZER_CARGO_DIR/target/release/libafl_cxx
3. 构建静态库:
bash
./configure --enable-shared=no
make
4. 获取测试套:
bash
curl -O https://raw.githubusercontent.com/glennrp/libpng/f8e5fa92b0e37ab597616f554bee254157998227/contrib/oss-fuzz/libpng_read_fuzzer.cc
5. 链接模糊测试器:
bash
$CXX libpng_read_fuzzer.cc .libs/libpng16.a -lz -o fuzz
6. 准备种子输入:
bash
mkdir seeds/
curl -o seeds/input.png https://raw.githubusercontent.com/glennrp/libpng/acfd50ae0ba3198ad734e5d4dec2b05341e50924/contrib/pngsuite/iftp1n3p08.png
7. 获取字典(可选):
bash
curl -O https://raw.githubusercontent.com/glennrp/libpng/2fff013a6935967960a5ae626fc21432807933dd/contrib/oss-fuzz/png.dict
8. 开始模糊测试:
bash
./fuzz --input seeds/ --cores 0 -x png.dict

Example: CMake Project

示例:CMake项目

Integrate LibAFL with CMake build system:
CMakeLists.txt:
cmake
project(BuggyProgram)
cmake_minimum_required(VERSION 3.0)

add_executable(buggy_program main.cc)

add_executable(fuzz main.cc harness.cc)
target_compile_definitions(fuzz PRIVATE NO_MAIN=1)
target_compile_options(fuzz PRIVATE -g -O2)
Build non-instrumented binary:
bash
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ .
cmake --build . --target buggy_program
Build fuzzer:
bash
export FUZZER_CARGO_DIR="/path/to/libafl/project"
cmake -DCMAKE_C_COMPILER=$FUZZER_CARGO_DIR/target/release/libafl_cc \
      -DCMAKE_CXX_COMPILER=$FUZZER_CARGO_DIR/target/release/libafl_cxx .
cmake --build . --target fuzz
Run fuzzing:
bash
./fuzz --input seeds/ --cores 0
将LibAFL与CMake构建系统集成:
CMakeLists.txt:
cmake
project(BuggyProgram)
cmake_minimum_required(VERSION 3.0)

add_executable(buggy_program main.cc)

add_executable(fuzz main.cc harness.cc)
target_compile_definitions(fuzz PRIVATE NO_MAIN=1)
target_compile_options(fuzz PRIVATE -g -O2)
构建非插桩二进制:
bash
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ .
cmake --build . --target buggy_program
构建模糊测试器:
bash
export FUZZER_CARGO_DIR="/path/to/libafl/project"
cmake -DCMAKE_C_COMPILER=$FUZZER_CARGO_DIR/target/release/libafl_cc \
      -DCMAKE_CXX_COMPILER=$FUZZER_CARGO_DIR/target/release/libafl_cxx .
cmake --build . --target fuzz
运行模糊测试:
bash
./fuzz --input seeds/ --cores 0

Troubleshooting

故障排除

ProblemCauseSolution
No coverage increasesInstrumentation failedVerify compiler wrapper used, check for
-fsanitize-coverage
Fuzzer won't startEmpty corpus with no interesting inputsProvide seed inputs that trigger code paths
Linker errors with
libafl_main
Runtime not linkedUse
-Wl,--whole-archive
or
-u libafl_main
LLVM version mismatchLibAFL requires LLVM 15-18Install compatible LLVM version, set environment variables
Rust compilation failsOutdated Rust or CargoUpdate Rust with
rustup update
Slow fuzzingSanitizers enabledExpected 2-5x slowdown, necessary for finding bugs
Environment variable interference
CC
,
CXX
,
RUSTFLAGS
set
Unset after building LibAFL project
Cannot attach debuggerMulti-process fuzzingRun in single-process mode (see Debugging section)
问题原因解决方案
覆盖率无提升插桩失败确认使用了编译器包装器,检查是否存在
-fsanitize-coverage
标志
模糊测试器无法启动测试语料库为空且无有价值输入提供可触发代码路径的种子输入
链接
libafl_main
时出错
未链接运行时库使用
-Wl,--whole-archive
-u libafl_main
LLVM版本不匹配LibAFL需要LLVM 15-18安装兼容的LLVM版本,设置环境变量
Rust编译失败Rust或Cargo版本过旧使用
rustup update
更新Rust
模糊测试速度慢启用了Sanitizers预期速度下降2-5倍,这是发现bug所必需的
环境变量干扰设置了
CC
CXX
RUSTFLAGS
构建LibAFL项目后取消设置这些变量
无法附加调试器使用了多进程模糊测试以单进程模式运行(请参阅调试部分)

Related Skills

相关技术

Technique Skills

技术文档

SkillUse Case
fuzz-harness-writingDetailed guidance on writing effective harnesses
address-sanitizerMemory error detection during fuzzing
undefined-behavior-sanitizerUndefined behavior detection
coverage-analysisMeasuring and improving code coverage
fuzzing-corpusBuilding and managing seed corpora
fuzzing-dictionariesCreating dictionaries for format-aware fuzzing
技术适用场景
fuzz-harness-writing编写高效测试套的详细指南
address-sanitizer模糊测试期间检测内存错误
undefined-behavior-sanitizer检测未定义行为
coverage-analysis测量和提升代码覆盖率
fuzzing-corpus构建和管理种子语料库
fuzzing-dictionaries创建格式感知模糊测试的字典

Related Fuzzers

相关模糊测试器

SkillWhen to Consider
libfuzzerSimpler setup, don't need LibAFL's advanced features
aflppMulti-core fuzzing without custom fuzzer development
cargo-fuzzFuzzing Rust projects with less setup
技术适用场景
libfuzzer搭建简单,不需要LibAFL的高级功能
aflpp多核模糊测试,无需开发自定义模糊测试器
cargo-fuzz以较少配置对Rust项目进行模糊测试

Resources

资源

Official Documentation

官方文档

Examples and Tutorials

示例与教程