Custom Mutators in AFL++

环境变量

  • AFL_CUSTOM_MUTATOR_LIBRARY:指向自定义变异的 so 库
  • AFL_CUSTOM_MUTATOR_ONLY 用于标记是否所有变异都是用自定义变异
  • AFL_DISABLE_TRIM 禁用 AFLPLUSPLUS 原生 TRIM(二分法搜索,对于高度结构化的输入没有意义)

API

1
void *afl_custom_init(afl_state_t *afl, unsigned int seed);

在 AFL++ 启动时调用,用于随机数生成和初始化缓冲区和状态

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
/*
data: 在 afl_custom_init 返回值(指针)
buf: 原始的输入数据
buf_size: 原始输入数据的大小
out_buf: 存放输出结果指针的指针
add_buf: 如果是需要两个样本结合变异,这是另一个样本
add_buf_size: 另一个样本的大小
max_size: 最大的变异大小
返回值: 返回自定义后的大小
*/
size_t afl_custom_fuzz(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, unsigned char *add_buf, size_t add_buf_size, size_t max_size);

自定义突变,例如自定义文件格式变异,修复文件校验和等,返回修改后的长度 > 0

1
2
3
4
5
6
7
8
/*
data: 在 afl_custom_init 返回值(指针)
buf: 正常情况下的变异内容
buf_size: 变异内容的大小
out_buf: 存放输出结果指针的指针
返回值: 返回自定义后的大小
*/
size_t afl_custom_post_process(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf);

在某些情况下,从自定义变异的数据格式不适合直接作为输入,例如内容要进行 base64 编码,这时候可以自定义该函数,在执行目标之前将数据转换为 API 预期的格式。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
data: 在 afl_custom_init 返回值(指针)
buf: 正常情况下的变异内容
buf_size: 变异内容的大小
返回值:猜测的迭代次数(如果不能够确定,则可以返回 0 或 1)
在每次修剪操作开始时调用,可以在这里接受并初始化缓冲区内容
*/
int afl_custom_init_trim(void *data, unsigned char *buf, size_t buf_size);

/*
data: 在 afl_custom_init 返回值(指针)
out_buf: 修剪后的内容指针
返回值:修剪后内容的大小
对缓冲区内容进行处理,把修改后的内容放置到 *out_buf
因为没有任何其他参数,所以应当在 afl_custom_init_trim 中记忆要修剪的数据
*/

size_t afl_custom_trim(void *data, unsigned char **out_buf);

/*
返回值:返回下一个将要修剪的迭代索引(0 -> afl_custom_init_trim 的返回值)
在每次修剪操作后调用,用于通知修剪是否成功,如果修剪失败则应将输入重置为最后一次已知的良好状态。
*/

int afl_custom_post_trim(void *data, unsigned char success);

样本随着变异可能会越来越大,为了确保文件最小,而且能够覆盖路径,则需要实现 trim 功能缩小样本。

1
2
3
4
/*
data: 在 afl_custom_init 返回值(指针)
*/
void afl_custom_deinit(void *data);

在结束时释放内存

TODO

1
2
3
4
5
6
7
unsigned int afl_custom_fuzz_count(void *data, const unsigned char *buf, size_t buf_size);
const char *afl_custom_describe(void *data, size_t max_description_len);
size_t afl_custom_havoc_mutation(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, size_t max_size);
unsigned char afl_custom_havoc_mutation_probability(void *data);
unsigned char afl_custom_queue_get(void *data, const unsigned char *filename);
u8 afl_custom_queue_new_entry(void *data, const unsigned char *filename_new_queue, const unsigned int *filename_orig_queue);
const char* afl_custom_introspection(my_mutator_t *data);

编译

1
gcc -shared -Wall -O3 example.c -o example.so

使用

1
2
export AFL_CUSTOM_MUTATOR_LIBRARY="/full/path/to/example_first.so;/full/path/to/example_second.so"
afl-fuzz /path/to/program

注意

避免内存泄漏

在过程中的所有内存申请都要及时清理,如果在本次函数调用中无法清理,可以在 afl_custom_init 时创建一块内存空间用于管理自主申请的空间,并且在 afl_custom_deinit 时把申请的空间都释放(也可以用 static 变量储存指针,并且用 realloc 来再分配)

来源

Custom Mutators in AFL++

0%