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