Compare commits

..

6 Commits

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

@ -96,7 +96,6 @@ 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,
@ -111,25 +110,21 @@ 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--) {
@ -153,11 +148,10 @@ 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--) {
@ -171,7 +165,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 */
@ -179,16 +173,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);
@ -208,63 +202,56 @@ 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;
@ -274,14 +261,13 @@ 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;
@ -293,7 +279,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
@ -312,7 +298,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;
@ -328,7 +314,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)) {
@ -342,7 +328,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) {
@ -354,7 +340,7 @@ static void dump_hex(u32 len, u8 *b_data) {
/* Small integers may be length fields. */
if (val && (val <= in_len || SWAP16(val) <= in_len)) {
//判断为运行长度
rtype = RESP_LEN;
break;
@ -363,7 +349,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;
@ -374,7 +360,7 @@ static void dump_hex(u32 len, u8 *b_data) {
}
case 4: {
//同上
u32 val = *(u32 *)(in_data + i);
/* Small integers may be length fields. */
@ -420,17 +406,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);
}
@ -438,7 +424,7 @@ static void dump_hex(u32 len, u8 *b_data) {
}
switch (rtype) {
//根据rtype分析的不同类型进行不同的上色便于用户区分
case RESP_NONE:
SAYF(cLGR bgGRA);
break;
@ -462,11 +448,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 {
@ -478,14 +464,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;
@ -523,9 +509,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;
@ -541,14 +527,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);
@ -563,34 +549,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) {
@ -606,7 +592,7 @@ static void analyze() {
prev_a10 = add_10;
}
//输出分析结果
dump_hex(in_len, b_data);
SAYF("\n");
@ -626,7 +612,7 @@ static void analyze() {
}
/* Handle Ctrl-C and the like. */
//用户自出终止程序的代理函数
static void handle_stop_sig(int sig) {
(void)sig;
@ -637,7 +623,7 @@ static void handle_stop_sig(int sig) {
}
/* Do basic preparations - persistent fds, filenames, etc. */
//设置测试环境
static void set_up_environment(char **argv) {
u8 *x;
@ -733,7 +719,7 @@ static void set_up_environment(char **argv) {
}
/* Setup signal handlers, duh. */
//设置信号处理程序,进行初始化
static void setup_signal_handlers(void) {
struct sigaction sa;
@ -758,7 +744,7 @@ static void setup_signal_handlers(void) {
}
/* Display usage hints. */
//当用户输入-h时调用此函数回显该工具的使用方法
static void usage(u8 *argv0) {
SAYF(
@ -815,7 +801,7 @@ static void usage(u8 *argv0) {
}
/* Main entry point */
//main函数用户使用的实际接口
int main(int argc, char **argv_orig, char **envp) {
s32 opt;

@ -91,116 +91,170 @@ static u8 use_64bit = 0;
to keep the code simple. */
static void edit_params(int argc, char **argv) {
// 获取临时目录路径和AFL_AS环境变量
u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS");
u32 i, input_index;
#ifdef __APPLE__
u8 use_clang_as = 0;
// 在MacOS下若使用clang且没有设置AFL_AS则使用clang作为汇编器
/* 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. */
if (clang_mode && !afl_as) {
use_clang_as = 1;
afl_as = getenv("AFL_CC"); // 获取AFL_CC环境变量
if (!afl_as) afl_as = getenv("AFL_CXX"); // 获取AFL_CXX环境变量
if (!afl_as) afl_as = "clang"; // 默认使用clang
afl_as = getenv("AFL_CC");
if (!afl_as) afl_as = getenv("AFL_CXX");
if (!afl_as) afl_as = "clang";
}
#endif
// 如果TMPDIR环境变量为空尝试从TEMP和TMP获取临时目录
#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. */
if (!tmp_dir) { tmp_dir = getenv("TEMP"); }
if (!tmp_dir) { tmp_dir = getenv("TMP"); }
if (!tmp_dir) { tmp_dir = "/tmp"; } // 默认临时目录为"/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"); // 参数过多,终止
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; // 跳过输入文件
// 处理64位和32位选项
if (i == input_index) continue;
if (!strcmp(argv[i], "--64")) {
use_64bit = 1;
} else if (!strcmp(argv[i], "--32")) {
use_64bit = 0;
}
#ifdef __APPLE__
// 在MacOS下处理架构选项
/* The Apple case is a bit different... */
if (!strcmp(argv[i], "-arch") && i + 1 < (u32)argc) {
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.");
}
#endif
// 跳过不相关的选项
/* 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__
// 如果使用clang作为汇编器追加相关选项
/* When calling clang as the upstream assembler, append -c -x assembler
and hope for the best. */
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. */
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) {
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());
}
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
wrap_things_up:
as_params[as_par_cnt++] = modified_file;
@ -224,13 +278,9 @@ static void add_instrumentation(void) {
skip_app = 0, instrument_next = 0;
#ifdef __APPLE__
<<<<<<< HEAD
u8 *colon_pos;
=======
u8 *colon_pos;
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
#endif /* __APPLE__ */
if (input_file) {
@ -253,6 +303,12 @@ static void add_instrumentation(void) {
if (!outf) { PFATAL("fdopen() failed"); }
while (fgets(line, MAX_LINE, inf)) {
/* 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. */
if (!pass_thru && !skip_intel && !skip_app && !skip_csect && instr_ok &&
instrument_next && line[0] == '\t' && isalpha(line[1])) {

@ -1895,132 +1895,125 @@ 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) {
// 如果启用了 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);
// 如果没有启用 ASAN则添加相应的编译选项来启用地址消毒
if (!aflcc->have_asan) {
insert_param(aflcc, "-fsanitize=address");
insert_param(aflcc, "-fno-common");
}
aflcc->have_asan = 1; // 标记已经启用了 ASAN
}
// 如果启用了 MSAN (内存消毒器),则进行相关配置
else if (getenv("AFL_USE_MSAN") || aflcc->have_msan) {
// 如果同时启用了 ASAN则报错因为 ASAN 和 MSAN 不能同时使用
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");
// 如果启用了 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; // 标记已经启用了 UBSAN
aflcc->have_ubsan = 1;
}
// 如果启用了 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; // 标记已经启用了 LTO
aflcc->have_flto = 1;
}
// 如果没有启用 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; // 标记已经启用了 CFISAN
aflcc->have_cfisan = 1;
}
}
}
/* Add params to enable LLVM SanCov, the native PCGUARD */
@ -2571,13 +2564,10 @@ 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");
@ -2589,46 +2579,31 @@ void add_misc_params(aflcc_state_t *aflcc) {
}
// 如果没有启用位置无关代码PIC则添加 -fPIC 参数
if (!aflcc->have_pic) {
insert_param(aflcc, "-fPIC");
}
if (!aflcc->have_pic) { insert_param(aflcc, "-fPIC"); }
// 如果环境变量 AFL_HARDEN 被设置,启用栈保护等安全选项
if (getenv("AFL_HARDEN")) {
// 启用所有函数的栈保护
insert_param(aflcc, "-fstack-protector-all");
// 如果未设置 Fortify设置 Fortify 防护等级
if (!aflcc->fortify_set)
add_defs_fortify(aflcc, 2);
if (!aflcc->fortify_set) add_defs_fortify(aflcc, 2);
}
// 如果环境变量 AFL_DONT_OPTIMIZE 未设置,启用优化选项
if (!getenv("AFL_DONT_OPTIMIZE")) {
// 启用调试符号生成
insert_param(aflcc, "-g");
// 如果没有设置 -O 优化级别,设置为 -O3最高优化
if (!aflcc->have_o)
insert_param(aflcc, "-O3");
// 如果没有设置循环展开,启用循环展开优化
if (!aflcc->have_unroll)
insert_param(aflcc, "-funroll-loops");
// 以下代码被注释掉了,但如果有指定架构优化选项(如 -march也可以启用
if (!aflcc->have_o) insert_param(aflcc, "-O3");
if (!aflcc->have_unroll) insert_param(aflcc, "-funroll-loops");
// 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");
}
}
@ -3107,44 +3082,6 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
static void process_params(aflcc_state_t *aflcc, u8 scan, u32 argc,
char **argv) {
<<<<<<< HEAD
u8 skip_next = 0;
while (--argc) {
u8 *cur = *(++argv);
if (skip_next > 0) {
skip_next--;
continue;
}
if (PARAM_MISS != parse_misc_params(aflcc, cur, scan)) continue;
if (PARAM_MISS != parse_fsanitize(aflcc, cur, scan)) continue;
if (PARAM_MISS != parse_linking_params(aflcc, cur, scan, &skip_next, argv))
continue;
if (*cur == '@') {
u8 *filename = cur + 1;
if (aflcc->debug) { DEBUGF("response file=%s\n", filename); }
FILE *f = fopen(filename, "r");
if (!f) {
if (!scan) insert_param(aflcc, cur);
continue;
}
struct stat st;
if (fstat(fileno(f), &st) || !S_ISREG(st.st_mode) || st.st_size < 1) {
fclose(f);
if (!scan) insert_param(aflcc, cur);
continue;
}
static u32 rsp_count = 2000;
if (scan) {
if (rsp_count == 0) FATAL("Too many response files provided!");
--rsp_count;
}
u32 argc_read = 1;
char **argv_read = ck_alloc(sizeof(char *));
argv_read[0] = "";
char *arg_buf = NULL;
u64 arg_len = 0;
enum fsm_state {
=======
// for (u32 x = 0; x < argc; ++x) fprintf(stderr, "[%u] %s\n", x, argv[x]);
/* Process the argument list. */
@ -3230,20 +3167,15 @@ static void process_params(aflcc_state_t *aflcc, u8 scan, u32 argc,
enum fsm_state {
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
fsm_whitespace, // whitespace seen so far
fsm_double_quote, // have unpaired double quote
fsm_single_quote, // have unpaired single quote
fsm_backslash, // a backslash is seen with no unpaired quote
fsm_normal // a normal char is seen
<<<<<<< HEAD
};
=======
};
// Workaround to append c to arg buffer, and append the buffer to argv
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
#define ARG_ALLOC(c) \
do { \
\
@ -3426,54 +3358,6 @@ static void process_params(aflcc_state_t *aflcc, u8 scan, u32 argc,
/* Process each of the existing argv, also add a few new args. */
static void edit_params(aflcc_state_t *aflcc, u32 argc, char **argv,
char **envp) {
<<<<<<< HEAD
add_real_argv0(aflcc);
if (aflcc->compiler_mode != GCC_PLUGIN && aflcc->compiler_mode != GCC) {
insert_param(aflcc, "-Wno-unused-command-line-argument");
}
if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG) {
add_assembler(aflcc);
}
if (aflcc->compiler_mode == GCC_PLUGIN) { add_gcc_plugin(aflcc); }
if (aflcc->compiler_mode == LLVM || aflcc->compiler_mode == LTO) {
if (aflcc->lto_mode && aflcc->have_instr_env) {
load_llvm_pass(aflcc, "afl-llvm-lto-instrumentlist.so");
}
if (getenv("AFL_LLVM_DICT2FILE")) {
load_llvm_pass(aflcc, "afl-llvm-dict2file.so");
}
if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) {
load_llvm_pass(aflcc, "split-switches-pass.so");
}
if (getenv("LAF_TRANSFORM_COMPARES") ||
getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
load_llvm_pass(aflcc, "compare-transform-pass.so");
}
if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") ||
getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) {
load_llvm_pass(aflcc, "split-compares-pass.so");
}
if (aflcc->cmplog_mode) {
insert_param(aflcc, "-fno-inline");
load_llvm_pass(aflcc, "cmplog-switches-pass.so");
load_llvm_pass(aflcc, "split-switches-pass.so");
}
if (aflcc->lto_mode) {
insert_param(aflcc, aflcc->lto_flag);
if (!aflcc->have_c) {
add_lto_linker(aflcc);
add_lto_passes(aflcc);
}
} else {
if (aflcc->instrument_mode == INSTRUMENT_PCGUARD) {
add_optimized_pcguard(aflcc);
} else if (aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE) {
add_native_pcguard(aflcc);
} else {
load_llvm_pass(aflcc, "afl-llvm-pass.so");
}
}
=======
add_real_argv0(aflcc);
@ -3573,7 +3457,6 @@ static void edit_params(aflcc_state_t *aflcc, u32 argc, char **argv,
}
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
if (aflcc->cmplog_mode) {
load_llvm_pass(aflcc, "cmplog-instructions-pass.so");
@ -3613,86 +3496,50 @@ static void edit_params(aflcc_state_t *aflcc, u32 argc, char **argv,
}
/* Main entry point */
classDiagram
class AFLCCMain {
+main(argc, argv, envp)
+initializeState()
+checkEnvironmentVariables()
+findDependencies()
+determineCompilerMode()
+determineInstrumentationMode()
+finalizeMode()
+processParameters()
+maybeShowUsage()
+notifyMode()
+debugArguments()
+editParameters()
+executeCompiler()
}
int main(int argc, char **argv, char **envp) {
class AFLCCState {
-cc_params: char**
-cc_par_cnt: u32
-passthrough: u8
-debug: u8
+aflcc_state_init(state, prog_name)
}
aflcc_state_t *aflcc = malloc(sizeof(aflcc_state_t));
aflcc_state_init(aflcc, (u8 *)argv[0]);
class EnvironmentChecker {
+check_environment_vars(envp)
}
check_environment_vars(envp);
class DependencyFinder {
+find_built_deps(aflcc)
}
find_built_deps(aflcc);
class CompilerModeHandler {
+compiler_mode_by_callname(aflcc)
+compiler_mode_by_environ(aflcc)
+compiler_mode_by_cmdline(aflcc, argc, argv)
}
compiler_mode_by_callname(aflcc);
compiler_mode_by_environ(aflcc);
compiler_mode_by_cmdline(aflcc, argc, argv);
class InstrumentationModeHandler {
+instrument_mode_by_environ(aflcc)
}
instrument_mode_by_environ(aflcc);
class ModeFinalizer {
+mode_final_checkout(aflcc, argc, argv)
}
mode_final_checkout(aflcc, argc, argv);
class ParameterProcessor {
+process_params(aflcc, start_idx, argc, argv)
}
process_params(aflcc, 1, argc, argv);
class UsageNotifier {
+maybe_usage(aflcc, argc, argv)
}
maybe_usage(aflcc, argc, argv);
class ModeNotifier {
+mode_notification(aflcc)
}
mode_notification(aflcc);
class Debugger {
+debugf_args(argc, argv)
}
if (aflcc->debug) debugf_args(argc, argv);
class ParameterEditor {
+edit_params(aflcc, argc, argv, envp)
}
edit_params(aflcc, argc, argv, envp);
if (aflcc->debug)
debugf_args((s32)aflcc->cc_par_cnt, (char **)aflcc->cc_params);
if (aflcc->passthrough) {
argv[0] = aflcc->cc_params[0];
execvp(aflcc->cc_params[0], (char **)argv);
} else {
execvp(aflcc->cc_params[0], (char **)aflcc->cc_params);
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 : 使
FATAL("Oops, failed to execute '%s' - check your PATH", aflcc->cc_params[0]);
return 0;
}

File diff suppressed because it is too large Load Diff

@ -23,8 +23,6 @@
how they affect the execution path.
*/
//引入了 AFL++ 的核心头文件、CMPLog 相关头文件、通用函数头文件等。
//根据编译选项,可能还会包含其他系统头文件,如内存映射、文件操作等。
#include "afl-fuzz.h"
#include "cmplog.h"
@ -84,9 +82,7 @@
\
\
} while (0)
//定义了与 zlib 相关的宏,用于处理压缩文件的读写操作。
//对于苹果系统,引入了特定的头文件以支持线程优先级设置。
//如果启用了性能分析,则声明了一个外部变量 time_spent_working 用于记录工作时间
#include <zlib.h>
#define ZLIBOPEN gzopen
#define ZLIBREAD ck_gzread
@ -110,14 +106,13 @@
#ifdef PROFILING
extern u64 time_spent_working;
#endif
//程序退出时的清理函数
static void at_exit() {//at_exit 函数在 AFL++ 程序退出时被调用,用于清理资源和终止子进程
//首先尝试获取环境变量 __AFL_TARGET_PID2 和 __AFL_TARGET_PID1这些变量存储了目标进程的 PID
static void at_exit() {
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) {
@ -135,11 +130,10 @@ static void at_exit() {//at_exit 函数在 AFL++ 程序退出时被调用,用
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) {
@ -179,14 +173,13 @@ static void at_exit() {//at_exit 函数在 AFL++ 程序退出时被调用,用
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(
@ -197,8 +190,7 @@ 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"
@ -219,11 +211,6 @@ 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
@ -236,12 +223,6 @@ 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"
@ -315,11 +296,10 @@ 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 " \
@ -328,7 +308,7 @@ static void usage(u8 *argv0, int more_help) {
#define PERSISTENT_MSG
#endif
SAYF(//用于输出详细的帮助信息,包括 AFL++ 使用的各种环境变量及其作用。
SAYF(
"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"
@ -431,59 +411,7 @@ 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(
@ -495,56 +423,50 @@ AFL_FUZZER_STATS_UPDATE_INTERVAL更新 fuzzer_stats 文件的间隔(以秒
#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 "
@ -555,9 +477,7 @@ AFL_FUZZER_STATS_UPDATE_INTERVAL更新 fuzzer_stats 文件的间隔(以秒
exit(1);
#undef PHYTON_SUPPORT
/*额外帮助:输出提示信息,建议用户查阅 README.md 文件以获取更多帮助。
退 exit(1) 退 1 退
使 #undef PHYTON_SUPPORT PHYTON_SUPPORT PYTHON_SUPPORT*/
}
#ifndef AFL_LIB
@ -624,10 +544,9 @@ 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*/;//用于存储 getopt 函数返回的选项字符
u64 prev_queued = 0;//自动同步标志,初始值为 0。
//用于记录上一次排队的项目数量。
u32 sync_interval_cnt /*同步间隔计数器*/= 0, seek_to = 0, show_help = 0, default_output = 1,
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,
map_size = get_map_size();
u8 *extras_dir[4];
u8 mem_limit_given = 0, exit_1 = 0, debug = 0,
@ -638,20 +557,9 @@ 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");
@ -665,8 +573,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
exit(0);
}
/*版本信息:如果命令行参数包含 --version则输出 AFL++ 的版本信息并退出程序。
--help usage 退*/
#if defined USE_COLOR && defined ALWAYS_COLORED
if (getenv("AFL_NO_COLOR") || getenv("AFL_NO_COLOUR")) {
@ -675,11 +582,11 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
"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"); }
@ -692,22 +599,15 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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:"
@ -794,25 +694,12 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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) {
@ -836,11 +723,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
}
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;
@ -849,12 +732,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
}
case 'p': /* Power schedule */
/*-p 选项
afl->schedule FASTCOEEXPLOITLINQUADMMOPTRAREEXPLORE SEEK
*/
if (!stricmp(optarg, "fast")) {
afl->schedule = FAST;
@ -906,11 +784,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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;
@ -918,13 +792,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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;
@ -934,28 +802,13 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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) {
@ -1009,14 +862,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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");
@ -1046,13 +892,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break;
case 'F': /* foreign sync dir */
/*-F 选项
-F
foreign_syncs */
if (!optarg) { FATAL("Missing path for -F"); }
if (!afl->is_main_node) {
@ -1084,13 +924,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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);
@ -1099,11 +933,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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");
@ -1114,13 +944,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break;
case 't': { /* timeout */
/*-t 选项
-t
+
5
timeout_given + */
u8 suffix = 0;
if (afl->timeout_given) { FATAL("Multiple -t options not supported"); }
@ -1150,14 +974,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
}
case 'm': { /* mem limit */
/*-m 选项
-m
TGkM
5
32 2000 MB*/
u8 suffix = 'M';
if (mem_limit_given) {
@ -1223,30 +1040,19 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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
@ -1264,22 +1070,13 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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");
@ -1305,26 +1102,14 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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;
@ -1347,12 +1132,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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
@ -1370,12 +1150,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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");
@ -1388,12 +1163,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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;
@ -1403,24 +1173,14 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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;
@ -1429,13 +1189,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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;
@ -1445,12 +1199,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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] == '-') {
@ -1462,12 +1211,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
} 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] == '-') {
@ -1479,20 +1223,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
} 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) {
@ -1555,23 +1286,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
} 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;
@ -1720,55 +1435,35 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
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);
@ -1778,14 +1473,7 @@ break 语句实际上在这里是多余的,因为 switch 语句的每个 case
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) {
@ -1807,19 +1495,13 @@ break 语句实际上在这里是多余的,因为 switch 语句的每个 case
}
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) {
@ -1828,24 +1510,18 @@ break 语句实际上在这里是多余的,因为 switch 语句的每个 case
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);
}
@ -1859,9 +1535,7 @@ break 语句实际上在这里是多余的,因为 switch 语句的每个 case
}
#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,
@ -1872,21 +1546,12 @@ break 语句实际上在这里是多余的,因为 switch 语句的每个 case
)
? 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;
@ -1895,13 +1560,7 @@ break 语句实际上在这里是多余的,因为 switch 语句的每个 case
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,9 +27,6 @@
*/
//林睿健阅读部分
#define AFL_MAIN
#include "config.h"
@ -100,10 +97,6 @@ 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,
@ -118,10 +111,6 @@ static const u8 count_class_lookup[256] = {
};
/*
kill_child
PID0
*/
static void kill_child() {
if (fsrv->child_pid > 0) {
@ -133,11 +122,6 @@ static void kill_child() {
}
/*
deinit_shmem
fsrvforkservershm_fuzz
NULL
*/
static sharedmem_t *deinit_shmem(afl_forkserver_t *fsrv,
sharedmem_t *shm_fuzz) {
@ -151,11 +135,7 @@ 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);
@ -172,12 +152,6 @@ 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;
@ -206,11 +180,7 @@ 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;
@ -226,11 +196,6 @@ 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) {
@ -246,11 +211,7 @@ static void at_exit_handler(void) {
}
/* Read initial file. */
/*
read_initial_file
in_file
*/
static void read_initial_file(void) {
struct stat st;
@ -278,11 +239,7 @@ 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;
@ -303,11 +260,7 @@ 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) {
@ -327,7 +280,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) {
@ -347,7 +300,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++;
@ -373,7 +326,7 @@ static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len,
}
} else {
/* 适当处理非崩溃输入 */
/* Handle non-crashing inputs appropriately. */
if (crash_mode) {
@ -399,11 +352,7 @@ 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];
@ -682,11 +631,7 @@ finalize_all:
}
/* Handle Ctrl-C and the like. */
/*
handle_stop_sig
sig
*/
static void handle_stop_sig(int sig) {
(void)sig;
@ -696,11 +641,7 @@ 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;
@ -798,10 +739,7 @@ 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;
@ -826,11 +764,7 @@ static void setup_signal_handlers(void) {
}
/* Display usage hints. */
/*
usage使
argv0
使
*/
static void usage(u8 *argv0) {
SAYF(
@ -895,272 +829,188 @@ 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"); }
@ -1171,7 +1021,6 @@ 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

@ -4,22 +4,25 @@
#include <stdbool.h>
#include "types.h"
#define TABLE_SIZE 10007 // Use a prime number for better distribution
// 使用一个质数作为哈希表的大小,有助于更好的分布
// 定义哈希节点结构体
typedef struct HashNode {
uint64_t key;
struct HashNode *next;
uint64_t key; // 哈希节点的键值
struct HashNode *next;// 指向下一个哈希节点的指针
} HashNode;
// 定义哈希表结构体
typedef struct HashMap {
HashNode **table;
HashNode **table;// 哈希表的数组,存储指向哈希节点的指针
} HashMap;
static HashMap *_hashmap;
static HashMap *_hashmap;// 静态变量,存储哈希表的实例
// 重置哈希表,如果未初始化则初始化,如果已初始化则清空
void hashmap_reset() {
if (unlikely(!_hashmap)) {
@ -48,13 +51,13 @@ void hashmap_reset() {
}
}
// 哈希函数,计算键值的哈希索引
static inline unsigned int hash(uint64_t key) {
return key % TABLE_SIZE;
}
// 搜索并添加键值如果type大于等于8则返回false
// type must be below 8
bool hashmap_search_and_add(uint8_t type, uint64_t key) {
@ -78,7 +81,7 @@ bool hashmap_search_and_add(uint8_t type, uint64_t key) {
return false;
}
// 搜索并添加指针类型的键值如果type大于等于8则返回false
// type must be below 8
bool hashmap_search_and_add_ptr(uint8_t type, u8 *key) {
@ -90,7 +93,7 @@ bool hashmap_search_and_add_ptr(uint8_t type, u8 *key) {
}
/* below is not used */
/* 下面的函数未使用 */
void hashmap_insert(uint64_t key) {
unsigned int index = hash(key);

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.
Loading…
Cancel
Save