commit message

pull/3/head
zhongfengrong 9 months ago
parent 295a40ad4b
commit 180081b7b7

@ -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 <lcamtuf@google.com>\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 <out_dir/queue/fuzz_bitmap. */
binary_mode = 1;
// 处理原始二进制模式参数
binary_mode = 1; // 设置为原始二进制模式
break;
case 'c':
if (keep_cores) FATAL("Multiple -c options not supported");
keep_cores = 1;
// 处理核心转储允许参数
if (keep_cores) FATAL("Multiple -c options not supported"); // 防止重复设置
keep_cores = 1; // 允许核心转储
break;
case 'V':
show_banner();
exit(0);
// 处理版本显示参数
show_banner(); // 显示工具的横幅信息
exit(0); // 退出程序
default:
// 如果遇到未知参数则显示用法提示
usage(argv[0]);
}
// 检查命令行参数的完整性,如果缺少必要参数则显示用法信息
if (optind == argc || !out_file) usage(argv[0]);
// 设置共享内存和信号处理
setup_shm();
setup_signal_handlers();
// 设置环境变量
set_up_environment();
// 查找用户提供的二进制文件路径
find_binary(argv[optind]);
// 如果不是安静模式,则显示正在执行的程序信息
if (!quiet_mode) {
show_banner();
ACTF("Executing '%s'...\n", target_path);
show_banner(); // 显示横幅信息
ACTF("Executing '%s'...\n", target_path); // 显示正在执行的程序路径
}
// 检测需要替换的文件参数
detect_file_args(argv + optind);
// 根据是否使用 QEMU 来准备参数数组
if (qemu_mode)
use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
else
use_argv = argv + optind;
use_argv = argv + optind; // 如果不是 QEMU使用原始参数数组
// 执行目标程序
run_target(use_argv);
// 写入执行结果
tcnt = write_results();
// 如果不是安静模式,则输出结果提示信息
if (!quiet_mode) {
if (!tcnt) FATAL("No instrumentation detected" cRST);
OKF("Captured %u tuples in '%s'." cRST, tcnt, out_file);
if (!tcnt) FATAL("No instrumentation detected" cRST); // 如果没有捕获到元组数据,则报错
OKF("Captured %u tuples in '%s'." cRST, tcnt, out_file); // 输出捕获到的元组数量
}
// 退出程序,返回状态值,状态值根据是否崩溃和超时进行设置
exit(child_crashed * 2 + child_timed_out);
}

Loading…
Cancel
Save