libafl
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLibAFL
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
适用场景
| Fuzzer | Best For | Complexity |
|---|---|---|
| libFuzzer | Quick setup, single-threaded | Low |
| AFL++ | Multi-core, general purpose | Medium |
| LibAFL | Custom fuzzers, advanced features, research | High |
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.shCompile 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 clangOr install a specific version via apt.llvm.org:
bash
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 15Configure 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 | shInstall additional dependencies:
bash
apt install libssl-dev pkg-configFor 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-toolsVerification
验证安装
Build LibAFL to verify installation:
bash
cd LibAFL/libafl_libfuzzer_runtime
./build.sh构建LibAFL以验证安装:
bash
cd LibAFL/libafl_libfuzzer_runtime
./build.shShould produce libFuzzer.a
Should produce libFuzzer.a
undefinedundefinedWriting 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 fuzzRunning:
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:
- Observers - Collect execution feedback (coverage, timing)
- Feedback - Determine if inputs are interesting
- Objective - Define fuzzing goals (crashes, timeouts)
- State - Maintain corpus and metadata
- Mutators - Generate new inputs
- Scheduler - Select which inputs to mutate
- Executor - Run the target with inputs
LibAFL模糊测试器由模块化组件组成:
- 观测器(Observers) - 收集执行反馈(覆盖率、耗时)
- 反馈(Feedback) - 判断输入是否有价值
- 目标(Objective) - 定义模糊测试目标(崩溃、超时)
- 状态(State) - 维护测试语料库和元数据
- 变异器(Mutators) - 生成新输入
- 调度器(Scheduler) - 选择要变异的输入
- 执行器(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 fuzzCompiler Wrapper (Recommended)
编译器包装器(推荐)
Create a LibAFL compiler wrapper to handle instrumentation automatically.
Create :
src/bin/libafl_cc.rsrust
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 fuzzSee 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.rsrust
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-sanitizer 和 undefined-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 1000bash
./fuzz --cores 0-7 --input corpus/ --output crashes/ --timeout 1000Text User Interface (TUI)
文本用户界面(TUI)
Enable graphical statistics view:
bash
./fuzz -tui=1 corpus/启用图形化统计视图:
bash
./fuzz -tui=1 corpus/Interpreting Output
输出解读
| Output | Meaning |
|---|---|
| Number of interesting test cases found |
| Number of crashes/timeouts found |
| Total number of target invocations |
| Current execution throughput |
| Code coverage percentage |
| Number of parallel fuzzing processes |
The fuzzer emits two main event types:
- UserStats - Regular heartbeat with current statistics
- Testcase - New interesting input discovered
| 输出内容 | 含义 |
|---|---|
| 发现的有价值测试用例数量 |
| 发现的崩溃/超时数量 |
| 目标程序的总调用次数 |
| 当前执行吞吐量 |
| 代码覆盖率百分比 |
| 并行模糊测试进程数量 |
模糊测试器会输出两种主要事件类型:
- UserStats - 包含当前统计信息的定期心跳
- Testcase - 发现新的有价值输入
Advanced Usage
高级用法
Tips and Tricks
技巧与窍门
| Tip | Why It Helps |
|---|---|
Use | Continue fuzzing after first crash |
Use | Persist corpus across restarts |
Enable TUI with | Better visualization of progress |
| Use specific LLVM version | Avoid compatibility issues |
Set | Prevent linking errors |
| 技巧 | 优势 |
|---|---|
使用 | 首次崩溃后继续模糊测试 |
使用 | 重启后保留测试语料库 |
使用 | 更好地可视化测试进度 |
| 使用特定LLVM版本 | 避免兼容性问题 |
正确设置 | 防止链接错误 |
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 fuzzPerformance Tuning
性能调优
| Setting | Impact |
|---|---|
| Multi-core fuzzing | Linear speedup with cores |
| Faster but non-persistent |
| Balanced speed and persistence |
| Sanitizers | 2-5x slowdown, essential for bugs |
Optimization level | Balance between speed and coverage |
| 设置 | 影响 |
|---|---|
| 多核模糊测试 | 随核心数量线性提升速度 |
| 速度更快但不持久 |
| 平衡速度和持久性 |
| 启用Sanitizers | 速度下降2-5倍,但对发现bug至关重要 |
优化级别 | 在速度和覆盖率之间取得平衡 |
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-dev2. 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_cxx3. Build static library:
bash
./configure --enable-shared=no
make4. Get harness:
bash
curl -O https://raw.githubusercontent.com/glennrp/libpng/f8e5fa92b0e37ab597616f554bee254157998227/contrib/oss-fuzz/libpng_read_fuzzer.cc5. Link fuzzer:
bash
$CXX libpng_read_fuzzer.cc .libs/libpng16.a -lz -o fuzz6. Prepare seeds:
bash
mkdir seeds/
curl -o seeds/input.png https://raw.githubusercontent.com/glennrp/libpng/acfd50ae0ba3198ad734e5d4dec2b05341e50924/contrib/pngsuite/iftp1n3p08.png7. Get dictionary (optional):
bash
curl -O https://raw.githubusercontent.com/glennrp/libpng/2fff013a6935967960a5ae626fc21432807933dd/contrib/oss-fuzz/png.dict8. 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-dev2. 设置编译器包装器:
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_cxx3. 构建静态库:
bash
./configure --enable-shared=no
make4. 获取测试套:
bash
curl -O https://raw.githubusercontent.com/glennrp/libpng/f8e5fa92b0e37ab597616f554bee254157998227/contrib/oss-fuzz/libpng_read_fuzzer.cc5. 链接模糊测试器:
bash
$CXX libpng_read_fuzzer.cc .libs/libpng16.a -lz -o fuzz6. 准备种子输入:
bash
mkdir seeds/
curl -o seeds/input.png https://raw.githubusercontent.com/glennrp/libpng/acfd50ae0ba3198ad734e5d4dec2b05341e50924/contrib/pngsuite/iftp1n3p08.png7. 获取字典(可选):
bash
curl -O https://raw.githubusercontent.com/glennrp/libpng/2fff013a6935967960a5ae626fc21432807933dd/contrib/oss-fuzz/png.dict8. 开始模糊测试:
bash
./fuzz --input seeds/ --cores 0 -x png.dictExample: 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_programBuild 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 fuzzRun 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 0Troubleshooting
故障排除
| Problem | Cause | Solution |
|---|---|---|
| No coverage increases | Instrumentation failed | Verify compiler wrapper used, check for |
| Fuzzer won't start | Empty corpus with no interesting inputs | Provide seed inputs that trigger code paths |
Linker errors with | Runtime not linked | Use |
| LLVM version mismatch | LibAFL requires LLVM 15-18 | Install compatible LLVM version, set environment variables |
| Rust compilation fails | Outdated Rust or Cargo | Update Rust with |
| Slow fuzzing | Sanitizers enabled | Expected 2-5x slowdown, necessary for finding bugs |
| Environment variable interference | | Unset after building LibAFL project |
| Cannot attach debugger | Multi-process fuzzing | Run in single-process mode (see Debugging section) |
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 覆盖率无提升 | 插桩失败 | 确认使用了编译器包装器,检查是否存在 |
| 模糊测试器无法启动 | 测试语料库为空且无有价值输入 | 提供可触发代码路径的种子输入 |
链接 | 未链接运行时库 | 使用 |
| LLVM版本不匹配 | LibAFL需要LLVM 15-18 | 安装兼容的LLVM版本,设置环境变量 |
| Rust编译失败 | Rust或Cargo版本过旧 | 使用 |
| 模糊测试速度慢 | 启用了Sanitizers | 预期速度下降2-5倍,这是发现bug所必需的 |
| 环境变量干扰 | 设置了 | 构建LibAFL项目后取消设置这些变量 |
| 无法附加调试器 | 使用了多进程模糊测试 | 以单进程模式运行(请参阅调试部分) |
Related Skills
相关技术
Technique Skills
技术文档
| Skill | Use Case |
|---|---|
| fuzz-harness-writing | Detailed guidance on writing effective harnesses |
| address-sanitizer | Memory error detection during fuzzing |
| undefined-behavior-sanitizer | Undefined behavior detection |
| coverage-analysis | Measuring and improving code coverage |
| fuzzing-corpus | Building and managing seed corpora |
| fuzzing-dictionaries | Creating dictionaries for format-aware fuzzing |
| 技术 | 适用场景 |
|---|---|
| fuzz-harness-writing | 编写高效测试套的详细指南 |
| address-sanitizer | 模糊测试期间检测内存错误 |
| undefined-behavior-sanitizer | 检测未定义行为 |
| coverage-analysis | 测量和提升代码覆盖率 |
| fuzzing-corpus | 构建和管理种子语料库 |
| fuzzing-dictionaries | 创建格式感知模糊测试的字典 |
Related Fuzzers
相关模糊测试器
| Skill | When to Consider |
|---|---|
| libfuzzer | Simpler setup, don't need LibAFL's advanced features |
| aflpp | Multi-core fuzzing without custom fuzzer development |
| cargo-fuzz | Fuzzing Rust projects with less setup |
| 技术 | 适用场景 |
|---|---|
| libfuzzer | 搭建简单,不需要LibAFL的高级功能 |
| aflpp | 多核模糊测试,无需开发自定义模糊测试器 |
| cargo-fuzz | 以较少配置对Rust项目进行模糊测试 |
Resources
资源
Official Documentation
官方文档
- LibAFL Book - Official handbook with comprehensive documentation
- LibAFL GitHub - Source code and examples
- LibAFL API Documentation - Rust API reference
- LibAFL Book - 官方手册,包含全面文档
- LibAFL GitHub - 源代码和示例
- LibAFL API Documentation - Rust API参考
Examples and Tutorials
示例与教程
- LibAFL Examples - Collection of example fuzzers
- cargo-fuzz with LibAFL - Using LibAFL as cargo-fuzz backend
- Testing Handbook LibAFL Examples - Complete working examples from this handbook
- LibAFL Examples - 示例模糊测试器集合
- cargo-fuzz with LibAFL - 将LibAFL作为cargo-fuzz后端使用
- Testing Handbook LibAFL Examples - 本手册中的完整可用示例