|
|
@ -23,6 +23,8 @@
|
|
|
|
how they affect the execution path.
|
|
|
|
how they affect the execution path.
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
//引入了 AFL++ 的核心头文件、CMPLog 相关头文件、通用函数头文件等。
|
|
|
|
|
|
|
|
//根据编译选项,可能还会包含其他系统头文件,如内存映射、文件操作等。
|
|
|
|
|
|
|
|
|
|
|
|
#include "afl-fuzz.h"
|
|
|
|
#include "afl-fuzz.h"
|
|
|
|
#include "cmplog.h"
|
|
|
|
#include "cmplog.h"
|
|
|
@ -82,7 +84,9 @@
|
|
|
|
\
|
|
|
|
\
|
|
|
|
\
|
|
|
|
\
|
|
|
|
} while (0)
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
//定义了与 zlib 相关的宏,用于处理压缩文件的读写操作。
|
|
|
|
|
|
|
|
//对于苹果系统,引入了特定的头文件以支持线程优先级设置。
|
|
|
|
|
|
|
|
//如果启用了性能分析,则声明了一个外部变量 time_spent_working 用于记录工作时间
|
|
|
|
#include <zlib.h>
|
|
|
|
#include <zlib.h>
|
|
|
|
#define ZLIBOPEN gzopen
|
|
|
|
#define ZLIBOPEN gzopen
|
|
|
|
#define ZLIBREAD ck_gzread
|
|
|
|
#define ZLIBREAD ck_gzread
|
|
|
@ -106,13 +110,14 @@
|
|
|
|
#ifdef PROFILING
|
|
|
|
#ifdef PROFILING
|
|
|
|
extern u64 time_spent_working;
|
|
|
|
extern u64 time_spent_working;
|
|
|
|
#endif
|
|
|
|
#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;
|
|
|
|
s32 i, pid1 = 0, pid2 = 0, pgrp = -1;
|
|
|
|
char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL};
|
|
|
|
char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL};
|
|
|
|
char *ptr;
|
|
|
|
char *ptr;
|
|
|
|
|
|
|
|
//如果找到有效的 PID,则获取其进程组 ID 并向进程组发送 SIGTERM 信号以终止整个进程组,
|
|
|
|
|
|
|
|
//然后单独向目标进程发送 SIGTERM 信号。
|
|
|
|
ptr = getenv("__AFL_TARGET_PID2");
|
|
|
|
ptr = getenv("__AFL_TARGET_PID2");
|
|
|
|
if (ptr && *ptr && (pid2 = atoi(ptr)) > 0) {
|
|
|
|
if (ptr && *ptr && (pid2 = atoi(ptr)) > 0) {
|
|
|
|
|
|
|
|
|
|
|
@ -130,10 +135,11 @@ static void at_exit() {
|
|
|
|
kill(pid1, SIGTERM);
|
|
|
|
kill(pid1, SIGTERM);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//尝试获取环境变量 CPU_AFFINITY_ENV_VAR,如果存在且非空,则删除该文件以解除 CPU 亲和性设置
|
|
|
|
ptr = getenv(CPU_AFFINITY_ENV_VAR);
|
|
|
|
ptr = getenv(CPU_AFFINITY_ENV_VAR);
|
|
|
|
if (ptr && *ptr) unlink(ptr);
|
|
|
|
if (ptr && *ptr) unlink(ptr);
|
|
|
|
|
|
|
|
//遍历 list 数组,获取每个环境变量的值,如果存在且非空,
|
|
|
|
|
|
|
|
//则根据编译选项使用不同的共享内存删除函数(shm_unlink 或 shmctl)来删除共享内存
|
|
|
|
i = 0;
|
|
|
|
i = 0;
|
|
|
|
while (list[i] != NULL) {
|
|
|
|
while (list[i] != NULL) {
|
|
|
|
|
|
|
|
|
|
|
@ -173,13 +179,14 @@ static void at_exit() {
|
|
|
|
pgrp = getpgid(pid1);
|
|
|
|
pgrp = getpgid(pid1);
|
|
|
|
if (pgrp > 0) { killpg(pgrp, kill_signal); }
|
|
|
|
if (pgrp > 0) { killpg(pgrp, kill_signal); }
|
|
|
|
kill(pid2, kill_signal);
|
|
|
|
kill(pid2, kill_signal);
|
|
|
|
|
|
|
|
//最后,获取环境变量 AFL_KILL_SIGNAL 的值作为要发送的信号类型(默认为 SIGKILL),
|
|
|
|
|
|
|
|
//然后再次检查 PID1 和 PID2,获取其进程组 ID 并向进程组发送相应的信号,单独向目标进程发送信号以确保其被终止
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Display usage hints. */
|
|
|
|
/* Display usage hints. */
|
|
|
|
|
|
|
|
//主要为显示说明
|
|
|
|
static void usage(u8 *argv0, int more_help) {
|
|
|
|
static void usage(u8 *argv0, int more_help) {
|
|
|
|
|
|
|
|
|
|
|
|
SAYF(
|
|
|
|
SAYF(
|
|
|
@ -190,7 +197,8 @@ static void usage(u8 *argv0, int more_help) {
|
|
|
|
"also see \n"
|
|
|
|
"also see \n"
|
|
|
|
" AFL_AUTORESUME)\n"
|
|
|
|
" AFL_AUTORESUME)\n"
|
|
|
|
" -o dir - output directory for fuzzer findings\n\n"
|
|
|
|
" -o dir - output directory for fuzzer findings\n\n"
|
|
|
|
|
|
|
|
//-i dir:指定输入目录,该目录包含用于模糊测试的测试用例。如果输入为 -,则表示恢复之前的模糊测试会话。
|
|
|
|
|
|
|
|
//-o dir:指定输出目录,用于存储模糊测试过程中发现的结果。
|
|
|
|
"Execution control settings:\n"
|
|
|
|
"Execution control settings:\n"
|
|
|
|
" -P strategy - set fix mutation strategy: explore (focus on new "
|
|
|
|
" -P strategy - set fix mutation strategy: explore (focus on new "
|
|
|
|
"coverage),\n"
|
|
|
|
"coverage),\n"
|
|
|
@ -211,6 +219,11 @@ static void usage(u8 *argv0, int more_help) {
|
|
|
|
"maximum.\n"
|
|
|
|
"maximum.\n"
|
|
|
|
" -m megs - memory limit for child process (%u MB, 0 = no limit "
|
|
|
|
" -m megs - memory limit for child process (%u MB, 0 = no limit "
|
|
|
|
"[default])\n"
|
|
|
|
"[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__)
|
|
|
|
#if defined(__linux__) && defined(__aarch64__)
|
|
|
|
" -A - use binary-only instrumentation (ARM CoreSight mode)\n"
|
|
|
|
" -A - use binary-only instrumentation (ARM CoreSight mode)\n"
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
@ -223,6 +236,12 @@ static void usage(u8 *argv0, int more_help) {
|
|
|
|
#if defined(__linux__)
|
|
|
|
#if defined(__linux__)
|
|
|
|
" -X - use VM fuzzing (NYX mode - standalone mode)\n"
|
|
|
|
" -X - use VM fuzzing (NYX mode - standalone mode)\n"
|
|
|
|
" -Y - use VM fuzzing (NYX mode - multiple instances 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
|
|
|
|
#endif
|
|
|
|
"\n"
|
|
|
|
"\n"
|
|
|
|
|
|
|
|
|
|
|
@ -296,10 +315,11 @@ static void usage(u8 *argv0, int more_help) {
|
|
|
|
#if defined USE_COLOR && !defined ALWAYS_COLORED
|
|
|
|
#if defined USE_COLOR && !defined ALWAYS_COLORED
|
|
|
|
#define DYN_COLOR \
|
|
|
|
#define DYN_COLOR \
|
|
|
|
"AFL_NO_COLOR or AFL_NO_COLOUR: switch colored console output off\n"
|
|
|
|
"AFL_NO_COLOR or AFL_NO_COLOUR: switch colored console output off\n"
|
|
|
|
|
|
|
|
//定义了 USE_COLOR 但未定义 ALWAYS_COLORED,则定义 DYN_COLOR 宏,用于提示用户如何关闭控制台的颜色输出
|
|
|
|
#else
|
|
|
|
#else
|
|
|
|
#define DYN_COLOR
|
|
|
|
#define DYN_COLOR
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//如果定义了 AFL_PERSISTENT_RECORD,则定义 PERSISTENT_MSG 宏,用于提示用户 AFL_PERSISTENT_RECORD 环境变量的作用
|
|
|
|
#ifdef AFL_PERSISTENT_RECORD
|
|
|
|
#ifdef AFL_PERSISTENT_RECORD
|
|
|
|
#define PERSISTENT_MSG \
|
|
|
|
#define PERSISTENT_MSG \
|
|
|
|
"AFL_PERSISTENT_RECORD: record the last X inputs to every crash in " \
|
|
|
|
"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
|
|
|
|
#define PERSISTENT_MSG
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
SAYF(
|
|
|
|
SAYF(//用于输出详细的帮助信息,包括 AFL++ 使用的各种环境变量及其作用。
|
|
|
|
"Environment variables used:\n"
|
|
|
|
"Environment variables used:\n"
|
|
|
|
"LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
|
|
|
|
"LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
|
|
|
|
"ASAN_OPTIONS: custom settings for ASAN\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"
|
|
|
|
" seconds (default: 60, minimum: 1)\n"
|
|
|
|
"\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_SIZE:Nyx 辅助缓冲区的大小,必须是 4096 的倍数。
|
|
|
|
|
|
|
|
AFL_NYX_DISABLE_SNAPSHOT_MODE 和 AFL_NYX_LOG:禁用快照模式和将 NYX hprintf 消息输出到另一个文件。
|
|
|
|
|
|
|
|
AFL_NYX_REUSE_SNAPSHOT:重用现有的 Nyx 根快照。
|
|
|
|
|
|
|
|
AFL_PATH:AFL 支持二进制文件的路径。
|
|
|
|
|
|
|
|
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 {
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
|
|
SAYF(
|
|
|
|
SAYF(
|
|
|
@ -423,50 +495,56 @@ static void usage(u8 *argv0, int more_help) {
|
|
|
|
#ifdef USE_PYTHON
|
|
|
|
#ifdef USE_PYTHON
|
|
|
|
SAYF("Compiled with %s module support, see docs/custom_mutators.md\n",
|
|
|
|
SAYF("Compiled with %s module support, see docs/custom_mutators.md\n",
|
|
|
|
(char *)PYTHON_VERSION);
|
|
|
|
(char *)PYTHON_VERSION);
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
如果定义了 USE_PYTHON,则输出 AFL++ 是使用 Python 模块支持编译的,并提示用户查看相关文档以了解如何使用自定义变异器。
|
|
|
|
|
|
|
|
否则,输出 AFL++ 是没有 Python 模块支持编译的*/
|
|
|
|
#else
|
|
|
|
#else
|
|
|
|
SAYF("Compiled without Python module support.\n");
|
|
|
|
SAYF("Compiled without Python module support.\n");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*如果定义了 AFL_PERSISTENT_RECORD,则输出 AFL++ 是使用持久记录支持编译的。
|
|
|
|
|
|
|
|
否则,输出 AFL++ 是没有持久记录支持编译的。*/
|
|
|
|
#ifdef AFL_PERSISTENT_RECORD
|
|
|
|
#ifdef AFL_PERSISTENT_RECORD
|
|
|
|
SAYF("Compiled with AFL_PERSISTENT_RECORD support.\n");
|
|
|
|
SAYF("Compiled with AFL_PERSISTENT_RECORD support.\n");
|
|
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
#else
|
|
|
|
SAYF("Compiled without AFL_PERSISTENT_RECORD support.\n");
|
|
|
|
SAYF("Compiled without AFL_PERSISTENT_RECORD support.\n");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*如果定义了 USEMMAP,则输出 AFL++ 是使用 shm_open 支持编译的。
|
|
|
|
|
|
|
|
否则,输出 AFL++ 是使用 shmat 支持编译的。*/
|
|
|
|
#ifdef USEMMAP
|
|
|
|
#ifdef USEMMAP
|
|
|
|
SAYF("Compiled with shm_open support.\n");
|
|
|
|
SAYF("Compiled with shm_open support.\n");
|
|
|
|
#else
|
|
|
|
#else
|
|
|
|
SAYF("Compiled with shmat support.\n");
|
|
|
|
SAYF("Compiled with shmat support.\n");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*如果定义了 ASAN_BUILD,则输出 AFL++ 是使用 ASAN 构建编译的。*/
|
|
|
|
#ifdef ASAN_BUILD
|
|
|
|
#ifdef ASAN_BUILD
|
|
|
|
SAYF("Compiled with ASAN_BUILD.\n");
|
|
|
|
SAYF("Compiled with ASAN_BUILD.\n");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*如果定义了 NO_SPLICING,则输出 AFL++ 是使用禁止拼接选项编译的*/
|
|
|
|
#ifdef NO_SPLICING
|
|
|
|
#ifdef NO_SPLICING
|
|
|
|
SAYF("Compiled with NO_SPLICING.\n");
|
|
|
|
SAYF("Compiled with NO_SPLICING.\n");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*如果定义了 FANCY_BOXES_NO_UTF,则输出 AFL++ 是没有 UTF-8 支持编译的,这会影响状态屏幕中的线条渲染。*/
|
|
|
|
#ifdef FANCY_BOXES_NO_UTF
|
|
|
|
#ifdef FANCY_BOXES_NO_UTF
|
|
|
|
SAYF("Compiled without UTF-8 support for line rendering in status screen.\n");
|
|
|
|
SAYF("Compiled without UTF-8 support for line rendering in status screen.\n");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*如果定义了 PROFILING,则输出 AFL++ 是使用性能分析编译的。*/
|
|
|
|
#ifdef PROFILING
|
|
|
|
#ifdef PROFILING
|
|
|
|
SAYF("Compiled with PROFILING.\n");
|
|
|
|
SAYF("Compiled with PROFILING.\n");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*如果定义了 INTROSPECTION,则输出 AFL++ 是使用自省编译的。*/
|
|
|
|
#ifdef INTROSPECTION
|
|
|
|
#ifdef INTROSPECTION
|
|
|
|
SAYF("Compiled with INTROSPECTION.\n");
|
|
|
|
SAYF("Compiled with INTROSPECTION.\n");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*如果定义了 _DEBUG,则输出 AFL++ 是使用调试模式编译的*/
|
|
|
|
#ifdef _DEBUG
|
|
|
|
#ifdef _DEBUG
|
|
|
|
SAYF("Compiled with _DEBUG.\n");
|
|
|
|
SAYF("Compiled with _DEBUG.\n");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*如果定义了 _AFL_DOCUMENT_MUTATIONS,则输出 AFL++ 是使用记录变异编译的。*/
|
|
|
|
#ifdef _AFL_DOCUMENT_MUTATIONS
|
|
|
|
#ifdef _AFL_DOCUMENT_MUTATIONS
|
|
|
|
SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n");
|
|
|
|
SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*如果定义了 _AFL_SPECIAL_PERFORMANCE,则输出 AFL++ 是使用特定系统的特殊性能选项编译的,并提醒用户这可能不适用于其他平台。*/
|
|
|
|
#ifdef _AFL_SPECIAL_PERFORMANCE
|
|
|
|
#ifdef _AFL_SPECIAL_PERFORMANCE
|
|
|
|
SAYF(
|
|
|
|
SAYF(
|
|
|
|
"Compiled with special performance options for this specific system, it "
|
|
|
|
"Compiled with special performance options for this specific system, it "
|
|
|
@ -477,7 +555,9 @@ static void usage(u8 *argv0, int more_help) {
|
|
|
|
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
exit(1);
|
|
|
|
#undef PHYTON_SUPPORT
|
|
|
|
#undef PHYTON_SUPPORT
|
|
|
|
|
|
|
|
/*额外帮助:输出提示信息,建议用户查阅 README.md 文件以获取更多帮助。
|
|
|
|
|
|
|
|
退出程序:调用 exit(1) 退出程序,返回状态码 1 表示程序因错误或异常而退出。
|
|
|
|
|
|
|
|
取消宏定义:使用 #undef PHYTON_SUPPORT 取消 PHYTON_SUPPORT 宏的定义,尽管这里可能是一个拼写错误,应该是 PYTHON_SUPPORT。*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef AFL_LIB
|
|
|
|
#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) {
|
|
|
|
int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
|
|
|
|
|
|
|
|
s32 opt, auto_sync = 0 /*, user_set_cache = 0*/;
|
|
|
|
s32 opt, auto_sync = 0 /*, user_set_cache = 0*/;//用于存储 getopt 函数返回的选项字符
|
|
|
|
u64 prev_queued = 0;
|
|
|
|
u64 prev_queued = 0;//自动同步标志,初始值为 0。
|
|
|
|
u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, default_output = 1,
|
|
|
|
//用于记录上一次排队的项目数量。
|
|
|
|
|
|
|
|
u32 sync_interval_cnt /*同步间隔计数器*/= 0, seek_to = 0, show_help = 0, default_output = 1,
|
|
|
|
map_size = get_map_size();
|
|
|
|
map_size = get_map_size();
|
|
|
|
u8 *extras_dir[4];
|
|
|
|
u8 *extras_dir[4];
|
|
|
|
u8 mem_limit_given = 0, exit_1 = 0, debug = 0,
|
|
|
|
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 timeval tv;
|
|
|
|
struct timezone tz;
|
|
|
|
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 = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH;
|
|
|
|
|
|
|
|
//根据 DOC_PATH 环境变量或默认路径 "docs" 初始化文档路径
|
|
|
|
if (argc > 1 && strcmp(argv_orig[1], "--version") == 0) {
|
|
|
|
if (argc > 1 && strcmp(argv_orig[1], "--version") == 0) {
|
|
|
|
|
|
|
|
|
|
|
|
printf("afl-fuzz" VERSION "\n");
|
|
|
|
printf("afl-fuzz" VERSION "\n");
|
|
|
@ -573,7 +665,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
exit(0);
|
|
|
|
exit(0);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*版本信息:如果命令行参数包含 --version,则输出 AFL++ 的版本信息并退出程序。
|
|
|
|
|
|
|
|
帮助信息:如果命令行参数包含 --help,则调用 usage 函数显示帮助信息并退出程序。*/
|
|
|
|
#if defined USE_COLOR && defined ALWAYS_COLORED
|
|
|
|
#if defined USE_COLOR && defined ALWAYS_COLORED
|
|
|
|
if (getenv("AFL_NO_COLOR") || getenv("AFL_NO_COLOUR")) {
|
|
|
|
if (getenv("AFL_NO_COLOR") || getenv("AFL_NO_COLOUR")) {
|
|
|
|
|
|
|
|
|
|
|
@ -582,11 +675,11 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
"compile time)");
|
|
|
|
"compile time)");
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*颜色输出:如果定义了 USE_COLOR 和 ALWAYS_COLORED,并且环境变量 AFL_NO_COLOR 或 AFL_NO_COLOUR 被设置,则输出警告信息,提示用户颜色设置在编译时已配置。*/
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
char **argv = argv_cpy_dup(argc, argv_orig);
|
|
|
|
char **argv = argv_cpy_dup(argc, argv_orig);
|
|
|
|
|
|
|
|
//argv_cpy_dup:复制命令行参数数组,以便在后续处理中使用
|
|
|
|
afl_state_t *afl = calloc(1, sizeof(afl_state_t));
|
|
|
|
afl_state_t *afl = calloc(1, sizeof(afl_state_t));
|
|
|
|
if (!afl) { FATAL("Could not create afl state"); }
|
|
|
|
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);
|
|
|
|
read_afl_environment(afl, envp);
|
|
|
|
if (afl->shm.map_size) { afl->fsrv.map_size = afl->shm.map_size; }
|
|
|
|
if (afl->shm.map_size) { afl->fsrv.map_size = afl->shm.map_size; }
|
|
|
|
exit_1 = !!afl->afl_env.afl_bench_just_one;
|
|
|
|
exit_1 = !!afl->afl_env.afl_bench_just_one;
|
|
|
|
|
|
|
|
//SAYF:输出 AFL++ 的版本信息和基于的原始 AFL 作者信息。
|
|
|
|
SAYF(cCYA "afl-fuzz" VERSION cRST
|
|
|
|
SAYF(cCYA "afl-fuzz" VERSION cRST
|
|
|
|
" based on afl by Michal Zalewski and a large online community\n");
|
|
|
|
" based on afl by Michal Zalewski and a large online community\n");
|
|
|
|
|
|
|
|
//gettimeofday:获取当前时间。
|
|
|
|
|
|
|
|
//rand_set_seed:根据当前时间设置随机种子,用于后续的随机数生成
|
|
|
|
gettimeofday(&tv, &tz);
|
|
|
|
gettimeofday(&tv, &tz);
|
|
|
|
rand_set_seed(afl, tv.tv_sec ^ tv.tv_usec ^ getpid());
|
|
|
|
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->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
|
|
|
|
// still available: HjJkKqruvwz
|
|
|
|
while ((opt = getopt(argc, argv,
|
|
|
|
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:"
|
|
|
|
"+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");
|
|
|
|
FATAL("Bad syntax used for -b");
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*getopt 循环:使用 getopt 函数解析命令行选项。
|
|
|
|
|
|
|
|
-a 选项:设置输入模式,可以是 "text"、"binary" 或 "default"。
|
|
|
|
|
|
|
|
-P 选项:设置固定的变异策略,可以是 "explore"、"exploit" 或指定一个秒数,表示在没有发现新结果时自动切换到 "exploit" 模式的时间。
|
|
|
|
|
|
|
|
-g 选项:设置生成的模糊输入的最小长度。
|
|
|
|
|
|
|
|
-G 选项:设置生成的模糊输入的最大长度。
|
|
|
|
|
|
|
|
-Z 选项:启用旧的种子选择方式。
|
|
|
|
|
|
|
|
-I 选项:设置信息执行命令。
|
|
|
|
|
|
|
|
-b 选项:绑定 AFL++ 进程到指定的 CPU 核心*/
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case 'c': {
|
|
|
|
case 'c': {
|
|
|
|
|
|
|
|
/*-c 选项
|
|
|
|
|
|
|
|
功能:用于启用或禁用 CMPLog 模式。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果选项参数为 "-",则表示禁用 CMPLog 模式。如果之前已经启用,则输出提示信息并禁用 CMPLog 模式,同时将 cmplog_binary 设置为 NULL。
|
|
|
|
|
|
|
|
如果选项参数不为 "-",则启用 CMPLog 模式,并将 cmplog_binary 设置为选项参数指定的路径。*/
|
|
|
|
|
|
|
|
|
|
|
|
if (strcmp(optarg, "-") == 0) {
|
|
|
|
if (strcmp(optarg, "-") == 0) {
|
|
|
|
|
|
|
|
|
|
|
@ -723,7 +836,11 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case 's': {
|
|
|
|
case 's': {
|
|
|
|
|
|
|
|
/*-s 选项
|
|
|
|
|
|
|
|
功能:用于设置固定的随机种子。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果选项参数为 NULL,则输出错误信息并终止程序。
|
|
|
|
|
|
|
|
否则,使用选项参数指定的种子值初始化随机数生成器,并设置 fixed_seed 标志为 1,表示使用固定的随机种子。*/
|
|
|
|
if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); }
|
|
|
|
if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); }
|
|
|
|
rand_set_seed(afl, strtoul(optarg, 0L, 10));
|
|
|
|
rand_set_seed(afl, strtoul(optarg, 0L, 10));
|
|
|
|
afl->fixed_seed = 1;
|
|
|
|
afl->fixed_seed = 1;
|
|
|
@ -732,7 +849,12 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case 'p': /* Power schedule */
|
|
|
|
case 'p': /* Power schedule */
|
|
|
|
|
|
|
|
/*-p 选项
|
|
|
|
|
|
|
|
功能:用于设置功率调度策略,决定如何计算种子的性能得分。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
根据选项参数的值,将 afl->schedule 设置为相应的功率调度策略枚举值。支持的策略包括 FAST、COE、EXPLOIT、LIN、QUAD、MMOPT、RARE、EXPLORE 和 SEEK。
|
|
|
|
|
|
|
|
如果选项参数不匹配任何已知策略,则输出错误信息并终止程序。
|
|
|
|
|
|
|
|
*/
|
|
|
|
if (!stricmp(optarg, "fast")) {
|
|
|
|
if (!stricmp(optarg, "fast")) {
|
|
|
|
|
|
|
|
|
|
|
|
afl->schedule = FAST;
|
|
|
|
afl->schedule = FAST;
|
|
|
@ -784,7 +906,11 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'e':
|
|
|
|
case 'e':
|
|
|
|
|
|
|
|
/*-e 选项
|
|
|
|
|
|
|
|
功能:用于设置目标程序输入文件的扩展名。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果 afl->file_extension 已经被设置,则输出错误信息并终止程序,表示不支持多个 -e 选项。
|
|
|
|
|
|
|
|
否则,将 afl->file_extension 设置为选项参数指定的扩展名。*/
|
|
|
|
if (afl->file_extension) { FATAL("Multiple -e options not supported"); }
|
|
|
|
if (afl->file_extension) { FATAL("Multiple -e options not supported"); }
|
|
|
|
|
|
|
|
|
|
|
|
afl->file_extension = optarg;
|
|
|
|
afl->file_extension = optarg;
|
|
|
@ -792,7 +918,13 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'i': /* input dir */
|
|
|
|
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 (afl->in_dir) { FATAL("Multiple -i options not supported"); }
|
|
|
|
if (optarg == NULL) { FATAL("Invalid -i option (got NULL)."); }
|
|
|
|
if (optarg == NULL) { FATAL("Invalid -i option (got NULL)."); }
|
|
|
|
afl->in_dir = optarg;
|
|
|
|
afl->in_dir = optarg;
|
|
|
@ -802,13 +934,28 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'o': /* output dir */
|
|
|
|
case 'o': /* output dir */
|
|
|
|
|
|
|
|
/*-o 选项
|
|
|
|
|
|
|
|
功能:用于指定输出目录,用于存储模糊测试过程中发现的结果。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果 afl->out_dir 已经被设置,则输出错误信息并终止程序,表示不支持多个 -o 选项。
|
|
|
|
|
|
|
|
否则,将 afl->out_dir 设置为选项参数指定的输出目录路径。*/
|
|
|
|
if (afl->out_dir) { FATAL("Multiple -o options not supported"); }
|
|
|
|
if (afl->out_dir) { FATAL("Multiple -o options not supported"); }
|
|
|
|
afl->out_dir = optarg;
|
|
|
|
afl->out_dir = optarg;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'M': { /* main sync ID */
|
|
|
|
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;
|
|
|
|
u8 *c;
|
|
|
|
|
|
|
|
|
|
|
|
if (afl->non_instrumented_mode) {
|
|
|
|
if (afl->non_instrumented_mode) {
|
|
|
@ -862,7 +1009,14 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'S': /* secondary sync id */
|
|
|
|
case 'S': /* secondary sync id */
|
|
|
|
|
|
|
|
/*-S 选项
|
|
|
|
|
|
|
|
功能:用于设置次级同步 ID,用于分布式模糊测试中的次级节点。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
检查是否处于非插桩模式或 ARM CoreSight 模式,如果是,则输出错误信息并终止程序,因为这些模式不支持 -S 选项。
|
|
|
|
|
|
|
|
检查是否已经设置了同步 ID,如果是,则输出错误信息并终止程序,表示不支持多个 -S 或 -M 选项。
|
|
|
|
|
|
|
|
检查选项参数是否以 - 开头,如果是,则输出错误信息并终止程序,因为 - 通常用于选项。
|
|
|
|
|
|
|
|
将同步 ID 设置为选项参数指定的值。
|
|
|
|
|
|
|
|
设置 is_secondary_node 标志为 1,表示当前节点是次级节点*/
|
|
|
|
if (afl->non_instrumented_mode) {
|
|
|
|
if (afl->non_instrumented_mode) {
|
|
|
|
|
|
|
|
|
|
|
|
FATAL("-S is not supported in 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;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'F': /* foreign sync dir */
|
|
|
|
case 'F': /* foreign sync dir */
|
|
|
|
|
|
|
|
/*-F 选项
|
|
|
|
|
|
|
|
功能:用于指定外部同步目录,用于分布式模糊测试中与其他模糊测试实例同步。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
检查是否提供了选项参数,如果没有,则输出错误信息并终止程序。
|
|
|
|
|
|
|
|
检查是否是主节点,如果不是,则输出错误信息并终止程序,因为 -F 选项只能在主节点中指定。
|
|
|
|
|
|
|
|
检查是否已经达到外部同步目录的最大数量限制,如果是,则输出错误信息并终止程序。
|
|
|
|
|
|
|
|
将外部同步目录添加到 foreign_syncs 数组中,并去除路径末尾的斜杠。*/
|
|
|
|
if (!optarg) { FATAL("Missing path for -F"); }
|
|
|
|
if (!optarg) { FATAL("Missing path for -F"); }
|
|
|
|
if (!afl->is_main_node) {
|
|
|
|
if (!afl->is_main_node) {
|
|
|
|
|
|
|
|
|
|
|
@ -924,7 +1084,13 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'f': /* target file */
|
|
|
|
case 'f': /* target file */
|
|
|
|
|
|
|
|
/*-f 选项
|
|
|
|
|
|
|
|
功能:用于指定目标程序读取的文件路径。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
检查是否已经设置了输出文件,如果是,则输出错误信息并终止程序,表示不支持多个 -f 选项。
|
|
|
|
|
|
|
|
将输出文件路径设置为选项参数指定的值。
|
|
|
|
|
|
|
|
设置 use_stdin 标志为 0,表示不使用标准输入。
|
|
|
|
|
|
|
|
设置 default_output 标志为 0,表示不使用默认输出。*/
|
|
|
|
if (afl->fsrv.out_file) { FATAL("Multiple -f options not supported"); }
|
|
|
|
if (afl->fsrv.out_file) { FATAL("Multiple -f options not supported"); }
|
|
|
|
|
|
|
|
|
|
|
|
afl->fsrv.out_file = ck_strdup(optarg);
|
|
|
|
afl->fsrv.out_file = ck_strdup(optarg);
|
|
|
@ -933,7 +1099,11 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'x': /* dictionary */
|
|
|
|
case 'x': /* dictionary */
|
|
|
|
|
|
|
|
/*-x 选项
|
|
|
|
|
|
|
|
功能:用于指定字典文件路径,用于辅助模糊测试。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
检查是否已经设置了超过四个字典文件,如果是,则输出错误信息并终止程序,表示不支持超过四个 -x 选项。
|
|
|
|
|
|
|
|
将字典文件路径添加到 extras_dir 数组中,并增加 extras_dir_cnt 计数。*/
|
|
|
|
if (extras_dir_cnt >= 4) {
|
|
|
|
if (extras_dir_cnt >= 4) {
|
|
|
|
|
|
|
|
|
|
|
|
FATAL("More than four -x options are not supported");
|
|
|
|
FATAL("More than four -x options are not supported");
|
|
|
@ -944,7 +1114,13 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 't': { /* timeout */
|
|
|
|
case 't': { /* timeout */
|
|
|
|
|
|
|
|
/*-t 选项
|
|
|
|
|
|
|
|
功能:用于设置每次运行的超时时间。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
检查是否已经设置了超时时间,如果是,则输出错误信息并终止程序,表示不支持多个 -t 选项。
|
|
|
|
|
|
|
|
解析选项参数,提取超时时间值和可能的后缀(如 +)。
|
|
|
|
|
|
|
|
如果超时时间值小于 5 毫秒,则输出错误信息并终止程序,表示超时时间过低。
|
|
|
|
|
|
|
|
根据后缀设置 timeout_given 标志,+ 表示自动计算超时时间。*/
|
|
|
|
u8 suffix = 0;
|
|
|
|
u8 suffix = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (afl->timeout_given) { FATAL("Multiple -t options not supported"); }
|
|
|
|
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 */
|
|
|
|
case 'm': { /* mem limit */
|
|
|
|
|
|
|
|
/*-m 选项
|
|
|
|
|
|
|
|
功能:用于设置子进程的内存限制。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
检查是否已经设置了内存限制,如果是,则输出警告信息,表示将覆盖之前的 -m 选项。
|
|
|
|
|
|
|
|
解析选项参数,提取内存限制值和可能的单位后缀(如 T、G、k、M)。
|
|
|
|
|
|
|
|
根据单位后缀将内存限制值转换为相应的字节数。
|
|
|
|
|
|
|
|
如果内存限制值小于 5 字节,则输出错误信息并终止程序,表示内存限制过低。
|
|
|
|
|
|
|
|
在 32 位系统上,如果内存限制值大于 2000 MB,则输出错误信息并终止程序,表示内存限制超出范围。*/
|
|
|
|
u8 suffix = 'M';
|
|
|
|
u8 suffix = 'M';
|
|
|
|
|
|
|
|
|
|
|
|
if (mem_limit_given) {
|
|
|
|
if (mem_limit_given) {
|
|
|
@ -1040,19 +1223,30 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
|
|
|
|
|
|
|
|
case 'd':
|
|
|
|
case 'd':
|
|
|
|
case 'D': /* old deterministic */
|
|
|
|
case 'D': /* old deterministic */
|
|
|
|
|
|
|
|
/*-d 和 -D 选项
|
|
|
|
|
|
|
|
功能:这两个选项已被弃用,用于旧的确定性模糊测试。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
输出警告信息,提示用户新的增强确定性模糊测试已默认激活,如果需要禁用,请使用 -z 选项。*/
|
|
|
|
WARNF(
|
|
|
|
WARNF(
|
|
|
|
"Parameters -d and -D are deprecated, a new enhanced deterministic "
|
|
|
|
"Parameters -d and -D are deprecated, a new enhanced deterministic "
|
|
|
|
"fuzzing is active by default, to disable it use -z");
|
|
|
|
"fuzzing is active by default, to disable it use -z");
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'z': /* no deterministic */
|
|
|
|
case 'z': /* no deterministic */
|
|
|
|
|
|
|
|
/*-z 选项
|
|
|
|
|
|
|
|
功能:用于禁用确定性模糊测试。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
设置 skip_deterministic 标志为 1,表示跳过确定性模糊测试阶段。*/
|
|
|
|
afl->skip_deterministic = 1;
|
|
|
|
afl->skip_deterministic = 1;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'B': /* load bitmap */
|
|
|
|
case 'B': /* load bitmap */
|
|
|
|
|
|
|
|
/*-B 选项
|
|
|
|
|
|
|
|
功能:用于加载位图,这是一个未公开的选项。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果已经设置了 in_bitmap,则输出错误信息并终止程序,表示不支持多个 -B 选项。
|
|
|
|
|
|
|
|
将 in_bitmap 设置为选项参数指定的位图文件路径。
|
|
|
|
|
|
|
|
说明:该选项用于在正常的模糊测试过程中发现有趣的测试用例时,加载之前运行产生的位图,*/
|
|
|
|
/* This is a secret undocumented option! It is useful if you find
|
|
|
|
/* This is a secret undocumented option! It is useful if you find
|
|
|
|
an interesting test case during a normal fuzzing process, and want
|
|
|
|
an interesting test case during a normal fuzzing process, and want
|
|
|
|
to mutate it without rediscovering any of the test cases already
|
|
|
|
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;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'C': /* crash mode */
|
|
|
|
case 'C': /* crash mode */
|
|
|
|
|
|
|
|
/*-C 选项
|
|
|
|
|
|
|
|
功能:用于设置崩溃模式。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果已经设置了 crash_mode,则输出错误信息并终止程序,表示不支持多个 -C 选项。
|
|
|
|
|
|
|
|
将 crash_mode 设置为 FSRV_RUN_CRASH,表示启用崩溃模式。*/
|
|
|
|
if (afl->crash_mode) { FATAL("Multiple -C options not supported"); }
|
|
|
|
if (afl->crash_mode) { FATAL("Multiple -C options not supported"); }
|
|
|
|
afl->crash_mode = FSRV_RUN_CRASH;
|
|
|
|
afl->crash_mode = FSRV_RUN_CRASH;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'n': /* dumb mode */
|
|
|
|
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) {
|
|
|
|
if (afl->is_main_node || afl->is_secondary_node) {
|
|
|
|
|
|
|
|
|
|
|
|
FATAL("Non instrumented mode is not supported with -M / -S");
|
|
|
|
FATAL("Non instrumented mode is not supported with -M / -S");
|
|
|
@ -1102,14 +1305,26 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'T': /* banner */
|
|
|
|
case 'T': /* banner */
|
|
|
|
|
|
|
|
/*-T 选项
|
|
|
|
|
|
|
|
功能:用于设置横幅。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果已经设置了 use_banner,则输出错误信息并终止程序,表示不支持多个 -T 选项。
|
|
|
|
|
|
|
|
将 use_banner 设置为选项参数指定的横幅文本。*/
|
|
|
|
if (afl->use_banner) { FATAL("Multiple -T options not supported"); }
|
|
|
|
if (afl->use_banner) { FATAL("Multiple -T options not supported"); }
|
|
|
|
afl->use_banner = optarg;
|
|
|
|
afl->use_banner = optarg;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
#ifdef __linux__
|
|
|
|
case 'X': /* NYX mode */
|
|
|
|
case 'X': /* NYX mode */
|
|
|
|
|
|
|
|
/*-X 和 -Y 选项(仅限 Linux)
|
|
|
|
|
|
|
|
功能:用于设置 Nyx 模式。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
-X 选项:设置 Nyx 独立模式。
|
|
|
|
|
|
|
|
检查是否已经设置了 nyx_mode,如果是,则输出错误信息并终止程序,表示不支持多个 -X 选项。
|
|
|
|
|
|
|
|
设置 nyx_parent、nyx_standalone 和 nyx_mode 标志,表示启用 Nyx 独立模式。
|
|
|
|
|
|
|
|
-Y 选项:设置 Nyx 分布式模式。
|
|
|
|
|
|
|
|
检查是否已经设置了 nyx_mode,如果是,则输出错误信息并终止程序,表示不支持多个 -Y 选项。
|
|
|
|
|
|
|
|
设置 nyx_mode 标志,表示启用 Nyx 分布式模式*/
|
|
|
|
if (afl->fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); }
|
|
|
|
if (afl->fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); }
|
|
|
|
|
|
|
|
|
|
|
|
afl->fsrv.nyx_parent = true;
|
|
|
|
afl->fsrv.nyx_parent = true;
|
|
|
@ -1132,7 +1347,12 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
case 'A': /* CoreSight mode */
|
|
|
|
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__)
|
|
|
|
#if !defined(__aarch64__) || !defined(__linux__)
|
|
|
|
FATAL("-A option is not supported on this platform");
|
|
|
|
FATAL("-A option is not supported on this platform");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
@ -1150,7 +1370,12 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'O': /* FRIDA mode */
|
|
|
|
case 'O': /* FRIDA mode */
|
|
|
|
|
|
|
|
/*-O 选项
|
|
|
|
|
|
|
|
功能:用于设置 FRIDA 模式。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
检查是否已经设置了 frida_mode,如果是,则输出错误信息并终止程序,表示不支持多个 -O 选项。
|
|
|
|
|
|
|
|
设置 frida_mode 标志,表示启用 FRIDA 模式。
|
|
|
|
|
|
|
|
检查环境变量 AFL_USE_FASAN,如果设置,则设置 frida_asan 标志为 1,表示使用 FRIDA 地址制裁模式。*/
|
|
|
|
if (afl->fsrv.frida_mode) {
|
|
|
|
if (afl->fsrv.frida_mode) {
|
|
|
|
|
|
|
|
|
|
|
|
FATAL("Multiple -O options not supported");
|
|
|
|
FATAL("Multiple -O options not supported");
|
|
|
@ -1163,7 +1388,12 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'Q': /* QEMU mode */
|
|
|
|
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"); }
|
|
|
|
if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); }
|
|
|
|
|
|
|
|
|
|
|
|
afl->fsrv.qemu_mode = 1;
|
|
|
|
afl->fsrv.qemu_mode = 1;
|
|
|
@ -1173,14 +1403,24 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'N': /* Unicorn mode */
|
|
|
|
case 'N': /* Unicorn mode */
|
|
|
|
|
|
|
|
/*-N 选项
|
|
|
|
|
|
|
|
功能:用于设置不删除模糊测试输入文件的标志。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
检查是否已经设置了 no_unlink,如果是,则输出错误信息并终止程序,表示不支持多个 -N 选项。
|
|
|
|
|
|
|
|
设置 no_unlink 标志为 true,表示在模糊测试过程中不删除输入文件。*/
|
|
|
|
if (afl->no_unlink) { FATAL("Multiple -N options not supported"); }
|
|
|
|
if (afl->no_unlink) { FATAL("Multiple -N options not supported"); }
|
|
|
|
afl->fsrv.no_unlink = (afl->no_unlink = true);
|
|
|
|
afl->fsrv.no_unlink = (afl->no_unlink = true);
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'U': /* Unicorn mode */
|
|
|
|
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"); }
|
|
|
|
if (afl->unicorn_mode) { FATAL("Multiple -U options not supported"); }
|
|
|
|
afl->unicorn_mode = 1;
|
|
|
|
afl->unicorn_mode = 1;
|
|
|
|
|
|
|
|
|
|
|
@ -1189,7 +1429,13 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'W': /* Wine+QEMU mode */
|
|
|
|
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"); }
|
|
|
|
if (afl->use_wine) { FATAL("Multiple -W options not supported"); }
|
|
|
|
afl->fsrv.qemu_mode = 1;
|
|
|
|
afl->fsrv.qemu_mode = 1;
|
|
|
|
afl->use_wine = 1;
|
|
|
|
afl->use_wine = 1;
|
|
|
@ -1199,7 +1445,12 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'V': {
|
|
|
|
case 'V': {
|
|
|
|
|
|
|
|
/*-V 选项
|
|
|
|
|
|
|
|
功能:用于设置 AFL++ 运行的最大时间。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
设置 most_time_key 标志为 1,表示启用了运行时间限制。
|
|
|
|
|
|
|
|
解析选项参数,提取最大运行时间值。
|
|
|
|
|
|
|
|
如果解析失败或参数格式不正确,则输出错误信息并终止程序。*/
|
|
|
|
afl->most_time_key = 1;
|
|
|
|
afl->most_time_key = 1;
|
|
|
|
if (!optarg || sscanf(optarg, "%llu", &afl->most_time) < 1 ||
|
|
|
|
if (!optarg || sscanf(optarg, "%llu", &afl->most_time) < 1 ||
|
|
|
|
optarg[0] == '-') {
|
|
|
|
optarg[0] == '-') {
|
|
|
@ -1211,7 +1462,12 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
} break;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'E': {
|
|
|
|
case 'E': {
|
|
|
|
|
|
|
|
/*-E 选项
|
|
|
|
|
|
|
|
功能:用于设置 AFL++ 运行的最大执行次数。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
设置 most_execs_key 标志为 1,表示启用了执行次数限制。
|
|
|
|
|
|
|
|
解析选项参数,提取最大执行次数值。
|
|
|
|
|
|
|
|
如果解析失败或参数格式不正确,则输出错误信息并终止程序。*/
|
|
|
|
afl->most_execs_key = 1;
|
|
|
|
afl->most_execs_key = 1;
|
|
|
|
if (!optarg || sscanf(optarg, "%llu", &afl->most_execs) < 1 ||
|
|
|
|
if (!optarg || sscanf(optarg, "%llu", &afl->most_execs) < 1 ||
|
|
|
|
optarg[0] == '-') {
|
|
|
|
optarg[0] == '-') {
|
|
|
@ -1223,7 +1479,20 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
} break;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'l': {
|
|
|
|
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'"); }
|
|
|
|
if (!optarg) { FATAL("missing parameter for 'l'"); }
|
|
|
|
char *c = optarg;
|
|
|
|
char *c = optarg;
|
|
|
|
while (*c) {
|
|
|
|
while (*c) {
|
|
|
@ -1286,7 +1555,23 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
} break;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'L': { /* MOpt mode */
|
|
|
|
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_now、key_puppet、g_now、w_now 等。
|
|
|
|
|
|
|
|
遍历每个“swarm”(群体),初始化相关的变量,如 swarm_fitness、stage_finds_puppet、probability_now、x_now、v_now、L_best、G_best、eff_best 等。
|
|
|
|
|
|
|
|
计算每个操作符的概率和速度。
|
|
|
|
|
|
|
|
确保概率值在合理范围内。
|
|
|
|
|
|
|
|
输出警告信息,提示用户 MOpt 模式不再被维护,且不如正常的 Havoc 模式有效。*/
|
|
|
|
if (afl->limit_time_sig) { FATAL("Multiple -L options not supported"); }
|
|
|
|
if (afl->limit_time_sig) { FATAL("Multiple -L options not supported"); }
|
|
|
|
|
|
|
|
|
|
|
|
afl->havoc_max_mult = HAVOC_MAX_MULT_MOPT;
|
|
|
|
afl->havoc_max_mult = HAVOC_MAX_MULT_MOPT;
|
|
|
@ -1435,35 +1720,55 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
case 'h':
|
|
|
|
case 'h':
|
|
|
|
show_help++;
|
|
|
|
show_help++;
|
|
|
|
break; // not needed
|
|
|
|
break; // not needed
|
|
|
|
|
|
|
|
/*-h 选项
|
|
|
|
|
|
|
|
功能:用于显示帮助信息。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
增加 show_help 计数器的值。
|
|
|
|
|
|
|
|
break 语句实际上在这里是多余的,因为 switch 语句的每个 case 都是独立的。
|
|
|
|
|
|
|
|
*/
|
|
|
|
case 'R':
|
|
|
|
case 'R':
|
|
|
|
|
|
|
|
/*-R 选项
|
|
|
|
|
|
|
|
功能:用于处理 Radamsa 相关的选项。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
输出错误信息并终止程序,提示用户 Radamsa 现在是一个自定义变异器,应该使用自定义变异器的方式(custom_mutators/radamsa/)来使用。*/
|
|
|
|
FATAL(
|
|
|
|
FATAL(
|
|
|
|
"Radamsa is now a custom mutator, please use that "
|
|
|
|
"Radamsa is now a custom mutator, please use that "
|
|
|
|
"(custom_mutators/radamsa/).");
|
|
|
|
"(custom_mutators/radamsa/).");
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*默认情况
|
|
|
|
|
|
|
|
功能:处理未匹配的选项。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果 show_help 未被设置,则将其设置为 1,表示需要显示帮助信息。*/
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
if (!show_help) { show_help = 1; }
|
|
|
|
if (!show_help) { show_help = 1; }
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*同步 ID 检查
|
|
|
|
|
|
|
|
功能:检查同步 ID 是否为保留名称。
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果 sync_id 被设置为 "addseeds",则输出错误信息并终止程序,因为 "addseeds" 是一个保留名称,不能用作同步 ID*/
|
|
|
|
if (afl->sync_id && strcmp(afl->sync_id, "addseeds") == 0) {
|
|
|
|
if (afl->sync_id && strcmp(afl->sync_id, "addseeds") == 0) {
|
|
|
|
|
|
|
|
|
|
|
|
FATAL("-M/-S name 'addseeds' is a reserved name, choose something else");
|
|
|
|
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 &&
|
|
|
|
if (afl->is_main_node == 1 && afl->schedule != FAST &&
|
|
|
|
afl->schedule != EXPLORE) {
|
|
|
|
afl->schedule != EXPLORE) {
|
|
|
|
|
|
|
|
|
|
|
|
FATAL("-M is compatible only with fast and explore -p power schedules");
|
|
|
|
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) {
|
|
|
|
if (optind == argc || !afl->in_dir || !afl->out_dir || show_help) {
|
|
|
|
|
|
|
|
|
|
|
|
usage(argv[0], 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)) {
|
|
|
|
if (unlikely(afl->afl_env.afl_persistent_record)) {
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef 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);
|
|
|
|
afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record);
|
|
|
|
|
|
|
|
|
|
|
|
if (afl->fsrv.persistent_record < 2) {
|
|
|
|
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;
|
|
|
|
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 "
|
|
|
|
OKF("AFL++ is maintained by Marc \"van Hauser\" Heuse, Dominik Maier, Andrea "
|
|
|
|
"Fioraldi and Heiko \"hexcoder\" Eißfeldt");
|
|
|
|
"Fioraldi and Heiko \"hexcoder\" Eißfeldt");
|
|
|
|
OKF("AFL++ is open source, get it at "
|
|
|
|
OKF("AFL++ is open source, get it at "
|
|
|
|
"https://github.com/AFLplusplus/AFLplusplus");
|
|
|
|
"https://github.com/AFLplusplus/AFLplusplus");
|
|
|
|
OKF("NOTE: AFL++ >= v3 has changed defaults and behaviours - see README.md");
|
|
|
|
OKF("NOTE: AFL++ >= v3 has changed defaults and behaviours - see README.md");
|
|
|
|
|
|
|
|
/*版本信息显示
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
输出 AFL++ 的维护者信息,包括 Marc "van Hauser" Heuse、Dominik Maier、Andrea Fioraldi 和 Heiko "hexcoder" Eißfeldt。
|
|
|
|
|
|
|
|
提示 AFL++ 是开源软件,并提供 GitHub 仓库链接。
|
|
|
|
|
|
|
|
提醒用户 AFL++ 从版本 3 开始改变了默认设置和行为,建议查看 README.md 文件了解详细信息。*/
|
|
|
|
#ifdef __linux__
|
|
|
|
#ifdef __linux__
|
|
|
|
if (afl->fsrv.nyx_mode) {
|
|
|
|
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");
|
|
|
|
OKF("Nyx is open source, get it at https://github.com/Nyx-Fuzz");
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Nyx 模式信息显示(仅限 Linux)
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果启用了 Nyx 模式,输出 Nyx 模式的信息,包括开发者和维护者 Sergej Schumilo,以及 Nyx 的 GitHub 仓库链接。*/
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// silently disable deterministic mutation if custom mutators are used
|
|
|
|
// silently disable deterministic mutation if custom mutators are used
|
|
|
|
if (!afl->skip_deterministic && afl->afl_env.afl_custom_mutator_only) {
|
|
|
|
if (!afl->skip_deterministic && afl->afl_env.afl_custom_mutator_only) {
|
|
|
|
|
|
|
|
/*确定性变异禁用
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果启用了自定义变异器且未禁用确定性变异,则自动禁用确定性变异。这是因为自定义变异器可能已经包含了确定性变异的功能。*/
|
|
|
|
afl->skip_deterministic = 1;
|
|
|
|
afl->skip_deterministic = 1;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (afl->fixed_seed) {
|
|
|
|
if (afl->fixed_seed) {
|
|
|
|
|
|
|
|
/*固定种子信息显示
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果设置了固定种子,则输出正在使用的固定种子值。*/
|
|
|
|
OKF("Running with fixed seed: %u", (u32)afl->init_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
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*信号配置
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
调用 configure_afl_kill_signals 函数配置 AFL++ 的信号处理,设置子进程和 fork 服务器的终止信号。如果启用了 QEMU、Unicorn、fauxsrv 或 Nyx 模式,则使用 SIGKILL 信号,否则使用 SIGTERM 信号。*/
|
|
|
|
configure_afl_kill_signals(
|
|
|
|
configure_afl_kill_signals(
|
|
|
|
&afl->fsrv, afl->afl_env.afl_child_kill_signal,
|
|
|
|
&afl->fsrv, afl->afl_env.afl_child_kill_signal,
|
|
|
|
afl->afl_env.afl_fsrv_kill_signal,
|
|
|
|
afl->afl_env.afl_fsrv_kill_signal,
|
|
|
@ -1546,12 +1872,21 @@ int main(int argc, char **argv_orig, char **envp) {
|
|
|
|
)
|
|
|
|
)
|
|
|
|
? SIGKILL
|
|
|
|
? SIGKILL
|
|
|
|
: SIGTERM);
|
|
|
|
: SIGTERM);
|
|
|
|
|
|
|
|
/*信号处理设置
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
调用 setup_signal_handlers 函数设置 AFL++ 的信号处理程序,以便在接收到特定信号时执行相应的操作。*/
|
|
|
|
setup_signal_handlers();
|
|
|
|
setup_signal_handlers();
|
|
|
|
check_asan_opts(afl);
|
|
|
|
check_asan_opts(afl);
|
|
|
|
|
|
|
|
/*ASAN 构建内存限制禁用(仅限 ASAN 构建)
|
|
|
|
|
|
|
|
逻辑:
|
|
|
|
|
|
|
|
如果 AFL++ 是使用 ASAN 构建的,并且设置了内存限制,则输出警告信息并禁用内存限制。这是因为 ASAN 可能需要更多的内存来检测内存问题。*/
|
|
|
|
afl->power_name = power_names[afl->schedule];
|
|
|
|
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) {
|
|
|
|
if (!afl->non_instrumented_mode && !afl->sync_id) {
|
|
|
|
|
|
|
|
|
|
|
|
auto_sync = 1;
|
|
|
|
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);
|
|
|
|
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__
|
|
|
|
#ifdef __linux__
|
|
|
|
if (afl->fsrv.nyx_mode) {
|
|
|
|
if (afl->fsrv.nyx_mode) {
|
|
|
|
|
|
|
|
|
|
|
|