diff --git "a/2024/AFLplusplus\346\272\220\347\240\201\345\210\206\346\236\220\342\200\224\342\200\224\350\246\206\347\233\226\347\216\207/index.html" "b/2024/AFLplusplus\346\272\220\347\240\201\345\210\206\346\236\220\342\200\224\342\200\224\350\246\206\347\233\226\347\216\207/index.html" index 4e589bb..ef330af 100644 --- "a/2024/AFLplusplus\346\272\220\347\240\201\345\210\206\346\236\220\342\200\224\342\200\224\350\246\206\347\233\226\347\216\207/index.html" +++ "b/2024/AFLplusplus\346\272\220\347\240\201\345\210\206\346\236\220\342\200\224\342\200\224\350\246\206\347\233\226\347\216\207/index.html" @@ -14,7 +14,7 @@ - + @@ -23,7 +23,7 @@ - + @@ -309,11 +309,16 @@

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
26
27
28
29
30
31
32
33
/* Updates the virgin bits, then reflects whether a new count or a new tuple is
* seen in ret. */
inline void discover_word(u8 *ret, u64 *current, u64 *virgin) {

/* Optimize for (*current & *virgin) == 0 - i.e., no bits in current bitmap
that have not been already cleared from the virgin map - since this will
almost always be the case. */

if (*current & *virgin) {

if (likely(*ret < 2)) {

u8 *cur = (u8 *)current;
u8 *vir = (u8 *)virgin;

/* Looks like we have not found any new bytes yet; see if any non-zero
bytes in current[] are pristine in virgin[]. */

if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) ||
(cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff) ||
(cur[4] && vir[4] == 0xff) || (cur[5] && vir[5] == 0xff) ||
(cur[6] && vir[6] == 0xff) || (cur[7] && vir[7] == 0xff))
*ret = 2;
else
*ret = 1;

}

*virgin &= ~*current;

}

}

首先,计算 *current & *virgin,即将current 指向的 8 个 bits 与 virgin 指向的 8 个 bits 进行按位与运算。

前面说到 bit=1currentvirgin 中的含义是相反的,那么 currentvirgin按位与的结果为 1,说明至少有一个桶,virgin是没到过的,而 current 到了。

-

接着,判断 likely(*ret < 2)*ret < 2 是一个很可能出现的情况,current找到一个新的 edge,才会将设置*ret=2

+

接着,判断 likely(*ret < 2),在 AFL++ 看来*ret < 2 是一个很可能出现的情况,current找到一个新的 edge,才会将设置*ret=2

判断 current 是否找到一个新的 edge,是通过依次比较 (cur[k] && vir[k] == 0xff), k=0...7 来实现的。vir[k]==0xff表示所有桶的 bit 位为 1,即这个 edge 从来没到过。而 cur[k]==1 表示当前 corpus 到了这个 edge,从而认为 corpus 找到了新 edge。

此处有个疑问:k 从 0 到 7 要怎么理解?从代码来看,current 和 virgin 的每个元素用 64 个 bit 来存储,分 8 次读取,某一次读取的 8 个 bit 是全为 1 就可以。那为什么不直接用 8 个 bit 来存储?

4. describe_op

在 AFL++ 获得一个 interesting 的 corpus 之后,会将其保存为文件。在保存之前,通过 describe_op 函数来生成文件名,在文件名中记录一些关键信息:

1
2
3
4
5
6
7
id: 记录 corpus 的 id 编号
sync: 从哪个目录同步过来
src: 从哪个 corpus 演化而来,记录来源 corpus 的 id
time: AFL++ 的运行时间
execs: AFL++ 的运行次数
+cov: 当前 corpus 找到了新 edge,即 has_new_bits 返回 2
+tout: 当前 corpus 运行超时
+ +

三、参考资料

    +
  1. AFL 源码阅读(六):队列、变异、同步
  2. +
  3. AFL++ 白皮书和源码阅读
  4. +