Bindiff原理
处理可执行文件的抽象结果,忽略具体的汇编级别的指令。
可以分为两个阶段,生成初始匹配和Drill Down
初始匹配
根据每个函数的的flow图生成一个签名,包括代码块数目,代码块之间的边数,子函数的调用数目。
对两个可执行文件生成了两组签名,就会创建初始匹配。通过选择每个可执行文件中具有共同特征的所有函数的子集来实现的。如果一个签名发生且仅发生一次在两个检查的签名子集中,则创建匹配。
调用图用于生成更多的匹配:如果匹配已知,则检查从匹配函数调用的所有函数的子集。这些子集明显小于所有函数的集合,因此找到唯一匹配的概率要高得多。重复这个过程直到无法找到匹配项。
运行bindiff以后,将拥有一个成功关联的函数列表,及两个无法关联的函数列表
General Matching Strategy
bindiff有一个合适的用于生成匹配的函数属性列表。从全局级别开始,考虑二进制中的所有函数,并为每个函数计算第一个属性。有几种可能的结果
- 该属性在所有二进制中都是唯一的,则认为二进制文件中该函数匹配
- 该属性在二进制文件中多次出现,匹配不明确。bindiff只考虑相同属性的函数,并进行Drill Down。Drill Down意味着尝试下一个最佳属性,直到算法结束/匹配到函数(1中的情况)/集合解散(有属性无法匹配到任何函数,就是3中的情况)
- 该属性在另一个二进制文件中没有该匹配项,则保留在未匹配集合中
在初始全局匹配结束后,考虑每个新匹配的调用者及调用。尝试对每个函数执行向下匹配,来匹配调用者和调用集合中的函数。
最后,对所有新匹配的函数进行基本块匹配(已经配对的函数进行基本块分析,更细粒度的匹配),并匹配从匹配的基本块调用的函数(调用引用匹配)。
然后才是结束单个属性的全局匹配,对剩下的不匹配的函数,应用下一个最佳属性。
函数匹配
这部分其实就是函数属性优先级列表,可以参考文档原文
基本块匹配
这部分没看
置信度和相似度
置信度:平均算法置信度(匹配质量),用于查找有sigmoid函数加权的特定匹配项
不是简单的进行平均,因为在完美匹配的函数/二进制中很少有单个弱匹配,不应当过多的降低置信度。类似,少数的强匹配也无法拯救大部分弱匹配。
函数相似度加权和:
- 25%,匹配的flow图中的边占总边数
- 15%,匹配的基本块占基本块总数
- 10%,匹配的指令数占总指令数目
- 50%,difference in flow graph MD index
得到的相似度再乘以置信度。
整个二进制的相似度:
- 35%,匹配的flow图中的边占总边数
- 25%,匹配的基本块占基本块总数
- 10%,匹配的函数占总函数的比例
- 10%,匹配的指令占总指令数目
- 20%,difference in call graph MD index
乘以置信度,只考虑非库函数。
MD index:基于函数的拓扑顺序,入度和出度的CFG哈希函数。参考 MD-Index paper