程序表示方法

常用的 5 种程序表示方法

在我们对程序进行推理分析之前,我们必须要有分析的基础 ------ 程序表示模型。

比较复杂的模型有:

  • 已编译的二进制代码

    • 难以将数据和代码分开
    • 通常应用于逆向工程或者安全分析任务
  • 源代码

    • 代码量非常大,不同语言差别很大
    • 代码之间的关系难以提取
    • 通常和注释结合分析

一个好的程序表示模型应该可以明确地分析出代码之间的关系,主要相关程序图表示模型有以下五种,下面将分别介绍:

抽象语法树 (Abstract Syntax Trees,AST)

定义:抽象语法树可以将程序源码转化为规范的树形结构。其中的叶子节点代表变量,数值和操作数,中间节点代表操作符,语句等。如下图对源码的转换:

应用:使用抽象语法树可以进行语法分析和转化,主要的应用场景有:

  • Simple bug pattern(简单 bug 模式???)
  • Style checking(类型检查)
  • Refatoring(重构)
  • Training prediction/completion models(训练预测和编译模型)

缺陷:即使是一样的程序,生成的抽象语法树可能不同。

控制流图(Control Flow Graphs,CFGs)

定义:程序控制流图可以表示程序执行时可能经过的路径。其中方框代表代码块,箭头表示可能的执行路径。如下图:

缺陷:程序语言的特定功能通常被抽象化,不利于整个程序的分析

程序依赖图(Program Dependence Graphs,PDG)

定义:程序依赖图描述了代码之间是如何相互影响的。Y$\rightarrow$X 表示 Y 影响了 X,或者 X 受到了 Y 的影响。

分类:两种主要的依赖关系

  • 数据依赖
  • 控制依赖(通过决策影响)

数据依赖:

控制依赖:

每个经过 Y 的节点都要经过 X 节点,X 的作用类似于 "看门狗"

应用:

  • 调试:什么地方有可能产生 bug?
  • 安全:有没有敏感信息泄露?
  • 测试:如何做到全覆盖测试?

程序调用图(Call Graphs)

定义:程序调用图描述了程序的组成。其中节点代表函数,箭头代表该函数可能调用的路径。如下图:

主要问题:如何处理函数指针?如何描述函数回调?

指向图(Points-to Graphs)

定义:通过变量的指向来分析程序。

主要存在的两个问题:

程序运行时表示方法

Trace 技术

以上提到的 5 种程序表示方法都是基于静态的表示,即不执行代码分析出来的结果。若对程序进行动态表示则需要动态分析技术。常用的技术有 trace 技术。

(上图左下角第二行和第三行不是很理解???)

动态分析缺陷:整个代码分析起来非常复杂,全部分析也不是很有必要。

总之,有了以上静态或者动态的模型,可以将程序进行转化并对将其应用在真实的代码中。

下小节将对程序中某些感兴趣的部分进行分析,即程序切片技术,而不是分析整个庞大的程序。

>> 回到课程主目录