05月01, 2018

基于图形比较二进制可执行文件的思路

  1. 对可执行文件进行逐字比较将无法产生可用输出,即使对最微不足道的变化也是如此。基于反汇编的基本方法比较指令不会返回有用的结果,因为编译器在指令顺序和分配寄存器方面的自由度很大。这意味着不同编译器版本或者不同的优化设置,会导致关于使用的指令和寄存器的很大改变。
  2. 为解决这个问题,bindiff使用基于图形的方法,所使用的算法不依赖基本块的实际内容basic blocks [a group of instructions without branches],一组没有分支的指令,而是使用算法分析可执行文件的两种不同图形结构,调用图形,通过将函数调用编码为边儿描述函数之间的关系,而函数本身被描述为节点,描述程序流程的控制流程图在一个函数内部进行描述。 观察两张图足以描述可执行文件中的大多数函数,如果比较可执行文件中的两个函数的边和来自调用图中相同的节点并且具有相似或相同的CFG,实际上是相同函数的几率非常高。
  3. 与基于指令的方法相比,“结构差异”具有许多优点,虽然编译器优化和标志通常会更改所有的指令和寄存器,但它们通常不会修改调用图或CFG (Note: Function inlining and loop unrolling are two popular counter examples that need to be addressed). 函数内联和循环展开是两个需要解决的反例,需要通过其他方法解决。

  4. 某个程序即使使用完全不同的编译器进行编译,针对不同操作系统甚至另一种体系结构,也会具有相似的CG和CFG

一个很好的例子是,针对基于ARM的ios 内核与基于X64 OS X内核相区别,以便将公开可用的符号转换为难以逆转的iphone os

  1. 为了比较call graph,需要先识别许多相应的节点,另外,对于简单的函数,没有或者只有简单控制流结构不能被识别使用 their trivial CFGs. 这个问题使用一组附加的函数属性来减少或解决。 这些属性包括:二进制函数内容,循环计数,字符串引用 these attributes include checks like a hash of the binary function content, loop count or string references 这些结果不是100%可靠的,可能会导致误报或者漏报,但是在大量实验之后,我们发现在现实中这个方法是令人惊讶的出色。

  2. MS11-083 was a very interesting vulnerability affecting the TCP/IP stack of all Windows operating systems since Vista. 例如这个 补丁Patch-Diffing: MS11-083

  3. 在比较两个版本之前,需要先试用IDA分析它们以创建IDB文件,再用BinDiff加载这两个文件,可以看到几乎所有的函数都是匹配的,大部分函数并没有显示任何修改,即便是编译器的版本可能改变了,也还好。 有一个技巧是,寻找 显示 包含 最多修改的函数,看BinDiff中相似性值,具有最低相似值的函数。 In the case of MS11-083 the function with the lowest similarity value is “IppRateLimitIcmp()”.

  4. 对比新旧CFG发现,插入了两个新的基本块,它们只调用IppDereferenceNeighbor()或IppDereferenceLocalAddress() alt
  5. Added function call alt
  6. 其他同类工具 DarunGrim and PatchDiff2 are both specialized on Patch Diffing

本文链接:https://harry.ren/post/binary-difference.html

-- EOF --

Comments