目录
前言
这是我读了部分AFL源码的产物,有些地方很可能表述或理解地并不准确,欢迎交流和指教。
(图片引用自AFL++文档)
主要内容是Instrument target和Fuzz本体
根据compiler的选择不同会影响后续fuzzing效率
LTO mode (afl-clang-lto/afl-clang-lto++)
LTO(Link Time Optimization)链接时优化是链接期间的程序优化,多个中间文件通过链接器合并在一起,并将它们组合为一个程序,缩减代码体积,因此链接时优化是对整个程序的分析和跨模块的优化。
需要llvm 11+,这是当前afl支持的效率最高的选择(理论上,实际情况会受未知因素影响,比如fuzzing libxml2的时候),也意味着编译要花更长时间
LLVM mode (afl-clang-fast/afl-clang-fast++)
依赖LLVM的optimizer,稳定性较高的编译器,用的比较多,可以跨平台(non-x86)编译
实现了编译级插桩,效果比汇编级插桩更好
GCC_PLUGIN mode (afl-gcc-fast/afl-g++-fast)
效果和LLVM mode差不多,不过依赖的是GCC_plugin,也比较推荐
GCC mode (afl-gcc/afl-g++) (or afl-clang/afl-clang++ for clang)
相较其他编译器,没别的特色,基本用不到
从编译的实现流程上理解插桩模式差异
考虑到afl的插桩方式随编译器的选择而变化,从最简单的afl-gcc开始入手。
先把一个简单程序用afl-gcc
编译,代码来源
很显然,只要输出指定字符串,程序就会访问到非法内存,同时程序根据输入头部的不同产生多个分支,从而测试AFL输入样本的变异过程
编译中程序显示对52处位置进行了插桩
把编译得到的文件丢进IDA,可以发现编译生成的函数中有多个__afl_maybe_log
,显然他们由afl-gcc的插桩产生。
当执行到这段代码,fuzzer知道这段代码被触发,从而统计每次输入样本的边缘覆盖率。
正常生成可执行文件过程为
IR:高级语言到汇编的中间语言,可以解决平台间的差异
llvm负责IR到汇编语言的转化,并在此过程中进行插桩
插桩的代码执行时与更新共享内存中的执行信息,从而对代码覆盖率进行统计
使用afl-clang-fast编译,产生的函数__sanitizer_cov_trace_pc_guard
,就是llvm插桩的经典例子
ASAN(Address Sanitizer):在数据前后添加禁止访问区域,访问到后报错
源代码比较长,我就挑了几个重要函数的源码进行分析
进入main函数,首先获取时间,循环读取参数
下面接了一大堆目录处理和前期检查的函数
forkserver、主进程、fork出的子进程间存在共享内存,这段共享内存由内核管理,其中存储数组,记录每次样本执行访问到的代码路径
该函数用于配置共享内存和virgin_bits
将三个状态数组全部初始化为255(0~65535)
int shmget(key_t key, size_t size, int shmflg)申请共享大小为65536的共享内存
void shmat(int shm_id, const void shm_addr, int shmflg) 访问共享内存
第一参数指定这一段共享内存的id
第二参数为NULL一般,shm_addr指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。
第三参数shm_flg是一组标志位,通常为0。
返回一个指向共享内存起始位置的指针,存入trace_bits
forkserver功能
调用链perform_dry_run(use_argv) -> calibrate_case(argv, q, use_mem, 0, 1) -> init_forkserver(argv)
perform_dry_run():每个测试用例都执行一次,仅对初始输入执行一次测试,以确保程序按预期运行
calibrate_case():校准一个新的测试用例,只在处理输入目录和发现新路径是执行
init_forkserver():用于初始化forkserver
初始参数中st_pipe[2], ctl_pipe[2]分别为状态管道和控制管道
接着fork出子进程forkserver并使其脱离主进程
重定向forkserver的stdout、stderr到dev_null_fd
视情况重定向stdin
完成后对FORKSRV_FD和FORKSRV_FD + 1进行重定向
linux之dup和dup2函数解析
执行execv之前还有一系列参数设置,这里先略过,如果execv执行失败,那么主进程将通过trace_bits = EXEC_FAIL_SIG(位于bitmap)获得信息。
主进程的pipe为fsrv_ctl_fd = ctl_pipe[1]用于写;fsrv_st_fd = st_pipe[0]用于读; 设置完成后等待forkserver的返回状态信号
各种初始设置完成后进入while循环,执行fuzzing主程序
先来看一个比较重要的数据结构queue_entry
的特点
其中top_rated里面存放的是bitmap中每个位置当前最短路径
功能:每次执行fuzz_one之前,简化队列
如果是dumb_mode或者score_changed为0(即上一次fuzz没有产生更好的路径),直接返回
遍历队列,还原favored设置
循环取出处于top_rate中并且被temp_v标记的用例,每取出一个,清除temp_v中所有属于这个entry的bit,并设置它的favored位,令queued_favored,如果这个用例还没被fuzz过,令pending_favored++,标记优先执行
简化队列,标记冗余项
功能:判断一次循环是否结束,是则初始化队列
queue_cur指向当前队列中元素,为空说明遍历到结尾
不为空则直接下一步
记录轮数、重置状态
seek_to的值来源于find_start_position(),找到fuzzer重启后的开始位置
(只在fuzzer重启的第一个循环里用到)这里把queue_cur抬高到seek_to位置,恢复重启前的状态
展示状态,就是命令行面板,每次状态更新或在其他状况下就会调用一次
非终端模式下输出循环数
queue_path不变,说明一整个循环未发现新路径,设置cycles_wo_finds+1或者use_splicing=1,他注释说会更换策略,但如果设置了-d参数,其实本来用的就是splicing,直接计数就行,cycles_wo_finds只是根据它的数量判断现在是否可以结束fuzzing,没别的影响
设置prev_queued为上一次的结果
如果设置了相关参数,sync_fuzzers()可以从其他fuzzer获取测试用例
终于到了最关键的地方
fuzz_one从当前队列中取一个用例执行
fuzz成功返回0,跳过或bailed out返回1
进来先判断是否有favored, non-fuzzed用例需要执行
如果有,则有99%的概率跳过在它之前的用例
即使没有需要优先fuzz的用例,非dumb_mode下,当前用例不是favored,队列中超过10个元素的情况下
直接把当前测试用例映射到内存,提高效率
out_buf不是从文件读,这里相当于直接用了malloc(len+1),即使mmap也不能提高效率
只有存在cal_failed被标记才会执行
cal_failed在calibrate_case()
中,发生以下情况会+1
同时afl允许我们通过设置,即使发生上述情况,也不在此阶段执行CALIBRATION(通过令cal_failed=3)
该判定位于perform_dry_run()
然而,出现上述问题会使cal_failures++,若报错比例过高,就会要求你检查设置
回到fuzz_one,若校准错误小于3
让存在校准问题的用例再次校准
非dumb_mode且该case尚未trim时执行
最后结果存储在out_buf
trim_case(char** argv, struct queue_entry* q, u8* in_buf)
len_p2=2^x > q->len
remove_len取len_p2/16与4的最大值
循环判断remove_len是否大于最小步长max(len_p2 /1024,4),满足则继续
否则跳转到7
格式化remove_len到tmp
内部循环,根据 remove_pos, trim_avail生成新case
static void write_with_gap(void* mem, u32 len, u32 skip_at, u32 skip_len)
功能:删除skip_at开始skip_len长度的内容,新内容存储于mem(此处为in_buf)
运行一次新case,确认当前删除是否影响bitmap
remove_len/2,回到3进行判断
needs_write为1(在5的if中设置)说明case需要更新,把in_buf内容写入文件,并更新bitmap信息
如果设置了skip_deterministic或者queue_cur->was_fuzzed或者queue_cur->passed_det=1
如果当前的queue_cur->exec_cksum % master_max
不等于master_id - 1
跳转havoc_stage
考虑到这部分代码比较长,我主要从功能上入手,结合部分代码分析
变异分为6个阶段
按位翻转,每次都是比特位级别的操作,从 1bit 到 32bit
_ar
是操作对象,_br
指明操作第几个字节(_bf) >> 3
中的第几个bit(128 >> ((_bf) & 7))
(从高位到低位)
一个异或相当于实现了对一个指定bit位的翻转
检测token并添加
从注释上理解token得概念:如果在某一段连续bit上进行连续翻转后,都能让程序产生新的路径,就称连续翻转的这些bit为一个token
common_fuzz_stuff(char** argv, u8* out_buf, u32 len)
用新的case运行程序,获取fault
检测fault值
如果FAULT_TMOUT并且subseq_tmouts(fuzz每个case时置零)未超出限制,返回1
若不是FAULT_TMOUT,subseq_tmouts=0
每次连续反转2个bit,步长为1bit
每次连续反转2个bit,步长为1bit
增加了effector map,每次连续反转8个bit,步长为8bit
与之前找token的方式相似,如果byte翻转生成了新路径,就让这个byte在effector map中位置为1,否则为0。目的也是让后续变异参考,确认哪些位置是关键的参数,绕过无用的数据。
初始只有第一个、最后一个位置为1
每次发现新路径设置1
发现有效位超过90%直接全为1
注意,如果采用dumb mode或从fuzzer后续不会用到effector map的结果
每次连续反转16个bit,步长为8bit
每次连续反转32个bit,步长为8bit
目的是测试易于整数溢出的数据
与位翻转不同,从 8bit 级别开始,而且每次进行的是加减运算操作
每次对8bit进行加减运算,步长8bit
case遍历
orig为每次操作的位置
effector map为0直接跳过
循环进行前后异或,一共ARITH_MAX=35轮
org与orig+j进行异或
要求每次产生的case不能与bitflip产生的相同,否则直接跳过
通过orig+j的方式生成新的case进行测试
与上一步相似,使用org-j生成新的case进行测试
恢复原case
每次对16bit进行加减运算,步长8bit,对小端、大端加减法都进行测试
每次对32bit进行加减运算,步长8bit,对小端、大端加减法都进行测试
使用“interesting values”对文件内容进行替换,替换内容为一系列确定的值
每次对8bit进行替换变异,步长8bit
case遍历
eff_map检验不为0
替换内容遍历
要求新case不能被bitfilp和arith生成过
朴实无华的执行并恢复原case
每次对16bit进行替换变异,步长8bit
每次对32bit进行替换变异,步长8bit
用户提供的字典里有token,用来替换要进行变异的文件内容,如果用户没提供就使用 bitflip 自动生成的 token
以8bit为步长,标记起始位置开始,替换为token
每个字节都替换一遍
遍历用户字典
出现以下情况,直接下一条token
替换,执行
所有token结束后恢复,跳回步骤1
以8bit为步长,标记起始位置插入token
以8bit为步长,标记起始位置开始,替换为在bitflip阶段生成的token
这是deterministic steps的最后一步
我们可以在这里设置完成状态
进行很大程度的杂乱破坏,随机组合,规则比较杂,但目的一致
通过将两个case按一定规则进行拼接,得到一个新case
HAVOC和SPLICING是相结合的,拼接case后会回到havoc进行随机变异
参考文章:
int
process(char
*
input
)
{
char
*
out;
char
*
rest;
int
len
;
if
(strncmp(
input
,
"u "
,
2
)
=
=
0
)
{
/
/
upper case command
char
*
rest;
len
=
strtol(
input
+
2
, &rest,
10
);
/
/
how many characters of the string to upper
-
case
rest
+
=
1
;
/
/
skip the first char (should be a space)
out
=
malloc(
len
+
strlen(
input
));
/
/
could be shorter, but play it safe
if
(
len
> (
int
)strlen(
input
))
{
printf(
"Specified length %d was larger than the input!\n"
,
len
);
return
1
;
}
else
if
(out
=
=
NULL)
{
printf(
"Failed to allocate memory\n"
);
return
1
;
}
for
(
int
i
=
0
; i !
=
len
; i
+
+
)
{
char c
=
rest[i];
if
(c >
96
&& c <
123
)
/
/
ascii a
-
z
{
c
-
=
32
;
}
out[i]
=
c;
}
out[
len
]
=
0
;
strcat(out, rest
+
len
);
/
/
append the remaining text
printf(
"%s"
, out);
free(out);
}
else
if
(strncmp(
input
,
"head "
,
5
)
=
=
0
)
{
/
/
head command
if
(strlen(
input
) >
6
)
{
len
=
strtol(
input
+
4
, &rest,
10
);
rest
+
=
1
;
/
/
skip the first char (should be a space)
rest[
len
]
=
'\0'
;
/
/
truncate string at specified offset
printf(
"%s\n"
, rest);
}
else
{
fprintf(stderr,
"head input was too small\n"
);
}
}
else
if
(strcmp(
input
,
"surprise!\n"
)
=
=
0
)
{
/
/
easter egg!
*
(char
*
)
1
=
2
;
}
else
{
return
1
;
}
return
0
;
}
int
main(
int
argc, char
*
argv[])
{
char
*
usage
=
"Usage: %s\n"
"Text utility - accepts commands and data on stdin and prints results to stdout.\n"
"\tInput | Output\n"
"\t------------------+-----------------------\n"
"\tu <N> <string> | Uppercased version of the first <N> bytes of <string>.\n"
"\thead <N> <string> | The first <N> bytes of <string>.\n"
;
char
input
[INPUTSIZE]
=
{
0
};
/
/
Slurp
input
if
(read(STDIN_FILENO,
input
, INPUTSIZE) <
0
)
{
fprintf(stderr,
"Couldn't read stdin.\n"
);
}
int
ret
=
process(
input
);
if
(ret)
{
fprintf(stderr, usage, argv[
0
]);
};
return
ret;
}
int
process(char
*
input
)
{
char
*
out;
char
*
rest;
int
len
;
if
(strncmp(
input
,
"u "
,
2
)
=
=
0
)
{
/
/
upper case command
char
*
rest;
len
=
strtol(
input
+
2
, &rest,
10
);
/
/
how many characters of the string to upper
-
case
rest
+
=
1
;
/
/
skip the first char (should be a space)
out
=
malloc(
len
+
strlen(
input
));
/
/
could be shorter, but play it safe
if
(
len
> (
int
)strlen(
input
))
{
printf(
"Specified length %d was larger than the input!\n"
,
len
);
return
1
;
}
else
if
(out
=
=
NULL)
{
printf(
"Failed to allocate memory\n"
);
return
1
;
}
for
(
int
i
=
0
; i !
=
len
; i
+
+
)
{
char c
=
rest[i];
if
(c >
96
&& c <
123
)
/
/
ascii a
-
z
{
c
-
=
32
;
}
out[i]
=
c;
}
out[
len
]
=
0
;
strcat(out, rest
+
len
);
/
/
append the remaining text
printf(
"%s"
, out);
free(out);
}
else
if
(strncmp(
input
,
"head "
,
5
)
=
=
0
)
{
/
/
head command
if
(strlen(
input
) >
6
)
{
len
=
strtol(
input
+
4
, &rest,
10
);
rest
+
=
1
;
/
/
skip the first char (should be a space)
rest[
len
]
=
'\0'
;
/
/
truncate string at specified offset
printf(
"%s\n"
, rest);
}
else
{
fprintf(stderr,
"head input was too small\n"
);
}
}
else
if
(strcmp(
input
,
"surprise!\n"
)
=
=
0
)
{
/
/
easter egg!
*
(char
*
)
1
=
2
;
}
else
{
return
1
;
}
return
0
;
}
int
main(
int
argc, char
*
argv[])
{
char
*
usage
=
"Usage: %s\n"
"Text utility - accepts commands and data on stdin and prints results to stdout.\n"
"\tInput | Output\n"
"\t------------------+-----------------------\n"
"\tu <N> <string> | Uppercased version of the first <N> bytes of <string>.\n"
"\thead <N> <string> | The first <N> bytes of <string>.\n"
;
char
input
[INPUTSIZE]
=
{
0
};
/
/
Slurp
input
if
(read(STDIN_FILENO,
input
, INPUTSIZE) <
0
)
{
fprintf(stderr,
"Couldn't read stdin.\n"
);
}
int
ret
=
process(
input
);
if
(ret)
{
fprintf(stderr, usage, argv[
0
]);
};
return
ret;
}
gettimeofday(&tv, &tz);
srandom(tv.tv_sec ^ tv.tv_usec ^ getpid());
while
((opt
=
getopt(argc, argv,
"+i:o:f:m:t:T:dnCB:S:M:x:Q"
)) >
0
)
switch (opt) {
case
'i'
:
/
*
input
dir
*
/
if
(in_dir) FATAL(
"Multiple -i options not supported"
);
in_dir
=
optarg;
…………
gettimeofday(&tv, &tz);
srandom(tv.tv_sec ^ tv.tv_usec ^ getpid());
while
((opt
=
getopt(argc, argv,
"+i:o:f:m:t:T:dnCB:S:M:x:Q"
)) >
0
)
switch (opt) {
case
'i'
:
/
*
input
dir
*
/
if
(in_dir) FATAL(
"Multiple -i options not supported"
);
in_dir
=
optarg;
…………
/
s数组定义
EXP_ST u8 virgin_bits[MAP_SIZE],
/
*
Regions yet untouched by fuzzing
*
/
virgin_tmout[MAP_SIZE],
/
*
Bits we haven't seen
in
tmouts
*
/
virgin_crash[MAP_SIZE];
/
*
Bits we haven't seen
in
crashes
*
/
EXP_ST void setup_shm(void) {
…………
if
(!in_bitmap) memset(virgin_bits,
255
, MAP_SIZE);
memset(virgin_tmout,
255
, MAP_SIZE);
memset(virgin_crash,
255
, MAP_SIZE);
/
s数组定义
EXP_ST u8 virgin_bits[MAP_SIZE],
/
*
Regions yet untouched by fuzzing
*
/
virgin_tmout[MAP_SIZE],
/
*
Bits we haven't seen
in
tmouts
*
/
virgin_crash[MAP_SIZE];
/
*
Bits we haven't seen
in
crashes
*
/
EXP_ST void setup_shm(void) {
…………
if
(!in_bitmap) memset(virgin_bits,
255
, MAP_SIZE);
memset(virgin_tmout,
255
, MAP_SIZE);
memset(virgin_crash,
255
, MAP_SIZE);
shm_id
=
shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL |
0600
);
…………
trace_bits
=
shmat(shm_id, NULL,
0
);
shm_id
=
shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL |
0600
);
…………
trace_bits
=
shmat(shm_id, NULL,
0
);
EXP_ST void init_forkserver(char
*
*
argv) {
static struct itimerval it;
int
st_pipe[
2
], ctl_pipe[
2
];
int
status;
s32 rlen;
EXP_ST void init_forkserver(char
*
*
argv) {
static struct itimerval it;
int
st_pipe[
2
], ctl_pipe[
2
];
int
status;
s32 rlen;
forksrv_pid
=
fork();
/
/
子进程为forkserver
if
(forksrv_pid <
0
) PFATAL(
"fork() failed"
);
/
/
fork失败
if
(!forksrv_pid) {
/
/
forkserver执行
…………
setsid();
/
/
让子进程完全独立运行
forksrv_pid
=
fork();
/
/
子进程为forkserver
if
(forksrv_pid <
0
) PFATAL(
"fork() failed"
);
/
/
fork失败
if
(!forksrv_pid) {
/
/
forkserver执行
…………
setsid();
/
/
让子进程完全独立运行
dup2(dev_null_fd,
1
);
dup2(dev_null_fd,
2
);
if
(out_file) {
dup2(dev_null_fd,
0
);
}
else
{
dup2(out_fd,
0
);
close(out_fd);
}
if
(dup2(ctl_pipe[
0
], FORKSRV_FD) <
0
) PFATAL(
"dup2() failed"
);
if
(dup2(st_pipe[
1
], FORKSRV_FD
+
1
) <
0
) PFATAL(
"dup2() failed"
);
dup2(dev_null_fd,
1
);
dup2(dev_null_fd,
2
);
if
(out_file) {
dup2(dev_null_fd,
0
);
}
else
{
dup2(out_fd,
0
);
close(out_fd);
}
if
(dup2(ctl_pipe[
0
], FORKSRV_FD) <
0
) PFATAL(
"dup2() failed"
);
if
(dup2(st_pipe[
1
], FORKSRV_FD
+
1
) <
0
) PFATAL(
"dup2() failed"
);
execv(target_path, argv);
/
*
Use a distinctive bitmap signature to tell the parent about execv()
falling through.
*
/
*
(u32
*
)trace_bits
=
EXEC_FAIL_SIG;
exit(
0
);
execv(target_path, argv);
/
*
Use a distinctive bitmap signature to tell the parent about execv()
falling through.
*
/
*
(u32
*
)trace_bits
=
EXEC_FAIL_SIG;
exit(
0
);
/
*
Close the unneeded endpoints.
*
/
close(ctl_pipe[
0
]);
close(st_pipe[
1
]);
fsrv_ctl_fd
=
ctl_pipe[
1
];
fsrv_st_fd
=
st_pipe[
0
];
/
/
等待返回消息
it.it_value.tv_sec
=
((exec_tmout
*
FORK_WAIT_MULT)
/
1000
);
it.it_value.tv_usec
=
((exec_tmout
*
FORK_WAIT_MULT)
%
1000
)
*
1000
;
setitimer(ITIMER_REAL, &it, NULL);
rlen
=
read(fsrv_st_fd, &status,
4
);
it.it_value.tv_sec
=
0
;
it.it_value.tv_usec
=
0
;
setitimer(ITIMER_REAL, &it, NULL);
if
(rlen
=
=
4
) {
OKF(
"All right - fork server is up."
);
return
;
}
/
*
Close the unneeded endpoints.
*
/
close(ctl_pipe[
0
]);
close(st_pipe[
1
]);
fsrv_ctl_fd
=
ctl_pipe[
1
];
fsrv_st_fd
=
st_pipe[
0
];
/
/
等待返回消息
it.it_value.tv_sec
=
((exec_tmout
*
FORK_WAIT_MULT)
/
1000
);
it.it_value.tv_usec
=
((exec_tmout
*
FORK_WAIT_MULT)
%
1000
)
*
1000
;
setitimer(ITIMER_REAL, &it, NULL);
rlen
=
read(fsrv_st_fd, &status,
4
);
it.it_value.tv_sec
=
0
;
it.it_value.tv_usec
=
0
;
setitimer(ITIMER_REAL, &it, NULL);
if
(rlen
=
=
4
) {
OKF(
"All right - fork server is up."
);
return
;
}
struct queue_entry {
u8
*
fname;
/
*
File
name
for
the test case
*
/
u32
len
;
/
*
Input
length
*
/
u8 cal_failed,
/
*
Calibration failed?
*
/
trim_done,
/
*
Trimmed?
*
/
was_fuzzed,
/
*
Had
any
fuzzing done yet?
*
/
passed_det,
/
*
Deterministic stages passed?
*
/
has_new_cov,
/
*
Triggers new coverage?
*
/
var_behavior,
/
*
Variable behavior?
*
/
favored,
/
*
Currently favored?
*
/
fs_redundant;
/
*
Marked as redundant
in
the fs?
*
/
u32 bitmap_size,
/
*
Number of bits
set
in
bitmap
*
/
exec_cksum;
/
*
Checksum of the execution trace
*
/
u64 exec_us,
/
*
Execution time (us)
*
/
handicap,
/
*
Number of queue cycles behind
*
/
depth;
/
*
Path depth
*
/
u8
*
trace_mini;
/
*
Trace bytes,
if
kept
*
/
u32 tc_ref;
/
*
Trace bytes ref count
*
/
struct queue_entry
*
next
,
/
*
Next
element,
if
any
*
/
*
next_100;
/
*
100
elements ahead
*
/
};
static struct queue_entry
*
queue,
/
*
Fuzzing queue (linked
list
)
*
/
*
queue_cur,
/
*
Current offset within the queue
*
/
*
queue_top,
/
*
Top of the
list
*
/
*
q_prev100;
/
*
Previous
100
marker
*
/
static struct queue_entry
*
top_rated[MAP_SIZE];
/
*
Top entries
for
bitmap bytes
*
/
struct queue_entry {
u8
*
fname;
/
*
File
name
for
the test case
*
/
u32
len
;
/
*
Input
length
*
/
u8 cal_failed,
/
*
Calibration failed?
*
/
trim_done,
/
*
Trimmed?
*
/
was_fuzzed,
/
*
Had
any
fuzzing done yet?
*
/
passed_det,
/
*
Deterministic stages passed?
*
/
has_new_cov,
/
*
Triggers new coverage?
*
/
var_behavior,
/
*
Variable behavior?
*
/
favored,
/
*
Currently favored?
*
/
fs_redundant;
/
*
Marked as redundant
in
the fs?
*
/
u32 bitmap_size,
/
*
Number of bits
set
in
bitmap
*
/
exec_cksum;
/
*
Checksum of the execution trace
*
/
u64 exec_us,
/
*
Execution time (us)
*
/
handicap,
/
*
Number of queue cycles behind
*
/
depth;
/
*
Path depth
*
/
u8
*
trace_mini;
/
*
Trace bytes,
if
kept
*
/
u32 tc_ref;
/
*
Trace bytes ref count
*
/
struct queue_entry
*
next
,
/
*
Next
element,
if
any
*
/
*
next_100;
/
*
100
elements ahead
*
/
};
static struct queue_entry
*
queue,
/
*
Fuzzing queue (linked
list
)
*
/
*
queue_cur,
/
*
Current offset within the queue
*
/
*
queue_top,
/
*
Top of the
list
*
/
*
q_prev100;
/
*
Previous
100
marker
*
/
static struct queue_entry
*
top_rated[MAP_SIZE];
/
*
Top entries
for
bitmap bytes
*
/
if
(dumb_mode || !score_changed)
return
;
if
(dumb_mode || !score_changed)
return
;
q
=
queue;
while
(q) {
q
-
>favored
=
0
;
q
=
q
-
>
next
;
}
q
=
queue;
while
(q) {
q
-
>favored
=
0
;
q
=
q
-
>
next
;
}
for
(i
=
0
; i < MAP_SIZE; i
+
+
)
if
(top_rated[i] && (temp_v[i >>
3
] & (
1
<< (i &
7
)))) {
u32 j
=
MAP_SIZE >>
3
;
while
(j
-
-
)
if
(top_rated[i]
-
>trace_mini[j])
temp_v[j] &
=
~top_rated[i]
-
>trace_mini[j];
top_rated[i]
-
>favored
=
1
;
queued_favored
+
+
;
if
(!top_rated[i]
-
>was_fuzzed) pending_favored
+
+
;
}
for
(i
=
0
; i < MAP_SIZE; i
+
+
)
if
(top_rated[i] && (temp_v[i >>
3
] & (
1
<< (i &
7
)))) {
u32 j
=
MAP_SIZE >>
3
;
while
(j
-
-
)
if
(top_rated[i]
-
>trace_mini[j])
temp_v[j] &
=
~top_rated[i]
-
>trace_mini[j];
top_rated[i]
-
>favored
=
1
;
queued_favored
+
+
;
if
(!top_rated[i]
-
>was_fuzzed) pending_favored
+
+
;
}
q
=
queue;
while
(q) {
mark_as_redundant(q, !q
-
>favored);
q
=
q
-
>
next
;
}
q
=
queue;
while
(q) {
mark_as_redundant(q, !q
-
>favored);
q
=
q
-
>
next
;
}
queue_cycle
+
+
;
current_entry
=
0
;
cur_skipped_paths
=
0
;
queue_cur
=
queue;
queue_cycle
+
+
;
current_entry
=
0
;
cur_skipped_paths
=
0
;
queue_cur
=
queue;
while
(seek_to) {
current_entry
+
+
;
seek_to
-
-
;
queue_cur
=
queue_cur
-
>
next
;
}
while
(seek_to) {
current_entry
+
+
;
seek_to
-
-
;
queue_cur
=
queue_cur
-
>
next
;
}
show_stats();
if
(not_on_tty) {
ACTF(
"Entering queue cycle %llu."
, queue_cycle);
fflush(stdout);
}
if
(not_on_tty) {
ACTF(
"Entering queue cycle %llu."
, queue_cycle);
fflush(stdout);
}
if
(queued_paths
=
=
prev_queued) {
if
(use_splicing) cycles_wo_finds
+
+
;
else
use_splicing
=
1
;
}
else
cycles_wo_finds
=
0
;
prev_queued
=
queued_paths;
if
(queued_paths
=
=
prev_queued) {
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2022-7-25 18:27
被Azyka编辑
,原因: 增加图片引用