一种内存变量分布动态发现方法

文档序号:9375219阅读:189来源:国知局
一种内存变量分布动态发现方法
【技术领域】
[0001] 本发明主要涉及一种软件(可执行文件)变量分析方法,更确切地是涉及软件分 析中在缺乏源代码情况下动态推测内存变量分布的方法。
【背景技术】
[0002] 内存变量分析,是软件分析,尤其是漏洞分析、恶意分析中重要的组成部分。在源 代码存在的情况下,可以直接分析源代码中的变量,从而获得内存变量分布。但对于缺乏源 代码的二进制可执行文件,对其内存变量分布的获得显得极为困难。
[0003] 数据结构反向工程与内存分布发现类似。DIVINE通过使用值集分析和指针分析 算法来恢复变量实体,可以识别栈中88%的变量和堆中89%的变量。但我们的方法更轻量 级。IDA Pro使用一个朴素的算法来推导内存分布,但是对于全局变量和栈只能针对有限 的模式(如" [esp+offset] "或" [ebp. offset] ")。并没有考虑本地变量在堆中通过指针、 结构等进行访问。Laika在图像中识别潜在的指针来估计对象位置和大小,然后通过块类 型类似的序列来检测对象。Reward在一个已知的函数(如系统调用)被调用时首先识别 参数的类型,然后,在程序动态执行过程中传递类型信息。但是,它依靠类型来获得初始类 型。如果数据结构没有在一个众所周知的函数中直接或间接显示,这些数据类型就不会被 识别。实际上,内部的变量和数据结构在程序中占有很大比例。Howard从二进制代码中动 态提取数据结构。与Howard相比,我们的方法是一个轻量级方法,无需对所有指令进行分 析。这样,我们的方法不仅提高了效率,而且降低了处理过程中的误报率。
[0004] 不变量的产生可以分析程序流程中不改变值的变量,一定程度上与本专利申请相 关。Daikon从程序执行过程中检测不变量,通过插入源程序来跟踪感兴趣的变量,然后运行 插入的程序并输入一些测试集,并推导插入变量和推导出的变量,这些变量在源程序中都 没有出现。这个方法被用在多个安全领域中,如逻辑漏洞检测、行为模型产生等。但是这些 方法有一些不足:1)它们使用随机输入来产生程序路径,因此覆盖率不高。2)它们需要手 动指出要分析的变量。3)它们从路径中分析变量,而我们的方法通过分析二进制内存操作 发现可能的内存分布。WIT将内存操作集的指令看作不变量和插入代码来阻止修改不在集 合中的对象。我们使用该方法作为标记指令。
[0005] 上述方法存在自动化程度不高、分析方法复杂的问题,本发明主要对指令执行过 程分析,提出一种内存变量分布动态发现方法,解决在缺乏源代码情况下,实现与某指令相 关的动态推测内存。

【发明内容】

[0006] 针对上述问题,本发明的目的在于能够在不需要源码的情况下,通过对目标软件 动态分析,从而发现与某程序语句相关的内存变量分布发现方法。由于内存变量结构随着 程序的运行可能随时发生变化,因此在动态分析过程中需要确定某条程序语句,并观察程 序执行到该语句时刻内存变量分布情况。具体分析过程如下:首先,选择程序中需要分析的 目标语句。例如该语句是漏洞可能存在的语句,或者是恶意代码所需要的敏感操作。其次, 生成能够使得程序到达该目标语句的输入。由于程序运行过程与外界输入密切相关,不同 的输入可能使得程序执行不同的路径。为了能够使得程序到达目标指令,需要构建特定的 输入。第三,当程序以构建的特定输入执行,对程序中被执行的目标语句进行分析,获得内 存变量结构。具体实现流程如下:
[0007] 1)根据目标语句选取内存:由于内存变量分布随着程序运行随时变化,因此我们 仅关心某个时刻程序的内存变量分布情况,如某条程序语句运行时刻等。这在软件安全漏 洞检测、恶意代码检测中具有重要应用价值。例如我们检测缓冲区溢出漏洞时,可以关注在 潜在错误指令发生的检测点位置操作的相关内存变量分布情况。
[0008] 2)生成到目标语句的路径:当我们得到候选的目标语句位置(即检测点位置),我 们产生一个路径到达这个位置,然后分析程序执行到这个位置时刻的内存变量分布情况。 首先,产生一个从起始指令语句位置到目标语句位置的静态路径,然后沿着这个静态路径 动态地运行程序,并记录所有依靠这个输入相关的约束条件。通过解决这些约束,我们可以 获得合适的输入,使得程序运行到目标位置。
[0009] 3)内存变量分布推导:当步骤2)得到的输入进入程序,我们观测在程序中指令是 如何在内存上操作的,然后产生目标指令相关的内存变量分布信息。例如,若目标是识别缓 冲区溢出漏洞,我们就需要首先识别缓冲区边界,即缓冲区及其邻居。我们使用两步方法 来推断内存变量分布。首先,识别在检测点被写的内存块m。通过这种方式,我们不需要分 析每条指令,仅需找到操作内存块m的指令。接着,我们这些指令中推导可能的内存变量分 布,忽略没有在m上操作的指令。
[0010] 与现有技术相比,本发明的积极效果为:
[0011] 本发明自动化程度高,能够同时分析堆和栈中的内存变量,属于一种轻量级方法, 无需对所有指令进行分析,能够在缺乏源代码情况下,实现与某指令相关的动态推测内存。
【附图说明】
[0012] 图1为基本框架图;
[0013] 图2为举例1中代码的内存分布情况;
[0014] 图3为举例1中可能的内存分布。
【具体实施方式】
[0015] 首先我们分析一个例子,说明内存变量分布识别。
[0016] 举例1 :我们有如下二进制代码,我们对其进行分析。
[0017]
[0018] 通过分析可知,由于sizein大于0x100程序将退出,但是当sizein等于0x100时, 循环中b[0x100 ]将获得用户输入。图2为举例1中相应代码在Microsoft Visual Studio 2005运行时内存中分布情况,而b实际的空间是从b[0]到b [0x99],此时,缓冲区溢出,如 果相邻内存是重要字段,比如size,然后后面举例1中13行,根据这个size再次申请内存, 就可以分配任意大小的缓冲区,恶意用户可以植入代码,给用户带来很大安全威胁。
[0019] 因此,如图1所示一种动态发现内存分布进行漏洞检测的方法主要包括三部分: 内存选取、路径产生和内存变量分布推导。本发明的方法可以在缺乏源代码的情况下,选取 所关注的错误指令发生的检测点位置操作相关内存,然后产生一个可以达到这个位置的路 径输入,最后找到一个输入到达该检测点,获得相关内存变量分布情况。具体过程如下:
[0020] 1)内存选取。我们需要从整个内存块中选取合适的部分。不同类型的漏洞可能 有不同的指令特征。在二进制代码中错误指令的位置被称为检测位置(check position)。 因此,我们关注在check positions处的内存操作。例如check position可以随意选取一 条可能引发漏洞的指令,例如循环内部的赋值指令。
[0021]
[0022] 2)路牷严生。为/严生一个从程序起始指令(写作Is)到目标指令(写作Ie)的 路径,我们首先产生一个从Is到Ie的静态路径。然后沿着静态路径动态运行程序,并记录 依据输入数据的所有约束条件。通过解决这些约束,我们可以获得合适的输入数据,直接让 程序运行到Ie。一个程序调用路径P由多个不同子程序Pi构成,我们产生一个程序调用路 径P,它从起始指令所在的子程序Ps到目标指令所在的子程序Pe。假设Is在程序Ps中, Ie在程序Pe中。我们考虑使用两步方法来产生静态路径:A)产生从Ps到Pe的程序调用 路径P ;B)对于P中每两个临近的节点Pi和Pj产生分支路径Bij。如果Is和Ie是在相 同程序中(如Ps = Pe),我们可以省略步骤A,仅使用步骤B来产生分支路径。
[0023] A)程序调用路径产生
[0024] 假设有两个子程序Ps和Pe (Ps辛Pe)。我们的目标是在Ps和Pe中产生程序调用 路径P。我们首先通过分析目标程序中的指令调用产生一个直接调用图Gc。具体生成方法 如下:将包括程序入口的子程序作为第一个节点,若该子程序包括调用指令(call指令), 将被调用的子程序作为节点,添加从第一个节点到该节点的边;之后以此类推,对这两个子 程序继续分析,直至产生这个程序的整个调用图为止。注意循环调用会使得Gc循环。我们 排除那些Gc中向后的边。然后我们可以从Ps到Pe直接通过调用图可达性分析即:扫描图 中所有节点和边,找到可以联通Ps和Pe的路径,产生一个程序调用路径P。非直接调用使 得结果不完整。非直接调用的目的主要由硬件和软件环境决定,程序语言的特征,如虚拟函 数和输入数据。动态分析通过使用种子输入来获得大部分简介调用的目的地址,包括前两 种类型和第三种类型的一部分目的地址。我们使用种子输入来分析程序中的间接调用目的 地址。虽然这是不完全的,但是我们可以使用更多的输入数据来优化结果。
[0025] B)分支路径产生
[0026] 假设Ii和Ij是相同子程序中的两个指令。为了找到一个分支路径B从Ii到I j, 我们应该首先发现一个指令路径I从Ii到Ij。我们依据Ii和Ij所在子程序产生一个控 制流图Gf,排除图中循环的向后的路径。控制流图Gf中每个节点是一条指令,每条边是指 令之间的流向关系。例如若指令a后跟着b,则有一条从a到b的边;如果a指令是跳转指 令,并跳向c,则有一条从a到c的边。我们还是用直接图可达性分析来获取I。注意间接 跳转会使得结果不完整,有点类似间接调用。我们使用上述方法来解决这个问题。分支路 径B是指令路径I的子集。我们只保持I中的分支路径来产生B。实际上,并不是B中所有 分支节点都是必须的。我们去掉分支节点中两个均达到Ij的分支。通过这个方式,我们得 到Ii和Ij之间的分支路径B。
[0027] 3)内存变量分布推导。当一个输入进入程序,我们观测在程序中指令是如何在内 存上操作的,然后产生指令相关的内存变量分布信息。为了能够有效推导出内存变量分布 情况,我们首先定义了一些规则,这些规则主要用于识别不同的内存单元,然后依据这些规 贝1J,我们可以进行优化,使用两步方法推导获得相应的内存变量分布情况。
[0028] A)基本规则
[0029] 当一个输入进入程序,我们观察程序中指令在内存中的操作。然后我们从这些指 令产生相应的内存分布。
[0030] 表1显示了内存操作的规则。当一个新的内存块M被分配,我们指定一个属性CM 到其属性集(标记为ε (M))。CM是指基本属性,它的值等于M的内存地址。如果一个内存 块没有被分配,就没有该属性。内存分配操作包括堆分配
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1