在二进制代码中查找循环的“标准”方法是什么?

逆向工程 二元分析 二进制
2021-06-15 09:41:52

我正在处理一些 x86(32/64 位)ELF 二进制代码。这些二进制文件是从 C 和 C++ 程序代码编译的,我正在尝试检测二进制文件中的循环。

我是这个领域的新手,我想知道在二进制代码中识别循环的标准方法是什么?

我更喜欢使用一些静态方法来检测循环实例,因为我无法生成性能良好的动态测试用例。

4个回答

这个问题的经典编译器理论答案是构建一个控制流图,然后进行图分析以识别自然循环。我相信这方面的算法可以在Dragon Book 中找到,并且在这些幻灯片中给出了总结:

http://www.cs.cmu.edu/afs/cs/academic/class/15745-s03/public/lectures/L7_handouts.pdf

您还可以看到 LLVM 如何实现其循环检测:

http://llvm.org/docs/doxygen/html/LoopInfo_8h_source.html

您要查找更多信息的搜索词是“自然循环”和“后缘”等。

您可能会发现有关查找递归函数的这个问题很有帮助,对此有非常好的答案。在二进制代码级别,恕我直言,检测循环(即一些jmp到同一目标)和递归调用(即一些call到同一目标)只有很小的区别

我认为没有标准的方法,但一种方法可能是使用约翰逊算法之东西来检测函数有向图中的循环。

您可以在类似NetworkX simple_cycles 的库中找到它的实现

从二进制代码中检测循环并不容易。有许多基于多种图数据结构(CFG、SSA 形式、DDG 等)的算法。我提供了一组额外的有用文档link1link2link3您可以检查MAQAO对基于 SSA 的环路检测器的实现。另外,我建议您检查 DynInst 的代码和文档link4

现在,您可以实现一个汇编代码分析器,它可以通过跟随分支来检测基本块/循环。

  1. 反汇编你的二进制文件并按照说明进行操作。
  2. 如果遇到条件跳转(Jxx 模式),检查它是向上跳转还是向下跳转。
  3. 如果跳跃点在上面,检查距离(Delta(BRANCH_ADDRESS,BRANCH_TARGET_ADDRESS)),如果距离不是太大(你必须决定一个限制)那么你可以对分支条件进行一些分析(检查是否它包含一个移位的寄存器[递增/递减])。分支条件分析可以是一个简单的模式匹配:

       Example 1: 
                 TEST X,X
                 Jxx  X
    
       Example 2: 
                 CMP  X,X
                 Jxx  X
    
       Example 3: 
                 DEC X
                 Jnz X
    

如果一切顺利,您就会得到一个基本块,它很可能是一个循环。

  1. 如果跳转指向下方,则其成为循环控制结构一部分的可能性较小。因此,您可以忽略它并继续执行下一条指令。

如果您需要更多毛茸茸的细节,我很乐意提供更多;)