好友
阅读权限35
听众
最后登录1970-1-1
|
风吹屁屁凉
发表于 2011-11-27 21:59
本帖最后由 风吹屁屁凉 于 2011-12-7 10:48 编辑
标 题: 【原创】VMP分析插件v1.1(2011/12/03更新)
作 者: zdhysd
时 间: 2011-11-26,10:55:22
链 接: http://bbs.pediy.com/showthread.php?t=143377
软件保护从加壳到后来的变形、虚拟机,和程序结合越来越紧密,保护方向也从最早的文件保护、反调试等转向代码保护。现在的虚拟机已经可以完全隐藏原始代码,如果使用的好,保护强度非常高。现在虚拟机使用的越来越多,用普通方法分析很麻烦,有必要找一种有效的分析方法了。
虚拟机本质上还是变形,只不过是从一个指令集变形到另一个指令集,而且指令是虚拟执行。它的强度在于每个指令功能都很简单,程序的其他功能都是靠这些指令的组合来实现,单独看一个指令几乎没有什么意义。虚拟机本身是程序正常功能的一部分,如果关键代码在虚拟机里是没办法分离或跳过的,只能分析虚拟代码。虚拟机加密如果不考虑速度,复杂度能无限增加,比如VMP用最大保护+变形加密一个不到40行汇编代码的程序,产生的虚拟指令超过20000个,每个虚拟指令执行时都需要几十条汇编指令。如果关键部分加了虚拟机,而且代码量很大,人工分析工作量几乎无法接受,只能自动分析。
VMP出现比较早,强度也不错,而且有破解版,可以自己加密程序然后分析,研究起来简单一些,先拿它来做实验,看能不能找到好的分析方法。我的想法是着重分析数据而不是代码,因为程序就是数据和算法,不管算法变形成什么样子,最终还是要操作相同的数据,可以根据程序对数据的操作来理解它的功能。
如果想分析一个数据,可以从一条操作它的指令开始,向前或向后跟踪所有操作,提取出所有相关的指令然后分析。这样做的好处是可以只分析关键部分,不受其他指令干扰,尤其是垃圾指令,因为垃圾指令根本不在跟踪链上。像VMP这种变形中大部分都是垃圾指令,真正变形很少的程序,几乎可以无视他的变形。
这种数据跟踪的方法很容易用于自动分析,只要提供指令对数据操作的信息就可以了,而且可以实现很多功能,比如清除垃圾指令和化简常量等,是以后分析的基础。向前跟踪可以知道数据是如何生成的,它的类型是什么,比如立即数和地址等。向后跟踪可以知道数据的用处,是JMP目标、解密用的常量或者其他东西。后来偶然看到数据流分析,发现和其中的UD链和DU链很像。已经做到这种程度了,还是按自己的想法做下去吧,基本思想都是差不多的。
现在只做到静态反汇编完整的虚拟程序,恢复程序结构和转移类型,简单的调试等,对虚拟机内部的自动分析还刚开始。调试简单的程序还可以,如果被虚拟化的程序很大,这个插件对分析的帮助并不太大,等化简做出来就有很高的实用价值了。但是可以看到完整的程序结构和转移,而且可以汇编代码和虚拟代码混合调试,调试虚拟代码和普通的调试操作几乎相同,会用OD的人应该都很熟悉,对分析还是有帮助的。
下面简单讲一下分析方法,原理看上去不算太难,但是做起来也要花很大功夫,尤其是一些细节方面要特别注意。
第一步是分析虚拟机引擎,收集一些信息,为反汇编和调试做准备,这里还是比较简单的。需要识别出指令表中所有的指令,提取解密操作码、处理程序地址和立即数的指令等。
首先提取每个指令处理程序的汇编代码,从第一条指令开始直到解码循环开始或堆栈检查程序。现在不考虑分支,VMP的指令处理程序中只有几个有分支,单独处理一下,这样简单点,清除变形后按特征识别就可以了。
VMP的变形做的确实不怎么样,几乎就是加垃圾指令,真正的变形很少,除了堆栈操作和一些读内存的指令以外就没有什么了,简单的清除一下垃圾指令就可以了。垃圾指令对识别还是有影响的,虽然不清除也可以识别,但是错误识别的几率也不小,FKVMP好像就没有清除,遇到垃圾指令中有RDTSC等指令时都会识别错误。
然后提取指令中解密立即数的代码和调整解码密码的代码,用数据跟踪找一下改变指定寄存器的指令就行了。vJMP的后半段是解码循环,其中包含操作码解密和指令处理程序地址解密,也要提取出来。还有自动生成指令信息,根据提取出来的指令处理程序分析指令功能,主要是对数据的操作,以后分析虚拟程序会用到。这里手工分析也可以,但是工作量很大还容易出错,遇到未知指令就没法反汇编了。现在是全自动,可以分析除vRET以外的所有指令。
这里用了一个小型的虚拟机,模拟了二十多个分析和加解密常用的指令,虚拟执行提取出来的解密代码做解码用,做数据跟踪时化简立即数和计算堆栈偏移也会用。还可以反向执行,把执行后的结果还原到执行前的状态,调试时设置vEIP、汇编时加密指令会用到。
有了上面的信息做反汇编和调试应该很容易了。反汇编需要模拟执行一些代码,先解密操作码,如果指令有数据的话再解密数据,然后调整解码密码继续反下一个指令就行了。遇到转移需要分析虚拟程序后计算目标,比较麻烦,后面会简单讲一下原理。VMP的指令格式还算简单,反起来也不太难,但是虚拟机真正的强度不在这里。
调试的话在一些地址设断点然后处理就可以了。现在的方法是在指令处理程序上设断点,指令断点直接中断,普通断点检查一下vEIP,如果相等就中断。进入虚拟机中断是在转到指令处理程序的RETN上设的断点,中断下来以后取消,执行vRET时再恢复。这种方法可能很慢,每次执行相同的指令处理程序时都要中断,以后会改成与普通调试用的INT3断点类似的方法,选一条不常用的指令做断点指令,比如vRET,只在这条指令的处理程序上设置断点,然后插入到要中断的位置。如果选择了检查虚拟机完整性选项,设断点后程序可能会出错,现在没有处理。
到这里就进入虚拟机内部了,现在才算开始真正的分析,当然难度也高了很多,这里和汇编语言几乎没有什么关系了。
现在只做到了分析转移目标和类型,恢复程序结构,其他的还刚开始做。这样难度已经很大了,分析的目标从汇编指令变成了虚拟指令,每个虚拟指令本身都很简单,靠复杂的组合来实现程序的功能,再加上变形、隐藏常量、检查虚拟机完整性等选项,要处理的东西就更多了。单独分析一个程序还行,要想通用,需要处理很多细节上的东西,要做的太多了。我做了大量的测试,现在基本做到在任何选项下加密不同的程序都能正确分析。
分析转移目标还是做数据跟踪,提取出生成转移目标的指令,再模拟执行计算出常量。VMP虚拟机引擎的汇编代码里计算常量的指令都很简单,只有一条路径,虚拟代码里就很复杂了,大部分都是多层分支再合并成一个变量,这里的分支指的是数据流的分支。隐藏常量和检查虚拟机完整性同时选择对常量计算也有影响,会在计算每个常量时读取虚拟机引擎的一部分代码参与计算。
不同的转移类型,比如无条件转移、条件转移、动态产生地址的转移、SWITCH等都有不同的产生目标地址的方法,再加上要和前面计算条件的代码分离,要做很多东西。模拟执行用的虚拟机模拟了大部分虚拟指令,为了分析方便还添加了几个其他的指令,比如堆栈操作,VMP的指令很少也都很简单,直接把处理程序抄下来就差不多了。
SWITCH也要单独处理,VMP会把多个分支表放在一起,分析时会当作一个,以后遇到其他SWITCH目标在已分析的分支表中时把相同的部分删除重新分析。
在壳的入口里还有一种动态产生目标的转移,通常是在前一个指令块里生成转移地址,根据执行的路径不同会有变化,现在只分析第一个转移到的目标。其实要全分析出来也是可以做到的,需要遍历所有执行路径,而且生成其他目标的指令块有可能现在还没有反汇编,每反汇编一次就要计算一次目标。
分析条件就麻烦一些了,需要找出所有标志操作,尤其是需要检查多个标志的条件,VMP会分成很多步来计算。因为虚拟机中没有比较指令,所有比较都是通过位操作来完成,而位操作最后是用与非和移位,计算过程很长,再加上隐藏常量等,一个条件计算下来可能要几百到上千条指令。我的方法是从最后一个使用的标志向前计算所有常量,如果几个常量合并算一个,再查找这些常量中包含哪些标志来初步确定转移类型。这只能确定条件转移检查什么标志,还不知道是标志为真时转移还是为假时转移,比如JZ、JNZ等,也不知道转移和不转移分别对应哪个分支,要结合其他信息来分析。
转移是VMP里重点保护的地方,虚拟指令中只有一个无条件转移vJMP,其他转移方式都是先计算出目标地址再用vJMP转到目标。在处理条件转移时会在堆栈里生成两个地址,作为转移目标列表连续存放,然后用条件比较的结果来查表。通常情况下第一个对应条件比较结果为0时的目标,也就是标志为假时的目标,第二个是非0时也就是标志为真时的目标。有时还会把条件NOT后再检查,也要单独处理。现在应该可以分析出标志为真和标志为假时分别对应哪个目标了,但还是不能确定条件转移的类型,因为在VMP中所有指令块顺序都被打乱并分散开了,不像汇编语言中条件不成立时直接执行下一条指令。指令块位置相关的信息已经被抹掉了,理论上讲想完全恢复是不可能的,但可以做到和原来的程序逻辑相同,结构尽可能接近。
恢复程序结构是用深度优先遍历的顺序反汇编再做排序,接在转移后面的指令块是条件不成立时的目标,和转移不相连的是条件成立时的目标,再结合条件可以得到转移类型。但这样只能保证结构图和加密前的程序同构,遇到分支可能会把条件取反,因为这样程序的逻辑也是不变的,这就没办法检查了。我用这个方法试了一下,效果还不错,程序结构可以正确恢复,大部分都相同,即使不同的地方也是符合程序原有的逻辑的,有可能还会优化。但是这些都要做很复杂的计算,不能保证一定正确,在分析之后还做了一些程序结构检查,可以查出比较明显的分析错误,比如条件不成立时的目标不是下一个指令块等,会给出提示。比较复杂的错误比如条件计算不正确就查不出来了,我手工测试了很多程序,基本没有什么问题。
退出虚拟机的返回地址也可以和转移目标用相同的方法得到,如果是常量就计算,不是常量有可能是整个函数被加密,退出虚拟机等于函数返回。VMP中函数调用和执行不能模拟的指令时也会退出虚拟机,现在遇到vRET就当作虚拟程序结束,即使是用作函数调用或联机指令也不会继续分析,还有异常处理的代码也没有分析,以后会加自动识别并继续分析。如果选择了退出虚拟机时加密寄存器选项,返回地址是解密寄存器的指令。在虚拟机中调用被虚拟化的函数有时不会退出虚拟机,这时有可能把被调用函数当作当前函数的一部分,现在还没有找到好的解决方法,以后也许会在找到重复指令块时再处理。
现在的方法是一边反汇编一边恢复程序结构,连续指令块对分析影响很大。一个指令块是完整的还是多个连在一起只有在发现转到其中的转移时才能确定,但是现在指令块反汇编后必须直接插入程序中对应的位置,只能在发现连续指令块时再调整,要处理很多东西,还可能有错误。开始时方法没设计好,一直在这个基础上做,以后会改成先反汇编出所有指令块再恢复结构。
界面和操作尽量做到和OD相似,大家对OD都很熟悉,用起来也方便。调试窗口是模仿OD的CPU窗口设计,用OD的表格窗口做子窗口,外观和操作几乎相同。拦截了一部分调试相关的快捷键、菜单和工具栏,进入虚拟机调试模式时转到插件处理,切换到汇编调试模式后恢复,调试虚拟指令和汇编指令可以用相同的操作。但是发现其他插件也有拦截这些东西的,我尽量做到兼容,但还是有可能发生冲突,导致不能使用某些调试功能。还有调用Setbreakpoint设置断点时如果不在已分析的代码中,OD会提示可疑的断点,有时调试虚拟代码时单步一次就弹出一个,对调试影响很大,不知道有什么办法去掉,实在不行就只能拦截弹出对话框了。
现在的算法分析速度有些慢,时间主要花在分析转移类型时的计算常量上,现在是每计算一个常量就做一次向前的数据跟踪,然后模拟执行计算出结果。以后会改成向后跟踪,计算出所有常量保留使用,速度应该会提高很多。因为速度慢,可能会造成OD停止响应,启动了一个新线程,但是OD的反汇编函数不支持多线程,我拦截了Disasm,调用前先进入临界区,如果有其他插件也拦截可能会出错,现在发现不能和FullDisasm一起使用。在状态栏里会显示分析进度,分析虚拟机时和分析进度相同,但是分析虚拟程序时由于不能确定后面还有多少指令,只能找到一点增加一点,不是很准确。
以后要做的就是化简和还原了,还原难度应该很大,化简其实现在的程序已经在用了,比如识别指令时的清除垃圾指令、分析转移时的化简常量等。现在只是程序内部使用,还没有做成通用的功能,下一步准备把化简做出来。这之前准备先做一些简单的功能,比如完善调试功能、代码高亮、汇编,识别函数调用等,这些都不是很难,应该很快可以做出来。这一版是一边研究一边写的代码,事先没有做很好的设计,结构比较乱,有些东西也不想在现在的程序上改了,做化简前可能会有大的修改。
使用说明
VMP分析插件1.10
插件功能
可以自动分析VMP虚拟机,识别虚拟指令,静态反汇编完整的虚拟程序,恢复程序结构和转移类型,识别调用目标、返回地址、分支表、循环等。可以动态调试虚拟程序,设置断点,单步执行,显示和修改虚拟寄存器、堆栈,设置指令指针,自动切换汇编调试和虚拟机调试等。在1.7、1.8、2.06版测试通过,其他版本不能保证正确运行,不支持旧版本VMP。
插件主菜单
编辑汇编指令信息
打开编辑汇编指令信息窗口。
编辑虚拟指令信息
打开编辑虚拟指令信息窗口。
打开调试窗口
打开调试虚拟机窗口。
启用虚拟机调试
选中以后可以调试虚拟代码,激活所有已设置的虚拟指令断点。
自动切换调试状态
如果选中,在启用虚拟机调试后可以自动在汇编调试和虚拟机调试之间切换,在虚拟机中中断时进入虚拟机调试,在虚拟机外中断时进入汇编调试。否则只要启用虚拟机调试,普通的汇编调试操作会被禁用,即使退出虚拟机也不能调试汇编指令,建议始终选中。
进入虚拟机时中断
选中后如果启用虚拟机调试,会在每次进入虚拟机时中断,切换到虚拟机调试。如果正在执行没有分析的程序会作为临时指令块显示,可以执行到返回,找到虚拟程序的入口再分析。
CPU窗口菜单
分析虚拟机
从选择位置开始分析虚拟机,如果有其他相关虚拟机也会自动分析。选择位置可以是虚拟程序入口前或虚拟机中除vRET、vCALL以外的任何位置,如果在vJMP中应保证在读取指令处理程序(MOV R32,DWORD PTR DS:[EAX*4+CONST])之前,否则会分析失败。
会在记录窗口里显示详细信息和进度,添加一些注释和标签,比如指令表、解码循环开始、堆栈检查程序、指令处理程序、执行虚拟指令等。注释的处理程序地址解密指令,文件如果有重定位,最后一条为重定位,虚拟机相关注释后会加指令表地址,有多个虚拟机时用来区分。
分析失败会提示,原因可以看记录,错误部分高亮显示,如果只是部分指令分析失败不会弹出提示窗口。
常见错误:
分析虚拟机失败、查找写入指令处理程序地址失败、查找读取操作码失败,这些有可能是选择位置不是VMP虚拟机或是不支持的版本。
识别处理程序时出现错误,可能是遇到未知的汇编指令,请查看指令处理程序后添加汇编指令信息。
识别处理程序失败,请添加虚拟指令,是因为没有找到匹配的特征,可以在编辑虚拟指令信息中添加虚拟指令。这种情况下可以自动分析指令信息,即使不处理一般也不会对使用造成影响,但是反汇编里会显示未知指令。
分析指令失败,可能已加壳,分析壳的入口可能会出现这种情况,一般是转到其他虚拟机的vJMP还没有被解压,可以等程序运行起来后再分析,不会对使用造成影响。
如果一个虚拟机完全分析成功,下次遇到相同的虚拟机时不会重复分析。
分析虚拟程序
从选择位置开始分析虚拟程序,选择位置必须在虚拟程序所有初始化之前,如果相关虚拟机没有分析,会先自动分析虚拟机。分析后可以在调试窗口中查看代码,在记录窗口里会显示分析信息,比如入口地址、初始堆栈等。如果分析过程中出现错误会提示,详细信息可以看记录,错误高亮显示。可以静态反汇编出完整的虚拟程序,恢复程序结构和转移类型。转移类型添加了检测TF的转移JT和JNT,虚拟程序中检测单步跟踪会用到。分析完成后会做结构检查,找出分析错误的地方,我尽可能做到分析准确,如果有不能确定的地方都会给出提示。现在的版本遇到vRET会作为虚拟程序结束,即使是用作函数调用和联机指令也不会继续分析。如果正在分析入口,而且入口被虚拟化,可能会提示指令块没有初始化,可以在程序运行起来以后再分析。
分析所有导出函数(测试用)
把选择的内存块里所有的导出函数作为虚拟程序分析,分析测试程序用,开始分析后不能停止,一般情况下不要使用。
插件窗口
编辑汇编指令信息窗口
可以在这里编辑汇编指令相关的信息,插件在分析虚拟机引擎时会用到这些信息,指令信息文件路径默认和插件相同。除非信息错误,不要修改已存在的指令,如果遇到没有的指令可以在这里添加。开始分析后不能插入或删除指令,可以在最后添加。
打开文件:选择并打开汇编指令信息文件,加载指令信息。如果文件中有错误会提示。
保存文件:把指令信息保存到文件,修改或添加指令信息后不会自动保存到文件,需要手动保存。
添加:把指令信息添加到当前选中的位置。
删除:删除当前选中的指令。
保存:保存修改过的信息,改变不会自动保存,修改后需要点击保存按钮,选择其他指令自动放弃修改。
操作码:指令操作码字符串,不能大于15个字符,只能用字母和数字,不分大小写。必须和OD的反汇编相同,否则无法识别指令。
操作数数量:指令操作数的数量,0到3,不包括隐含操作数,必须和OD的反汇编相同,否则无法识别指令。
读寄存器:指令读取的寄存器,包括隐含操作数,可以使用32位、16位、8位通用寄存器、EIP和段寄存器,用','分隔。
写寄存器:指令写入的寄存器,包括隐含操作数,和读寄存器格式相同。
读标志:指令读取的标志,可以使用CF、PF、AF、ZF、SF、TF、IF、DF、OF,用','分隔。
写标志:指令写入的标志,和读标志格式相同。
读操作数:指令读取操作数的方式,不包括隐含操作数,如果直接使用操作数选择"内容",如果只使用内存操作数的地址(比如LEA)选择"地址",操作数不存在选择"没有"。
写操作数:指令写入操作数的方式,不包括隐含操作数,如果写入选择"内容",操作数不存在选择"没有"。
FPU:如果指令是FPU指令请选择,在分析时FPU指令不会被作为垃圾指令清除。
编辑虚拟指令信息窗口
可以在这里编辑虚拟指令相关的信息,插件在分析虚拟程序时会用到这些信息,指令信息文件路径默认和插件相同。除非信息错误,不要修改已存在的指令,如果遇到没有的指令可以在这里添加。开始分析后不能插入或删除指令,可以在最后添加。在程序中硬编码了一些指令操作码,请不要修改。
打开文件:选择并打开虚拟指令信息文件,加载指令信息。如果文件中有错误会提示。
保存文件:把指令信息保存到文件,修改或添加指令信息后不会自动保存到文件,需要手动保存。
添加:把指令信息添加到当前选中的位置。
删除:删除当前选中的指令。
保存:保存修改过的信息,改变不会自动保存,修改后需要点击保存按钮,选择其他指令自动放弃修改。
操作数中的添加:把操作数信息添加到当前选中的位置
操作数中的删除:删除当前选中的操作数
操作数中的保存:保存修改过的操作数信息,改变不会自动保存,修改后需要点击保存按钮,选择其他操作数自动放弃修改。
添加指令:是否为用户添加的指令,插件为了分析方便,添加了一些指令,比如堆栈操作等,现在只在内部使用
操作码:指令操作码字符串,不能大于15个字符,只能用字母和数字,不分大小写。指令后加操作数长度(字节),虚拟机指令前加v,用户添加指令不加。
代码高亮:代码高亮使用的颜色,目前未实现。
特征指令:如果是用户添加指令,为指令处理程序,否则为指令特征。特征在识别虚拟指令时使用,每行一个,不分顺序,只要指令处理程序中包含全部特征指令就算匹配成功。特征中可以使用不精确指令,比如R32、CONST等符号,和OD格式相同。
如果多个指令都包含一个特征,应该把这个特征放在后面,比如vPushImm1的特征
ADD ESI,1
SUB EBP,2
MOV WORD PTR [EBP],AX
在vPushReg1中也有,但是vPushReg1的特征
MOV AL,BYTE PTR [EAX+EDI]
MOV WORD PTR [EBP],AX
在vPushImm1中没有,应该把vPushReg1放在vPushImm1之前。
特征ADD ESI,CONST匹配ESI(vEIP)常量改变,由于VMP中指令流方向每次可能不同,而且有可能使用ADD、SUB、INC、DEC、LEA等不同方法计算,这个特征在计算时只要发现ESI(vEIP)改变的常量绝对值和特征相同时就算匹配成功。
指令说明:描述指令的功能,可以在调试时的信息窗口显示。在指令描述中1字节作为2字节、2字节作为1字节表示只有低8位有效,堆栈操作压入、弹出和PUSH、POP相同,vESP会改变,读取、保存vESP不改变。
分析虚拟机时自动获取:如果选中,会在分析虚拟机找到对应的指令时自动获取指令信息,只能自动分析指令信息下的内容,不能分析用户添加的指令和vRET。
下面的内容可以自动分析
执行后检查堆栈:指令执行后是否检查堆栈,一般情况下虚拟堆栈长度增加时会检查堆栈。
指令数据:指令中包含的数据类型。
数据长度:指令中包含的数据长度。
vEIP改变:指令执行后ESI(vEIP)的改变,不能为负数,反向指令流会自动处理。
vESP改变:指令执行后EBP(vESP)的改变。
操作数类型:指令对操作数的读写方式和类型。
操作数长度:操作数的长度。
操作数堆栈偏移:堆栈相关操作数相对指令执行前vESP的偏移。
操作数说明:目前没有使用。
调试窗口
模仿OD的CPU窗口设计,用OD的表格窗口做子窗口,界面和操作几乎相同,界面和菜单文字与OllyDbg汉化第二版相同。
插件拦截了一些OD的调试操作,进入虚拟机调试模式时自动转到插件处理,退出虚拟机时恢复。功能与操作大部分和OD相同,可以设断点、单步、设置vEIP等。
现在的断点有两种,普通断点和指令断点,普通断点作用和OD中的断点相同,指令断点会在执行指定的指令时中断,和指令地址无关。现在普通断点是在指令处理程序上设置INT3断点,中断时检查vEIP是否相等,如果在常用的指令上设置断点可能速度非常慢,以后会换方法。调试时如果遇到没有分析的虚拟程序,比如选择了进入虚拟机中断,中断到没有分析过的地方,会作为临时指令块反汇编,这种指令块不能分析,只能调试,如果想分析可以在返回后分析虚拟程序入口。
现在调试和分析信息不能保存到UDD文件,分析信息和断点等在重启OD后会丢失,不关闭OD重新调试相同的程序可以保留分析结果。
拦截的OD菜单
运行、单步步入、单步步过、执行到返回和原来的功能相同,进入虚拟机调试模式时转到插件处理。
执行到用户代码是在执行到返回后步过vRET。
自动步入、自动步过、跟踪步入、跟踪步过目前不支持,进入虚拟机调试模式时会禁用。
拦截的OD工具栏
和菜单相同,如果有其他插件拦截了OD的窗口函数,有可能不能使用工具栏里的调试功能,我尽量做到兼容,但还是可能发生冲突。
拦截的OD快捷键
和菜单相同
调试窗口下的所有子窗口可以用TAB和SHIFT+TAB切换到上个和下个。
下面是调试窗口中的子窗口
指令窗口
地址:显示虚拟指令地址。
HEX 数据:显示解密后的指令字节码。
反汇编:显示反汇编的虚拟指令。
注释:显示自动分析得到的注释。
指令窗口菜单
断点-切换:在选择指令上切换断点。
断点-运行到选定位置:在选择指令上设置一次性断点然后运行。
断点-指令断点:用选择指令的操作码设置指令断点,执行所有相同指令时都会中断中断。
断点-删除指令断点:删除选择指令对应的指令断点。
断点-运行到选定指令:用选择指令的操作码设置一次性指令断点然后运行。
断点-指令断点(输入操作码):弹出对话框输入指令操作码,设置指令断点。
断点-一次性指令断点(输入操作码):弹出对话框输入指令操作码,设置一次性指令断点。
转到-vEIP:显示位置转到当前的vEIP。
转到-表达式:弹出对话框输入表达式,显示位置转到表达式计算结果。表达式支持OD语法,可以使用虚拟寄存器和除ESP以外的真实寄存器。
转到-上个函数过程:显示位置转到上个已分析的虚拟程序。
转到-下个函数过程:显示位置转到下个已分析的虚拟程序。
转到-上个指令块:显示位置转到上个已分析的指令块。
转到-下个指令块:显示位置转到下个已分析的指令块。
转到-转移来自:列出所有转到选择指令的地址,显示位置转到指定的地址,如果选择指令是分支表,包括引用分支表的地址。
查看-临时指令块:显示位置转到临时指令块。
查看-模块:显示位置转到指定的模块。
跟随:跟随指令的转移目标,如果转移类型是SWITCH会跟随到分支表。
此处为新 vEIP:设置vEIP到指定的指令,会自动调整解码密码,目前不能设置到其他虚拟机。
指令窗口快捷键
ENTER:和菜单 跟随 相同。
CTRL+G:和菜单 转到-表达式 相同。
CTRL+*:和菜单 此处为新 vEIP 相同。
*:和菜单 转到-vEIP 相同。
CTRL+-:和菜单 转到-上个函数过程 相同。
CTRL++:和菜单 转到-下个函数过程 相同。
SHIFT+-:和菜单 转到-上个指令块 相同。
SHIFT++:和菜单 转到-下个指令块 相同。
F2:和菜单 断点-切换 相同。
F4:和菜单 断点-运行到选定位置 相同。
信息窗口
和OD的信息窗口功能基本相同,点击标题可以在运行时信息和指令说明之间切换。
现在运行时信息可以显示指令操作数内容,转移来自,转移目标、解码后的调用和返回地址。
信息窗口菜单
暂时没有添加。
信息窗口快捷键
暂时没有添加。
寄存器窗口
寄存器:显示寄存器名,vR0-vR15是通用寄存器,vESP是栈顶指针,vEIP是指令指针,vKEY是解码密码,vREG指向通用寄存器,分别对应真实寄存器的EBP、ESI、EBX、EDI。
值:显示寄存器值,vEIP、vKEY可能和ESI、EBX不同,在虚拟机中中断时解码循环已经执行,为了和反汇编内容对应,显示的值会调整到执行前的状态。
注释:目前没有使用,以后会显示地址解码信息,和OD的寄存器窗口类似。
寄存器窗口菜单
修改-递增、递减、置 0、置 1、修改:和OD操作相同,不能修改vEIP和vKEY,要修改vEIP请使用指令窗口的设置vEIP,vKEY会自动调整。
反汇编窗口中跟随、数据窗口中跟随、堆栈窗口中跟随:跟随数值到指定窗口。
寄存器窗口快捷键
ENTER:和OD相同,通用寄存器、vESP、vREG是修改,vEIP是反汇编窗口中跟随。
16进制数字:和OD相同,在通用寄存器、vESP、vREG上可以修改。
+、-:和OD相同,递增、递减。
堆栈窗口
地址:显示堆栈地址。
数值:显示指定地址的值。
注释:目前没有使用,以后会显示地址解码信息,和OD的堆栈窗口类似。
堆栈窗口菜单
修改、编辑:和OD相同。
转到 vESP、转到 vREG:显示位置转到指定寄存器值。
转到表达式:弹出对话框输入表达式,显示位置转到表达式计算结果。表达式支持OD语法,可以使用虚拟寄存器和除ESP以外的真实寄存器。
反汇编窗口中跟随、数据窗口中跟随、堆栈窗口中跟随:跟随数值到指定窗口。
堆栈窗口快捷键
ENTER:跟随,如果数值可以跟随到多个窗口,顺序为反汇编、堆栈、数据。
CTRL+G:和菜单 转到表达式 相同。
CTRL+E:和菜单 编辑 相同。
数据窗口
使用OD的DUMP窗口,操作完全相同。
已知问题和注意事项
插件为了处理多线程,拦截了Disasm,在调用时会进入临界区。如果有其他插件也拦截,可能会出错,已经发现和FullDisasm有冲突,不能一起使用,以后可能会修改。
调试操作拦截了一些OD的功能,可能和其他插件有冲突。
反汇编格式应使用OD的默认格式,用MASM语法,选择显示默认段,不能选择使用串操作的简易形式、使用RET代替RETN,选择 解码区分大小的16/32位助记符为:PUSHAW/PUSHAD,不要选择其他插件如FullDisasm可以改变反汇编格式的选项。
由于在程序中使用指令数组索引,开始分析后不能插入或删除汇编指令和虚拟指令信息,可以在最后添加,以后会改成MAP。
现在分析虚拟程序不能识别用vRET的函数调用、联机指令,会作为虚拟程序结束,不能分析异常处理。如果调用被虚拟化的函数可能被当作当前函数的一部分,这时产生的程序结构比较乱。
如果选择检查虚拟机完整性,设断点可能会导致被调试程序出错,以后会处理。
请不要在OD的断点窗口删除或禁用插件设置的断点,这可能造成插件不稳定。
设置断点或单步时可能会提示可疑的断点,请选是。有时单步一次弹出一个,对调试造成很大影响,不知道有什么办法能去掉,以后实在不行就拦截弹出窗口了。
如果虚拟程序在进入解码循环前有垃圾分支,进入虚拟机中断可能不能停在第一条指令上。
有时虚拟程序中会出现两个指令块开始地址相同、方向相反的现象,在虚拟程序中调用被虚拟化的函数也可能会出现重复地址,指令窗口中的跟随、转到等功能可能会当作一个指令块,导致跟随位置错误。
附件 VMP分析插件 是插件程序,请把指令信息文件和插件放在一起,否则需要在编辑指令信息中设置文件路径。
附件 测试程序 中包含了几个简单的测试程序,用VMP2.06加密,可以测试程序基本结构和不同加密选项,所有加密的函数都已导出。还有一个加密了所有导出函数的OD,可以用分析所有导出函数测试。OD的入口点太短不能加密,分析时会提示错误,其他的只有一个函数结构还原错误,暂时不准备改了。OD里经常调用被虚拟化的函数,分析时可能会把多个函数混在一起,反出来的结构有些乱。
2011/12/03更新 v1.1
修复了当前vEIP和断点之间有与断点相同的指令时拦截断点记录和更新CPU窗口失败的问题,现在不会设置焦点到OD的CPU窗口了。
修复了程序关闭有时不会清除断点的问题,现在的方法遇到动态加载的DLL中有虚拟机时重启后可能不能恢复断点,加保存断点到UDD再后修复。
现在如果在分析没有结束时退出OD会自动结束分析线程,不会弹出错误窗口了。
指令窗口的此处为新vEIP功能可以设置vEIP到不同的虚拟机了。
更换了普通断点原理,使用类似汇编调试INT3断点的方法,大幅提高设置断点后的运行速度,几乎与没有断点时相同。
插件主菜单
添加 打开断点窗口:打开断点控制窗口。
拦截OD快捷键
添加 ALT+B:在虚拟机调试状态下会打开断点控制窗口。
指令窗口菜单
添加 断点-条件:在选择指令上添加条件断点或编辑条件,在条件成立或错误时中断。
添加 断点-指令条件断点:设置指令条件断点或编辑条件,在条件成立或错误时中断。
添加 断点-指令条件断点(运行后):设置指令条件断点或编辑条件,指令运行后检查条件,在条件成立或错误时中断,vRet会在进入虚拟机时检查。
修改 现在所有指令断点会弹出对话框输入指令操作码,如果有选择指令,初始内容为选择指令的操作码。
修改 断点-运行到选定指令:改为 运行到指令。
去掉 断点-指令断点(输入操作码):可以用 断点-指令断点 代替。
去掉 断点-一次性指令断点(输入操作码):可以用 断点-运行到指令 代替。
指令窗口快捷键
添加 SHIFT+F2:和菜单 断点-条件 相同。
添加窗口 断点
可以查看、删除、激活、禁用、编辑断点。
禁用虚拟机调试时所有内容显示灰色,标题加 虚拟机调试已禁用,这时所有断点无效。临时指令块中的普通断点在临时指令块失效后会显示未知模块,这样的断点不会起作用,请删除。
断点窗口
地址:普通断点显示地址,指令断点显示指令操作码。
模块:显示断点所属的模块,指令断点作用于所有模块,临时指令块中的普通断点只在指令块内有效。
激活:显示断点的状态、条件等。
反汇编:普通断点显示反汇编,指令断点显示指令操作码。
注释:显示指令的注释。
断点窗口菜单
删除:删除断点,如果启用了进入虚拟机中断,进入虚拟机后会在vRet设置一次性指令断点,这个断点不能删除。
激活:启用断点。
禁止:禁用断点,不能禁用一次性断点。
编辑条件:编辑断点的条件,不能编辑一次性断点,如果要改变指令断点的执行前/执行后检查,请重新设置断点。
反汇编窗口中跟随:跟随普通断点地址到指令窗口,不能跟随指令断点。
全部激活:启用所有断点。
全部禁止:禁用所有断点。
全部删除:删除所有断点。
断点窗口快捷键
ENTER:和菜单 反汇编窗口中跟随 相同。
SPACE:和菜单 激活/禁止 相同。
DELETE:和菜单 删除 相同。
鼠标双击:和菜单 反汇编窗口中跟随 相同。
这次更新主要更换了普通断点原理,添加了断点控制、条件断点。指令条件断点在查找某些特定值时比较方便,如果想要知道12345678在虚拟机中什么地方生成,可以在常用的计算指令上设置执行后条件断点,比如在vNand4上设置[vESP+4]==12345678,一般都能找到。条件断点如果频繁发生,速度可能有些慢,还有一点要注意的是执行后条件断点中使用的堆栈偏移要按指令执行后的vESP计算,而指令信息的操作数中使用的是执行前的vESP。在虚拟机调试模式时可以按ALT+B打开断点控制窗口,由于考虑到调试虚拟机时也有可能需要汇编断点,只拦截了快捷键,可以用菜单和工具栏打开OD的断点窗口。
现在的普通断点使用插入vRet的方法,只有在执行vRet时才会发生中断,速度提高很多。一开始认为很简单,其实还是要考虑很多东西的,比如中断时要恢复原来的指令,需要重设解码密码、设置EAX中的指令、修改EIP到原来的指令处理程序等,指令执行后还要把断点设回去,现在是在执行虚拟指令上设置断点,执行下一条指令时恢复。
下次更新来点实用的功能,准备把汇编和插入指令做出来,这样就可以修改虚拟程序了。汇编应该不难,关键是如何处理汇编后指令长度不同,我的想法是如果指令比原来的长,把指令块分成两段,添加一个vJmp转移出去,执行完成后再回来,这就可以直接插入或拦截虚拟程序了。 |
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|