虚拟指令还原方法、装置、设备及存储介质转让专利

申请号 : CN202011110351.X

文献号 : CN112199160B

文献日 :

基本信息:

PDF:

法律信息:

相似专利:

发明人 : 乐德广

申请人 : 常熟理工学院

摘要 :

本发明实施例公开了一种虚拟指令还原方法、装置、设备及存储介质,其中,所述虚拟指令还原方法,包括:虚拟机动态指令追踪;局部变量表位置确定;处理函数识别;处理函数执行前后所有寄存器值确定;处理函数操作数栈所对应的寄存器确定;处理函数操作数栈所对应的寄存器确定;处理函数所对应的虚拟指令还原。针对恶意用户利用虚拟机保护技术来逃脱杀毒软件对其程序中恶意代码的检测,提出了一种基于动态指令追踪记录和字节码处理函数语义分析的虚拟机虚拟指令还原方法。

权利要求 :

1.一种虚拟指令还原方法,其特征在于,包括:虚拟机动态指令追踪;

局部变量表位置确定;

处理函数识别;包括:所述虚拟机采用了线索式解释执行,其通过设定的方式实现相邻处理函数的跳转;执行如下识别方法:轮询虚拟机动态指令追踪记录,如果匹配到两种处理函数的结束特征,则创建一个新的处理函数实例,之后把轮询的后续指令添加到该实例中,直至一个新的特征出现,则表示该实例的指令序列结束;以此类推,循环结束后,可以得到所有被执行的处理函数的实例集合;

处理函数执行前后所有寄存器值确定;

处理函数操作数栈所对应的寄存器确定;

处理函数对操作数栈和局部变量表的读指令标记;

处理函数所对应的虚拟指令还原;包括:得到每个处理函数对操作数栈栈顶的变化值,对操作数栈的读次数和对局部变量区的读次数这3个重要数据;根据这三个数据,推断该处理函数所对应的虚拟指令。

2.根据权利要求1所述的虚拟指令还原方法,其特征在于,所述虚拟机的内存读取轨迹的集合就是虚拟机指令的执行轨迹,记作VMTrace,该VMTrace记录包含了以下信息:完整执行的汇编指令;

被执行汇编指令的静态地址;

每条指令执行后被修改的寄存器及其被修改后的值。

3.根据权利要求1所述的虚拟指令还原方法,其特征在于,采用缓存延迟写入方法将执行期的每条指令的寄存器值和内存读写信息记录为VMTrace文件。

4.根据权利要求1所述的虚拟指令还原方法,其特征在于,所述处理函数执行前后所有寄存器值确定的方法,包括:根据识别的处理函数,确定每个处理函数执行前后寄存器的值。

5.根据权利要求1所述的虚拟指令还原方法,其特征在于,所述处理函数操作数栈所对应的寄存器确定的方法,包括:首先确认在进入虚拟机之前,操作数栈所对应的寄存器;然后跟踪分析操作数栈的变化情况进一步确定每个虚拟机操作数栈所对应的寄存器。

6.一种虚拟指令还原装置,其特征在于,包括:追踪模块,用于虚拟机动态指令追踪;

确定模块,用于局部变量表位置确定;

识别模块,用于处理函数识别;包括:所述虚拟机采用了线索式解释执行,其通过设定的方式实现相邻处理函数的跳转;执行如下识别方法:轮询虚拟机动态指令追踪记录,如果匹配到两种处理函数的结束特征,则创建一个新的处理函数实例,之后把轮询的后续指令添加到该实例中,直至一个新的特征出现,则表示该实例的指令序列结束;以此类推,循环结束后,可以得到所有被执行的处理函数的实例集合;

执行模块,用于处理函数执行前后所有寄存器值确定;

对应模块,用于处理函数操作数栈所对应的寄存器确定;

操作模块,用于处理函数对操作数栈和局部变量表的读指令标记;

还原模块,用于处理函数所对应的虚拟指令还原;包括:得到每个处理函数对操作数栈栈顶的变化值,对操作数栈的读次数和对局部变量区的读次数这3个重要数据;根据这三个数据,推断该处理函数所对应的虚拟指令。

7.一种虚拟指令还原设备,包括存储器、处理器及存储在存储器上并可在处理器上运行的计算机程序,其特征在于,所述处理器执行所述程序时实现权利要求1~5中任意一项所述虚拟指令还原方法。

8.一种计算机可读存储介质,其特征在于,存储有计算机可执行指令,所述计算机可执行指令用于执行权利要求1~5中任意一项所述虚拟指令还原方法。

说明书 :

虚拟指令还原方法、装置、设备及存储介质

技术领域

[0001] 本发明涉及虚拟指令技术领域,也涉及信息安全、软件保护和软件构造技术领域,特别涉及一种虚拟指令还原方法、装置、设备及存储介质,尤指一种虚拟机保护的虚拟指令
还原方法、装置、设备及存储介质。

背景技术

[0002] 虚拟机指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。而虚拟机软件就是能够为不同的操作系统提供虚拟机功能的软件。虚
拟机保护是一把双刃剑,它在保护用户软件防止被被恶意攻击而受到破解、篡改或盗版等
威胁的同时,许多恶意程序也利用虚拟机保护技术将恶意代码虚拟化变换,从而逃避杀毒
或木马检测等软件对其检测。因此,除了虚拟机保护的正向研究,还需针对许多恶意代码利
用虚拟机保护逃避检测等问题从对虚拟机的逆向分析的角度开展研究。
[0003] 已有的虚拟机逆向分析技术通过逆向虚拟机结构来化简虚拟指令,并将虚拟指令转换中间语言,然后将中间语言编译转换为对应的X86指令的方法来还原被保护的代码。这
种基于虚拟机结构的分析方法要求虚拟机解释器的结构满足一定条件,因此并不具有通用
性,此外,通过指令化简很难有效应对虚拟机中使用高强度加固代码。

发明内容

[0004] 本发明实施例提供了一种虚拟指令还原方法、装置、设备及存储介质,针对恶意用户利用虚拟机保护技术来逃脱杀毒软件对其程序中恶意代码的检测,提出了一种基于动态
指令追踪记录和字节码处理函数语义分析的虚拟机虚拟指令还原方法。
[0005] 本发明实施例提供了一种虚拟指令还原方法,包括:
[0006] 虚拟机动态指令追踪;
[0007] 局部变量表位置确定;
[0008] 处理函数识别;包括:所述虚拟机采用了线索式解释执行,其通过设定的方式实现相邻处理函数的跳转;执行如下识别方法:
[0009] 轮询虚拟机动态指令追踪记录,如果匹配到两种处理函数的结束特征,则创建一个新的处理函数实例,之后把轮询的后续指令添加到该实例中,直至一个新的特征出现,则
表示该实例的指令序列结束;以此类推,循环结束后,可以得到所有被执行的处理函数的实
例集合;
[0010] 处理函数执行前后所有寄存器值确定;
[0011] 处理函数操作数栈所对应的寄存器确定;
[0012] 处理函数对操作数栈和局部变量表的读指令标记;
[0013] 处理函数所对应的虚拟指令还原;包括:得到每个处理函数对操作数栈栈顶的变化值,对操作数栈的读次数和对局部变量区的读次数这3个重要数据;根据这三个数据,推
断该处理函数所对应的虚拟指令。
[0014] 进一步的,所述虚拟机的内存读取轨迹的集合就是虚拟机指令的执行轨迹,记作VMTrace,该VMTrace记录包含了以下信息:
[0015] 完整执行的汇编指令;
[0016] 被执行汇编指令的静态地址;
[0017] 每条指令执行后被修改的寄存器及其被修改后的值。
[0018] 进一步的,采用缓存延迟写入方法将执行期的每条指令的寄存器值和内存读写信息记录为VMTrace文件。
[0019] 进一步的,所述处理函数识别,包括:所述虚拟机采用了线索式解释执行,其通过设定的方式实现相邻处理函数的跳转;执行如下识别方法:
[0020] 轮询虚拟机动态指令追踪记录,如果匹配到两种处理函数的结束特征,则创建一个新的处理函数实例,之后把轮询的后续指令添加到该实例中,直至一个新的特征出现,则
表示该实例的指令序列结束。以此类推,循环结束后,可以得到所有被执行的处理函数的实
例集合。
[0021] 进一步的,所述处理函数执行前后所有寄存器值确定的方法,包括:根据识别的处理函数,确定每个处理函数执行前后寄存器的值。
[0022] 进一步的,所述处理函数操作数栈所对应的寄存器确定的方法,包括:首先确认在进入虚拟机之前,操作数栈所对应的寄存器。然后跟踪分析操作数栈的变化情况进一步确
定每个虚拟机操作数栈所对应的寄存器。
[0023] 进一步的,述处理函数所对应的虚拟指令还原的方法,包括:得到每个处理函数对操作数栈栈顶的变化值,对操作数栈的读次数和对局部变量区的读次数这3个重要数据;根
据这三个数据,推断该处理函数所对应的虚拟指令。
[0024] 本发明实施例还提供一种虚拟指令还原装置,包括:
[0025] 追踪模块,用于虚拟机动态指令追踪;
[0026] 确定模块,用于局部变量表位置确定;
[0027] 识别模块,用于处理函数识别;包括:所述虚拟机采用了线索式解释执行,其通过设定的方式实现相邻处理函数的跳转;执行如下识别方法:
[0028] 轮询虚拟机动态指令追踪记录,如果匹配到两种处理函数的结束特征,则创建一个新的处理函数实例,之后把轮询的后续指令添加到该实例中,直至一个新的特征出现,则
表示该实例的指令序列结束;以此类推,循环结束后,可以得到所有被执行的处理函数的实
例集合;
[0029] 执行模块,用于处理函数执行前后所有寄存器值确定;
[0030] 对应模块,用于处理函数操作数栈所对应的寄存器确定;
[0031] 操作模块,用于处理函数对操作数栈和局部变量表的读指令标记;
[0032] 还原模块,用于处理函数所对应的虚拟指令还原;包括:得到每个处理函数对操作数栈栈顶的变化值,对操作数栈的读次数和对局部变量区的读次数这3个重要数据;根据这
三个数据,推断该处理函数所对应的虚拟指令。
[0033] 本发明实施例还提供一种虚拟指令还原设备,包括存储器、处理器及存储在存储器上并可在处理器上运行的计算机程序,所述处理器执行所述程序时实现所述虚拟指令还
原方法。
[0034] 本发明实施例还提供一种计算机可读存储介质,存储有计算机可执行指令,所述计算机可执行指令用于执行所述虚拟指令还原方法。
[0035] 本发明实施例,其方法包括:虚拟机动态指令追踪;局部变量表位置确定;处理函数识别;处理函数执行前后所有寄存器值确定;处理函数操作数栈所对应的寄存器确定;处
理函数对操作数栈和局部变量表的读指令标记;处理函数所对应的虚拟指令还原。由此构
建的用于隐藏待保护指令的花指令除了可以迷惑反汇编器的递归扫描之外,通过结合计算
花指令和垃圾花指令还可以抵御反汇编器的线性扫描和攻击者的动态跟踪调试。
[0036] 本发明的其它特征和优点将在随后的说明书中阐述,并且,部分地从说明书中变得显而易见,或者通过实施本发明而了解。本发明的目的和其他优点可通过在说明书、权利
要求书以及附图中所特别指出的结构来实现和获得。

附图说明

[0037] 图1是本发明实施例的所述虚拟指令还原方法的整体流程图;
[0038] 图2是本发明实施例的所述vmtrace记录的该函数执行的所有汇编指令序列的示意图;
[0039] 图3是本发明实施例的所述虚拟指令还原装置的结构图。

具体实施方式

[0040] 下文中将结合附图对本发明的实施例进行详细说明。
[0041] 在附图的流程图示出的步骤可以在诸如一组计算机可执行指令的计算机系统中执行。并且,虽然在流程图中示出了逻辑顺序,但是在某些情况下,可以以不同于此处的顺
序执行所示出或描述的步骤。
[0042] 针对当前虚拟机保护软件分析方法对于还原虚拟指令方面存在的不足,本发明实施例提出一种基于动态数据流分析的虚拟机保护软件分析方法,利用动态调试将虚拟机解
释器动态执行过程中的数据流信息记录成VMTrace文件,并以这些文件作为分析基础,提取
虚拟机指令的执行轨迹,精确定位出虚拟机解释器,然后通过聚类分析识别虚拟机字节码
处理函数,接着基于虚拟机解释过程本身的特征采用改进的特征分析算法对虚拟机字节码
处理函数的执行指令的生成过程进行分层次、分阶段还原。最终由结合控制流和数据生成
过程对虚拟指令进行重构。
[0043] 也就是,本发明实施例通过分析出虚拟机的动态处理函数位置,分析这些处理函数上汇编指令的含义,从而确定虚拟指令的语义。虚拟机采用的是基于栈的虚拟机,其栈帧
包括局部变量表和操作数栈这两个部分,每条指令在解释执行时,根据字节码,会将操作数
在操作数栈中进行计算,并保存在局部变量区中。不同的虚拟操作指令对局部变量区的读
写次数和对操作数栈栈顶的改变都有各自的特征。通过对这些特征的分析,从而确定它们
对应的操作码语义。
[0044] 针对上述情况,如图1所示,本发明实施例提出一种虚拟指令还原方法,包括:
[0045] 步骤101,虚拟机动态指令追踪。
[0046] 其中,所述虚拟机动态指令追踪为:对于虚拟机的虚拟指令逆向分析,获取真实可靠的虚拟机动态执行信息是重要的基础环节。为此,本发明实施例通过指令动态追踪的方
法记录虚拟机执行轨迹。一个执行轨迹代表了一个程序在运行中的动态指令的有限序列
(I1; • • • ; In)。对此在一个实施例中,所述虚拟机的内存读取轨迹的集合就是虚拟机
指令的执行轨迹,记作VMTrace,本发明实施例开发vmtrace插件工具来搜集虚拟机保护程
序的执行轨迹。图2显示了使用vmtrace工具执行一个被虚拟机保护的函数时,vmtrace记录
了该函数执行的所有汇编指令序列。
[0047] 从图2中可以看出,该VMTrace记录主要包含了以下信息:
[0048] (1)完整执行的汇编指令;
[0049] (2)被执行汇编指令的静态地址;
[0050] (3)每条指令执行后被修改的寄存器及其被修改后的值。由于虚拟机的处理函数中加入了大量混淆指令,因此实际执行到的动态指令数量往往规模庞大。为了提高效率,在
一个实施例中,采用缓存延迟写入方法将执行期的每条指令的寄存器值和内存读写信息记
录为VMTrace文件。
[0051] 步骤102,局部变量表位置确定。
[0052] 其中,当虚拟机加固后的可执行程序运行时,其在进入虚拟机之前,程序会开辟一段内存作为局部变量表。局部变量表的内存位置在离开虚拟机之前不会变化,虚拟机通过
指令“sub esp, esp_space”来开辟局部变量表的内存空间,所以通过在进入虚拟机之前的
VMTrace中用如下语句查找“sub esp, esp_space”来确定局部变量表的位置:
[0053] vm_handler.local_variable_table.addr=[esp]。
[0054] 步骤103,处理函数识别。
[0055] 其中,在大量的虚拟机指令序列中,其虚拟机在完成一次解释执行前,都会表现出某种固有的特征,比如跳转到取指令的位置。在一个实施例中,所述处理函数识别,包括:所
述虚拟机采用了线索式解释执行,其通过设定的如下汇编语言代码表述的两种方式实现相
邻处理函数的跳转;
[0056] 方式 1:
[0057] xxxx: push reg
[0058] xxxx: ret
[0059] 方式 2:
[0060] xxxx: jmp reg
[0061] 以上两种方式中,reg的值是下一跳处理函数的地址,通过在虚拟机的动态指令追踪记录中匹配如上两种情况可以进行处理函数的划分和识别。此外,每一个处理函数执行
结束之前,esp寄存器都会指向局部变量表的位置,可以以该约束作为处理函数识别的加强
条件,提高处理函数识别的成功率。识别处理函数的伪代码逻辑如下代码所示:
[0062] for line_num in range(start, end):  //轮询Trace记录
[0063]         inst = Inst(line_num)  //获取一条新指令
[0064]         if vm_handler: //判断是否创建处理函数
[0065]             vm_handler.add_inst(inst)  //将该指令添加至VMHandler中
[0066]         if (re.search(r'ret', inst.text) and esp_value == inst.get_reg_in_chg('ESP')) or re.search(r'\bjmp\b.*\be(ax|bx|cx|dx|di|si|bp|sp)\b', 
inst.text): //特征模式匹配是否成功
[0067]             if vm_handler:  //判断是否创建处理函数
[0068]                vm_hanlders.append(vm_handler)  //将当前的处理函数存入处理函数集合中
[0069]             vm_handler = VMHandler(index, inst.line_num + 1)  //创建一个新的处理函数
[0070]             index = index + 1  //处理函数索引值加1
[0071] 也就是执行如下识别方法:
[0072] 如上述伪代码所示,轮询虚拟机动态指令追踪记录,如果匹配到两种处理函数的结束特征,则创建一个新的处理函数实例,之后把轮询的后续指令添加到该实例中,直至一
个新的特征出现,则表示该实例的指令序列结束。以此类推,循环结束后,可以得到所有被
执行的处理函数的实例集合。
[0073] 步骤104,处理函数执行前后所有寄存器值确定。
[0074] 其中,在一个实施例中,所述处理函数执行前后所有寄存器值确定的方法,包括:根据步骤103而得到的识别的处理函数,确定每个处理函数执行前后寄存器的值。在处理函
数的虚拟机动态指令追踪记录中,第1行会显示每个寄存器的值,之后VMTrace每条记录的
最后1列会记录每条指令执行后被修改的寄存器及其被修改后的值。根据这两个条件,可以
确定每个处理函数执行前后所有寄存器的值。这里分别用enter_status和exit_status表
示,即如下所示:
[0075] vm_hanlder.enter_status = {…}
[0076] vm_hanlder.exit_status = {…}
[0077] 其中,vm_hanlder.enter_status表示处理函数执行前所有寄存器的值;vm_hanlder.exit_status表示处理函数执行后所有寄存器的值;
[0078] 步骤105,处理函数操作数栈所对应的寄存器确定。
[0079] 其中,所述虚拟机中的操作数栈对应的寄存器并不固定,它可能通过寄存器轮转的方式动态修改。在一个实施例中,所述处理函数操作数栈所对应的寄存器确定的方法,包
括:首先确认在进入虚拟机之前,操作数栈所对应的寄存器。然后跟踪分析操作数栈的变化
情况进一步确定每个虚拟机操作数栈所对应的寄存器。虚拟机会通过如下汇编语言代码表
述的两种方式切换操作数栈所对应的寄存器。
[0080] 方式1:
[0081] xxxx: xchg op_stack_reg, reg1
[0082] xxxx: mov reg2, reg1
[0083] 方式2:
[0084] xxxx: mov reg, op_stack_reg
[0085] 根据如上两种方式所实现的判断条件都不是强约束,即可能出现符合条件但操作数栈对应的寄存器没有改变的情况。那么可以进一步通过其变化值的范围来增加识别的准
确性,用于识别的判定算法的伪代码逻辑如下所示:
[0086] xchg_fmt = r'\bxchg\b.*'  //正则匹配特征字符串变量赋值
[0087]     xchg_pattern = xchg_fmt + op_stack_reg  //构建方式1特征匹配字符串
[0088]     xchg_on = False  //设置xchg_on标志为False
[0089]     for vm_handler in vm_handlers:  //遍历处理函数集合
[0090]         vm_handler.op_stack_entry_reg = op_stack_reg  //给操作数栈入口寄存器赋值
[0091]         for i, inst in enumerate(vm_handler.insts): //遍历每个处理函数中的指令
[0092]             if re.search(xchg_pattern, inst.text): // 方式1特征模式正则匹配是否成功
[0093]                 xchg_on = True   //如果匹配成功,设置xchg_on标志为True
[0094]                 if op_stack_reg == inst.op_data1:  //如果操作数栈寄存器等于inst.op_data1
[0095]                     op_stack_reg = inst.op_data2  //操作数栈寄存器等于inst.op_data2
[0096]                 else:
[0097]                     op_stack_reg = inst.op_data1 //如果操作数栈寄存器不等于inst.op_data1,则操作数栈寄存器等于inst.op_data1
[0098]            elif re.search(r'^mov( !.*\[).*' + op_stack_reg, inst.text): // 方式2特征模式正则匹配是否成功
[0099]                 op_stack_reg_candidate = inst.op_data1//如果式2特征模式正则匹配成功,则候选的操作数栈寄存器为inst.op_data1
[0100]                 if xchg_on: //判断xchg_on是否为True
[0101]                     op_stack_reg = inst.op_data1 //如果xchg_on为True,则操作数栈寄存器为inst.op_data1
[0102]                     xchg_on = False //设置xchg_on标志为False
[0103]         xchg_on = False //设置xchg_on标志为False
[0104]         op_stack_chg = vm_handler.exit_status[op_stack_reg] ‑ vm_handler.enter_status[vm_handler.op_stack_entry_reg] //计算操作数栈栈顶变化值
[0105]         # if not in [‑8, 8] maybe error. so use candidate.
[0106]         if op_stack_chg not in range(‑8, 9): //判断操作数栈栈顶值的范围是否为[‑8,8]
[0107]             vm_handler.op_stack_exit_reg = op_stack_reg_candidate //如果操作数栈栈顶值不在 [‑8,8] 范围,则出口操作数栈寄存器为op_stack_reg_
candidate
[0108]             op_stack_reg = op_stack_reg_candidate  //将op_stack_reg_candidate赋值给操作数栈寄存器
[0109]         else:
[0110]             vm_handler.op_stack_exit_reg = op_stack_reg  //如果操作数栈栈顶值在 [‑8,8] 范围,则出口操作数栈寄存器为op_stack_reg
[0111]         xchg_pattern = xchg_fmt + op_stack_reg  //构建方式1特征匹配字符串
[0112] 其中op_stack_chg 表示检测到条件后新寄存器的值与原来寄存器值的变化量,op_stack_reg_candidate表示检测到条件可能切换到的新寄存器。如果其变化量在可能的
范围内,就使用新的寄存器替换原寄存器。
[0113] 步骤106,处理函数对操作数栈和局部变量表的读指令标记。
[0114] 其中,现在每个处理函数的操作数栈和局部变量表所对应的寄存器已经可知,以这些寄存器作为查找条件即可找到每个处理函数中对操作数栈和局部变量表读操作的指
令集合:
[0115] vm_handler.op_stack.ins={Is1,Is2,…Isi,…,IsM},1
[0116] vm_handler.local_var_table.ins={Iv1,Iv2,…Ivj,…,IvN}, 1
[0117] 其中,vm_handler.op_stack.ins表示处理函数中对操作数栈读操作的指令集合,vm_handler.local_var_table.ins表示处理函数中对局部变量表读操作的指令集合。
[0118] 判定处理函数中对操作数栈和局部变量表读写的汇编指令算法伪代码逻辑如下所示:
[0119] for vm_handler in vm_handlers: //遍历解释例程集
[0120]         op_stack_pattern = r'\bmov\b.*\[' + vm_handler.op_stack_entry_reg //构造被用于操作数栈读指令正则匹配的被匹配字符串
[0121]         for i, inst in enumerate(vm_handler.insts): //遍历每个解释例程中的指令
[0122]             if inst.indrect_type == READ_MODE: //判断是否为读指令 判断区分是"mov eax, [esp]"还是“mov [esp], eax”;即判断是从内存地址上读,还是写到
内存地址中。
[0123]                 if re.search(r'\bmov\b.*\[esp.*', inst.text): //局部变量表读指令特征正则匹配
[0124]                     vm_handler.local_var_table_insts.append(i) //如果匹配成功,则记录该局部变量表读指令
[0125]                 elif re.search(op_stack_pattern, inst.text): //操作数栈读指令特征正则匹配
[0126]                     vm_handler.op_stack_insts.append(i) //如果匹配成功,则记录该操作数栈读指令
[0127] 如上述伪代码所示,所述‘读操作’在汇编层面的表示即为mov指令,使用mov指令从对应的操作数栈或者局部变量表区域将数据读出来。
[0128] 步骤107,处理函数所对应的虚拟指令还原。
[0129] 其中,基于以上分析的内容,在一个实施例中,所述处理函数所对应的虚拟指令还原的方法,包括:可以得到:
[0130] (1)每个处理函数对操作数栈栈顶的变化值,(2)对操作数栈的读次数,(3)对局部变量区的读次数这3个重要数据;其中,对操作数栈栈顶的变化值可通过以下方式计算。
[0131] vm_handler.op_stack_chg = vm_handler.exit_status[vm_handler.op_stack_exit_reg] ‑ vm_handler.enter_status[vm_handler.op_stack_entry_reg]
[0132] 其中vm_handler.op_stack_chg表示处理函数对操作数栈栈顶的变化值。
[0133] 另外两个值根据步骤5获取的指令集合可知。
[0134] vm_handler.op_stack_read_times=Max[i]
[0135] vm_handler.local_var_table_read_times=Max[j]
[0136] 其中,vm_handler.op_stack_read_times表示对操作数栈的读次数。vm_handler.local_var_table_read_times表示对局部变量区的读次数。
[0137] 根据这三个数据,可以推断该处理函数所对应的虚拟指令。依据标准如表1所示:
[0138] 表1
[0139]
[0140] 根据表1,处理函数所对应的虚拟指令还原算法的伪代码如下所示:
[0141] if vm_handler.op_stack_chg == {‑2, ‑4, ‑8}://判断操作数栈变化范围是否为‑2,‑4或‑8
[0142]     if local_var_table_read_times: //判断局部变量表读次数是否大于0
[0143]         vm_handler.VMByteCode = Tload; //虚拟指令为Tload
[0144]     else:
[0145]         vm_handler.VMByteCode = Tconst; //虚拟指令为Tconst
[0146] else if vm_handler.op_stack_chg == 0: //判断操作数栈变化范围是否为0
[0147]     if op_stack_read_times > 0: //判断操作数栈的读次数是否大于0
[0148]         vm_handler.VMByteCode = Tmath; //虚拟指令为Tmath
[0149]     else:
[0150]         vm_handler.VMByteCode = Tnop; //虚拟指令为Tnop
[0151] else if vm_handler.op_stack_chg == {2, 4, 6, 8}://判断操作数栈变化范围是否为2,4,6或者8
[0152]     if local_var_table_read_times: //判断局部变量表读次数是否大于0
[0153]         vm_handler.VMByteCode = Tstore; //虚拟指令为Tstore
[0154]     else:
[0155]         vm_handler.VMByteCode = Tpop; //虚拟指令为Tpop
[0156] else:
[0157]     vm_handler.VMByteCode = TUnknown; //虚拟指令为TUnknown
[0158] 算法以操作数栈栈顶的变化值为主判断依据,然后在其内部再进一步判断其他条件,从而判定该处理函数对应的虚拟指令。
[0159] 如图3所示,本发明实施例还提供一种虚拟指令还原装置,包括:
[0160] 追踪模块71,用于虚拟机动态指令追踪;
[0161] 确定模块72,用于局部变量表位置确定;
[0162] 识别模块73,用于处理函数识别;
[0163] 执行模块74,用于处理函数执行前后所有寄存器值确定;
[0164] 对应模块75,用于处理函数操作数栈所对应的寄存器确定;
[0165] 操作模块76,用于处理函数对操作数栈和局部变量表的读指令标记;
[0166] 还原模块77,用于处理函数所对应的虚拟指令还原。
[0167] 本发明实施例还提供一种虚拟指令还原设备,包括存储器、处理器及存储在存储器上并可在处理器上运行的计算机程序,所述处理器执行所述程序时实现所述虚拟指令还
原方法。
[0168] 本发明实施例还提供一种计算机可读存储介质,存储有计算机可执行指令,所述计算机可执行指令用于执行所述虚拟指令还原方法。
[0169] 在本实施例中,上述存储介质可以包括但不限于:U盘、只读存储器(ROM,ReadOnlyMemory)、随机存取存储器(RAM,RandomAccessMemory)、移动硬盘、磁碟或者光盘
等各种可以存储程序代码的介质。
[0170] 本领域普通技术人员可以理解,上文中所公开方法中的全部或某些步骤、系统、装置中的功能模块/单元可以被实施为软件、固件、硬件及其适当的组合。在硬件实施方式中,
在以上描述中提及的功能模块/单元之间的划分不一定对应于物理组件的划分;例如,一个
物理组件可以具有多个功能,或者一个功能或步骤可以由若干物理组件合作执行。某些组
件或所有组件可以被实施为由处理器,如数字信号处理器或微处理器执行的软件,或者被
实施为硬件,或者被实施为集成电路,如专用集成电路。这样的软件可以分布在计算机可读
介质上,计算机可读介质可以包括计算机存储介质(或非暂时性介质)和通信介质(或暂时
性介质)。如本领域普通技术人员公知的,术语计算机存储介质包括在用于存储信息(诸如
计算机可读指令、数据结构、程序模块或其他数据)的任何方法或技术中实施的易失性和非
易失性、可移除和不可移除介质。计算机存储介质包括但不限于RAM、ROM、EEPROM、闪存或其
他存储器技术、CD‑ROM、数字多功能盘(DVD)或其他光盘存储、磁盒、磁带、磁盘存储或其他
磁存储装置、或者可以用于存储期望的信息并且可以被计算机访问的任何其他的介质。此
外,本领域普通技术人员公知的是,通信介质通常包含计算机可读指令、数据结构、程序模
块或者诸如载波或其他传输机制之类的调制数据信号。