学习libfuzzer使用
可以参考的教程:
教程
官方git网址:
git
官方说明页面:
说明
翻译git的说明:www.giantbranch.cn/2020/03/08/libfuzzer 文档/
安装
依照官方教程,运行下面命令
# Install git and get this tutorial
sudo apt-get --yes install git
git clone https://github.com/google/fuzzing.git fuzzing
# Get fuzzer-test-suite
git clone https://github.com/google/fuzzer-test-suite.git FTS
./fuzzing/tutorial/libFuzzer/install-deps.sh # Get deps
./fuzzing/tutorial/libFuzzer/install-clang.sh # Get fresh clang binaries
测试目标
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
DoSomethingWithData(Data, Size);
return 0;
}
DoSomethingWithData函数就是要被测试的目标,他需要接收Data和Size两个输入。extern "C"指名函数从此开始测试。
比如下面的fuzz_me.cc程序,被测函数格式如此
#include <stdint.h>
#include <stddef.h>
bool FuzzMe(const uint8_t *Data, size_t DataSize) {
return DataSize >= 3 &&
Data[0] == 'F' &&
Data[1] == 'U' &&
Data[2] == 'Z' &&
Data[3] == 'Z'; // :‑<
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
FuzzMe(Data, Size);
return 0;
}
运行
使用如下命令运行:
clang++ -g -fsanitize=address,fuzzer fuzzing/tutorial/libFuzzer/fuzz_me.cc -o fuzz_me
其中clang是编译器,-g启用调试信息,使错误消息更易于阅读(可选);-fsanitize=fuzzer 向libfuzzer提供进程内覆盖信息,并与libfuzzer运行时链接(必须);-fsanitize=address 启用AddressSanitizer 是一个内存泄漏检测工具,可以检测内存泄漏,参考链接AddressSanitizer;后面就是要测试的程序的路径;-o fuzz_me指明了生成文件的格式。
运行后会在执行的文件夹下生成一个可执行程序fuzz_me和crash文件(如有)
随后执行:
./fuzz_me
会看到本次测试的详细信息,包括ERROR等。
其中,输出的含义:
- 首先输出的是配置信息,有关fuzzer的选项和配置的信息,包括当前的初始种子,可以通过-seed=N来指定。
- 下面是输出事件和统计信息:
READ:fuzzer已经从语料库目录读取了所有输入样本
INITED:模糊器已完成初始化,包括运行语料库中的所有样本
NEW:发现新路径,并将输入保存到语料库目录
REDUCE:找到一个更好,一般指更小的输入触发以前的路径(设置-reduce_inputs=0,可以禁用)
pulse:fuzzer已经生成2^n的输入(主要是定期生成让用户知道模糊器仍在工作)
DONE:模糊测试完成,达到了迭代限制(-runs)或者时间限制(-max_total_time)
RELOAD:fuzzer定期从语料库重新加载输入,这样,就可以发现其他模糊测试工具发现的输入
- cov是覆盖的范围,代码块或者边数。
- libfuzzer用不同的signals来评估代码覆盖率:边覆盖率,边的数量,value profiles,间接调用和被调用等,将他们合并在一起,就是features (ft)。
- corp:当前内存中测试的语料库的数量/大小(单位为bytes),覆盖cov的内容。
- lim:当前限制的输入长度,随着时间推移,会增加到-max_len。
- exec/s:每秒的迭代次数。
- rss:当前内存的消耗。
倒数第二行是本次崩溃的信息,记录到了crash-0eb8e4e…中,可以复现该崩溃信息:
可选的参数
- 与自定义种子库一起使用:
./woff2-2016-05-06-fsanitize_fuzzer MY_CORPUS/ seeds/
其中MY_CORPUS/是语料库目录,触发有趣代码路径的输入会写入该文件夹。seeds/是自定义的种子语料库
- -jobs=N 将生成N个独立的作业,但不超过拥有的内核数量的一半。
- -workers=M 用于设置允许的并行作业数
- –dict=afl/dictionaries/xml.dict 用于指定字典,当输入格式由标记组成或者具有大量魔术值,使用字典会很有效。
mkdir CORPUS
./libxml2-v2.9.2-fsanitize_fuzzer -dict=afl/dictionaries/xml.dict -jobs=8 -workers=8 CORPUS
代码覆盖率可视化
使用clang的覆盖统计功能,更多功能参见clang
clang -fprofile-instr-generate -fcoverage-mapping ~/fuzzing/tutorial/libFuzzer/fuzz_me.cc \
~/Fuzzer/standalone/StandaloneFuzzTargetMain.c
mkdir CORPUS # Create an empty corpus dir.
echo -n A > CORPUS/A && ./a.out CORPUS/* && \
llvm-profdata merge -sparse *.profraw -o default.profdata && \
llvm-cov show a.out -instr-profile=default.profdata -name=FuzzMe
行覆盖统计: