libafl by trailofbits/skills
npx skills add https://github.com/trailofbits/skills --skill libaflLibAFL 是一个模块化的模糊测试库,实现了基于 AFL 的模糊测试器(如 AFL++)的功能。与传统模糊测试器不同,LibAFL 以 Rust 库的形式,以模块化和可定制的方式提供所有功能。它可以作为 libFuzzer 的直接替代品使用,也可以作为库从头构建自定义模糊测试器。
| 模糊测试器 | 最适合 | 复杂度 |
|---|---|---|
| libFuzzer | 快速设置,单线程 | 低 |
| AFL++ | 多核,通用目的 | 中 |
| LibAFL | 自定义模糊测试器,高级功能,研究 | 高 |
在以下情况下选择 LibAFL:
LibAFL 可以作为 libFuzzer 的直接替代品使用,只需最少的设置:
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// 使用模糊测试器提供的数据调用你的代码
my_function(data, size);
return 0;
}
构建 LibAFL 的 libFuzzer 兼容层:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
git clone https://github.com/AFLplusplus/LibAFL
cd LibAFL/libafl_libfuzzer_runtime
./build.sh
编译并运行:
clang++ -DNO_MAIN -g -O2 -fsanitize=fuzzer-no-link libFuzzer.a harness.cc main.cc -o fuzz
./fuzz corpus/
安装 Clang:
apt install clang
或者通过 apt.llvm.org 安装特定版本:
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 15
为 Rust 配置环境:
export RUSTFLAGS="-C linker=/usr/bin/clang-15"
export CC="clang-15"
export CXX="clang++-15"
安装 Rust:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
安装额外的依赖项:
apt install libssl-dev pkg-config
对于 libFuzzer 兼容模式,安装 nightly Rust:
rustup toolchain install nightly --component llvm-tools
构建 LibAFL 以验证安装:
cd LibAFL/libafl_libfuzzer_runtime
./build.sh
# 应该生成 libFuzzer.a
在使用直接替代模式时,LibAFL 测试套件遵循与 libFuzzer 相同的模式:
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// 你的模糊测试目标代码放在这里
return 0;
}
当将 LibAFL 作为 Rust 库构建自定义模糊测试器时,测试套件逻辑直接集成到模糊测试器中。有关完整模式,请参阅下面的“编写自定义模糊测试器”部分。
另请参阅: 有关详细的测试套件编写技术,请参阅 harness-writing 技术技能。
LibAFL 支持两种主要使用模式:
将 LibAFL 作为 libFuzzer 的替代品,用于现有的测试套件。
编译:
clang++ -DNO_MAIN -g -O2 -fsanitize=fuzzer-no-link libFuzzer.a harness.cc main.cc -o fuzz
运行:
./fuzz corpus/
对于长期活动推荐:
./fuzz -fork=1 -ignore_crashes=1 corpus/
使用 LibAFL 组件构建完全自定义的模糊测试器。
创建项目:
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:
[lib]
crate-type = ["staticlib"]
另请参阅: 有关详细的测试套件编写技术、处理复杂输入的模式和高级策略,请参阅 fuzz-harness-writing 技术技能。
LibAFL 模糊测试器由模块化组件组成:
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. 设置观察器
let edges_observer = HitcountsMapObserver::new(
unsafe { std_edges_map_observer("edges") }
).track_indices();
let time_observer = TimeObserver::new("time");
// 2. 定义反馈
let mut feedback = feedback_or!(
MaxMapFeedback::new(&edges_observer),
TimeFeedback::new(&time_observer)
);
// 3. 定义目标
let mut objective = feedback_or_fast!(
CrashFeedback::new(),
TimeoutFeedback::new()
);
// 4. 创建或恢复状态
let mut state = state.unwrap_or_else(|| {
StdState::new(
StdRand::new(),
InMemoryCorpus::new(),
OnDiskCorpus::new(&output_dir).unwrap(),
&mut feedback,
&mut objective,
).unwrap()
});
// 5. 设置变异器
let mutator = StdScheduledMutator::new(havoc_mutations());
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
// 6. 设置调度器
let scheduler = IndexesLenTimeMinimizerScheduler::new(
&edges_observer,
QueueScheduler::new()
);
// 7. 创建模糊测试器
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
// 8. 定义测试套件
let mut harness = |input: &BytesInput| {
let buf = input.target_bytes().as_slice();
libfuzzer_test_one_input(buf);
ExitKind::Ok
};
// 9. 设置执行器
let mut executor = InProcessExecutor::with_timeout(
&mut harness,
tuple_list!(edges_observer, time_observer),
&mut fuzzer,
&mut state,
&mut restarting_mgr,
timeout,
)?;
// 10. 加载初始输入
if state.must_load_initial_inputs() {
state.load_initial_inputs(
&mut fuzzer,
&mut executor,
&mut restarting_mgr,
&input_dir
)?;
}
// 11. 开始模糊测试
fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut restarting_mgr)?;
Ok(())
};
// 启动模糊测试器
Launcher::builder()
.run_client(&mut run_client)
.cores(&cores)
.build()
.launch()
.unwrap();
}
手动指定所有插桩标志:
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
创建 LibAFL 编译器包装器以自动处理插桩。
创建src/bin/libafl_cc.rs:
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();
}
编译并使用:
cargo build --release
target/release/libafl_cxx -DNO_MAIN -g -O2 main.cc harness.cc -o fuzz
另请参阅: 有关详细的消毒器配置、常见问题和高级标志,请参阅 address-sanitizer 和 undefined-behavior-sanitizer 技术技能。
./fuzz --cores 0 --input corpus/
./fuzz --cores 0,8-15 --input corpus/
这将运行 9 个客户端:一个在核心 0 上,8 个在核心 8-15 上。
./fuzz --cores 0-7 --input corpus/ --output crashes/ --timeout 1000
启用图形统计视图:
./fuzz -tui=1 corpus/
| 输出 | 含义 |
|---|---|
corpus: N | 发现的有趣测试用例数量 |
objectives: N | 发现的崩溃/超时数量 |
executions: N | 目标调用的总次数 |
exec/sec: N | 当前执行吞吐量 |
edges: X% | 代码覆盖率百分比 |
clients: N | 并行模糊测试进程数量 |
模糊测试器发出两种主要事件类型:
| 技巧 | 为何有帮助 |
|---|---|
使用 -fork=1 -ignore_crashes=1 | 在第一次崩溃后继续模糊测试 |
使用 InMemoryOnDiskCorpus | 在重启之间保持语料库持久化 |
使用 -tui=1 启用 TUI | 更好地可视化进度 |
| 使用特定的 LLVM 版本 | 避免兼容性问题 |
正确设置 RUSTFLAGS | 防止链接错误 |
避免存储来自同一错误的重复崩溃:
添加回溯观察器:
let backtrace_observer = BacktraceObserver::owned(
"BacktraceObserver",
libafl::observers::HarnessType::InProcess
);
更新执行器:
let mut executor = InProcessExecutor::with_timeout(
&mut harness,
tuple_list!(edges_observer, time_observer, backtrace_observer),
&mut fuzzer,
&mut state,
&mut restarting_mgr,
timeout,
)?;
使用哈希反馈更新目标:
let mut objective = feedback_and!(
feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()),
NewHashFeedback::new(&backtrace_observer)
);
这确保只保存具有唯一回溯的崩溃。
使用字典引导模糊测试朝向特定标记:
从文件添加标记:
let mut tokens = Tokens::new();
if let Some(tokenfile) = &tokenfile {
tokens.add_from_file(tokenfile)?;
}
state.add_metadata(tokens);
更新变异器:
let mutator = StdScheduledMutator::new(
havoc_mutations().merge(tokens_mutations())
);
硬编码标记示例(PNG):
state.add_metadata(Tokens::from([
vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG 头部
"IHDR".as_bytes().to_vec(),
"IDAT".as_bytes().to_vec(),
"PLTE".as_bytes().to_vec(),
"IEND".as_bytes().to_vec(),
]));
另请参阅: 有关详细的字典创建策略和特定格式的字典,请参阅 fuzzing-dictionaries 技术技能。
自动从程序中提取魔术值和校验和:
在编译器包装器中启用:
cc.add_pass(LLVMPasses::AutoTokens)
在模糊测试器中加载自动标记:
tokens += libafl_targets::autotokens()?;
验证标记部分:
echo "p (uint8_t *)__token_start" | gdb fuzz
| 设置 | 影响 |
|---|---|
| 多核模糊测试 | 随核心数量线性加速 |
InMemoryCorpus | 更快但不持久 |
InMemoryOnDiskCorpus | 平衡速度和持久性 |
| 消毒器 | 2-5 倍减速,对发现错误至关重要 |
优化级别 -O2 | 速度和覆盖率之间的平衡 |
以单进程模式运行模糊测试器以便于调试:
// 用直接调用替换启动器
run_client(None, SimpleEventManager::new(monitor), 0).unwrap();
// 注释掉:
// Launcher::builder()
// .run_client(&mut run_client)
// ...
// .launch()
然后使用 GDB 调试:
gdb --args ./fuzz --cores 0 --input corpus/
使用 LibAFL 对 libpng 进行模糊测试:
1. 获取源代码:
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. 设置编译器包装器:
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. 构建静态库:
./configure --enable-shared=no
make
4. 获取测试套件:
curl -O https://raw.githubusercontent.com/glennrp/libpng/f8e5fa92b0e37ab597616f554bee254157998227/contrib/oss-fuzz/libpng_read_fuzzer.cc
5. 链接模糊测试器:
$CXX libpng_read_fuzzer.cc .libs/libpng16.a -lz -o fuzz
6. 准备种子:
mkdir seeds/
curl -o seeds/input.png https://raw.githubusercontent.com/glennrp/libpng/acfd50ae0ba3198ad734e5d4dec2b05341e50924/contrib/pngsuite/iftp1n3p08.png
7. 获取字典(可选):
curl -O https://raw.githubusercontent.com/glennrp/libpng/2fff013a6935967960a5ae626fc21432807933dd/contrib/oss-fuzz/png.dict
8. 开始模糊测试:
./fuzz --input seeds/ --cores 0 -x png.dict
将 LibAFL 与 CMake 构建系统集成:
CMakeLists.txt:
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)
构建未插桩的二进制文件:
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ .
cmake --build . --target buggy_program
构建模糊测试器:
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
运行模糊测试:
./fuzz --input seeds/ --cores 0
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 覆盖率不增加 | 插桩失败 | 验证是否使用了编译器包装器,检查是否有 -fsanitize-coverage |
| 模糊测试器无法启动 | 语料库为空,没有有趣输入 | 提供能触发代码路径的种子输入 |
与 libafl_main 的链接器错误 | 运行时未链接 | 使用 -Wl,--whole-archive 或 -u libafl_main |
| LLVM 版本不匹配 | LibAFL 需要 LLVM 15-18 | 安装兼容的 LLVM 版本,设置环境变量 |
| Rust 编译失败 | Rust 或 Cargo 过时 | 使用 rustup update 更新 Rust |
| 模糊测试速度慢 | 启用了消毒器 | 预期 2-5 倍减速,对发现错误是必要的 |
| 环境变量干扰 | 设置了 CC、CXX、RUSTFLAGS | 构建 LibAFL 项目后取消设置 |
| 无法附加调试器 | 多进程模糊测试 | 以单进程模式运行(参见调试部分) |
| 技能 | 使用场景 |
|---|---|
| fuzz-harness-writing | 编写有效测试套件的详细指南 |
| address-sanitizer | 模糊测试期间的内存错误检测 |
| undefined-behavior-sanitizer | 未定义行为检测 |
| coverage-analysis | 测量和改进代码覆盖率 |
| fuzzing-corpus | 构建和管理种子语料库 |
| fuzzing-dictionaries | 为格式感知模糊测试创建字典 |
| 技能 | 何时考虑 |
|---|---|
| libfuzzer | 更简单的设置,不需要 LibAFL 的高级功能 |
| aflpp | 无需自定义模糊测试器开发的多核模糊测试 |
| cargo-fuzz | 以较少设置对 Rust 项目进行模糊测试 |
每周安装量
1.1K
仓库
GitHub 星标数
3.9K
首次出现
2026年1月19日
安全审计
安装于
claude-code986
opencode934
gemini-cli916
codex910
cursor889
github-copilot859
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.
| 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:
LibAFL can be used as a drop-in replacement for libFuzzer with minimal setup:
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:
git clone https://github.com/AFLplusplus/LibAFL
cd LibAFL/libafl_libfuzzer_runtime
./build.sh
Compile and run:
clang++ -DNO_MAIN -g -O2 -fsanitize=fuzzer-no-link libFuzzer.a harness.cc main.cc -o fuzz
./fuzz corpus/
Install Clang:
apt install clang
Or install a specific version via apt.llvm.org:
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 15
Configure environment for Rust:
export RUSTFLAGS="-C linker=/usr/bin/clang-15"
export CC="clang-15"
export CXX="clang++-15"
Install Rust:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Install additional dependencies:
apt install libssl-dev pkg-config
For libFuzzer compatibility mode, install nightly Rust:
rustup toolchain install nightly --component llvm-tools
Build LibAFL to verify installation:
cd LibAFL/libafl_libfuzzer_runtime
./build.sh
# Should produce libFuzzer.a
LibAFL harnesses follow the same pattern as libFuzzer when using drop-in replacement mode:
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 supports two primary usage modes:
Use LibAFL as a replacement for libFuzzer with existing harnesses.
Compilation:
clang++ -DNO_MAIN -g -O2 -fsanitize=fuzzer-no-link libFuzzer.a harness.cc main.cc -o fuzz
Running:
./fuzz corpus/
Recommended for long campaigns:
./fuzz -fork=1 -ignore_crashes=1 corpus/
Build a fully customized fuzzer using LibAFL components.
Create project:
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:
[lib]
crate-type = ["staticlib"]
See Also: For detailed harness writing techniques, patterns for handling complex inputs, and advanced strategies, see the fuzz-harness-writing technique skill.
A LibAFL fuzzer consists of modular components:
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();
}
Manually specify all instrumentation flags:
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
Create a LibAFL compiler wrapper to handle instrumentation automatically.
Createsrc/bin/libafl_cc.rs:
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:
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.
./fuzz --cores 0 --input corpus/
./fuzz --cores 0,8-15 --input corpus/
This runs 9 clients: one on core 0, and 8 on cores 8-15.
./fuzz --cores 0-7 --input corpus/ --output crashes/ --timeout 1000
Enable graphical statistics view:
./fuzz -tui=1 corpus/
| Output | Meaning |
|---|---|
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:
| Tip | Why 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 version | Avoid compatibility issues |
Set RUSTFLAGS correctly | Prevent linking errors |
Avoid storing duplicate crashes from the same bug:
Add backtrace observer:
let backtrace_observer = BacktraceObserver::owned(
"BacktraceObserver",
libafl::observers::HarnessType::InProcess
);
Update executor:
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:
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.
Use dictionaries to guide fuzzing toward specific tokens:
Add tokens from file:
let mut tokens = Tokens::new();
if let Some(tokenfile) = &tokenfile {
tokens.add_from_file(tokenfile)?;
}
state.add_metadata(tokens);
Update mutator:
let mutator = StdScheduledMutator::new(
havoc_mutations().merge(tokens_mutations())
);
Hard-coded tokens example (PNG):
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.
Automatically extract magic values and checksums from the program:
Enable in compiler wrapper:
cc.add_pass(LLVMPasses::AutoTokens)
Load auto tokens in fuzzer:
tokens += libafl_targets::autotokens()?;
Verify tokens section:
echo "p (uint8_t *)__token_start" | gdb fuzz
| Setting | Impact |
|---|---|
| Multi-core fuzzing | Linear speedup with cores |
InMemoryCorpus | Faster but non-persistent |
InMemoryOnDiskCorpus | Balanced speed and persistence |
| Sanitizers | 2-5x slowdown, essential for bugs |
Optimization level -O2 | Balance between speed and coverage |
Run fuzzer in single-process mode for easier debugging:
// 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:
gdb --args ./fuzz --cores 0 --input corpus/
Fuzzing libpng using LibAFL:
1. Get source code:
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:
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:
./configure --enable-shared=no
make
4. Get harness:
curl -O https://raw.githubusercontent.com/glennrp/libpng/f8e5fa92b0e37ab597616f554bee254157998227/contrib/oss-fuzz/libpng_read_fuzzer.cc
5. Link fuzzer:
$CXX libpng_read_fuzzer.cc .libs/libpng16.a -lz -o fuzz
6. Prepare seeds:
mkdir seeds/
curl -o seeds/input.png https://raw.githubusercontent.com/glennrp/libpng/acfd50ae0ba3198ad734e5d4dec2b05341e50924/contrib/pngsuite/iftp1n3p08.png
7. Get dictionary (optional):
curl -O https://raw.githubusercontent.com/glennrp/libpng/2fff013a6935967960a5ae626fc21432807933dd/contrib/oss-fuzz/png.dict
8. Start fuzzing:
./fuzz --input seeds/ --cores 0 -x png.dict
Integrate LibAFL with CMake build system:
CMakeLists.txt:
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:
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ .
cmake --build . --target buggy_program
Build fuzzer:
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:
./fuzz --input seeds/ --cores 0
| Problem | Cause | Solution |
|---|---|---|
| No coverage increases | Instrumentation failed | Verify compiler wrapper used, check for -fsanitize-coverage |
| Fuzzer won't start | Empty corpus with no interesting inputs | Provide seed inputs that trigger code paths |
Linker errors with libafl_main | Runtime not linked | Use -Wl,--whole-archive or -u libafl_main |
| LLVM version mismatch | LibAFL requires LLVM 15-18 | Install compatible LLVM version, set environment variables |
| Rust compilation fails | Outdated Rust or Cargo |
| 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 |
| 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 |
Weekly Installs
1.1K
Repository
GitHub Stars
3.9K
First Seen
Jan 19, 2026
Security Audits
Gen Agent Trust HubFailSocketPassSnykWarn
Installed on
claude-code986
opencode934
gemini-cli916
codex910
cursor889
github-copilot859
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
Flutter 缓存与性能优化指南:实现离线优先数据持久化与渲染加速
1,000 周安装
React Sentry 安装配置指南:错误监控、日志记录与性能追踪
1,000 周安装
Next.js 16.1.1 生产模式指南:App Router、缓存、Turbopack 与安全更新
1,000 周安装
Railway部署管理指南:列出、查看日志、重新部署与移除部署操作详解
1,000 周安装
Railway 文档助手 - 获取最新 Railway 平台部署、项目、定价等技术文档
1,000 周安装
search-first 开发技能:先调研再编码,避免重复造轮子的系统化工作流程
1,100 周安装
Update Rust with rustup update |
| Slow fuzzing | Sanitizers enabled | Expected 2-5x slowdown, necessary for finding bugs |
| Environment variable interference | CC, CXX, RUSTFLAGS set | Unset after building LibAFL project |
| Cannot attach debugger | Multi-process fuzzing | Run in single-process mode (see Debugging section) |