afl-fuzz.c main函数简单流程
发表于更新于
字数总计:1.1k阅读时长:4分钟 中国
AFL笔记笔记fuzzafl-fuzz.c main函数简单流程
Ivoripuionafl-fuzz.c main函数简单流程(关键步骤省略)
预处理
1
| SAYF(cCYA "afl-fuzz " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
|
1
| doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
|
1 2
| gettimeofday(&tv, &tz); srandom(tv.tv_sec ^ tv.tv_usec ^ getpid());
|
根据命令行初始化并检查一些参数;
- i:输入语料文件夹,对应变量
in_dir
;
- o:fuzz输出文件夹,对应变量
out_dir
;
- M,S:多线程模式下的Master和Server,Master会采取强制确定性变异,然后进行随进行变异,而Server会采取dumb mode进行fuzz,即不进行确定性变异;
- f:用来进行fuzz的文件,对应变量
out_file
;
- x:确定性变异阶段的字典(?),对应变量
extras_dir
;
- t:目标程序运行case的限制时间,对应变量
timeout_given
;
- m:目标程序运行内存的限制,对应变量
mem_limit
;
- d:跳过确定性变异,对应变量
skip_deterministic
;
- B:指定fuzz_bitmap来跳过该case;
- C:crash mode;
- n:dumb mode(随机模式,且不进行插桩);
- T:text banner;
- Q;QEMU mode;
设置信号句柄sa
:
1
| setup_signal_handlers();
|
1
| if (sync_id) fix_up_sync();
|
1 2
| if (!strcmp(in_dir, out_dir)) FATAL("Input and output directories can't be the same");
|
1 2 3 4 5 6
| if (dumb_mode) {
if (crash_mode) FATAL("-C and -n are mutually exclusive"); if (qemu_mode) FATAL("-Q and -n are mutually exclusive");
}
|
1
| save_cmdline(argc, argv);
|
- 调整banner的展示效果(将fuzzer id写上):
1
| fix_up_banner(argv[optind]);
|
1 2 3
| #ifdef HAVE_AFFINITY bind_to_free_cpu(); #endif
|
- 检查crash的转存以及CPU的管理者(主要通过检查
/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
这类的设备文件):
1 2
| check_crash_handling(); check_cpu_governor();
|
- 检查环境变量
AFL_POST_LIBRARY
,该环境变量用于对变异后的testcases格式进行修正,如计算校验和等:
使用后会进行如下编译:
1
| gcc -shared -Wall -O3 post_library.so.c -o post_library.so
|
- 设置共享内存块以及virgin_bits(用来记录总分支路径信息:Regions yet untouched by fuzzing):
喂数据
- 读取测试用例进入队列中,包括对输入文件夹权限、内容等的检查:
- 自动载入token,即检查输入文件夹中是否有token文件夹,有则载入。这里查阅资料后:
- 使用token是用来执行bitflip时降低消耗资源的一种策略,即将一个token代表一系列变异后覆盖路径未变化的语料。
- 在输出文件中为输入文件(变异后的)创建硬链接,以”id:”开头:
# define CASE_PREFIX "id:"
,并根据其进行适当的调整:
1
| if (extras_dir) load_extras(extras_dir);
|
- 若没有设置”-t”的参数,则找到一个合理的”timeout”值,以防止不断地收缩这个”timeout”值:
1
| if (!timeout_given) find_timeout();
|
1
| if (!out_file) setup_stdio_file();
|
- 检查目标程序的存在,且不是一个shell脚本,通过检查ELF头来判断是否为一个ELF文件,可以通过设置”AFL_SKIP_BIN_CHECK”环境变量来跳过该项检查:
1
| check_binary(argv[optind]);
|
1
| start_time = get_cur_time();
|
1 2 3 4
| if (qemu_mode) use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind); else use_argv = argv + optind;
|
执行fuzz(具体步骤后续详细分析)
- dry run,将种子文件直接作为输入文件喂给目标程序:
1
| perform_dry_run(use_argv);
|
- 从队列中找到最合适的testcase,赋值给top_rated[],并且设置q->favored:
1
| seek_to = find_start_position();
|
1
| write_stats_file(0, 0, 0);
|
1
| if (stop_soon) goto stop_fuzzing;
|
1 2 3 4 5
| if (!not_on_tty) { sleep(4); start_time += 4000; if (stop_soon) goto stop_fuzzing; }
|
- 收尾工作,包括关闭文件描述符,销毁队列、token文件夹等:
1 2 3 4 5 6 7 8 9 10 11
| fclose(plot_file); destroy_queue(); destroy_extras(); ck_free(target_path); ck_free(sync_id);
alloc_report();
OKF("We're done here. Have a nice day!\n");
exit(0);
|
参考链接:
https://www.jianshu.com/p/487f5e451325
https://blog.csdn.net/wxh0000mm/article/details/108828040
https://bbs.pediy.com/thread-218671.htm