一、下载libfuzzer
由于最新版本的libfuzzer只支持clang++,不支持g++,所以我们需要下载老版本的libfuzzer
下载网址:https://github.com/llvm/llvm-project/tree/8f7fc95ab7aab395ec06affa8c705eee2432fcdc/compiler-rt/lib/fuzzer
二、安装
在编译libfuzzer的时候会报关于-fPIE的错误。此时需要在libfuzzer目录下改动build.sh,用以下代码替换「加了一个-fPIE」
libfuzzer目录:/home/ise/lj/libfuzzer/libfuzzer-workshop/libFuzzer/Fuzzer
#!/bin/sh
LIBFUZZER_SRC_DIR=$(dirname $0)
CXX="${CXX:-clang}"
for f in $LIBFUZZER_SRC_DIR/*.cpp; do
$CXX -g -fPIE -O2 -fno-omit-frame-pointer -std=c++11 $f -c &
done
wait
rm -f libFuzzer.a
ar ru libFuzzer.a Fuzzer*.o
rm -f Fuzzer*.o
然后运行build.sh,得到编译好的libFuzzer.a文件「我把它拷贝到了待测函数的目录下」
三、设置fuzzer入口
待测函数目录:/home/ise/lj/libfuzzer/libfuzzer-workshop/lessons/04
然后就可以开始准备运行fuzzer了
四、运行时「选项」及「代码」
选项
-fsanitize=fuzzer (必需):为 libFuzzer 提供进程内覆盖信息并与 libFuzzer 运行时链接。
-fsanitize=address(推荐):启用AddressSanitizer
-g(推荐):启用调试信息,使错误消息更易于阅读。
trace-pc:追踪执行过的基本块BB,在每个edge中插入__saitizer_cov_trace_pc()函数,可定义该函数作为相应的回调处理
代码
路径:/home/ise/lj/libfuzzer/libfuzzer-workshop/lessons/04
使用g++将「first_fuzzer.cc」和「libFuzzer.a」进行链接得到「first_fuzzer」文件
/usr/bin/x86_64-linux-gnu-g++ -g -fsanitize=address -fsanitize-coverage=trace-pc -pthread first_fuzzer.cc ./libFuzzer.a -o first_fuzzer
# 或者链接后直接运行first_fuzzer
/usr/bin/x86_64-linux-gnu-g++ -g -fsanitize=address -fsanitize-coverage=trace-pc -pthread first_fuzzer.cc ./libFuzzer.a -o first_fuzzer && ./first_fuzzer
将标准输出与标准错误输出合并后存储在fuzz-0.log文件中,在面板上过滤并显示出错误信息:
执行「first_fuzzer」文件,设定语料库目录CORPUS_DIR/。将标准输出与标准错误输出合并后,过滤出错误信息
# 输出错误到.log中
./first_fuzzer CORPUS_DIR/ > fuzz-0.log 2>&1 | grep ERROR
# 或者只输出错误
./first_fuzzer CORPUS_DIR/ 2>&1 | grep ERROR
# 或者全部输出
./first_fuzzer CORPUS_DIR/ 2>&1
五、输出部分解析
在操作期间,模糊器将信息打印到stderr。
INFO: Seed: 1523017872
INFO: Loaded 1 modules (16 guards): [0x744e60, 0x744ea0),
INFO: -max_len is not provided, using 64
INFO: A corpus is not provided, starting from an empty corpus
#0 READ units: 1
#1 INITED cov: 3 ft: 2 corp: 1/1b exec/s: 0 rss: 24Mb
#3811 NEW cov: 4 ft: 3 corp: 2/2b exec/s: 0 rss: 25Mb L: 1 MS: 5 ChangeBit-ChangeByte-ChangeBit-ShuffleBytes-ChangeByte-
#3827 NEW cov: 5 ft: 4 corp: 3/4b exec/s: 0 rss: 25Mb L: 2 MS: 1 CopyPart-
#3963 NEW cov: 6 ft: 5 corp: 4/6b exec/s: 0 rss: 25Mb L: 2 MS: 2 ShuffleBytes-ChangeBit-
#4167 NEW cov: 7 ft: 6 corp: 5/9b exec/s: 0 rss: 25Mb L: 3 MS: 1 InsertByte-
...
输出的早期部分包括有关fuzzer选项和配置的信息,包括当前随机种子(在seed:line中;这可以用-seed=n标志覆盖)。
其他输出行具有事件代码和统计信息的形式。可能的事件代码为:
- READ:Fuzzer已经从语料库目录中读取了所有提供的输入样本。
- INITED:fuzzer已经完成初始化,包括通过被测代码运行每个初始输入样本。
- NEW:fuzzer已经创建了一个测试输入,它覆盖了被测代码的新领域。此输入将保存到主语料库目录。
- REDUCE:fuzzer发现了一个更好(更小)的输入,可以触发先前发现的特征(设置-reduce_inputs=0以禁用)。
- pulse:fuzzer已产生2N输入(定期产生,以保证用户fuzzer仍在工作)。
- DONE:fuzzer已完成操作,因为它已达到指定的迭代限制(-runs)或时间限制(-max_total_time)。
- RELOAD:fuzzer正在定期从corpus目录重新加载输入;这允许它发现由其他fuzzer进程发现的任何输入(请参见并行模糊)。
每个输出行还报告以下统计信息(非零时):
- COV:执行当前语料库所涵盖的代码块或边的总数。
- FT:libFuzzer使用不同的信号来评估代码覆盖率:边缘覆盖,边缘计数器,值配置文件,间接调用者/被调用者对等。这些组合的信号称为特征(ft : )。
- CORP:当前内存中测试语料库中的条目数及其大小(以字节为单位)。
- LIM:语料库中新条目长度的当前限制。 随着时间的推移逐渐增加,直到达到最大长度(-max_len)。
- EXEC/ S:每秒的模糊器迭代次数。
- RSS:当前的内存消耗。
对于NEW事件,输出行还包括有关生成新输入的变异操作的信息:
- L:新输入的大小(以字节为单位)。
- MS: <操作>计数和用于生成输入的变异操作列表。