diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 4af6518..0bc41db 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -452,344 +452,336 @@ static void detect_file_args(char** argv) { argv[i] = n_arg; *aa_loc = '@'; + // 如果 at_file 不是绝对路径,则释放 aa_subst 内存 if (at_file[0] != '/') ck_free(aa_subst); } - i++; + i++; // 进入下一个参数 } - free(cwd); /* not tracked */ + free(cwd); // 释放当前工作目录内存,但不进行追踪 } - -/* Show banner. */ - +// 显示工具的横幅信息 static void show_banner(void) { - + // 输出工具名称以及作者信息 SAYF(cCYA "afl-showmap " cBRI VERSION cRST " by \n"); - } -/* Display usage hints. */ - +// 显示用法提示信息 static void usage(u8* argv0) { + show_banner(); // 显示横幅信息 - show_banner(); - + // 输出工具的用法信息和参数说明 SAYF("\n%s [ options ] -- /path/to/target_app [ ... ]\n\n" "Required parameters:\n\n" - " -o file - file to write the trace data to\n\n" + " -o file - file to write the trace data to\n\n" // 输出文件参数 + // 输出工具的用法信息和参数说明 "Execution control settings:\n\n" - " -t msec - timeout for each run (none)\n" - " -m megs - memory limit for child process (%u MB)\n" - " -Q - use binary-only instrumentation (QEMU mode)\n\n" + " -t msec - timeout for each run (none)\n" // 设置每次执行的超时时间,单位为毫秒 + " -m megs - memory limit for child process (%u MB)\n" // 设置子进程的内存限制,单位为MB + // 其他参数和设置选项的说明 "Other settings:\n\n" - " -q - sink program's output and don't show messages\n" - " -e - show edge coverage only, ignore hit counts\n" - " -c - allow core dumps\n" - " -V - show version number and exit\n\n" + " -q - sink program's output and don't show messages\n" // 隐藏程序输出,不显示信息 + " -e - show edge coverage only, ignore hit counts\n" // 仅显示边缘覆盖,忽略命中计数 + " -c - allow core dumps\n" // 允许生成核心转储 + " -V - show version number and exit\n\n" // 显示版本号并退出 + // 说明该工具的功能,并指向额外的帮助信息 "This tool displays raw tuple data captured by AFL instrumentation.\n" "For additional help, consult %s/README.\n\n" cRST, - argv0, MEM_LIMIT, doc_path); + argv0, MEM_LIMIT, doc_path); // 输出用法信息,包括程序名、内存限制和文档路径 - exit(1); + exit(1); // 退出程序,返回错误状态 -} +} -/* Find binary. */ +// 查找可执行二进制文件的函数 static void find_binary(u8* fname) { + u8* env_path = 0; // 环境变量路径 + struct stat st; // 文件状态信息 - u8* env_path = 0; - struct stat st; - + // 如果文件名包含 '/' 或者环境变量 PATH 不存在,直接使用提供的路径 if (strchr(fname, '/') || !(env_path = getenv("PATH"))) { + target_path = ck_strdup(fname); // 复制目标路径 - target_path = ck_strdup(fname); - + // 检查文件的状态,确认其存在且可执行 if (stat(target_path, &st) || !S_ISREG(st.st_mode) || !(st.st_mode & 0111) || st.st_size < 4) - FATAL("Program '%s' not found or not executable", fname); - + FATAL("Program '%s' not found or not executable", fname); // 如果不可执行,则报错 } else { - + // 逐个遍历 PATH 中的目录,并查找目标程序 while (env_path) { + u8 *cur_elem, *delim = strchr(env_path, ':'); // 分割当前路径元素 - u8 *cur_elem, *delim = strchr(env_path, ':'); - + // 如果找到分隔符,则处理当前路径元素 if (delim) { + cur_elem = ck_alloc(delim - env_path + 1); // 分配内存 + memcpy(cur_elem, env_path, delim - env_path); // 复制当前路径 + delim++; // 指向下一个路径元素 + } else + cur_elem = ck_strdup(env_path); // 没有分隔符,直接复制 - cur_elem = ck_alloc(delim - env_path + 1); - memcpy(cur_elem, env_path, delim - env_path); - delim++; - - } else cur_elem = ck_strdup(env_path); - - env_path = delim; + env_path = delim; // 更新环境路径 + // 构造目标路径 if (cur_elem[0]) - target_path = alloc_printf("%s/%s", cur_elem, fname); + target_path = alloc_printf("%s/%s", cur_elem, fname); // 拼接路径 else - target_path = ck_strdup(fname); + target_path = ck_strdup(fname); // 若当前路径为空则直接使用文件名 - ck_free(cur_elem); + ck_free(cur_elem); // 释放当前路径元素的内存 + // 检查拼接后的目标路径是否有效 if (!stat(target_path, &st) && S_ISREG(st.st_mode) && - (st.st_mode & 0111) && st.st_size >= 4) break; - - ck_free(target_path); - target_path = 0; + (st.st_mode & 0111) && st.st_size >= 4) break; // 找到可执行文件,退出查找 + ck_free(target_path); // 释放无效目标路径内存 + target_path = 0; // 重新初始化目标路径 } + // 如果没有找到目标程序,则报错 if (!target_path) FATAL("Program '%s' not found or not executable", fname); - } - } -/* Fix up argv for QEMU. */ +// 修复针对 QEMU 的 argv 参数 static char** get_qemu_argv(u8* own_loc, char** argv, int argc) { - - char** new_argv = ck_alloc(sizeof(char*) * (argc + 4)); + char** new_argv = ck_alloc(sizeof(char*) * (argc + 4)); // 分配新的参数数组内存 u8 *tmp, *cp, *rsl, *own_copy; - /* Workaround for a QEMU stability glitch. */ - + // 为了处理 QEMU 的稳定性问题,禁止链式调用 setenv("QEMU_LOG", "nochain", 1); + // 将原始参数复制到新的参数数组中 memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc); - new_argv[2] = target_path; - new_argv[1] = "--"; - - /* Now we need to actually find qemu for argv[0]. */ + new_argv[2] = target_path; // 新参数的第三个元素为目标路径 + new_argv[1] = "--"; // 添加分隔符 " -- " 以告诉 QEMU 参数的结束 + // 查找 afl-qemu-trace 的路径,使用 AFL_PATH 环境变量 tmp = getenv("AFL_PATH"); - if (tmp) { + cp = alloc_printf("%s/afl-qemu-trace", tmp); // 拼接 AFL_PATH - cp = alloc_printf("%s/afl-qemu-trace", tmp); - + // 如果没有找到,则报错 if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp); - target_path = new_argv[0] = cp; - return new_argv; - + target_path = new_argv[0] = cp; // 将找到的路径赋值给目标路径 + return new_argv; // 返回新的参数数组 } + // 复制当前程序的路径以查找 afl-qemu-trace own_copy = ck_strdup(own_loc); - rsl = strrchr(own_copy, '/'); + rsl = strrchr(own_copy, '/'); // 找到最后一个 '/' 的位置 if (rsl) { + *rsl = 0; // 将最后一个 '/' 替换为终止符 - *rsl = 0; - + // 拼接 afl-qemu-trace 路径 cp = alloc_printf("%s/afl-qemu-trace", own_copy); - ck_free(own_copy); + ck_free(own_copy); // 释放复制的路径内存 + // 检查拼接后的路径是否有效 if (!access(cp, X_OK)) { - - target_path = new_argv[0] = cp; - return new_argv; - + target_path = new_argv[0] = cp; // 更新目标路径 + return new_argv; // 返回新的参数数组 } + } else + ck_free(own_copy); // 如果没有找到 '/',则释放内存 - } else ck_free(own_copy); - + // 在默认的 BIN_PATH 查找 afl-qemu-trace if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) { - - target_path = new_argv[0] = BIN_PATH "/afl-qemu-trace"; - return new_argv; - + target_path = new_argv[0] = BIN_PATH "/afl-qemu-trace"; // 设置目标路径 + return new_argv; // 返回新的参数数组 } + // 如果以上步骤都未能找到 afl-qemu-trace,则报错 FATAL("Unable to find 'afl-qemu-trace'."); - } -/* Main entry point */ +/* + Main entry point +*/ int main(int argc, char** argv) { - s32 opt; - u8 mem_limit_given = 0, timeout_given = 0, qemu_mode = 0; - u32 tcnt; - char** use_argv; + s32 opt; // 选项变量 + u8 mem_limit_given = 0, timeout_given = 0, qemu_mode = 0; // 标志变量 + u32 tcnt; // 计数变量,用于记录捕获的元组数量 + char** use_argv; // 用于存储最终的参数数组 + // 检查文档路径是否存在,用于后续帮助信息 doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; + // 处理命令行参数 while ((opt = getopt(argc,argv,"+o:m:t:A:eqZQbcV")) > 0) - switch (opt) { - case 'o': - - if (out_file) FATAL("Multiple -o options not supported"); - out_file = optarg; + // 处理输出文件参数 + if (out_file) FATAL("Multiple -o options not supported"); // 防止重复设置 + out_file = optarg; // 保存输出文件路径 break; case 'm': { + u8 suffix = 'M'; // 默认单位为MB - u8 suffix = 'M'; - - if (mem_limit_given) FATAL("Multiple -m options not supported"); - mem_limit_given = 1; - - if (!strcmp(optarg, "none")) { - - mem_limit = 0; - break; - - } - - if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 || - optarg[0] == '-') FATAL("Bad syntax used for -m"); - - switch (suffix) { - - case 'T': mem_limit *= 1024 * 1024; break; - case 'G': mem_limit *= 1024; break; - case 'k': mem_limit /= 1024; break; - case 'M': break; - - default: FATAL("Unsupported suffix or bad syntax for -m"); + // 检查是否已经设置了内存限制 + if (mem_limit_given) FATAL("Multiple -m options not supported"); + mem_limit_given = 1; - } - - if (mem_limit < 5) FATAL("Dangerously low value of -m"); - - if (sizeof(rlim_t) == 4 && mem_limit > 2000) - FATAL("Value of -m out of range on 32-bit systems"); + // 如果输入为 "none",则不设置内存限制 + if (!strcmp(optarg, "none")) { + mem_limit = 0; // 设置内存限制为0 + break; + } + // 解析输入的内存限制 + if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 || + optarg[0] == '-') FATAL("Bad syntax used for -m"); + + // 根据单位调整内存限制 + switch (suffix) { + case 'T': mem_limit *= 1024 * 1024; break; // TB + case 'G': mem_limit *= 1024; break; // GB + case 'k': mem_limit /= 1024; break; // kB + case 'M': break; // MB + default: FATAL("Unsupported suffix or bad syntax for -m"); // 报错 } - break; + // 设置的内存值不能低于阈值5 + if (mem_limit < 5) FATAL("Dangerously low value of -m"); + + // 在32位系统中,内存限制不能超过2000MB + if (sizeof(rlim_t) == 4 && mem_limit > 2000) + FATAL("Value of -m out of range on 32-bit systems"); + } + break; case 't': - + // 处理超时时间参数 if (timeout_given) FATAL("Multiple -t options not supported"); timeout_given = 1; + // 如果不为 "none",则将输入解析为超时时间 if (strcmp(optarg, "none")) { - exec_tmout = atoi(optarg); + exec_tmout = atoi(optarg); // 将时间转换为整数 + // 超时时间设置不能低于20毫秒 if (exec_tmout < 20 || optarg[0] == '-') FATAL("Dangerously low value of -t"); - } - break; case 'e': - - if (edges_only) FATAL("Multiple -e options not supported"); - edges_only = 1; + // 处理边缘覆盖参数 + if (edges_only) FATAL("Multiple -e options not supported"); // 防止重复设置 + edges_only = 1; // 设置为只显示边缘覆盖 break; case 'q': - - if (quiet_mode) FATAL("Multiple -q options not supported"); - quiet_mode = 1; + // 处理安静模式参数 + if (quiet_mode) FATAL("Multiple -q options not supported"); // 防止重复设置 + quiet_mode = 1; // 启用安静模式 break; case 'Z': - - /* This is an undocumented option to write data in the syntax expected - by afl-cmin. Nobody else should have any use for this. */ - + // 处理 afl-cmin 特定功能参数 cmin_mode = 1; - quiet_mode = 1; + quiet_mode = 1; // 同时启用安静模式 break; case 'A': - - /* Another afl-cmin specific feature. */ - at_file = optarg; + // 处理替代文件参数 + at_file = optarg; // 保存替代文件名 break; case 'Q': + // 处理 QEMU 特定功能参数 + if (qemu_mode) FATAL("Multiple -Q options not supported"); // 防止重复设置 + if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU; // 若未设置内存限制,则使用 QEMU 的默认值 - if (qemu_mode) FATAL("Multiple -Q options not supported"); - if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU; - - qemu_mode = 1; + qemu_mode = 1; // 启用 QEMU 模式 break; case 'b': - - /* Secret undocumented mode. Writes output in raw binary format - similar to that dumped by afl-fuzz in