注意
本文最后更新于 2024-02-12,文中内容可能已过时。
环境变量
- 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++