使用程序计数器(指令指针)值中的模式检测循环

时间:2012-05-16 17:40:55

标签: algorithm parsing reverse-engineering

我有一个程序计数器在执行特定代码时所采用的值序列。使用这个,我想对生成这个可执行文件的原始代码进行一些静态分析(要清楚:原始代码不可用) - 特别是,有多少循环,以及它们是如何嵌套的。举个例子,

A: for()
B:     if () 
C:         ...
D:     else
E:         ...
F:     for () {
G:         ...
H:         ...
I:     }

在这种情况下,程序计数器序列可能是:A B C D F {G H I G H I G H I} A B D E F {G H I G H I} A B D E F {G H I G H I G H I G H I}

从上面的序列中,我怎样才能知道有两个循环,一个嵌套在另一个循环中?只是指向要使用的适当解析技术也会有所帮助。

可以进行一些简化假设,例如原始代码中没有goto,也没有编译器优化的循环展开。

1 个答案:

答案 0 :(得分:2)

  1. 从程序计数器序列中生成一个图形,其中每个程序计数器是一个顶点,序列中的每对连续程序计数器都是一个有向边。 (如果从一个顶点到另一个顶点有多条边,则只保留其中一个)。
  2. 从序列中第一个程序计数器生成的顶点开始,执行深度优先搜索以查找循环。找到每个循环后,将此循环的最后一个边移动到单独的列表中。
  3. 找到所有循环并移出图表后,您将获得一个DAG(有向无环图)。在此DAG上执行拓扑排序,以恢复程序中正确的语句顺序,与源代码完全相同,除非if / else阻止(您无法从程序计数器序列中确定哪一个是'如果',哪个一个是'否则')。为了获得正确的结果,在拓扑排序没有规定任何特定顺序的情况下,应该使用深度优先搜索顺序。要正确放置while / for循环体,可以使用步骤2中的一些附加信息:循环检测算法可以标记每个循环的第二个节点。
  4. 要分析if / else块,请在图表中创建单独的拆分/合并列表。
  5. 将循环列表(在步骤2中提取)和if / else列表(在步骤4中提取)组合成单个间隔列表。使用这些区间的关系(哪一个嵌套在另一个区间内)为所有for / if / else语句构造树。
  6. 在某些情况下,'如果'阻止在'结束时循环while{...if{}}可能会被错误地检测到,如{loop {} ...},具有相同的起始地址'而'和'循环'。由于'起始地址为'不能与任何嵌套循环的起始地址重合,这可以很容易地后处理回while{...if{}}。 (嵌套' do-while'循环可能具有相同的起始地址,但它们对嵌套' if')没有任何问题。

  7. 这种方法只能在最简单的情况下工作,如果没有“转移”,“打破”,或任何其他跳出循环以及何时“跳出”。循环只检查一个条件。