Compare commits

..

30 Commits
ciao ... main

Author SHA1 Message Date
jingheng23 5388405798 from mrcl
1 month ago
Five b02665dfaf five提交
1 month ago
1LuB 417f2b72fc (⊙_⊙)?
1 month ago
LRJ 1769701da1 慕容承霖提交
1 month ago
pp6szq3fo fb0e71ec2b 上传文件至 'src/AFLplusplus-stable/src'
1 month ago
LRJ b8a806faf4 林睿健阅读部分
1 month ago
LRJ b20b0cba68 0109
1 month ago
1LuB 38233e1c84 123
1 month ago
p98n2ja4z 872bca58cd ADD file via upload
1 month ago
p98n2ja4z e88421ff36 Delete 'src/AFLplusplus-stable/src/afl-analyze.c'
1 month ago
ciao_ 6048b9431b 11
2 months ago
pp6szq3fo da972d8375 Delete '新建 文本文档.txt'
2 months ago
pp6szq3fo 01407018c1 Delete '乔成炜202212409016.docx'
2 months ago
py2qwehgm faa103021c ADD file via upload
2 months ago
pp6szq3fo dd18cff714 ADD file via upload
2 months ago
p98n2ja4z 9829fae5a7 Merge pull request '。' (#5) from ph2ocwf5z/AFLplusplus:five into main
2 months ago
Five b34e507083 修改
2 months ago
Five 07a2430fdc yep
2 months ago
p98n2ja4z 75b9d284f3 整体逻辑框架
4 months ago
pqg5afj7f 54cf7395a5 ADD file via upload
4 months ago
Five e950591f61 emmm
4 months ago
Five cf9ee76aae five
4 months ago
ph2ocwf5z e12b99bad1 ADD file via upload
4 months ago
p98n2ja4z de1ce7bc50 Merge pull request '李林轩_branch' (#2) from 李林轩_branch into main
4 months ago
1LuB 833075b5d9 Merge branch 'main' of https://bdgit.educoder.net/p98n2ja4z/AFLplusplus
4 months ago
1LuB 945de3a2c8 llxswlp
4 months ago
p98n2ja4z 2fd062c0b6 Delete 'doc/1.docx'
4 months ago
p98n2ja4z d65d488b97 afl_analyze.c 功能分析
4 months ago
1LuB 366233b009 doc
4 months ago
1LuB dbc698415f v1.0
4 months ago

Binary file not shown.

@ -1,5 +1,2 @@
# QQLLMW
[afl-fuzz-stats.c](src\AFLplusplus-stable\src\afl-fuzz-stats.c) 注释代码
本人负责项目编译运行

Binary file not shown.

@ -96,6 +96,7 @@ static afl_forkserver_t fsrv = {0}; /* The forkserver */
/* Classify tuple counts. This is a slow & naive version, but good enough here.
*/
//将模糊测试的错误数进行归并,在不造成太大影响的情况下减少运算、提升性能
static u8 count_class_lookup[256] = {
[0] = 0,
@ -110,21 +111,25 @@ static u8 count_class_lookup[256] = {
};
//结束子进程
static void kill_child() {
if (fsrv.child_pid > 0) {
//kill函数杀死对应pid的子进程并将其标志位置为1
kill(fsrv.child_pid, fsrv.child_kill_signal);
//将子进程的pid置为-1即无法选中
fsrv.child_pid = -1;
}
}
//对内存中的字节进行分类通过预定的count_class_lookup数组实现分类的效果
static void classify_counts(u8 *mem, u32 mem_size) {
u32 i = mem_size;
//如果只对边缘探测有要求只用设置为bool变量
if (edges_only) {
while (i--) {
@ -148,10 +153,11 @@ static void classify_counts(u8 *mem, u32 mem_size) {
}
/* See if any bytes are set in the bitmap. */
//遍历整个bitmap检查是否有字节在bitmap里面被设置了
static inline u8 anything_set(void) {
//使用fsrv.trace_bits模拟bitmap
u32 *ptr = (u32 *)fsrv.trace_bits;
//map_size的大小除以4因为是按字节进行搜索
u32 i = (map_size >> 2);
while (i--) {
@ -165,7 +171,7 @@ static inline u8 anything_set(void) {
}
/* Get rid of temp files (atexit handler). */
//在函数结束时调用,删除临时文件
static void at_exit_handler(void) {
unlink(fsrv.out_file); /* Ignore errors */
@ -173,16 +179,16 @@ static void at_exit_handler(void) {
}
/* Read initial file. */
//读取需要分析的文件的起始状态
static void read_initial_file(void) {
struct stat st;
s32 fd = open(in_file, O_RDONLY);
//无法读取分支
if (fd < 0) { PFATAL("Unable to open '%s'", in_file); }
//读取到的文件内容为空分支
if (fstat(fd, &st) || !st.st_size) { FATAL("Zero-sized input file."); }
//读取文件内容超过缓存最大值分支
if (st.st_size >= TMIN_MAX_FILE) {
FATAL("Input file is too large (%ld MB max)", TMIN_MAX_FILE / 1024 / 1024);
@ -202,56 +208,63 @@ static void read_initial_file(void) {
/* Execute target application. Returns exec checksum, or 0 if program
times out. */
//起一个目标程序的镜像进程,用于在不影响程序正常使用的前提下对程序进行模糊测试
static u64 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
//将该程序的镜像地址写入到测试栈中
afl_fsrv_write_to_testcase(&fsrv, mem, len);
//使用afl_fsrv_run_target函数尝试运行镜像进程并将结果返回到fsrv_run_result_t对象中
fsrv_run_result_t ret = afl_fsrv_run_target(&fsrv, exec_tmout, &stop_soon);
//创建镜像失败分支
if (ret == FSRV_RUN_ERROR) {
FATAL("Error in forkserver");
} else if (ret == FSRV_RUN_NOINST) {
}
//运行镜像缺失分支
else if (ret == FSRV_RUN_NOINST) {
FATAL("Target not instrumented");
} else if (ret == FSRV_RUN_NOBITS) {
}
//运行报错分支
else if (ret == FSRV_RUN_NOBITS) {
FATAL("Failed to run target");
}
//调用classify_counts函数对测试进程内存中的字节进行分类以作进一步模糊测试
classify_counts(fsrv.trace_bits, fsrv.map_size);
//全局变量中total_execs自增对测试程序数进行记录
total_execs++;
if (stop_soon) {
//用户操作退出Ctrl+C弹出退出示警
SAYF(cRST cLRD "\n+++ Analysis aborted by user +++\n" cRST);
exit(1);
}
/* Always discard inputs that time out. */
//镜像运行超时全局变量中exec_hangs自增对测试程序超时数进行记录
if (fsrv.last_run_timed_out) {
exec_hangs++;
return 0;
}
//校验和
u64 cksum = hash64(fsrv.trace_bits, fsrv.map_size, HASH_CONST);
if (ret == FSRV_RUN_CRASH) {
/* We don't actually care if the target is crashing or not,
except that when it does, the checksum should be different. */
//校验和全1异或每位取反
cksum ^= 0xffffffff;
}
//记录初始校验和
if (first_run) { orig_cksum = cksum; }
return cksum;
@ -261,13 +274,14 @@ static u64 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
#ifdef USE_COLOR
/* Helper function to display a human-readable character. */
//将内存内字节打印成用户可读字符
static void show_char(u8 val) {
switch (val) {
case 0 ... 32:
case 127 ... 255:
//通过格式化输出实现
SAYF("#%02x", val);
break;
@ -279,7 +293,7 @@ static void show_char(u8 val) {
}
/* Show the legend */
//将内存字节设置为不同字体颜色,方便用户区分
static void show_legend(void) {
SAYF(" " cLGR bgGRA " 01 " cRST " - no-op block " cBLK bgLGN
@ -298,7 +312,7 @@ static void show_legend(void) {
#endif /* USE_COLOR */
/* Interpret and report a pattern in the input file. */
//以16进制形式储存文件分析字节行为
static void dump_hex(u32 len, u8 *b_data) {
u32 i;
@ -314,7 +328,7 @@ static void dump_hex(u32 len, u8 *b_data) {
u8 rtype = b_data[i] & 0x0f;
/* Look ahead to determine the length of run. */
//确定运行长度
while (i + rlen < len && (b_data[i] >> 7) == (b_data[i + rlen] >> 7)) {
if (rtype < (b_data[i + rlen] & 0x0f)) {
@ -328,7 +342,7 @@ static void dump_hex(u32 len, u8 *b_data) {
}
/* Try to do some further classification based on length & value. */
//对字节相应类型进行分类
if (rtype == RESP_FIXED) {
switch (rlen) {
@ -338,9 +352,9 @@ static void dump_hex(u32 len, u8 *b_data) {
u16 val = *(u16 *)(in_data + i);
/* Small integers may be length fields. */
if (val && (val <= in_len || SWAP16(val) <= in_len)) {
//判断为运行长度
rtype = RESP_LEN;
break;
@ -349,7 +363,7 @@ static void dump_hex(u32 len, u8 *b_data) {
/* Uniform integers may be checksums. */
if (val && abs(in_data[i] - in_data[i + 1]) > 32) {
//判断为校验和
rtype = RESP_CKSUM;
break;
@ -360,7 +374,7 @@ static void dump_hex(u32 len, u8 *b_data) {
}
case 4: {
//同上
u32 val = *(u32 *)(in_data + i);
/* Small integers may be length fields. */
@ -406,17 +420,17 @@ static void dump_hex(u32 len, u8 *b_data) {
for (off = 0; off < rlen; off++) {
/* Every 16 digits, display offset. */
//每4个字节作为一组进行输出
if (!((i + off) % 16)) {
if (off) { SAYF(cRST cLCY ">"); }
if (use_hex_offsets) {
//规格化输出
SAYF(cRST cGRA "%s[%06x] " cRST, (i + off) ? "\n" : "", i + off);
} else {
//规格化输出
SAYF(cRST cGRA "%s[%06u] " cRST, (i + off) ? "\n" : "", i + off);
}
@ -424,7 +438,7 @@ static void dump_hex(u32 len, u8 *b_data) {
}
switch (rtype) {
//根据rtype分析的不同类型进行不同的上色便于用户区分
case RESP_NONE:
SAYF(cLGR bgGRA);
break;
@ -448,11 +462,11 @@ static void dump_hex(u32 len, u8 *b_data) {
break;
}
//输出
show_char(in_data[i + off]);
if (off != rlen - 1 && (i + off + 1) % 16) {
//补齐
SAYF(" ");
} else {
@ -464,14 +478,14 @@ static void dump_hex(u32 len, u8 *b_data) {
}
#else
//根据用户是否需求16进制进行输出的处理
if (use_hex_offsets)
SAYF(" Offset %x, length %u: ", i, rlen);
else
SAYF(" Offset %u, length %u: ", i, rlen);
switch (rtype) {
//输出测试分析得到的信息
case RESP_NONE:
SAYF("no-op block\n");
break;
@ -509,9 +523,9 @@ static void dump_hex(u32 len, u8 *b_data) {
}
/* Actually analyze! */
//分析函数
static void analyze() {
//初始化变量
u32 i;
u32 boring_len = 0, prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0;
@ -527,14 +541,14 @@ static void analyze() {
#endif /* USE_COLOR */
for (i = 0; i < in_len; i++) {
//遍历程序的每一个字节
u64 xor_ff, xor_01, sub_10, add_10;
u8 xff_orig, x01_orig, s10_orig, a10_orig;
/* Perform walking byte adjustments across the file. We perform four
operations designed to elicit some response from the underlying
code. */
//对程序的每个字节进行异或0xff、异或0x01、减0x10、加0x20操作然后进行运行分析查看是否会对程序的运行产生影响
in_data[i] ^= 0xff;
xor_ff = analyze_run_target(in_data, in_len, 0);
@ -549,34 +563,34 @@ static void analyze() {
in_data[i] -= 0x10;
/* Classify current behavior. */
//记录校验和,以观察是否有影响
xff_orig = (xor_ff == orig_cksum);
x01_orig = (xor_01 == orig_cksum);
s10_orig = (sub_10 == orig_cksum);
a10_orig = (add_10 == orig_cksum);
if (xff_orig && x01_orig && s10_orig && a10_orig) {
//如果都不报错,则将该字节标记为无用项
b_data[i] = RESP_NONE;
boring_len++;
} else if (xff_orig || x01_orig || s10_orig || a10_orig) {
//报错则标记为错误项
b_data[i] = RESP_MINOR;
boring_len++;
} else if (xor_ff == xor_01 && xor_ff == sub_10 && xor_ff == add_10) {
//如果经过不同方式修改后的校验和相等,则将该字节标记为可自修复项
b_data[i] = RESP_FIXED;
} else {
//否则则将该字节标记为变异项
b_data[i] = RESP_VARIABLE;
}
/* When all checksums change, flip most significant bit of b_data. */
//如果所有变异操作都与上一个字节的测试不一样,就翻转最高位
if (prev_xff != xor_ff && prev_x01 != xor_01 && prev_s10 != sub_10 &&
prev_a10 != add_10) {
@ -592,7 +606,7 @@ static void analyze() {
prev_a10 = add_10;
}
//输出分析结果
dump_hex(in_len, b_data);
SAYF("\n");
@ -612,7 +626,7 @@ static void analyze() {
}
/* Handle Ctrl-C and the like. */
//用户自出终止程序的代理函数
static void handle_stop_sig(int sig) {
(void)sig;
@ -623,7 +637,7 @@ static void handle_stop_sig(int sig) {
}
/* Do basic preparations - persistent fds, filenames, etc. */
//设置测试环境
static void set_up_environment(char **argv) {
u8 *x;
@ -719,7 +733,7 @@ static void set_up_environment(char **argv) {
}
/* Setup signal handlers, duh. */
//设置信号处理程序,进行初始化
static void setup_signal_handlers(void) {
struct sigaction sa;
@ -744,7 +758,7 @@ static void setup_signal_handlers(void) {
}
/* Display usage hints. */
//当用户输入-h时调用此函数回显该工具的使用方法
static void usage(u8 *argv0) {
SAYF(
@ -801,7 +815,7 @@ static void usage(u8 *argv0) {
}
/* Main entry point */
//main函数用户使用的实际接口
int main(int argc, char **argv_orig, char **envp) {
s32 opt;

@ -91,244 +91,114 @@ static u8 use_64bit = 0;
to keep the code simple. */
static void edit_params(int argc, char **argv) {
<<<<<<< HEAD
u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS");
u32 i, input_index;
#ifdef __APPLE__
u8 use_clang_as = 0;
if (clang_mode && !afl_as) {
use_clang_as = 1;
afl_as = getenv("AFL_CC");
if (!afl_as) afl_as = getenv("AFL_CXX");
if (!afl_as) afl_as = "clang";
}
#endif
if (!tmp_dir) { tmp_dir = getenv("TEMP"); }
if (!tmp_dir) { tmp_dir = getenv("TMP"); }
if (!tmp_dir) { tmp_dir = "/tmp"; }
as_params = ck_alloc((argc + 32) * sizeof(u8 *));
if (unlikely((INT_MAX - 32) < argc || !as_params)) {
FATAL("Too many parameters passed to as");
}
as_params[0] = afl_as ? afl_as : (u8 *)"as";
as_params[argc] = 0;
for (input_index = argc - 1; input_index > 0; input_index--) {
input_file = argv[input_index];
if (strncmp(input_file, "-g", 2)) break;
}
if (input_index == 0)
FATAL("Could not find input file (not called through afl-gcc?)");
for (i = 1; (s32)i < argc; i++) {
if (i == input_index) continue;
if (!strcmp(argv[i], "--64")) {
use_64bit = 1;
} else if (!strcmp(argv[i], "--32")) {
use_64bit = 0;
}
#ifdef __APPLE__
if (!strcmp(argv[i], "-arch") && i + 1 < (u32)argc) {
=======
// 获取临时目录路径和AFL_AS环境变量
u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS");
u32 i, input_index;
#ifdef __APPLE__
u8 use_clang_as = 0;
/* On MacOS X, the Xcode cctool 'as' driver is a bit stale and does not work
with the code generated by newer versions of clang that are hand-built
by the user. See the thread here: https://goo.gl/HBWDtn.
To work around this, when using clang and running without AFL_AS
specified, we will actually call 'clang -c' instead of 'as -q' to
compile the assembly file.
The tools aren't cmdline-compatible, but at least for now, we can
seemingly get away with this by making only very minor tweaks. Thanks
to Nico Weber for the idea. */
// 在MacOS下若使用clang且没有设置AFL_AS则使用clang作为汇编器
if (clang_mode && !afl_as) {
use_clang_as = 1;
afl_as = getenv("AFL_CC");
if (!afl_as) afl_as = getenv("AFL_CXX");
if (!afl_as) afl_as = "clang";
afl_as = getenv("AFL_CC"); // 获取AFL_CC环境变量
if (!afl_as) afl_as = getenv("AFL_CXX"); // 获取AFL_CXX环境变量
if (!afl_as) afl_as = "clang"; // 默认使用clang
}
#endif
#endif /* __APPLE__ */
/* Although this is not documented, GCC also uses TEMP and TMP when TMPDIR
is not set. We need to check these non-standard variables to properly
handle the pass_thru logic later on. */
// 如果TMPDIR环境变量为空尝试从TEMP和TMP获取临时目录
if (!tmp_dir) { tmp_dir = getenv("TEMP"); }
if (!tmp_dir) { tmp_dir = getenv("TMP"); }
if (!tmp_dir) { tmp_dir = "/tmp"; }
if (!tmp_dir) { tmp_dir = "/tmp"; } // 默认临时目录为"/tmp"
// 为汇编参数分配内存,确保不会超过最大参数个数
as_params = ck_alloc((argc + 32) * sizeof(u8 *));
if (unlikely((INT_MAX - 32) < argc || !as_params)) {
FATAL("Too many parameters passed to as");
FATAL("Too many parameters passed to as"); // 参数过多,终止
}
// 设置汇编器命令
as_params[0] = afl_as ? afl_as : (u8 *)"as";
as_params[argc] = 0;
/* Find the input file. It's usually located near the end.
Assume there won't be any arguments referring to files after the input
file, e.g. as input.s -o output.o */
// 查找输入文件,通常位于命令行参数的最后
for (input_index = argc - 1; input_index > 0; input_index--) {
input_file = argv[input_index];
/* Clang may add debug arguments after the input file. */
// 如果遇到调试选项,跳过
if (strncmp(input_file, "-g", 2)) break;
}
// 如果没有找到输入文件,输出错误信息
if (input_index == 0)
FATAL("Could not find input file (not called through afl-gcc?)");
// 遍历参数,处理与汇编相关的选项
for (i = 1; (s32)i < argc; i++) {
if (i == input_index) continue; // 跳过输入文件
if (i == input_index) continue;
// 处理64位和32位选项
if (!strcmp(argv[i], "--64")) {
use_64bit = 1;
} else if (!strcmp(argv[i], "--32")) {
use_64bit = 0;
}
#ifdef __APPLE__
/* The Apple case is a bit different... */
// 在MacOS下处理架构选项
if (!strcmp(argv[i], "-arch") && i + 1 < (u32)argc) {
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
if (!strcmp(argv[i + 1], "x86_64"))
use_64bit = 1;
else if (!strcmp(argv[i + 1], "i386"))
FATAL("Sorry, 32-bit Apple platforms are not supported.");
<<<<<<< HEAD
}
if (clang_mode && (!strcmp(argv[i], "-q") || !strcmp(argv[i], "-Q")))
continue;
#endif
as_params[as_par_cnt++] = argv[i];
}
#ifdef __APPLE__
if (use_clang_as) {
as_params[as_par_cnt++] = "-c";
as_params[as_par_cnt++] = "-x";
as_params[as_par_cnt++] = "assembler";
}
#endif
if (input_file[0] == '-') {
if (!strcmp(input_file + 1, "-version")) {
just_version = 1;
modified_file = input_file;
goto wrap_things_up;
}
if (input_file[1]) {
FATAL("Incorrect use (not called through afl-gcc?)");
} else {
input_file = NULL;
}
} else {
=======
}
/* Strip options that set the preference for a particular upstream
assembler in Xcode. */
// 跳过不相关的选项
if (clang_mode && (!strcmp(argv[i], "-q") || !strcmp(argv[i], "-Q")))
continue;
#endif /* __APPLE__ */
// 将参数添加到汇编器参数列表
as_params[as_par_cnt++] = argv[i];
}
#ifdef __APPLE__
/* When calling clang as the upstream assembler, append -c -x assembler
and hope for the best. */
// 如果使用clang作为汇编器追加相关选项
if (use_clang_as) {
as_params[as_par_cnt++] = "-c";
as_params[as_par_cnt++] = "-x";
as_params[as_par_cnt++] = "assembler";
}
#endif
#endif /* __APPLE__ */
// 如果输入文件是"-"参数,检查是否为版本信息
if (input_file[0] == '-') {
if (!strcmp(input_file + 1, "-version")) {
just_version = 1;
modified_file = input_file;
goto wrap_things_up;
goto wrap_things_up; // 跳到结束处理
}
if (input_file[1]) {
FATAL("Incorrect use (not called through afl-gcc?)");
} else {
input_file = NULL;
input_file = NULL; // 没有文件参数
}
} else {
/* Check if this looks like a standard invocation as a part of an attempt
to compile a program, rather than using gcc on an ad-hoc .s file in
a format we may not understand. This works around an issue compiling
NSS. */
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
// 检查输入文件是否为临时文件,并决定是否需要通过工具传递
if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) &&
strncmp(input_file, "/var/tmp/", 9) &&
strncmp(input_file, "/tmp/", 5) &&
getenv("AFL_AS_FORCE_INSTRUMENT") == NULL) {
<<<<<<< HEAD
pass_thru = 1;
} else if (getenv("AFL_AS_FORCE_INSTRUMENT")) {
unsetenv("AFL_AS_FORCE_INSTRUMENT");
unsetenv("AFL_AS_FORCE_INSTRUMENT"); // 强制插桩的环境变量取消
}
}
modified_file = alloc_printf("%s/.afl-%u-%u-%u.s", tmp_dir, (u32)getpid(),
(u32)time(NULL), (u32)random());
=======
pass_thru = 1;
} else if (getenv("AFL_AS_FORCE_INSTRUMENT")) {
unsetenv("AFL_AS_FORCE_INSTRUMENT");
}
}
// 为汇编文件生成一个唯一的临时文件名
modified_file = alloc_printf("%s/.afl-%u-%u-%u.s", tmp_dir, (u32)getpid(),
(u32)time(NULL), (u32)random());
}
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
wrap_things_up:
@ -383,15 +253,6 @@ static void add_instrumentation(void) {
if (!outf) { PFATAL("fdopen() failed"); }
while (fgets(line, MAX_LINE, inf)) {
<<<<<<< HEAD
=======
/* In some cases, we want to defer writing the instrumentation trampoline
until after all the labels, macros, comments, etc. If we're in this
mode, and if the line starts with a tab followed by a character, dump
the trampoline now. */
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
if (!pass_thru && !skip_intel && !skip_app && !skip_csect && instr_ok &&
instrument_next && line[0] == '\t' && isalpha(line[1])) {

@ -1895,196 +1895,132 @@ param_st parse_fsanitize(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan) {
these have_*, otherwise they may not work as expected.
*/
void add_sanitizers(aflcc_state_t *aflcc, char **envp) {
<<<<<<< HEAD
if (getenv("AFL_USE_ASAN") || aflcc->have_asan) {
if (getenv("AFL_USE_MSAN") || aflcc->have_msan)
FATAL("ASAN and MSAN are mutually exclusive");
if (getenv("AFL_HARDEN"))
FATAL("ASAN and AFL_HARDEN are mutually exclusive");
if (aflcc->compiler_mode == GCC_PLUGIN && !aflcc->have_staticasan) {
insert_param(aflcc, "-static-libasan");
}
add_defs_fortify(aflcc, 0);
if (!aflcc->have_asan) {
insert_param(aflcc, "-fsanitize=address");
insert_param(aflcc, "-fno-common");
}
aflcc->have_asan = 1;
} else if (getenv("AFL_USE_MSAN") || aflcc->have_msan) {
if (getenv("AFL_USE_ASAN") || aflcc->have_asan)
FATAL("ASAN and MSAN are mutually exclusive");
if (getenv("AFL_HARDEN"))
FATAL("MSAN and AFL_HARDEN are mutually exclusive");
add_defs_fortify(aflcc, 0);
if (!aflcc->have_msan) { insert_param(aflcc, "-fsanitize=memory"); }
aflcc->have_msan = 1;
}
if (getenv("AFL_USE_UBSAN") || aflcc->have_ubsan) {
if (!aflcc->have_ubsan) {
insert_param(aflcc, "-fsanitize=undefined");
insert_param(aflcc, "-fsanitize-undefined-trap-on-error");
insert_param(aflcc, "-fno-sanitize-recover=all");
}
if (!aflcc->have_fp) {
insert_param(aflcc, "-fno-omit-frame-pointer");
aflcc->have_fp = 1;
}
aflcc->have_ubsan = 1;
}
if (getenv("AFL_USE_TSAN") || aflcc->have_tsan) {
if (!aflcc->have_fp) {
insert_param(aflcc, "-fno-omit-frame-pointer");
aflcc->have_fp = 1;
}
if (!aflcc->have_tsan) { insert_param(aflcc, "-fsanitize=thread"); }
aflcc->have_tsan = 1;
}
if (getenv("AFL_USE_LSAN") && !aflcc->have_lsan) {
insert_param(aflcc, "-fsanitize=leak");
add_defs_lsan_ctrl(aflcc);
aflcc->have_lsan = 1;
}
if (getenv("AFL_USE_CFISAN") || aflcc->have_cfisan) {
if (aflcc->compiler_mode == GCC_PLUGIN || aflcc->compiler_mode == GCC) {
if (!aflcc->have_fcf) { insert_param(aflcc, "-fcf-protection=full"); }
} else {
if (!aflcc->lto_mode && !aflcc->have_flto) {
uint32_t i = 0, found = 0;
while (envp[i] != NULL && !found) {
if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
}
if (!found) { insert_param(aflcc, "-flto"); }
aflcc->have_flto = 1;
}
if (!aflcc->have_cfisan) { insert_param(aflcc, "-fsanitize=cfi"); }
if (!aflcc->have_hidden) {
insert_param(aflcc, "-fvisibility=hidden");
aflcc->have_hidden = 1;
}
aflcc->have_cfisan = 1;
}
}
=======
// 如果启用了 ASAN (地址消毒器),则进行相关配置
if (getenv("AFL_USE_ASAN") || aflcc->have_asan) {
// 如果同时启用了 MSAN (内存消毒器),则报错,因为 ASAN 和 MSAN 不能同时使用
if (getenv("AFL_USE_MSAN") || aflcc->have_msan)
FATAL("ASAN and MSAN are mutually exclusive");
// 如果启用了 AFL_HARDEN则报错因为 ASAN 和 AFL_HARDEN 不能同时使用
if (getenv("AFL_HARDEN"))
FATAL("ASAN and AFL_HARDEN are mutually exclusive");
// 如果是 GCC 插件模式,并且没有启用静态 ASAN 库,则添加静态 ASAN 库的选项
if (aflcc->compiler_mode == GCC_PLUGIN && !aflcc->have_staticasan) {
insert_param(aflcc, "-static-libasan");
}
// 添加 fortify 配置0表示没有额外的强化
add_defs_fortify(aflcc, 0);
if (!aflcc->have_asan) {
// 如果没有启用 ASAN则添加相应的编译选项来启用地址消毒
if (!aflcc->have_asan) {
insert_param(aflcc, "-fsanitize=address");
insert_param(aflcc, "-fno-common");
}
aflcc->have_asan = 1;
} else if (getenv("AFL_USE_MSAN") || aflcc->have_msan) {
aflcc->have_asan = 1; // 标记已经启用了 ASAN
}
// 如果启用了 MSAN (内存消毒器),则进行相关配置
else if (getenv("AFL_USE_MSAN") || aflcc->have_msan) {
// 如果同时启用了 ASAN则报错因为 ASAN 和 MSAN 不能同时使用
if (getenv("AFL_USE_ASAN") || aflcc->have_asan)
FATAL("ASAN and MSAN are mutually exclusive");
// 如果启用了 AFL_HARDEN则报错因为 MSAN 和 AFL_HARDEN 不能同时使用
if (getenv("AFL_HARDEN"))
FATAL("MSAN and AFL_HARDEN are mutually exclusive");
// 添加 fortify 配置0表示没有额外的强化
add_defs_fortify(aflcc, 0);
// 如果没有启用 MSAN则添加相应的编译选项来启用内存消毒
if (!aflcc->have_msan) { insert_param(aflcc, "-fsanitize=memory"); }
aflcc->have_msan = 1;
aflcc->have_msan = 1; // 标记已经启用了 MSAN
}
// 如果启用了 UBSAN (未定义行为消毒器),则进行相关配置
if (getenv("AFL_USE_UBSAN") || aflcc->have_ubsan) {
// 如果没有启用 UBSAN则添加相应的编译选项来启用未定义行为消毒
if (!aflcc->have_ubsan) {
insert_param(aflcc, "-fsanitize=undefined");
insert_param(aflcc, "-fsanitize-undefined-trap-on-error");
insert_param(aflcc, "-fno-sanitize-recover=all");
}
// 如果没有启用帧指针,则添加相应的选项来启用帧指针
if (!aflcc->have_fp) {
insert_param(aflcc, "-fno-omit-frame-pointer");
aflcc->have_fp = 1;
}
aflcc->have_ubsan = 1;
aflcc->have_ubsan = 1; // 标记已经启用了 UBSAN
}
// 如果启用了 TSAN (线程消毒器),则进行相关配置
if (getenv("AFL_USE_TSAN") || aflcc->have_tsan) {
// 如果没有启用帧指针,则添加相应的选项来启用帧指针
if (!aflcc->have_fp) {
insert_param(aflcc, "-fno-omit-frame-pointer");
aflcc->have_fp = 1;
}
// 如果没有启用 TSAN则添加相应的编译选项来启用线程消毒
if (!aflcc->have_tsan) { insert_param(aflcc, "-fsanitize=thread"); }
aflcc->have_tsan = 1;
aflcc->have_tsan = 1; // 标记已经启用了 TSAN
}
// 如果启用了 LSAN (泄漏消毒器),则进行相关配置
if (getenv("AFL_USE_LSAN") && !aflcc->have_lsan) {
// 添加编译选项来启用泄漏消毒
insert_param(aflcc, "-fsanitize=leak");
// 添加 LSAN 控制的定义
add_defs_lsan_ctrl(aflcc);
aflcc->have_lsan = 1;
aflcc->have_lsan = 1; // 标记已经启用了 LSAN
}
// 如果启用了 CFISAN (控制流完整性消毒器),则进行相关配置
if (getenv("AFL_USE_CFISAN") || aflcc->have_cfisan) {
// 如果是 GCC 插件模式或 GCC 模式,则启用完整的控制流保护
if (aflcc->compiler_mode == GCC_PLUGIN || aflcc->compiler_mode == GCC) {
// 如果没有启用控制流保护,则添加相应选项
if (!aflcc->have_fcf) { insert_param(aflcc, "-fcf-protection=full"); }
} else {
// 如果没有启用 LTO (链接时优化),则添加 LTO 选项
if (!aflcc->lto_mode && !aflcc->have_flto) {
uint32_t i = 0, found = 0;
while (envp[i] != NULL && !found) {
if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
}
if (!found) { insert_param(aflcc, "-flto"); }
aflcc->have_flto = 1;
aflcc->have_flto = 1; // 标记已经启用了 LTO
}
// 如果没有启用 CFISAN则添加相应选项来启用控制流完整性消毒
if (!aflcc->have_cfisan) { insert_param(aflcc, "-fsanitize=cfi"); }
// 如果没有启用隐藏符号,则启用隐藏符号选项
if (!aflcc->have_hidden) {
insert_param(aflcc, "-fvisibility=hidden");
aflcc->have_hidden = 1;
}
aflcc->have_cfisan = 1;
aflcc->have_cfisan = 1; // 标记已经启用了 CFISAN
}
}
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
}
/* Add params to enable LLVM SanCov, the native PCGUARD */
@ -2635,10 +2571,13 @@ void add_gcc_plugin(aflcc_state_t *aflcc) {
/* Add some miscellaneous params required by our instrumentation. */
void add_misc_params(aflcc_state_t *aflcc) {
// 如果环境变量 AFl_NO_BUILTIN 或其他相关环境变量被设置,或者启用了 LTO 模式
// 则禁用内置的字符串和内存比较函数
if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
getenv("AFL_LLVM_LAF_ALL") || getenv("AFL_LLVM_CMPLOG") ||
aflcc->lto_mode) {
// 禁用常见的字符串和内存比较函数的内置实现,防止与模糊测试产生冲突
insert_param(aflcc, "-fno-builtin-strcmp");
insert_param(aflcc, "-fno-builtin-strncmp");
insert_param(aflcc, "-fno-builtin-strcasecmp");
@ -2650,31 +2589,46 @@ void add_misc_params(aflcc_state_t *aflcc) {
}
if (!aflcc->have_pic) { insert_param(aflcc, "-fPIC"); }
// 如果没有启用位置无关代码PIC则添加 -fPIC 参数
if (!aflcc->have_pic) {
insert_param(aflcc, "-fPIC");
}
// 如果环境变量 AFL_HARDEN 被设置,启用栈保护等安全选项
if (getenv("AFL_HARDEN")) {
// 启用所有函数的栈保护
insert_param(aflcc, "-fstack-protector-all");
if (!aflcc->fortify_set) add_defs_fortify(aflcc, 2);
// 如果未设置 Fortify设置 Fortify 防护等级
if (!aflcc->fortify_set)
add_defs_fortify(aflcc, 2);
}
// 如果环境变量 AFL_DONT_OPTIMIZE 未设置,启用优化选项
if (!getenv("AFL_DONT_OPTIMIZE")) {
// 启用调试符号生成
insert_param(aflcc, "-g");
if (!aflcc->have_o) insert_param(aflcc, "-O3");
if (!aflcc->have_unroll) insert_param(aflcc, "-funroll-loops");
// 如果没有设置 -O 优化级别,设置为 -O3最高优化
if (!aflcc->have_o)
insert_param(aflcc, "-O3");
// 如果没有设置循环展开,启用循环展开优化
if (!aflcc->have_unroll)
insert_param(aflcc, "-funroll-loops");
// 以下代码被注释掉了,但如果有指定架构优化选项(如 -march也可以启用
// if (strlen(aflcc->march_opt) > 1 && aflcc->march_opt[0] == '-')
// insert_param(aflcc, aflcc->march_opt);
}
// 如果设置了 x_set 标志,插入 -x none 参数
if (aflcc->x_set) {
insert_param(aflcc, "-x");
insert_param(aflcc, "none");
}
}
@ -3659,50 +3613,86 @@ static void edit_params(aflcc_state_t *aflcc, u32 argc, char **argv,
}
/* Main entry point */
int main(int argc, char **argv, char **envp) {
aflcc_state_t *aflcc = malloc(sizeof(aflcc_state_t));
aflcc_state_init(aflcc, (u8 *)argv[0]);
check_environment_vars(envp);
find_built_deps(aflcc);
compiler_mode_by_callname(aflcc);
compiler_mode_by_environ(aflcc);
compiler_mode_by_cmdline(aflcc, argc, argv);
instrument_mode_by_environ(aflcc);
mode_final_checkout(aflcc, argc, argv);
process_params(aflcc, 1, argc, argv);
maybe_usage(aflcc, argc, argv);
classDiagram
class AFLCCMain {
+main(argc, argv, envp)
+initializeState()
+checkEnvironmentVariables()
+findDependencies()
+determineCompilerMode()
+determineInstrumentationMode()
+finalizeMode()
+processParameters()
+maybeShowUsage()
+notifyMode()
+debugArguments()
+editParameters()
+executeCompiler()
}
mode_notification(aflcc);
class AFLCCState {
-cc_params: char**
-cc_par_cnt: u32
-passthrough: u8
-debug: u8
+aflcc_state_init(state, prog_name)
}
if (aflcc->debug) debugf_args(argc, argv);
class EnvironmentChecker {
+check_environment_vars(envp)
}
edit_params(aflcc, argc, argv, envp);
class DependencyFinder {
+find_built_deps(aflcc)
}
if (aflcc->debug)
debugf_args((s32)aflcc->cc_par_cnt, (char **)aflcc->cc_params);
class CompilerModeHandler {
+compiler_mode_by_callname(aflcc)
+compiler_mode_by_environ(aflcc)
+compiler_mode_by_cmdline(aflcc, argc, argv)
}
if (aflcc->passthrough) {
class InstrumentationModeHandler {
+instrument_mode_by_environ(aflcc)
}
argv[0] = aflcc->cc_params[0];
execvp(aflcc->cc_params[0], (char **)argv);
class ModeFinalizer {
+mode_final_checkout(aflcc, argc, argv)
}
} else {
class ParameterProcessor {
+process_params(aflcc, start_idx, argc, argv)
}
execvp(aflcc->cc_params[0], (char **)aflcc->cc_params);
class UsageNotifier {
+maybe_usage(aflcc, argc, argv)
}
}
class ModeNotifier {
+mode_notification(aflcc)
}
FATAL("Oops, failed to execute '%s' - check your PATH", aflcc->cc_params[0]);
class Debugger {
+debugf_args(argc, argv)
}
return 0;
class ParameterEditor {
+edit_params(aflcc, argc, argv, envp)
}
}
class Executor {
+execute_compiler(aflcc, argv)
}
AFLCCMain --> AFLCCState : 使
AFLCCMain --> EnvironmentChecker : 使
AFLCCMain --> DependencyFinder : 使
AFLCCMain --> CompilerModeHandler : 使
AFLCCMain --> InstrumentationModeHandler : 使
AFLCCMain --> ModeFinalizer : 使
AFLCCMain --> ParameterProcessor : 使
AFLCCMain --> UsageNotifier : 使
AFLCCMain --> ModeNotifier : 使
AFLCCMain --> Debugger : 使
AFLCCMain --> ParameterEditor : 使
AFLCCMain --> Executor : 使

File diff suppressed because it is too large Load Diff

@ -28,508 +28,590 @@
#include "envs.h"
#include <limits.h>
// 定义一个二维数组用于存储模糊测试fuzzing的不同状态信息。
static char fuzzing_state[4][12] = {"started :-)", "in progress", "final phase",
"finished..."};
// 函数用于获取当前的模糊测试状态。
char *get_fuzzing_state(afl_state_t *afl) {
// 获取当前时间(毫秒)。
u64 cur_ms = get_cur_time();
// 计算自上次发现问题以来经过的时间。
u64 cur_ms = get_cur_time();
u64 last_find = cur_ms - afl->last_find_time;
// 计算当前运行周期的时间。
u64 cur_run_time = cur_ms - afl->start_time;
// 计算总的运行时间。
u64 cur_total_run_time = afl->prev_run_time + cur_run_time;
// 如果是非插桩模式,返回"in progress"状态。
if (unlikely(afl->non_instrumented_mode)) {
return fuzzing_state[1];
} else if (unlikely(cur_run_time <
60 * 3 * 1000 || // 如果当前运行周期小于3分钟
cur_total_run_time <
60 * 5 * 1000)) { // 或者总运行时间小于5分钟
// 返回"started :-)"状态。
} else if (unlikely(cur_run_time < 60 * 3 * 1000 ||
cur_total_run_time < 60 * 5 * 1000)) {
return fuzzing_state[0];
} else {
// 计算最近一次发现问题占当前运行时间的百分比。
u64 last_find_100 = 100 * last_find;
u64 percent_cur = last_find_100 / cur_run_time;
// 计算最近一次发现问题占总运行时间的百分比。
u64 percent_total = last_find_100 / cur_total_run_time;
// 如果当前和总运行时间的百分比都大于等于80%,返回"finished..."状态。
if (unlikely(percent_cur >= 80 && percent_total >= 80)) {
return fuzzing_state[3];
// 如果当前和总运行时间的百分比都大于等于55%,返回"final phase"状态。
} else if (unlikely(percent_cur >= 55 && percent_total >= 55)) {
return fuzzing_state[2];
// 否则,返回"in progress"状态。
} else {
return fuzzing_state[1];
}
}
}
/* 写入模糊测试设置文件 */
/* Write fuzzer setup file */
// 函数用于写入模糊测试器的设置文件。
void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
// 定义两个用于存储文件名的数组。
u8 fn[PATH_MAX], fn2[PATH_MAX];
// 构造目标哈希文件的路径并创建该文件。
snprintf(fn2, PATH_MAX, "%s/target_hash", afl->out_dir);
FILE *f2 = create_ffile(fn2);
// 在Linux系统中如果启用了nyx模式则加载目标哈希。
#ifdef __linux__
if (afl->fsrv.nyx_mode) {
nyx_load_target_hash(&afl->fsrv);
// 将64位目标哈希写入文件。
fprintf(f2, "%llx\n", afl->fsrv.nyx_target_hash64);
} else {
// 否则,计算并写入目标二进制的哈希。
fprintf(f2, "%p\n", (void *)get_binary_hash(afl->fsrv.target_path));
}
#else
// 在非Linux系统中计算并写入目标二进制的哈希。
fprintf(f2, "%p\n", (void *)get_binary_hash(afl->fsrv.target_path));
#endif
// 关闭目标哈希文件。
fclose(f2);
// 构造模糊测试器设置文件的路径并创建该文件。
snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir);
FILE *f = create_ffile(fn);
u32 i;
// 写入环境变量部分的标题。
fprintf(f, "# environment variables:\n");
// 计算环境变量数组的长度。
u32 s_afl_env = (u32)sizeof(afl_environment_variables) /
sizeof(afl_environment_variables[0]) -
1U;
// 遍历环境变量数组。
for (i = 0; i < s_afl_env; ++i) {
char *val;
// 如果环境变量已设置,则获取其值。
if ((val = getenv(afl_environment_variables[i])) != NULL) {
// 将环境变量及其值写入设置文件。
fprintf(f, "%s=%s\n", afl_environment_variables[i], val);
}
}
// 关闭设置文件。
fclose(f);
}
// 写入命令行参数到设置文件。
fprintf(f, "# command line:\n");
fprintf(f, "# command line:\n");
// 定义一个 size_t 类型的变量 j用于循环计数。
size_t j;
// 遍历命令行参数列表。
for (i = 0; i < argc; ++i) {
// 如果不是第一个参数,输出一个空格以分隔参数。
if (i) fprintf(f, " ");
size_t j;
for (i = 0; i < argc; ++i) {
// 在 Android 系统中,使用 memchr 函数检查参数中是否包含单引号。
if (i) fprintf(f, " ");
#ifdef __ANDROID__
if (memchr(argv[i], '\'', strlen(argv[i]))) {
if (memchr(argv[i], '\'', strlen(argv[i]))) {
#else
// 在非 Android 系统中,使用 strchr 函数检查参数中是否包含单引号。
if (strchr(argv[i], '\'')) {
if (strchr(argv[i], '\'')) {
#endif
// 如果参数中包含单引号,输出一个单引号开始标记参数。
fprintf(f, "'");
// 遍历参数字符串中的每个字符。
for (j = 0; j < strlen(argv[i]); j++)
// 如果字符是单引号,输出两个单引号以转义它。
if (argv[i][j] == '\'') fprintf(f, "'\"'\"'");
// 否则,正常输出字符。
else
fprintf(f, "%c", argv[i][j]);
// 参数字符串结束后,输出一个单引号结束标记。
fprintf(f, "'");
// 如果参数中不包含单引号,直接输出参数。
} else {
fprintf(f, "'%s'", argv[i]);
fprintf(f, "'");
for (j = 0; j < strlen(argv[i]); j++)
if (argv[i][j] == '\'')
fprintf(f, "'\"'\"'");
else
fprintf(f, "%c", argv[i][j]);
fprintf(f, "'");
} else {
fprintf(f, "'%s'", argv[i]);
}
}
}
// 输出换行符,结束命令行参数的写入。
fprintf(f, "\n");
// 关闭设置文件。
fclose(f);
// 这行代码的目的是避免编译器警告,表明该变量在当前上下文中未使用。
(void)(afl_environment_deprecated);
fprintf(f, "\n");
fclose(f);
(void)(afl_environment_deprecated);
}
// 定义一个函数,用于检查字符串 line 是否以 key 开头。
static bool starts_with(char *key, char *line) {
// 使用 strncmp 函数比较 key 和 line 的前 strlen(key) 个字符。
return strncmp(key, line, strlen(key)) == 0;
}
/* 当恢复模糊测试时,加载现有的统计文件。*/
/* load some of the existing stats file when resuming.*/
void load_stats_file(afl_state_t *afl) {
// 定义文件指针 f用于读取统计文件。
FILE *f;
// 定义缓冲区 buf用于存储从文件中读取的行。
u8 buf[MAX_LINE];
// 定义指针 lptr指向 buf 中当前处理的行。
u8 *lptr;
// 定义文件名 fn用于存储统计文件的路径。
u8 fn[PATH_MAX];
// 定义行号 lineno用于记录读取的行数。
u32 lineno = 0;
// 构造统计文件的路径并尝试打开文件。
u8 buf[MAX_LINE];
u8 *lptr;
u8 fn[PATH_MAX];
u32 lineno = 0;
snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
f = fopen(fn, "r");
if (!f) {
// 如果无法打开文件,输出警告信息并返回。
WARNF("Unable to load stats file '%s'", fn);
return;
}
// 循环读取文件中的每一行。
while ((lptr = fgets(buf, MAX_LINE, f))) {
// 每次读取新行时,行号递增。
lineno++;
// 初始化指针 lstartptr 指向当前行的开始。
u8 *lstartptr = lptr;
// 初始化指针 rptr 指向当前行的结束。
u8 *rptr = lptr + strlen(lptr) - 1;
// 定义 keystring 用于存储行中的键。
u8 keystring[MAX_LINE];
// 移动 lptr 指针,跳过行中的非键部分,直到遇到冒号或行尾。
u8 keystring[MAX_LINE];
while (*lptr != ':' && lptr < rptr) {
lptr++;
}
// 如果当前行是空行或者只包含换行符,输出警告信息并继续处理下一行。
if (*lptr == '\n' || !*lptr) {
WARNF("Unable to read line %d of stats file", lineno);
continue;
}
// 如果当前字符是冒号,表示这一行包含键值对信息。
if (*lptr == ':') {
// 将冒号替换为字符串结束符,分割键和值。
*lptr = 0;
strcpy(keystring, lstartptr);
// 移动指针到值的开始位置。
lptr++;
// 定义指针 nptr用于strtoull函数中的转换。
char *nptr;
// 如果键是"run_time"将值转换为毫秒并存储到afl->prev_run_time。
if (starts_with("run_time", keystring)) {
afl->prev_run_time = 1000 * strtoull(lptr, &nptr, 10);
}
// 如果键是"cycles_done"将值转换为无符号长长整型并存储到afl->queue_cycle。
if (starts_with("cycles_done", keystring)) {
afl->queue_cycle =
strtoull(lptr, &nptr, 10) ? strtoull(lptr, &nptr, 10) + 1 : 0;
}
// 如果键是"calibration_time"将值转换为微秒并存储到afl->calibration_time_us。
if (starts_with("calibration_time", keystring)) {
afl->calibration_time_us = strtoull(lptr, &nptr, 10) * 1000000;
}
// 如果键是"sync_time"将值转换为微秒并存储到afl->sync_time_us。
if (starts_with("sync_time", keystring)) {
afl->sync_time_us = strtoull(lptr, &nptr, 10) * 1000000;
}
// 如果键是"cmplog_time"将值转换为微秒并存储到afl->cmplog_time_us。
if (starts_with("cmplog_time", keystring)) {
afl->cmplog_time_us = strtoull(lptr, &nptr, 10) * 1000000;
}
// 如果键是"trim_time"将值转换为微秒并存储到afl->trim_time_us。
if (starts_with("trim_time", keystring)) {
afl->trim_time_us = strtoull(lptr, &nptr, 10) * 1000000;
}
// 如果键是"execs_done"将值转换为无符号长长整型并存储到afl->fsrv.total_execs。
if (starts_with("execs_done", keystring)) {
afl->fsrv.total_execs = strtoull(lptr, &nptr, 10);
}
// 如果键是"corpus_count"将值转换为无符号整型并存储到afl->queued_items。
if (starts_with("corpus_count", keystring)) {
u32 corpus_count = strtoul(lptr, &nptr, 10);
if (corpus_count != afl->queued_items) {
WARNF(
"queue/ has been modified -- things might not work, you're "
"on your own!");
sleep(3);
}
}
// 如果键是"corpus_found"将值转换为无符号整型并存储到afl->queued_discovered。
if (starts_with("corpus_found", keystring)) {
afl->queued_discovered = strtoul(lptr, &nptr, 10);
}
// 如果键是"corpus_imported"将值转换为无符号整型并存储到afl->queued_imported。
if (starts_with("corpus_imported", keystring)) {
afl->queued_imported = strtoul(lptr, &nptr, 10);
}
// 如果键是"max_depth"将值转换为无符号整型并存储到afl->max_depth。
if (starts_with("max_depth", keystring)) {
afl->max_depth = strtoul(lptr, &nptr, 10);
}
// 如果键是"saved_crashes"将值转换为无符号长长整型并存储到afl->saved_crashes。
if (starts_with("saved_crashes", keystring)) {
afl->saved_crashes = strtoull(lptr, &nptr, 10);
}
// 如果键是"saved_hangs"将值转换为无符号长长整型并存储到afl->saved_hangs。
if (starts_with("saved_hangs", keystring)) {
afl->saved_hangs = strtoull(lptr, &nptr, 10);
}
}
// 如果有保存的崩溃信息写入README文件。
if (afl->saved_crashes) { write_crash_readme(afl); }
}
// 结束函数。
return;
}
/* Update stats file for unattended monitoring. */
// 函数用于写入 AFL++ 的统计信息到文件。
void write_stats_file(afl_state_t * afl, u32 t_bytes, double bitmap_cvg,
double stability, double eps) {
if (afl->saved_crashes) { write_crash_readme(afl); }
return;
}
/* Update stats file for unattended monitoring. */
void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
double stability, double eps) {
#ifndef __HAIKU__
// 在非 Haiku 系统中,获取子进程的资源使用情况。
struct rusage rus;
struct rusage rus;
#endif
// 获取当前时间。
u64 cur_time = get_cur_time();
// 定义临时和最终的统计文件名。
u8 fn_tmp[PATH_MAX], fn_final[PATH_MAX];
// 定义文件指针。
FILE *f;
// 构造临时统计文件的路径。
snprintf(fn_tmp, PATH_MAX, "%s/.fuzzer_stats_tmp", afl->out_dir);
// 构造最终统计文件的路径。
snprintf(fn_final, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
// 创建并打开临时统计文件。
f = create_ffile(fn_tmp);
// 如果没有提供 bitmap_cvg, stability, eps则使用上一次的值。
if (!bitmap_cvg && !stability && !eps) {
bitmap_cvg = afl->last_bitmap_cvg;
stability = afl->last_stability;
} else {
// 否则更新上一次的值。
afl->last_bitmap_cvg = bitmap_cvg;
afl->last_stability = stability;
afl->last_eps = eps;
}
u64 cur_time = get_cur_time();
u8 fn_tmp[PATH_MAX];
u8 fn_final[PATH_MAX];
FILE *f;
// 如果距离上次更新平均执行次数的时间超过60秒或者这是第一次更新则更新平均执行次数。
if (unlikely(!afl->last_avg_exec_update ||
cur_time - afl->last_avg_exec_update >= 60000)) {
afl->last_avg_execs_saved =
(double)(1000 * (afl->fsrv.total_execs - afl->last_avg_execs)) /
(double)(cur_time - afl->last_avg_exec_update);
afl->last_avg_execs = afl->fsrv.total_execs;
afl->last_avg_exec_update = cur_time;
}
snprintf(fn_tmp, PATH_MAX, "%s/.fuzzer_stats_tmp", afl->out_dir);
snprintf(fn_final, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
f = create_ffile(fn_tmp);
/* Keep last values in case we're called from another context
where exec/sec stats and such are not readily available. */
if (!bitmap_cvg && !stability && !eps) {
bitmap_cvg = afl->last_bitmap_cvg;
stability = afl->last_stability;
} else {
afl->last_bitmap_cvg = bitmap_cvg;
afl->last_stability = stability;
afl->last_eps = eps;
}
if ((unlikely(!afl->last_avg_exec_update ||
cur_time - afl->last_avg_exec_update >= 60000))) {
afl->last_avg_execs_saved =
(double)(1000 * (afl->fsrv.total_execs - afl->last_avg_execs)) /
(double)(cur_time - afl->last_avg_exec_update);
afl->last_avg_execs = afl->fsrv.total_execs;
afl->last_avg_exec_update = cur_time;
}
#ifndef __HAIKU__
// 在非 Haiku
// 系统中获取子进程的资源使用情况如果失败则将内存使用设置为0。
if (getrusage(RUSAGE_CHILDREN, &rus)) { rus.ru_maxrss = 0; }
if (getrusage(RUSAGE_CHILDREN, &rus)) { rus.ru_maxrss = 0; }
#endif
// 计算总运行时间(毫秒)。
u64 runtime_ms = afl->prev_run_time + cur_time - afl->start_time;
// 计算总开销时间(毫秒)。
u64 overhead_ms = (afl->calibration_time_us + afl->sync_time_us +
afl->trim_time_us + afl->cmplog_time_us) /
1000;
// 如果运行时间为0则设置为1以避免除以0的错误。
if (!runtime_ms) { runtime_ms = 1; }
// 写入统计信息到文件。
fprintf(f, "start_time : %llu\n" /* ... 其他统计信息 ... */,
/* 参数列表 */);
// 忽略错误,继续执行。
// 如果启用了调试模式,写入额外的调试信息。
if (afl->debug) {
u32 i = 0;
fprintf(f, "virgin_bytes :");
// 遍历 virgin_bits 数组写入非0xff的值。
for (i = 0; i < afl->fsrv.real_map_size; i++) {
if (afl->virgin_bits[i] != 0xff) {
fprintf(f, " %u[%02x]", i, afl->virgin_bits[i]);
}
}
fprintf(f, "\n");
fprintf(f, "var_bytes :");
// 遍历 var_bytes 数组写入非0的值。
for (i = 0; i < afl->fsrv.real_map_size; i++) {
if (afl->var_bytes[i]) { fprintf(f, " %u", i); }
u64 runtime_ms = afl->prev_run_time + cur_time - afl->start_time;
u64 overhead_ms = (afl->calibration_time_us + afl->sync_time_us +
afl->trim_time_us + afl->cmplog_time_us) /
1000;
if (!runtime_ms) { runtime_ms = 1; }
fprintf(
f,
"start_time : %llu\n"
"last_update : %llu\n"
"run_time : %llu\n"
"fuzzer_pid : %u\n"
"cycles_done : %llu\n"
"cycles_wo_finds : %llu\n"
"time_wo_finds : %llu\n"
"fuzz_time : %llu\n"
"calibration_time : %llu\n"
"cmplog_time : %llu\n"
"sync_time : %llu\n"
"trim_time : %llu\n"
"execs_done : %llu\n"
"execs_per_sec : %0.02f\n"
"execs_ps_last_min : %0.02f\n"
"corpus_count : %u\n"
"corpus_favored : %u\n"
"corpus_found : %u\n"
"corpus_imported : %u\n"
"corpus_variable : %u\n"
"max_depth : %u\n"
"cur_item : %u\n"
"pending_favs : %u\n"
"pending_total : %u\n"
"stability : %0.02f%%\n"
"bitmap_cvg : %0.02f%%\n"
"saved_crashes : %llu\n"
"saved_hangs : %llu\n"
"last_find : %llu\n"
"last_crash : %llu\n"
"last_hang : %llu\n"
"execs_since_crash : %llu\n"
"exec_timeout : %u\n"
"slowest_exec_ms : %u\n"
"peak_rss_mb : %lu\n"
"cpu_affinity : %d\n"
"edges_found : %u\n"
"total_edges : %u\n"
"var_byte_count : %u\n"
"havoc_expansion : %u\n"
"auto_dict_entries : %u\n"
"testcache_size : %llu\n"
"testcache_count : %u\n"
"testcache_evict : %u\n"
"afl_banner : %s\n"
"afl_version : " VERSION
"\n"
"target_mode : %s%s%s%s%s%s%s%s%s%s\n"
"command_line : %s\n",
(afl->start_time /*- afl->prev_run_time*/) / 1000, cur_time / 1000,
runtime_ms / 1000, (u32)getpid(),
afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
afl->longest_find_time > cur_time - afl->last_find_time
? afl->longest_find_time / 1000
: ((afl->start_time == 0 || afl->last_find_time == 0)
? 0
: (cur_time - afl->last_find_time) / 1000),
(runtime_ms - MIN(runtime_ms, overhead_ms)) / 1000,
afl->calibration_time_us / 1000000, afl->cmplog_time_us / 1000000,
afl->sync_time_us / 1000000, afl->trim_time_us / 1000000,
afl->fsrv.total_execs,
afl->fsrv.total_execs / ((double)(runtime_ms) / 1000),
afl->last_avg_execs_saved, afl->queued_items, afl->queued_favored,
afl->queued_discovered, afl->queued_imported, afl->queued_variable,
afl->max_depth, afl->current_entry, afl->pending_favored,
afl->pending_not_fuzzed, stability, bitmap_cvg, afl->saved_crashes,
afl->saved_hangs, afl->last_find_time / 1000, afl->last_crash_time / 1000,
afl->last_hang_time / 1000, afl->fsrv.total_execs - afl->last_crash_execs,
afl->fsrv.exec_tmout, afl->slowest_exec_ms,
#ifndef __HAIKU__
#ifdef __APPLE__
(unsigned long int)(rus.ru_maxrss >> 20),
#else
(unsigned long int)(rus.ru_maxrss >> 10),
#endif
#else
-1UL,
#endif
#ifdef HAVE_AFFINITY
afl->cpu_aff,
#else
-1,
#endif
t_bytes, afl->fsrv.real_map_size, afl->var_byte_count, afl->expand_havoc,
afl->a_extras_cnt, afl->q_testcase_cache_size,
afl->q_testcase_cache_count, afl->q_testcase_evictions, afl->use_banner,
afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "",
afl->fsrv.cs_mode ? "coresight" : "",
afl->non_instrumented_mode ? " non_instrumented " : "",
afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "",
afl->persistent_mode ? "persistent " : "",
afl->shmem_testcase_mode ? "shmem_testcase " : "",
afl->deferred_mode ? "deferred " : "",
(afl->unicorn_mode || afl->fsrv.qemu_mode || afl->fsrv.cs_mode ||
afl->non_instrumented_mode || afl->no_forkserver || afl->crash_mode ||
afl->persistent_mode || afl->deferred_mode)
? ""
: "default",
afl->orig_cmdline);
/* ignore errors */
if (afl->debug) {
u32 i = 0;
fprintf(f, "virgin_bytes :");
for (i = 0; i < afl->fsrv.real_map_size; i++) {
if (afl->virgin_bits[i] != 0xff) {
fprintf(f, " %u[%02x]", i, afl->virgin_bits[i]);
}
fprintf(f, "\n");
}
// 关闭文件。
fclose(f);
// 将临时文件重命名为最终文件。
rename(fn_tmp, fn_final);
fprintf(f, "\n");
fprintf(f, "var_bytes :");
for (i = 0; i < afl->fsrv.real_map_size; i++) {
if (afl->var_bytes[i]) { fprintf(f, " %u", i); }
}
fprintf(f, "\n");
}
fclose(f);
rename(fn_tmp, fn_final);
}
#ifdef INTROSPECTION
// 函数用于写入队列的统计信息。
void write_queue_stats(afl_state_t * afl) {
FILE *f;
// 构造队列数据文件的路径。
u8 *fn = alloc_printf("%s/queue_data", afl->out_dir);
// 尝试打开文件。
if ((f = fopen(fn, "w")) != NULL) {
u32 id;
// 写入列标题。
fprintf(
f,
"# filename, length, exec_us, selected, skipped, mutations, finds, "
"crashes, timeouts, bitmap_size, perf_score, weight, colorized, "
"favored, disabled\n");
// 遍历队列中的每个条目。
for (id = 0; id < afl->queued_items; ++id) {
struct queue_entry *q = afl->queue_buf[id];
// 写入队列条目的统计信息。
fprintf(f, "\"%s\",%u,%llu,%u,%u,%llu,%u,%u,%u,%u,%.3f,%.3f,%u,%u,%u\n",
q->fname, q->len, q->exec_us, q->stats_selected,
q->stats_skipped, q->stats_mutated, q->stats_finds,
q->stats_crashes, q->stats_tmouts, q->bitmap_size,
q->perf_score, q->weight, q->colorized, q->favored,
q->disabled);
}
void write_queue_stats(afl_state_t *afl) {
FILE *f;
u8 *fn = alloc_printf("%s/queue_data", afl->out_dir);
if ((f = fopen(fn, "w")) != NULL) {
u32 id;
fprintf(f,
"# filename, length, exec_us, selected, skipped, mutations, finds, "
"crashes, timeouts, bitmap_size, perf_score, weight, colorized, "
"favored, disabled\n");
for (id = 0; id < afl->queued_items; ++id) {
struct queue_entry *q = afl->queue_buf[id];
fprintf(f, "\"%s\",%u,%llu,%u,%u,%llu,%u,%u,%u,%u,%.3f,%.3f,%u,%u,%u\n",
q->fname, q->len, q->exec_us, q->stats_selected, q->stats_skipped,
q->stats_mutated, q->stats_finds, q->stats_crashes,
q->stats_tmouts, q->bitmap_size, q->perf_score, q->weight,
q->colorized, q->favored, q->disabled);
// 关闭文件。
fclose(f);
}
// 释放文件名字符串的内存。
ck_free(fn);
fclose(f);
}
ck_free(fn);
}
#endif
/* Update the plot file if there is a reason to. */
// 函数用于根据条件可能更新绘图文件。
void maybe_update_plot_file(afl_state_t * afl, u32 t_bytes, double bitmap_cvg,
double eps) {
// 如果不需要更新UI或者程序即将停止或者统计数据没有变化或者运行时间小于60秒则不更新绘图文件。
if (unlikely(!afl->force_ui_update &&
(afl->stop_soon ||
(afl->plot_prev_qp == afl->queued_items &&
afl->plot_prev_pf == afl->pending_favored &&
afl->plot_prev_pnf == afl->pending_not_fuzzed &&
afl->plot_prev_ce == afl->current_entry &&
afl->plot_prev_qc == afl->queue_cycle &&
afl->plot_prev_uc == afl->saved_crashes &&
afl->plot_prev_uh == afl->saved_hangs &&
afl->plot_prev_md == afl->max_depth &&
afl->plot_prev_ed == afl->fsrv.total_execs) ||
!afl->queue_cycle ||
get_cur_time() - afl->start_time <= 60000))) {
return;
}
void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
double eps) {
if (unlikely(!afl->force_ui_update &&
(afl->stop_soon ||
(afl->plot_prev_qp == afl->queued_items &&
afl->plot_prev_pf == afl->pending_favored &&
afl->plot_prev_pnf == afl->pending_not_fuzzed &&
afl->plot_prev_ce == afl->current_entry &&
afl->plot_prev_qc == afl->queue_cycle &&
afl->plot_prev_uc == afl->saved_crashes &&
afl->plot_prev_uh == afl->saved_hangs &&
afl->plot_prev_md == afl->max_depth &&
afl->plot_prev_ed == afl->fsrv.total_execs) ||
!afl->queue_cycle ||
get_cur_time() - afl->start_time <= 60000))) {
// 更新绘图文件中的上一次统计数据。
afl->plot_prev_qp = afl->queued_items;
afl->plot_prev_pf = afl->pending_favored;
afl->plot_prev_pnf = afl->pending_not_fuzzed;
afl->plot_prev_ce = afl->current_entry;
afl->plot_prev_qc = afl->queue_cycle;
afl->plot_prev_uc = afl->saved_crashes;
afl->plot_prev_uh = afl->saved_hangs;
afl->plot_prev_md = afl->max_depth;
afl->plot_prev_ed = afl->fsrv.total_execs;
/* 在绘图文件中记录以下字段:
relative_time, cycles_done, cur_item, corpus_count, corpus_not_fuzzed,
favored_not_fuzzed, saved_crashes, saved_hangs, max_depth,
execs_per_sec, edges_found */
// 写入统计数据到绘图文件。
fprintf(afl->fsrv.plot_file,
"%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, "
"%llu, %u\n",
((afl->prev_run_time + get_cur_time() - afl->start_time) / 1000),
afl->queue_cycle - 1, afl->current_entry, afl->queued_items,
afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg,
afl->saved_crashes, afl->saved_hangs, afl->max_depth, eps,
afl->plot_prev_ed, t_bytes); /* ignore errors */
// 清空输出缓冲区,确保数据写入文件。
fflush(afl->fsrv.plot_file);
}
/* 记录确定性阶段的效率 */
// 函数用于记录确定性阶段的效率数据。
void plot_profile_data(afl_state_t * afl, struct queue_entry * q) {
// 获取当前时间(毫秒)。
u64 current_ms = get_cur_time() - afl->start_time;
// 计算当前的边数非255字节
u32 current_edges = count_non_255_bytes(afl, afl->virgin_bits);
// 计算确定性发现率。
double det_finding_rate = (double)afl->havoc_prof->total_det_edge * 100.0 /
(double)current_edges,
det_time_rate = (double)afl->havoc_prof->total_det_time * 100.0 /
(double)current_ms;
// 初始化未确定的位数量。
u32 ndet_bits = 0;
// 遍历 skipdet_g->virgin_det_bits 数组,计算未确定的位数量。
for (u32 i = 0; i < afl->fsrv.map_size; i++) {
if (afl->skipdet_g->virgin_det_bits[i]) ndet_bits += 1;
}
return;
// 计算已确定的模糊测试率。
double det_fuzzed_rate = (double)ndet_bits * 100.0 / (double)current_edges;
// 写入确定性阶段的效率数据到文件。
fprintf(afl->fsrv.det_plot_file,
"[%02lld:%02lld:%02lld] fuzz %d (%d), find %d/%d among %d(%02.2f) "
"and spend %lld/%lld(%02.2f), cover %02.2f yet, %d/%d undet bits, "
"continue %d.\n",
current_ms / 1000 / 3600, (current_ms / 1000 / 60) % 60,
(current_ms / 1000) % 60, afl->current_entry, q->fuzz_level,
afl->havoc_prof->edge_det_stage, afl->havoc_prof->edge_havoc_stage,
current_edges, det_finding_rate,
afl->havoc_prof->det_stage_time / 1000,
afl->havoc_prof->havoc_stage_time / 1000, det_time_rate,
det_fuzzed_rate, q->skipdet_e->undet_bits,
afl->skipdet_g->undet_bits_threshold, q->skipdet_e->continue_inf);
// 清空输出缓冲区,确保数据写入文件。
fflush(afl->fsrv.det_plot_file);
}
afl->plot_prev_qp = afl->queued_items;
afl->plot_prev_pf = afl->pending_favored;
afl->plot_prev_pnf = afl->pending_not_fuzzed;
afl->plot_prev_ce = afl->current_entry;
afl->plot_prev_qc = afl->queue_cycle;
afl->plot_prev_uc = afl->saved_crashes;
afl->plot_prev_uh = afl->saved_hangs;
afl->plot_prev_md = afl->max_depth;
afl->plot_prev_ed = afl->fsrv.total_execs;
/* Fields in the file:
relative_time, afl->cycles_done, cur_item, corpus_count, corpus_not_fuzzed,
favored_not_fuzzed, saved_crashes, saved_hangs, max_depth,
execs_per_sec, edges_found */
fprintf(afl->fsrv.plot_file,
"%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, "
"%u\n",
((afl->prev_run_time + get_cur_time() - afl->start_time) / 1000),
afl->queue_cycle - 1, afl->current_entry, afl->queued_items,
afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg,
afl->saved_crashes, afl->saved_hangs, afl->max_depth, eps,
afl->plot_prev_ed, t_bytes); /* ignore errors */
fflush(afl->fsrv.plot_file);
}
/* Log deterministic stage efficiency */
void plot_profile_data(afl_state_t *afl, struct queue_entry *q) {
u64 current_ms = get_cur_time() - afl->start_time;
u32 current_edges = count_non_255_bytes(afl, afl->virgin_bits);
double det_finding_rate = (double)afl->havoc_prof->total_det_edge * 100.0 /
(double)current_edges,
det_time_rate = (double)afl->havoc_prof->total_det_time * 100.0 /
(double)current_ms;
u32 ndet_bits = 0;
for (u32 i = 0; i < afl->fsrv.map_size; i++) {
if (afl->skipdet_g->virgin_det_bits[i]) ndet_bits += 1;
}
double det_fuzzed_rate = (double)ndet_bits * 100.0 / (double)current_edges;
fprintf(afl->fsrv.det_plot_file,
"[%02lld:%02lld:%02lld] fuzz %d (%d), find %d/%d among %d(%02.2f) "
"and spend %lld/%lld(%02.2f), cover %02.2f yet, %d/%d undet bits, "
"continue %d.\n",
current_ms / 1000 / 3600, (current_ms / 1000 / 60) % 60,
(current_ms / 1000) % 60, afl->current_entry, q->fuzz_level,
afl->havoc_prof->edge_det_stage, afl->havoc_prof->edge_havoc_stage,
current_edges, det_finding_rate,
afl->havoc_prof->det_stage_time / 1000,
afl->havoc_prof->havoc_stage_time / 1000, det_time_rate,
det_fuzzed_rate, q->skipdet_e->undet_bits,
afl->skipdet_g->undet_bits_threshold, q->skipdet_e->continue_inf);
fflush(afl->fsrv.det_plot_file);
}
/* Check terminal dimensions after resize. */
static void check_term_size(afl_state_t *afl) {

@ -23,6 +23,8 @@
how they affect the execution path.
*/
//引入了 AFL++ 的核心头文件、CMPLog 相关头文件、通用函数头文件等。
//根据编译选项,可能还会包含其他系统头文件,如内存映射、文件操作等。
#include "afl-fuzz.h"
#include "cmplog.h"
@ -82,7 +84,9 @@
\
\
} while (0)
//定义了与 zlib 相关的宏,用于处理压缩文件的读写操作。
//对于苹果系统,引入了特定的头文件以支持线程优先级设置。
//如果启用了性能分析,则声明了一个外部变量 time_spent_working 用于记录工作时间
#include <zlib.h>
#define ZLIBOPEN gzopen
#define ZLIBREAD ck_gzread
@ -106,13 +110,14 @@
#ifdef PROFILING
extern u64 time_spent_working;
#endif
static void at_exit() {
//程序退出时的清理函数
static void at_exit() {//at_exit 函数在 AFL++ 程序退出时被调用,用于清理资源和终止子进程
//首先尝试获取环境变量 __AFL_TARGET_PID2 和 __AFL_TARGET_PID1这些变量存储了目标进程的 PID
s32 i, pid1 = 0, pid2 = 0, pgrp = -1;
char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL};
char *ptr;
//如果找到有效的 PID则获取其进程组 ID 并向进程组发送 SIGTERM 信号以终止整个进程组,
//然后单独向目标进程发送 SIGTERM 信号。
ptr = getenv("__AFL_TARGET_PID2");
if (ptr && *ptr && (pid2 = atoi(ptr)) > 0) {
@ -130,10 +135,11 @@ static void at_exit() {
kill(pid1, SIGTERM);
}
//尝试获取环境变量 CPU_AFFINITY_ENV_VAR如果存在且非空则删除该文件以解除 CPU 亲和性设置
ptr = getenv(CPU_AFFINITY_ENV_VAR);
if (ptr && *ptr) unlink(ptr);
//遍历 list 数组,获取每个环境变量的值,如果存在且非空,
//则根据编译选项使用不同的共享内存删除函数shm_unlink 或 shmctl来删除共享内存
i = 0;
while (list[i] != NULL) {
@ -173,13 +179,14 @@ static void at_exit() {
pgrp = getpgid(pid1);
if (pgrp > 0) { killpg(pgrp, kill_signal); }
kill(pid2, kill_signal);
//最后,获取环境变量 AFL_KILL_SIGNAL 的值作为要发送的信号类型(默认为 SIGKILL
//然后再次检查 PID1 和 PID2获取其进程组 ID 并向进程组发送相应的信号,单独向目标进程发送信号以确保其被终止
}
}
/* Display usage hints. */
//主要为显示说明
static void usage(u8 *argv0, int more_help) {
SAYF(
@ -190,7 +197,8 @@ static void usage(u8 *argv0, int more_help) {
"also see \n"
" AFL_AUTORESUME)\n"
" -o dir - output directory for fuzzer findings\n\n"
//-i dir指定输入目录该目录包含用于模糊测试的测试用例。如果输入为 -,则表示恢复之前的模糊测试会话。
//-o dir指定输出目录用于存储模糊测试过程中发现的结果。
"Execution control settings:\n"
" -P strategy - set fix mutation strategy: explore (focus on new "
"coverage),\n"
@ -211,6 +219,11 @@ static void usage(u8 *argv0, int more_help) {
"maximum.\n"
" -m megs - memory limit for child process (%u MB, 0 = no limit "
"[default])\n"
//-P strategy设置固定的变异策略。可以选择 explore专注于发现新覆盖率或 exploit专注于触发崩溃。还可以设置在没有发现新结果时自动切换到 exploit 模式的时间(以秒为单位),并在发现新覆盖率时切换回 explore 模式。
//-p schedule设置功率调度策略用于计算种子的性能得分。可选的策略包括 explore默认、fast、exploit、seek、rare、mmopt、coe、lin 和 quad。具体的策略选择和效果可以参考 AFL++ 的文档。
//-f file指定被模糊测试程序读取的文件位置默认为标准输入或 @@。
//-t msec设置每次运行的超时时间自动缩放默认为指定的毫秒数。可以在超时值后加上 +,表示自动计算超时时间,指定的值为最大值。
//-m megs设置子进程的内存限制以兆字节为单位默认为 0表示不限制
#if defined(__linux__) && defined(__aarch64__)
" -A - use binary-only instrumentation (ARM CoreSight mode)\n"
#endif
@ -223,6 +236,12 @@ static void usage(u8 *argv0, int more_help) {
#if defined(__linux__)
" -X - use VM fuzzing (NYX mode - standalone mode)\n"
" -Y - use VM fuzzing (NYX mode - multiple instances mode)\n"
//-A在 ARM 架构的 Linux 系统上使用二进制插桩ARM CoreSight 模式)。
//-O使用 FRIDA 模式进行二进制插桩。
//-Q在 Linux 系统上,使用 QEMU 模式进行二进制插桩。
//-U在 Linux 系统上,使用基于 Unicorn 的插桩Unicorn 模式)。
//-W在 Linux 系统上,使用基于 QEMU 和 Wine 的插桩Wine 模式)。
//-X 和 -Y在 Linux 系统上,使用 VM 模糊测试NYX 模式),分别支持独立模式和多实例模式。
#endif
"\n"
@ -296,10 +315,11 @@ static void usage(u8 *argv0, int more_help) {
#if defined USE_COLOR && !defined ALWAYS_COLORED
#define DYN_COLOR \
"AFL_NO_COLOR or AFL_NO_COLOUR: switch colored console output off\n"
//定义了 USE_COLOR 但未定义 ALWAYS_COLORED则定义 DYN_COLOR 宏,用于提示用户如何关闭控制台的颜色输出
#else
#define DYN_COLOR
#endif
//如果定义了 AFL_PERSISTENT_RECORD则定义 PERSISTENT_MSG 宏,用于提示用户 AFL_PERSISTENT_RECORD 环境变量的作用
#ifdef AFL_PERSISTENT_RECORD
#define PERSISTENT_MSG \
"AFL_PERSISTENT_RECORD: record the last X inputs to every crash in " \
@ -308,7 +328,7 @@ static void usage(u8 *argv0, int more_help) {
#define PERSISTENT_MSG
#endif
SAYF(
SAYF(//用于输出详细的帮助信息,包括 AFL++ 使用的各种环境变量及其作用。
"Environment variables used:\n"
"LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
"ASAN_OPTIONS: custom settings for ASAN\n"
@ -411,7 +431,59 @@ static void usage(u8 *argv0, int more_help) {
" seconds (default: 60, minimum: 1)\n"
"\n"
);
/*
LD_BIND_LAZY AFL++ LD_BIND_NOW
ASAN_OPTIONS MSAN_OPTIONS ASAN MSAN AFL++
AFL_AUTORESUME
AFL_BENCH_JUST_ONE AFL_BENCH_UNTIL_CRASH退
AFL_CMPLOG_ONLY_NEW CMPLog
AFL_CRASH_EXITCODE AFL++ 退
AFL_CUSTOM_MUTATOR_LIBRARY AFL_CUSTOM_MUTATOR_ONLY使
AFL_CYCLE_SCHEDULES
AFL_DEBUG AFL_DEBUG_CHILD stdout/stderr
AFL_DISABLE_REDUNDANT AFL_DISABLE_TRIM
AFL_DUMB_FORKSRV使 fork
AFL_EXIT_WHEN_DONE AFL_EXIT_ON_TIME退退
AFL_EXIT_ON_SEED_ISSUES退
AFL_EXPAND_HAVOC_NOW Havoc
AFL_FAST_CAL
AFL_FORCE_UI
AFL_FORKSRV_INIT_TMOUT fork
AFL_HANG_TMOUT
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES
AFL_IGNORE_PROBLEMS AFL_IGNORE_PROBLEMS_COVERAGE
AFL_IGNORE_SEED_PROBLEMS AFL_IGNORE_TIMEOUTS退
AFL_IGNORE_UNKNOWN_ENVS
AFL_IMPORT_FIRST
AFL_INPUT_LEN_MIN/AFL_INPUT_LEN_MAX AFL++
AFL_PIZZA_MODE AFL++ 4 1
AFL_KILL_SIGNAL AFL_FORK_SERVER_KILL_SIGNAL fork ID
AFL_MAP_SIZE
AFL_MAX_DET_EXTRAS使
AFL_NO_AFFINITY AFL_TRY_AFFINITY使 CPU 使 CPU
AFL_NO_ARITH AFL_NO_AUTODICT
AFL_NO_CPU_RED AFL_NO_FORKSRV CPU 使 execve 使 fork
AFL_NO_SNAPSHOT AFL_NO_STARTUP_CALIBRATION使
AFL_NO_WARN_INSTABILITY AFL_NO_UI
AFL_NYX_AUX_SIZENyx 4096
AFL_NYX_DISABLE_SNAPSHOT_MODE AFL_NYX_LOG NYX hprintf
AFL_NYX_REUSE_SNAPSHOT Nyx
AFL_PATHAFL
AFL_PYTHON_MODULE使 Python
AFL_QUIET fork
AFL_POST_PROCESS_KEEP_ORIGINAL
AFL_PRELOAD LD_PRELOAD/DYLD_INSERT_LIBRARIES
AFL_TARGET_ENV
AFL_SHUFFLE_QUEUE
AFL_SKIP_BIN_CHECK AFL_SKIP_CPUFREQ AFL CPU
AFL_STATSD StatsD
AFL_NO_FASTRESUME AFL_NO_SYNC
AFL_SYNC_TIME AFL_FINAL_SYNC退
AFL_NO_CRASH_README README
AFL_TESTCACHE_SIZE AFL_TMPDIR
AFL_EARLY_FORKSERVER AFL_PERSISTENT AFL-clang-fast/AFL-clang-lto/AFL-gcc-fast fork
AFL_DEFER_FORKSRV fork __AFL_INIT
AFL_FUZZER_STATS_UPDATE_INTERVAL fuzzer_stats */
} else {
SAYF(
@ -423,50 +495,56 @@ static void usage(u8 *argv0, int more_help) {
#ifdef USE_PYTHON
SAYF("Compiled with %s module support, see docs/custom_mutators.md\n",
(char *)PYTHON_VERSION);
/*
USE_PYTHON AFL++ 使 Python 使
AFL++ Python */
#else
SAYF("Compiled without Python module support.\n");
#endif
/*如果定义了 AFL_PERSISTENT_RECORD则输出 AFL++ 是使用持久记录支持编译的。
AFL++ */
#ifdef AFL_PERSISTENT_RECORD
SAYF("Compiled with AFL_PERSISTENT_RECORD support.\n");
#else
SAYF("Compiled without AFL_PERSISTENT_RECORD support.\n");
#endif
/*如果定义了 USEMMAP则输出 AFL++ 是使用 shm_open 支持编译的。
AFL++ 使 shmat */
#ifdef USEMMAP
SAYF("Compiled with shm_open support.\n");
#else
SAYF("Compiled with shmat support.\n");
#endif
/*如果定义了 ASAN_BUILD则输出 AFL++ 是使用 ASAN 构建编译的。*/
#ifdef ASAN_BUILD
SAYF("Compiled with ASAN_BUILD.\n");
#endif
/*如果定义了 NO_SPLICING则输出 AFL++ 是使用禁止拼接选项编译的*/
#ifdef NO_SPLICING
SAYF("Compiled with NO_SPLICING.\n");
#endif
/*如果定义了 FANCY_BOXES_NO_UTF则输出 AFL++ 是没有 UTF-8 支持编译的,这会影响状态屏幕中的线条渲染。*/
#ifdef FANCY_BOXES_NO_UTF
SAYF("Compiled without UTF-8 support for line rendering in status screen.\n");
#endif
/*如果定义了 PROFILING则输出 AFL++ 是使用性能分析编译的。*/
#ifdef PROFILING
SAYF("Compiled with PROFILING.\n");
#endif
/*如果定义了 INTROSPECTION则输出 AFL++ 是使用自省编译的。*/
#ifdef INTROSPECTION
SAYF("Compiled with INTROSPECTION.\n");
#endif
/*如果定义了 _DEBUG则输出 AFL++ 是使用调试模式编译的*/
#ifdef _DEBUG
SAYF("Compiled with _DEBUG.\n");
#endif
/*如果定义了 _AFL_DOCUMENT_MUTATIONS则输出 AFL++ 是使用记录变异编译的。*/
#ifdef _AFL_DOCUMENT_MUTATIONS
SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n");
#endif
/*如果定义了 _AFL_SPECIAL_PERFORMANCE则输出 AFL++ 是使用特定系统的特殊性能选项编译的,并提醒用户这可能不适用于其他平台。*/
#ifdef _AFL_SPECIAL_PERFORMANCE
SAYF(
"Compiled with special performance options for this specific system, it "
@ -477,7 +555,9 @@ static void usage(u8 *argv0, int more_help) {
exit(1);
#undef PHYTON_SUPPORT
/*额外帮助:输出提示信息,建议用户查阅 README.md 文件以获取更多帮助。
退 exit(1) 退 1 退
使 #undef PHYTON_SUPPORT PHYTON_SUPPORT PYTHON_SUPPORT*/
}
#ifndef AFL_LIB
@ -544,9 +624,10 @@ static void fasan_check_afl_preload(char *afl_preload) {
int main(int argc, char **argv_orig, char **envp) {
s32 opt, auto_sync = 0 /*, user_set_cache = 0*/;
u64 prev_queued = 0;
u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, default_output = 1,
s32 opt, auto_sync = 0 /*, user_set_cache = 0*/;//用于存储 getopt 函数返回的选项字符
u64 prev_queued = 0;//自动同步标志,初始值为 0。
//用于记录上一次排队的项目数量。
u32 sync_interval_cnt /*同步间隔计数器*/= 0, seek_to = 0, show_help = 0, default_output = 1,
map_size = get_map_size();
u8 *extras_dir[4];
u8 mem_limit_given = 0, exit_1 = 0, debug = 0,
@ -557,9 +638,20 @@ int main(int argc, char **argv_orig, char **envp) {
struct timeval tv;
struct timezone tz;
/*eek_to用于指定从哪个位置开始处理队列。
show_help
default_output 1
map_size get_map_size
extras_dir[4]
mem_limit_given
exit_1
debug
extras_dir_cnt
afl_preload frida_afl_preload AFL
use_argv
struct timeval tv struct timezone tz*/
doc_path = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH;
//根据 DOC_PATH 环境变量或默认路径 "docs" 初始化文档路径
if (argc > 1 && strcmp(argv_orig[1], "--version") == 0) {
printf("afl-fuzz" VERSION "\n");
@ -573,7 +665,8 @@ int main(int argc, char **argv_orig, char **envp) {
exit(0);
}
/*版本信息:如果命令行参数包含 --version则输出 AFL++ 的版本信息并退出程序。
--help usage 退*/
#if defined USE_COLOR && defined ALWAYS_COLORED
if (getenv("AFL_NO_COLOR") || getenv("AFL_NO_COLOUR")) {
@ -582,11 +675,11 @@ int main(int argc, char **argv_orig, char **envp) {
"compile time)");
}
/*颜色输出:如果定义了 USE_COLOR 和 ALWAYS_COLORED并且环境变量 AFL_NO_COLOR 或 AFL_NO_COLOUR 被设置,则输出警告信息,提示用户颜色设置在编译时已配置。*/
#endif
char **argv = argv_cpy_dup(argc, argv_orig);
//argv_cpy_dup复制命令行参数数组以便在后续处理中使用
afl_state_t *afl = calloc(1, sizeof(afl_state_t));
if (!afl) { FATAL("Could not create afl state"); }
@ -599,15 +692,22 @@ int main(int argc, char **argv_orig, char **envp) {
read_afl_environment(afl, envp);
if (afl->shm.map_size) { afl->fsrv.map_size = afl->shm.map_size; }
exit_1 = !!afl->afl_env.afl_bench_just_one;
//SAYF输出 AFL++ 的版本信息和基于的原始 AFL 作者信息。
SAYF(cCYA "afl-fuzz" VERSION cRST
" based on afl by Michal Zalewski and a large online community\n");
//gettimeofday获取当前时间。
//rand_set_seed根据当前时间设置随机种子用于后续的随机数生成
gettimeofday(&tv, &tz);
rand_set_seed(afl, tv.tv_sec ^ tv.tv_usec ^ getpid());
//afl->shmem_testcase_mode设置为 1表示始终尝试使用共享内存进行模糊测试。
afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing
/*分配内存:为 afl_state_t 结构体分配内存,用于存储 AFL++ 的状态信息。
AFL_DEBUG
afl_state_init AFL
afl_fsrv_init
read_afl_environment AFL++
*/
// still available: HjJkKqruvwz
while ((opt = getopt(argc, argv,
"+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:"
@ -694,12 +794,25 @@ int main(int argc, char **argv_orig, char **envp) {
FATAL("Bad syntax used for -b");
}
/*getopt 循环:使用 getopt 函数解析命令行选项。
-a "text""binary" "default"
-P "explore""exploit" "exploit"
-g
-G
-Z
-I
-b AFL++ CPU */
break;
}
case 'c': {
/*-c 选项
CMPLog
"-" CMPLog CMPLog cmplog_binary NULL
"-" CMPLog cmplog_binary */
if (strcmp(optarg, "-") == 0) {
@ -723,7 +836,11 @@ int main(int argc, char **argv_orig, char **envp) {
}
case 's': {
/*-s 选项
NULL
使 fixed_seed 1使*/
if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); }
rand_set_seed(afl, strtoul(optarg, 0L, 10));
afl->fixed_seed = 1;
@ -732,7 +849,12 @@ int main(int argc, char **argv_orig, char **envp) {
}
case 'p': /* Power schedule */
/*-p 选项
afl->schedule FASTCOEEXPLOITLINQUADMMOPTRAREEXPLORE SEEK
*/
if (!stricmp(optarg, "fast")) {
afl->schedule = FAST;
@ -784,7 +906,11 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'e':
/*-e 选项
afl->file_extension -e
afl->file_extension */
if (afl->file_extension) { FATAL("Multiple -e options not supported"); }
afl->file_extension = optarg;
@ -792,7 +918,13 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'i': /* input dir */
/*-i 选项
afl->in_dir -i
NULL -i
afl->in_dir
"-" afl->in_place_resume 1*/
if (afl->in_dir) { FATAL("Multiple -i options not supported"); }
if (optarg == NULL) { FATAL("Invalid -i option (got NULL)."); }
afl->in_dir = optarg;
@ -802,13 +934,28 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'o': /* output dir */
/*-o 选项
afl->out_dir -o
afl->out_dir */
if (afl->out_dir) { FATAL("Multiple -o options not supported"); }
afl->out_dir = optarg;
break;
case 'M': { /* main sync ID */
/*-M 选项
ID
ARM CoreSight -M
ID -S -M
- -
ID
old_seed_selection 1使
disable_trim 1
ID : ID
is_main_node 1
*/
u8 *c;
if (afl->non_instrumented_mode) {
@ -862,7 +1009,14 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'S': /* secondary sync id */
/*-S 选项
ID
ARM CoreSight -S
ID -S -M
- -
ID
is_secondary_node 1*/
if (afl->non_instrumented_mode) {
FATAL("-S is not supported in non-instrumented mode");
@ -892,7 +1046,13 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'F': /* foreign sync dir */
/*-F 选项
-F
foreign_syncs */
if (!optarg) { FATAL("Missing path for -F"); }
if (!afl->is_main_node) {
@ -924,7 +1084,13 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'f': /* target file */
/*-f 选项
-f
use_stdin 0使
default_output 0使*/
if (afl->fsrv.out_file) { FATAL("Multiple -f options not supported"); }
afl->fsrv.out_file = ck_strdup(optarg);
@ -933,7 +1099,11 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'x': /* dictionary */
/*-x 选项
-x
extras_dir extras_dir_cnt */
if (extras_dir_cnt >= 4) {
FATAL("More than four -x options are not supported");
@ -944,7 +1114,13 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 't': { /* timeout */
/*-t 选项
-t
+
5
timeout_given + */
u8 suffix = 0;
if (afl->timeout_given) { FATAL("Multiple -t options not supported"); }
@ -974,7 +1150,14 @@ int main(int argc, char **argv_orig, char **envp) {
}
case 'm': { /* mem limit */
/*-m 选项
-m
TGkM
5
32 2000 MB*/
u8 suffix = 'M';
if (mem_limit_given) {
@ -1040,19 +1223,30 @@ int main(int argc, char **argv_orig, char **envp) {
case 'd':
case 'D': /* old deterministic */
/*-d 和 -D 选项
使 -z */
WARNF(
"Parameters -d and -D are deprecated, a new enhanced deterministic "
"fuzzing is active by default, to disable it use -z");
break;
case 'z': /* no deterministic */
/*-z 选项
skip_deterministic 1*/
afl->skip_deterministic = 1;
break;
case 'B': /* load bitmap */
/*-B 选项
in_bitmap -B
in_bitmap
*/
/* This is a secret undocumented option! It is useful if you find
an interesting test case during a normal fuzzing process, and want
to mutate it without rediscovering any of the test cases already
@ -1070,13 +1264,22 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'C': /* crash mode */
/*-C 选项
crash_mode -C
crash_mode FSRV_RUN_CRASH*/
if (afl->crash_mode) { FATAL("Multiple -C options not supported"); }
afl->crash_mode = FSRV_RUN_CRASH;
break;
case 'n': /* dumb mode */
/*-n 选项
-M -S 使
non_instrumented_mode -n
AFL_DUMB_FORKSRV non_instrumented_mode 1 2*/
if (afl->is_main_node || afl->is_secondary_node) {
FATAL("Non instrumented mode is not supported with -M / -S");
@ -1102,14 +1305,26 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'T': /* banner */
/*-T 选项
use_banner -T
use_banner */
if (afl->use_banner) { FATAL("Multiple -T options not supported"); }
afl->use_banner = optarg;
break;
#ifdef __linux__
case 'X': /* NYX mode */
/*-X 和 -Y 选项(仅限 Linux
Nyx
-X Nyx
nyx_mode -X
nyx_parentnyx_standalone nyx_mode Nyx
-Y Nyx
nyx_mode -Y
nyx_mode Nyx */
if (afl->fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); }
afl->fsrv.nyx_parent = true;
@ -1132,7 +1347,12 @@ int main(int argc, char **argv_orig, char **envp) {
break;
#endif
case 'A': /* CoreSight mode */
/*-A 选项(仅限 ARM64 和 Linux
ARM CoreSight
ARM CoreSight -M -S 使
cs_mode -A
cs_mode ARM CoreSight */
#if !defined(__aarch64__) || !defined(__linux__)
FATAL("-A option is not supported on this platform");
#endif
@ -1150,7 +1370,12 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'O': /* FRIDA mode */
/*-O 选项
FRIDA
frida_mode -O
frida_mode FRIDA
AFL_USE_FASAN frida_asan 1使 FRIDA */
if (afl->fsrv.frida_mode) {
FATAL("Multiple -O options not supported");
@ -1163,7 +1388,12 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'Q': /* QEMU mode */
/*-Q 选项
QEMU
qemu_mode -Q
qemu_mode 1 QEMU
mem_limit MEM_LIMIT_QEMU QEMU */
if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); }
afl->fsrv.qemu_mode = 1;
@ -1173,14 +1403,24 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'N': /* Unicorn mode */
/*-N 选项
no_unlink -N
no_unlink true*/
if (afl->no_unlink) { FATAL("Multiple -N options not supported"); }
afl->fsrv.no_unlink = (afl->no_unlink = true);
break;
case 'U': /* Unicorn mode */
/*-U 选项
Unicorn
unicorn_mode -U
unicorn_mode 1 Unicorn
mem_limit MEM_LIMIT_UNICORN Unicorn
*/
if (afl->unicorn_mode) { FATAL("Multiple -U options not supported"); }
afl->unicorn_mode = 1;
@ -1189,7 +1429,13 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'W': /* Wine+QEMU mode */
/*-W 选项
Wine+QEMU
use_wine -W
qemu_mode 1 QEMU
use_wine 1 Wine
mem_limit 0*/
if (afl->use_wine) { FATAL("Multiple -W options not supported"); }
afl->fsrv.qemu_mode = 1;
afl->use_wine = 1;
@ -1199,7 +1445,12 @@ int main(int argc, char **argv_orig, char **envp) {
break;
case 'V': {
/*-V 选项
AFL++
most_time_key 1
*/
afl->most_time_key = 1;
if (!optarg || sscanf(optarg, "%llu", &afl->most_time) < 1 ||
optarg[0] == '-') {
@ -1211,7 +1462,12 @@ int main(int argc, char **argv_orig, char **envp) {
} break;
case 'E': {
/*-E 选项
AFL++
most_execs_key 1
*/
afl->most_execs_key = 1;
if (!optarg || sscanf(optarg, "%llu", &afl->most_execs) < 1 ||
optarg[0] == '-') {
@ -1223,7 +1479,20 @@ int main(int argc, char **argv_orig, char **envp) {
} break;
case 'l': {
/*-l 选项
CMPLog
CMPLog
'0''1' CMPLog 1
'2' CMPLog 2
'3' CMPLog 3
'a''A'
's''S'
't''T'
'x''X'
'r''R'
CMPLog CMPLOG_LVL_MAX cmplog_max_filesize MAX_FILE*/
if (!optarg) { FATAL("missing parameter for 'l'"); }
char *c = optarg;
while (*c) {
@ -1286,7 +1555,23 @@ int main(int argc, char **argv_orig, char **envp) {
} break;
case 'L': { /* MOpt mode */
/*-L 选项
MOpt
limit_time_sig -L
havoc_max_mult HAVOC_MAX_MULT_MOPT MOpt Havoc
-1 limit_time_sig -1 MOpt limit_time_puppet 0
0 -1 0 2000000 -1
limit_time_sig 1
old_seed_selection 1使
60 * 1000
MOpt swarm_nowkey_puppetg_noww_now
swarm swarm_fitnessstage_finds_puppetprobability_nowx_nowv_nowL_bestG_besteff_best
MOpt Havoc */
if (afl->limit_time_sig) { FATAL("Multiple -L options not supported"); }
afl->havoc_max_mult = HAVOC_MAX_MULT_MOPT;
@ -1435,35 +1720,55 @@ int main(int argc, char **argv_orig, char **envp) {
case 'h':
show_help++;
break; // not needed
/*-h 选项
show_help
break switch case
*/
case 'R':
/*-R 选项
Radamsa
Radamsa 使custom_mutators/radamsa/使*/
FATAL(
"Radamsa is now a custom mutator, please use that "
"(custom_mutators/radamsa/).");
break;
/*默认情况
show_help 1*/
default:
if (!show_help) { show_help = 1; }
}
}
/*同步 ID 检查
ID
sync_id "addseeds" "addseeds" ID*/
if (afl->sync_id && strcmp(afl->sync_id, "addseeds") == 0) {
FATAL("-M/-S name 'addseeds' is a reserved name, choose something else");
}
/*主节点和功率调度检查
is_main_node 1 FAST EXPLORE -M FAST EXPLORE */
if (afl->is_main_node == 1 && afl->schedule != FAST &&
afl->schedule != EXPLORE) {
FATAL("-M is compatible only with fast and explore -p power schedules");
}
/*参数检查和帮助信息显示
optind argc show_help usage 退*/
if (optind == argc || !afl->in_dir || !afl->out_dir || show_help) {
usage(argv[0], show_help);
@ -1473,7 +1778,14 @@ int main(int argc, char **argv_orig, char **envp) {
if (unlikely(afl->afl_env.afl_persistent_record)) {
#ifdef AFL_PERSISTENT_RECORD
/*持久记录配置检查
AFL_PERSISTENT_RECORD
afl_env.afl_persistent_record
AFL++ 使 AFL_PERSISTENT_RECORD
fsrv.persistent_record
2 AFL_PERSISTENT_RECORD 2 100 1000
AFL++ 使 AFL_PERSISTENT_RECORD AFL++ AFL_PERSISTENT_RECORD */
afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record);
if (afl->fsrv.persistent_record < 2) {
@ -1495,13 +1807,19 @@ int main(int argc, char **argv_orig, char **envp) {
}
if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
/*内存限制调整
CMPLog 260 CMPLog */
OKF("AFL++ is maintained by Marc \"van Hauser\" Heuse, Dominik Maier, Andrea "
"Fioraldi and Heiko \"hexcoder\" Eißfeldt");
OKF("AFL++ is open source, get it at "
"https://github.com/AFLplusplus/AFLplusplus");
OKF("NOTE: AFL++ >= v3 has changed defaults and behaviours - see README.md");
/*版本信息显示
AFL++ Marc "van Hauser" HeuseDominik MaierAndrea Fioraldi Heiko "hexcoder" Eißfeldt
AFL++ GitHub
AFL++ 3 README.md */
#ifdef __linux__
if (afl->fsrv.nyx_mode) {
@ -1510,18 +1828,24 @@ int main(int argc, char **argv_orig, char **envp) {
OKF("Nyx is open source, get it at https://github.com/Nyx-Fuzz");
}
/*Nyx 模式信息显示(仅限 Linux
Nyx Nyx Sergej Schumilo Nyx GitHub */
#endif
// silently disable deterministic mutation if custom mutators are used
if (!afl->skip_deterministic && afl->afl_env.afl_custom_mutator_only) {
/*确定性变异禁用
*/
afl->skip_deterministic = 1;
}
if (afl->fixed_seed) {
/*固定种子信息显示
使*/
OKF("Running with fixed seed: %u", (u32)afl->init_seed);
}
@ -1535,7 +1859,9 @@ int main(int argc, char **argv_orig, char **envp) {
}
#endif
/*信号配置
configure_afl_kill_signals AFL++ fork QEMUUnicornfauxsrv Nyx 使 SIGKILL 使 SIGTERM */
configure_afl_kill_signals(
&afl->fsrv, afl->afl_env.afl_child_kill_signal,
afl->afl_env.afl_fsrv_kill_signal,
@ -1546,12 +1872,21 @@ int main(int argc, char **argv_orig, char **envp) {
)
? SIGKILL
: SIGTERM);
/*信号处理设置
setup_signal_handlers AFL++ 便*/
setup_signal_handlers();
check_asan_opts(afl);
/*ASAN 构建内存限制禁用(仅限 ASAN 构建)
AFL++ 使 ASAN ASAN */
afl->power_name = power_names[afl->schedule];
/*ASAN 选项检查
check_asan_opts ASAN AFL++ ASAN 使*/
/*功率调度名称设置
power_names afl->power_name */
if (!afl->non_instrumented_mode && !afl->sync_id) {
auto_sync = 1;
@ -1560,7 +1895,13 @@ int main(int argc, char **argv_orig, char **envp) {
OKF("No -M/-S set, autoconfiguring for \"-S %s\"", afl->sync_id);
}
/*Nyx 模式同步配置(仅限 Linux
Nyx
Nyx ID "default"
Nyx
ID "0" ID "0"
ID ID 1*/
#ifdef __linux__
if (afl->fsrv.nyx_mode) {

@ -27,6 +27,9 @@
*/
//林睿健阅读部分
#define AFL_MAIN
#include "config.h"
@ -97,6 +100,10 @@ static sharedmem_t *shm_fuzz;
/* Classify tuple counts. This is a slow & naive version, but good enough here.
*/
/*
count_class_lookup
*/
static const u8 count_class_lookup[256] = {
[0] = 0,
@ -111,6 +118,10 @@ static const u8 count_class_lookup[256] = {
};
/*
kill_child
PID0
*/
static void kill_child() {
if (fsrv->child_pid > 0) {
@ -122,6 +133,11 @@ static void kill_child() {
}
/*
deinit_shmem
fsrvforkservershm_fuzz
NULL
*/
static sharedmem_t *deinit_shmem(afl_forkserver_t *fsrv,
sharedmem_t *shm_fuzz) {
@ -135,7 +151,11 @@ static sharedmem_t *deinit_shmem(afl_forkserver_t *fsrv,
}
/* Apply mask to classified bitmap (if set). */
/*
apply_mask
memmask
NULL
*/
static void apply_mask(u32 *mem, u32 *mask) {
u32 i = (map_size >> 2);
@ -152,6 +172,12 @@ static void apply_mask(u32 *mem, u32 *mask) {
}
/*
classify_counts
fsrvforkserver
edges_only
使count_class_lookup
*/
static void classify_counts(afl_forkserver_t *fsrv) {
u8 *mem = fsrv->trace_bits;
@ -180,7 +206,11 @@ static void classify_counts(afl_forkserver_t *fsrv) {
}
/* See if any bytes are set in the bitmap. */
/*
anything_set
fsrvforkserver
1
*/
static inline u8 anything_set(afl_forkserver_t *fsrv) {
u32 *ptr = (u32 *)fsrv->trace_bits;
@ -196,6 +226,11 @@ static inline u8 anything_set(afl_forkserver_t *fsrv) {
}
/*
at_exit_handler退
remove_shm
remove_out_file
*/
static void at_exit_handler(void) {
if (remove_shm) {
@ -211,7 +246,11 @@ static void at_exit_handler(void) {
}
/* Read initial file. */
/*
read_initial_file
in_file
*/
static void read_initial_file(void) {
struct stat st;
@ -239,7 +278,11 @@ static void read_initial_file(void) {
}
/* Write output file. */
/*
write_to_file
pathmemlen
*/
static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
s32 ret;
@ -260,7 +303,11 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
/* Execute target application. Returns 0 if the changes are a dud, or
1 if they should be kept. */
/*
tmin_run_target
fsrvforkservermemlenfirst_run
*/
static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len,
u8 first_run) {
@ -280,7 +327,7 @@ static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len,
}
/* Always discard inputs that time out, unless we are in hang mode */
/* 如果处于挂起模式,总是丢弃超时的输入 */
if (hang_mode) {
switch (ret) {
@ -300,7 +347,7 @@ static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len,
classify_counts(fsrv);
apply_mask((u32 *)fsrv->trace_bits, (u32 *)mask_bitmap);
/* 根据当前模式处理崩溃输入 */
if (ret == FSRV_RUN_TMOUT) {
missed_hangs++;
@ -326,7 +373,7 @@ static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len,
}
} else {
/* 适当处理非崩溃输入 */
/* Handle non-crashing inputs appropriately. */
if (crash_mode) {
@ -352,7 +399,11 @@ static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len,
}
/* Actually minimize! */
/*
minimize
fsrvforkserver
*/
static void minimize(afl_forkserver_t *fsrv) {
static u32 alpha_map[256];
@ -631,7 +682,11 @@ finalize_all:
}
/* Handle Ctrl-C and the like. */
/*
handle_stop_sig
sig
*/
static void handle_stop_sig(int sig) {
(void)sig;
@ -641,7 +696,11 @@ static void handle_stop_sig(int sig) {
}
/* Do basic preparations - persistent fds, filenames, etc. */
/*
set_up_environment
fsrvforkserverargv
*/
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
u8 *x;
@ -739,7 +798,10 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
}
/* Setup signal handlers, duh. */
/*
setup_signal_handlers
便Ctrl-C
*/
static void setup_signal_handlers(void) {
struct sigaction sa;
@ -764,7 +826,11 @@ static void setup_signal_handlers(void) {
}
/* Display usage hints. */
/*
usage使
argv0
使
*/
static void usage(u8 *argv0) {
SAYF(
@ -829,188 +895,272 @@ static void usage(u8 *argv0) {
}
/* Main entry point */
/*
argcargvenvp
退
*/
int main(int argc, char **argv_orig, char **envp) {
//程序的主入口点,接收命令行参数和环境变量
s32 opt;
//用于存储getopt函数返回的当前选项字符。
u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0,
del_limit_given = 0;
//定义了一些标志变量用于记录是否已经设置了内存限制、超时时间、unicorn模式、wine模式和删除长度限制。
char **use_argv;
//用于存储处理后的参数列表,可能会根据模式不同而进行修改。
char **argv = argv_cpy_dup(argc, argv_orig);
//复制命令行参数,以便在解析选项时修改参数列表。
afl_forkserver_t fsrv_var = {0};
//初始化一个afl_forkserver_t类型的变量用于管理forkserver。
if (getenv("AFL_DEBUG")) { debug = 1; }
fsrv = &fsrv_var;
afl_fsrv_init(fsrv);
map_size = get_map_size();
fsrv->map_size = map_size;
//设置forkserver的共享内存区域大小。
doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
//尝试访问文档路径如果不存在则使用默认的“docs”路径。
SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n");
//打印程序的欢迎信息和版本号。
while ((opt = getopt(argc, argv, "+i:o:f:m:t:l:B:xeAOQUWXYHh")) > 0) {
//循环处理命令行参数getopt会解析短选项和长选项。
switch (opt) {
//根据getopt返回的选项字符执行相应的操作。
case 'i':
//如果选项是'i',表示输入文件。
if (in_file) { FATAL("Multiple -i options not supported"); }
//检查是否已经设置了输入文件,如果设置了多次,则报错。
in_file = optarg;
//将输入文件的路径设置到in_file变量。
break;
case 'o':
//如果选项是'o',表示输出文件。
if (output_file) { FATAL("Multiple -o options not supported"); }
//检查是否已经设置了输出文件,如果设置了多次,则报错。
output_file = optarg;
//将输出文件的路径设置到output_file变量。
break;
case 'f':
//如果选项是'f',表示被测试程序读取的输入文件(标准输入)。
if (out_file) { FATAL("Multiple -f options not supported"); }
//检查是否已经设置了输入文件,如果设置了多次,则报错。
fsrv->use_stdin = 0;
//设置标志,表示不使用标准输入。
out_file = ck_strdup(optarg);
//复制输入文件的路径到out_file变量。
break;
case 'e':
//如果选项是'e',表示仅考虑边缘覆盖,忽略命中次数。
if (edges_only) { FATAL("Multiple -e options not supported"); }
//检查是否已经设置了仅考虑边缘覆盖,如果设置了多次,则报错。
if (hang_mode) {
//检查是否已经设置了挂起模式,如果同时设置了仅考虑边缘覆盖和挂起模式,则报错。
FATAL("Edges only and hang mode are mutually exclusive.");
//报错,因为仅考虑边缘覆盖和挂起模式不能同时设置。
}
edges_only = 1;
//设置标志,表示仅考虑边缘覆盖。
break;
case 'x':
//如果选项是'x',表示将非零退出代码视为崩溃。
if (exit_crash) { FATAL("Multiple -x options not supported"); }
//检查是否已经设置了将非零退出代码视为崩溃,如果设置了多次,则报错。
exit_crash = 1;
//设置标志,表示将非零退出代码视为崩溃。
break;
case 'm': {
//如果选项是'm',表示设置子进程的内存限制。
//使用花括号创建一个新的作用域,用于存储局部变量。
u8 suffix = 'M';
//定义一个变量suffix默认值为'M',表示内存单位是兆字节。
if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
//检查是否已经设置了内存限制,如果设置了多次,则报错。
mem_limit_given = 1;
//设置标志,表示已经设置了内存限制。
if (!optarg) { FATAL("Wrong usage of -m"); }
//检查是否提供了内存限制的参数,如果没有提供,则报错。
if (!strcmp(optarg, "none")) {
//检查参数是否是“none”表示不设置内存限制。
fsrv->mem_limit = 0;
//设置内存限制为0。
break;
//跳出内存限制设置。
}
//结束内存限制设置的条件判断。
if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 ||
optarg[0] == '-') {
//尝试解析内存限制的参数,如果解析失败或参数以负号开头,则报错。
FATAL("Bad syntax used for -m");
//报错,因为内存限制的参数语法不正确。
}
//结束内存限制设置的条件判断。
switch (suffix) {
//根据解析出的后缀,转换内存限制的单位。
case 'T':
fsrv->mem_limit *= 1024 * 1024;
break;
//如果后缀是'T',表示内存限制的单位是太字节,转换为兆字节。
case 'G':
fsrv->mem_limit *= 1024;
break;
//如果后缀是'G',表示内存限制的单位是吉字节,转换为兆字节。
case 'k':
fsrv->mem_limit /= 1024;
break;
//如果后缀是'k',表示内存限制的单位是千字节,转换为兆字节。
case 'M':
break;
//如果后缀是'M',表示内存限制的单位是兆字节,不需要转换。
default:
FATAL("Unsupported suffix or bad syntax for -m");
//如果后缀不支持或语法错误,则报错。
}
//结束单位转换的switch语句。
if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); }
//检查内存限制是否过低如果低于5兆字节则报错。
if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) {
//检查在32位系统上内存限制是否过高如果超过2000兆字节则报错。
FATAL("Value of -m out of range on 32-bit systems");
//报错因为32位系统上内存限制过高。
}
//结束内存限制设置。
}
//结束内存限制设置的局部作用域。
break;
//结束'm'选项的处理。
case 't':
//如果选项是't',表示设置每次运行的超时时间。
if (timeout_given) { FATAL("Multiple -t options not supported"); }
//检查是否已经设置了超时时间,如果设置了多次,则报错。
timeout_given = 1;
//设置标志,表示已经设置了超时时间。
if (!optarg) { FATAL("Wrong usage of -t"); }
//检查是否提供了超时时间的参数,如果没有提供,则报错。
fsrv->exec_tmout = atoi(optarg);
//将超时时间的参数转换为整数并设置到fsrv->exec_tmout。
if (fsrv->exec_tmout < 10 || optarg[0] == '-') {
//检查超时时间是否过低或参数以负号开头,如果是,则报错。
FATAL("Dangerously low value of -t");
//报错,因为超时时间过低。
}
//结束超时时间设置的条件判断。
break;
//结束't'选项的处理。
case 'A': /* CoreSight mode */
//如果选项是'A'表示使用ARM CoreSight模式。
#if !defined(__aarch64__) || !defined(__linux__)
FATAL("-A option is not supported on this platform");
#endif
//检查是否在支持的平台上,如果不是,则报错。
if (fsrv->cs_mode) { FATAL("Multiple -A options not supported"); }
//检查是否已经设置了CoreSight模式如果设置了多次则报错。
fsrv->cs_mode = 1;
//设置标志表示使用CoreSight模式。
break;
//结束'A'选项的处理。
case 'O': /* FRIDA mode */
//如果选项是'O'表示使用FRIDA模式。
if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); }
//检查是否已经设置了FRIDA模式如果设置了多次则报错。
fsrv->frida_mode = 1;
//设置标志表示使用FRIDA模式。
setenv("AFL_FRIDA_INST_SEED", "1", 1);
//设置环境变量用于FRIDA模式。
break;
//结束'O'选项的处理。
case 'Q':
//如果选项是'Q'表示使用QEMU模式。
if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
//检查是否已经设置了QEMU模式如果设置了多次则报错。
if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; }
//如果未设置内存限制则使用QEMU模式的默认内存限制。
fsrv->qemu_mode = 1;
//设置标志表示使用QEMU模式。
break;
//结束'Q'选项的处理。
case 'U':
//如果选项是'U'表示使用Unicorn模式。
if (unicorn_mode) { FATAL("Multiple -Q options not supported"); }
//检查是否已经设置了Unicorn模式如果设置了多次则报错。
if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; }
//如果未设置内存限制则使用Unicorn模式的默认内存限制。
unicorn_mode = 1;
//设置标志表示使用Unicorn模式。
break;
//结束'U'选项的处理。
case 'W': /* Wine+QEMU mode */
//如果选项是'W'表示使用Wine+QEMU模式。
if (use_wine) { FATAL("Multiple -W options not supported"); }
//检查是否已经设置了Wine+QEMU模式如果设置了多次则报错。
fsrv->qemu_mode = 1;
//设置标志表示使用QEMU模式。
use_wine = 1;
//设置标志表示使用Wine。
if (!mem_limit_given) { fsrv->mem_limit = 0; }
//如果未设置内存限制则设置为0。
break;
//结束'W'选项的处理。
case 'Y': // fallthough
#ifdef __linux__
case 'X': /* NYX mode */
//
if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); }
@ -1021,6 +1171,7 @@ int main(int argc, char **argv_orig, char **envp) {
break;
#else
case 'X':
//如果选项是'X'表示使用Nyx模式。
FATAL("Nyx mode is only availabe on linux...");
break;
#endif

@ -1,4 +1,3 @@
/*
american fuzzy lop++ - stats related routines
---------------------------------------------
@ -29,7 +28,6 @@
#include "envs.h"
#include <limits.h>
//乔成炜
// 定义一个二维数组用于存储模糊测试fuzzing的不同状态信息。
static char fuzzing_state[4][12] = {"started :-)", "in progress", "final phase",
"finished..."};

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 KiB

Loading…
Cancel
Save