0x00 Questions
这篇文章意在解决“嵌套”的条件结构(注意这里的嵌套并不是狭义上控制结构嵌套),这是一个比较难处理的问题,在找到一个能触发新分支
这里通过一个代码片段,来特别地说明几种特殊的情况:
控制流依赖,L6依赖于L2,L3,L4。(这里的依赖对象是分支条件,下同) 数据流依赖,L6依赖于L2,L3。
如果我们想要进入L6的true分支,首先(1 L6 is reachable,(2 satisfies L6’s condition。
0x01 The ways
1.1 分支条件的控制流依赖
这个依赖可以看作是从CFG上剥离出来的东西,图上的点从基本块变成了分支条件,什么是分支条件?可以更具体一点,cmp/jmpz(nz) 等等的组合,为了把分支条件之间的关系,描述更加紧密,文中抽象了一个叫prior conditional statements 的概念,对一个指定的路径条件
这个定义在实现过程中还是比较抽象,需要具体的研究一下它的性质,首先考虑它并不是一个等价关系(不满足对称性),那么它是一个偏序吗?自反性很显然,传递性也很显然,反对称性呢?考虑两个不相同的路径条件是否相互为prior conditional statement ,这个不要去想的太复杂,在这篇文章描述的依赖关系下,是不可能做到,因为执行流,两个statements,肯定有一个是先执行的。
抛开反对称性不说,重点关注它的传递性,这里prior conditional statement 关系我用
通常来说dominator tree只定义在过程内,文中又进一步改进,引入了过程间的prior conditional statement 关系,这个也很好理解,如果一个路径条件
我以为文中技术实现是完全建立在静态分析上,但是直到读到这里,trace和stack的出现,告诉我极有可能是在动态过程中做的,而且文中给的找immediate prior conditional statement的算法是可以在动态做的。
Intraprocedural immediate prior conditional statement:(
和 s在同一个函数内 不是 的 post-dominator (post-dominator :如果 到exit -point的所有路径都经过 )
Interprocedural immediate prior conditional statement(
和 不在同一个函数内 - 当
执行的时候, 的返回地址在当前的栈中。 是 执行过的最后一个调用, 不是 的post-dominators
文中还提到的路径分支包含terminator的情况,其实这种属于上面第一种情况了,因为第二个条件已经限定了。但是作者在这里还是特别的拿出来说了一下,我还是在这个放个小例子:
1 | if(x==1){ |
1.2 分支条件的数据流依赖
用
这种情况下只考虑了分支条件的控制流依赖,并没有考虑路径条件之前的数据流依赖,这里文中又定义了第二种关系effective prior conditional statements ,我们需要稍微去改变一下上面我们的直觉,先忽略考虑reachable,我们需要改变
1.3 求解约束
前面已经提到求解约束的一个策略,在这里需要综合考量reachable 和 satisfy constraints ,文中在这里提出了三种可选的策略,顺序执行:
- Prioritize reachability
- Prioritize satisfiability
- Joint optimization for both reachability and satisfiability
1.3.1 Prioritize satisfiability
这个策略非常有意思,修改
bracktrace过程从
还是用F2中的例子来说明问题:假设当前的输入为
1.3.3 Joint optimization for both reachability and satisfiability
总结一下,Prioritize reachability旨在修改那些不会影响EPrior(s)的input bytes,保证
表示 中每一个路径条件的黑盒抽象函数,同样使用和Angora一样的转换表:
其中
相当于一个max函数, 二元运算符表示取最大的那个操作数,并用 表示 的抽象运算。观察这里转换表比Angora多了一个 ,用于区别路径条件类型的最小正数。当 的时候,必然有 , 在这里把 作为预期最优解。(我觉得应该是 ,如何保证每个 这个事实?)。需要注意的是它这里要比Angora做的更好,因为Angora在计算偏导数的时候,并不能保证 是reachable,这样得到的结果没有意义,Angora面对这个问题,只是简单提到了通过改变单位分向量的值。这里Matryoshka可以强制保证previous分支选择,来保证计算过程。 同样这样也用F2中的例子来说明问题,让
为初始 : 通过梯度下降,最终会得到一个solution 为
1.4 隐式条件路径
直接用例子来说明问题:
L6计算显式的
作者并不想按照通常的手法来操作,而是通过相关的策略把隐式污点过程筛出来:假设当前的
如果存在一个
所有在r之前的条件路径
所有显式的effective prior conditional statements
所有已知的隐式的effective prior conditional statements
如果结果s是unreachable则
1 | y=0; |
假设original input对L13是reachable,但是mutated input是unreachable.两次的路径序列:
- L4:true;L8:true;L12:true
- L4:false;L8:false;L12:false
逆序比较:
L12不属于
,按照验证算法,这里是L13是unreachable的,所以L12属于隐式的effective prior conditional statement L8不属于
,按照验证算法,这里L13还是reachable的,所以L8不属于隐式的effective prior conditional statement L3不属于
,按照验证算法,这里是L13是reachable的,所以L3不属于隐式的effective prior conditional statement
奇怪得到的结果却是L3不属于隐式的effective prior conditional statement,原文中的逆序比较似乎不合理?这个演算结果我没有想到。
0x01 Self Conclusion
在看Angora我就有一个疑问,关于梯度下降算法,因为无法保证目标路径分支是reachable的,所以计算梯度得到的结果是毫无意义的,在这篇文章里面给了我想要的答案,作者似乎修补了这个很重要的问题,用force的方法,保证两次走过的路径条件一样。疑问又来了,这样做的理论依据在哪呢?