前言
winafl
是 afl
在 windows
的移植版, winafl
使用 dynamorio
来统计代码覆盖率,并且使用共享内存的方式让 fuzzer
知道每个测试样本的覆盖率信息。本文主要介绍 winafl
不同于 afl
的部分,对于 afl 的变异策略等部分没有介绍,对于 afl
的分析可以看
https://paper.seebug.org/496/#arithmetic
源码分析
winafl
主要分为两个部分 afl-fuzz.c
和 winafl.c
, 前者是 fuzzer
的主程序 ,后面的是收集程序运行时信息的 dynamorio
插件的源码。
afl-fuzz
main
winafl
的入口时 afl-fuzz.c
, 其中的 main
函数的主要代码如下
int main(int argc, char** argv) {
// 加载变异数据修正模块
setup_post();
if (!in_bitmap) memset(virgin_bits, 255, MAP_SIZE); // MAP_SIZE --> 0x00010000
setup_shm(); // 设置共享内存
init_count_class16();
setup_dirs_fds(); // 设置模糊测试过程中的文件存放位置
read_testcases(); // 读取测试用例到队列
// 首先跑一遍所有的测试用例, 记录信息到样本队列
perform_dry_run(use_argv);
// 模糊测试主循环
while (1) {
u8 skipped_fuzz;
// 每次循环从样本队列里面取测试用例
cull_queue();
// 对测试用例进行测试
skipped_fuzz = fuzz_one(use_argv);
queue_cur = queue_cur->next;
current_entry++;
}
}
- 首先设置一些
fuzz
过程中需要的状态值,比如共享内存、输入输出位置。 - 然后通过
perform_dry_run
把提供的所有测试用例让目标程序跑一遍,同时统计执行过程中的覆盖率信息。 - 之后就开始进行模糊测试的循环,每次取样本出来,然后交给
fuzz_one
对该样本进行fuzz
.
post_handler
该函数里面最重要的就是 fuzz_one
函数, 该函数的作用是完成一个样本的模糊测试,这里面实现了 afl 中的模糊测试策略,使用这些测试策略生成一个样本后,使用采用 common_fuzz_stuff
函数来让目标程序执行测试用例。common_fuzz_stuff
的主要代码如下
static u8 common_fuzz_stuff(char** argv, u8* out_buf, u32 len) {
u8 fault;
// 如果提供了数据修正函数,则调用
if (post_handler) {
out_buf = post_handler(out_buf, &len);
if (!out_buf || !len) return 0;
}
write_to_testcase(out_buf, len);
// 让目标程序执行测试用例,并返回执行结果
fault = run_target(argv, exec_tmout);
函数首先会判断是否提供了 post_handler
, 如果提供了 post_handler
就会使用提供的 post_handler
对变异得到的测试数据进行处理, post_handler
函数指针在 setup_post
函数中设置。
static void setup_post(void) {
HMODULE dh;
u8* fn = getenv("AFL_POST_LIBRARY"); // 通过环境变量获取 post_handler 所在 dll 的路径
u32 tlen = 6;
if (!fn) return;
ACTF("Loading postprocessor from '%s'...", fn);
dh = LoadLibraryA(fn);
if (!dh) FATAL("%s", dlerror());
post_handler = (u8* (*)(u8*,u32*))GetProcAddress(dh, "afl_postprocess"); // 加载dll 获取函数地址
if (!post_handler) FATAL("Symbol 'afl_postprocess' not found.");
/* Do a quick test. It's better to segfault now than later =) */
post_handler("hello", &tlen);
OKF("Postprocessor installed successfully.");
}
该函数首先从 AFL_POST_LIBRARY
环境变量里面拿到 post_handler
所在 dll
的路径, 然后设置 post_handler
为 dll
里面的 afl_postprocess
函数的地址。该函数在 fuzzer
运行的开头会调用。 post_handler 的定义如下
static u8* (*post_handler)(u8* buf, u32* len);
参数: buf 输入内存地址, len 输入内存的长度
返回值