配置环境
clang
apt-get install clang
版本amd64 (1:4.0-34ubuntu2)
llvm
apt-get install llvm
版本llvm-4.0
运行实验
假设要编译一个程序 test.c,最好将test.c放在afl-statics文件夹下,因为需要互相调用文件(test.bc和afl-llvm-rt.o)。
第一步,运行标准afl,生成测试用例
先用标准afl编译并运行test.c,生成n个测试用例在output文件里。
(可以查看afl文档如何运行)
1. 将编译器修改为标准afl。cd到afl文件夹下,执行make
。然后cd到llvm-mode文件夹下,执行make
。
2. 编译。cd到test.c所在的文件夹下,执行 ../afl-2.52b/afl-clang-fast ./test.c -o ./test
3. 运行。在test.c所在文件夹新建input和output文件夹,并在input文件夹中新建输入文件,然后执行../afl-2.52b/afl-fuzz -i ./input -o ./output ./test
(标准用户输入)(实验中用此项)
或者执行../afl-2.52b/afl-fuzz -i ./input -o ./output ./test @@
(从文件输入)
注意:input是一个文件夹,里面需要开始给一个测试用例,随便写一个文件即可。
运行一段时间后,会有测试用例生成在 output里,output结果如下图:
第二步,运行afl-statics,得到到达次数
先修改编译器,在afl-statics源文件下直接make
,运行结果如下图:
再在其中的llvm_mode文件夹下make
,运行结果如下图:
然后按如下顺序,在test.c所在文件夹下编译并运行:
./afl-clang-fast -emit-llvm -c ./test.c -o ./test.bc
(如果是c++ 用afl-clang-fast++),运行结果如下图:
clang ./test.bc ./afl-llvm-rt.o -o ./test
(如果是c++ 用clang++),运行结果如下图:
./afl-fuzz -i- -o ./output -k ./out_file ./test
,运行结果如下图:
产生的out_file
文件如下所示:
第三步:得到CFG
在afl-statics下运行 ./transition -b ./test.bc -o ./out_file2
,运行结果如下图:
生成的out_file2
内容如下:
结果格式
最终结果就是out_file 和 outfile2
- out_file 是一个文件,里面是最终结果。
结构如下:
1:100
2:12
3:22
……
用冒号分开, 第一个是id,第二个是执行的次数。
序号是随机产生的,如果out_file2中出现了节点编号,但是out_file中未出现,表示到达的次数为0。
- out_file2是节点转移关系
格式如下:
1-2
2-3
3-2
……
表示节点1可以到达2,2可以到达3,3可以到达2
测试程序 test.c
#include <stdio.h>
#define STDIN 0
void AFL_Check(){}
int cgc_strcmp(char* s1, char* s2)
{
if (s1 == NULL)
{
if (s2 == NULL)
{
return (0);
}
else
{
return (-1);
}
}
if (s2 == NULL)
{
return (1);
}
int i = 0;
while (s1[i] != '\0')
{
if (s2[i] == '\0')
{
return (1);
}
if (s1[i] < s2[i])
{
return (-1);
}
else if (s1[i] > s2[i])
{
return (1);
}
AFL_Check();
i++;
}
if (s2[i] == '\0')
{
*((int*)0) = 1;
AFL_Check();
return (0);
}
return (-1);
}
int main(){
char s[256];
int ret= read(STDIN,s,256);
if(ret==0) return 1;
s[ret-1] ='\0';
cgc_strcmp(s,"4abcdef");
}