从程序集文件创建控制流图

时间:2016-02-20 20:57:32

标签: parsing assembly control-flow-graph

我想使用C语言从汇编文件创建控制流图(CFG)。我一直在考虑它,这些是我的想法: 1.创建块 - 逐行处理装配文件 - 找到重要的说明,如功能名称,块名称,跳转说明,呼叫说明或离开/返回以及其他一些 - 可能使用正则表达式找到它们?但我还没有在Windows上找到C的正则表达式实现。 - 在符合上述说明之后,在匹配某些结构之前保存指令,这是我的阻止 2.创建CFG - 块中的somhow创建了CFG,但我不知道

有谁能给我一些建议怎么做?如果有更好的语言可以做到这一点,如果你告诉我,我会恭喜你 谢谢你的时间和帮助。

3 个答案:

答案 0 :(得分:2)

OP需要的是一种训练有素的方法来完成这项任务。

他需要一个很好的汇编源代码解析器,所以他知道他有一个准确的表示。除了纯粹的解析部分,他还会有 非常完整地模拟汇编程序,包括所有复杂情况,例如宏,条件块,多个位置计数器,绝对/相对/外部符号等。(仅依靠正则表达式构建一个好的解析器是行不通的。)

然后,他需要通过检查机器指令和分支的序列来计算控制流图的第一估计。 这可能比它看起来更难做;在大而复杂的汇编代码中,人们将入口点滥用到程序中,因此有时很难分辨出什么是指令,什么是数据。

(这是我在大型x86应用程序中使用的一个技巧。我想在很多地方为我的代码添加健全性检查。完整性测试看起来像这样:

  <test for some sane condition>
  jf  location+3       ; this branchs to a breakpoint in the middle of the next instruction
  cmp  al, 0xCC        ; the immediate value is a BREAKPOINT opcode

它们是紧凑的,当发生一些不良事件时会发生断点。但是当分析该程序的控制流时,“jmp false”有时会分支到一条指令的 middle 。 OP模型怎么样?)

下一个复杂因素是指向代码的指针。汇编程序代码经常生成许多指向其他指令的指针,然后在不同的地方隐藏这些指针(调用指令将它们推送到x86的数据堆栈上),检索它们,然后执行“jmp indirect”。如果您想知道jmp可能在哪里,您需要跟踪内存位置可能包含的可能值,这意味着您需要进行数据流分析(值如何到达那里,从哪里开始)并与调用图结合构造(不能达到那个功能?好吧,然后去哪里不会影响这段代码)来计算合理的答案。

通过临时方法完成所有这些操作最终会产生不准确(无用)的答案。 OP需要找到一个框架来构建他的解析器,并且如果他希望得到一个好的结果,就可以实现高质量的点到分析算法。

C并非专门用于支持此任务。它可以带来足够的额外汗水,但对于任何编程语言都是如此。

(检查我的生物是否有这样的框架.OP可以使用任何适用于他的框架。)

答案 1 :(得分:1)

更简单的方法是组装程序集文件,然后反汇编它。大多数解析问题都被消除了。反汇编将为标签,操作码和操作数提供固定列,因此只需要很少的解析。

使用反汇编,执行两次传递。第一步是创建一个数据结构来表示每个指令来收集所有跳转目标。

第二遍是创建表示basic blocks的结构(一个带有单个入口点和出口的代码块)。将每个基本块链接到其后继块。基本块可以有零个,一个或两个后继(或者在跳转表的情况下为N个后继)。以RET结尾的基本块具有零后继。以无条件跳转结束的基本块有一个后继块。具有条件跳转的基本块有两个后继 - 跳过或跳跃的目标。没有前任的基本块是子程序入口点或死(或无效)代码。

跳转目标是基本块的开始,是无条件跳转后的指令(应该是跳转目标或子程序入口点)。

缺少运行程序(通过真实硬件或仿真器),确定间接跳跃的目标是不可行的。我建议支持几个简单的情况:1)跳转表,其中表在程序内2)跳过用于链接到另一个可执行文件的全局内存位置(并且反汇编器列出目标是什么)。在第一种情况下,基本块可以具有任意多个后继块。在第二种情况下,基本块只有一个后继者。

请注意,我故意将CALL作为CFG的一部分。当我实施一个CFG grapher时,就是我所做的。我的画家一次只显示一个功能。如果双击CALL,则显示子程序的CFG。

但是,如果要将整个子例程树包含在单个CFG中,则CALL将是基本块的结尾,而CALL之后的指令将是基本块的开头。请注意,除了最简单的程序之外,很难查看程序的整个CFG。

我遗漏了INT和IRET,因为我假设您正在处理用户模式应用程序。如果没有,那么像调用RET一样处理调用和IRET之类的INT。可以从启用中断的任何地方调用硬件中断服务程序(ISR),因此不会(通常)对ISR进行任何直接调用 - 它只会坐在一边。更一般地说,如果您正在处理内核模式软件,您将有其他各种考虑因素。

答案 2 :(得分:0)

我遇到了和你一样的问题,没有找到任何现成的解决方案,所以我用 Python 自己写了一个简单的:https://github.com/Kazhuu/asm2cfg

请注意,我仅使用 GDB 的函数反汇编转储对其进行了测试。我认为这可以扩展到与 objdump 一起使用。