粗略分析一下NET的vm虚拟机
本帖最后由 梦游枪手 于 2019-8-13 22:35 编辑前言
vmp3.4版本发布有一段时间了,这个版本更新不但支持了NET,还把巨恶心的虚拟机移植到NET了。出于好奇,我分析了一下NET的vm虚拟机,并整理一下当成分析笔记。
准备
dnspy,脱过vmp壳的NET程序样本(从wwh1004大佬的帖子下载的)
分析
用dnspy载入样本,找到Main入口。
2B1B6FC1是vm虚拟机类,3FE73680是vm_dispatch,它的部分代码如下。
这时候需要默念一句VM大法好,把它们的名字尽量还原。(其实是人肉分析handle,变量名和函数名不一定对。)
可以跟图里同样的地方下断点,运行程序,停下后按F11就能跳转到handle了,直接下到handle()那里是没用的。
下面我挑几个地方说一下。
1.栈
搞过vm的都知道vm虚拟机是栈式虚拟机,它所有的操作,包括计算,都要通过堆栈来进行。NET版同样是栈式虚拟机。
。
NET版的vm虚拟机,vm_stack字段就是它的栈,用它来模拟普通环境下的堆栈操作。还有寄存器,vm_eip,handle表也都是用字段来模拟。
2.handle
handle表是在vm虚拟机类的构造方法里填充的。
这段代码大致上是读取handle的指针,然后转换成vm的handle类,再写到handle表里。我们在dispatch里面下断看看填充完的handle表。
一共256条handle,有耐性的同学可以把handle表全部搞定,不过我是没这个耐性了。
3.数值计算
以vm_add handle为例子。
vm_add会从堆栈弹出两个操作数
再把相加后的结果压回堆栈。
与普通环境的区别就是没有标志位,其他的计算handle也是这样。
4.条件跳转
跟普通环境下相似,分别压入两个地址,用vm_cmp的结果计算target。
运行样本,在vm_cmp处下断,输入6,回车,观察vm_stack。
走完cmp,看下栈顶
stack>stack,所以栈顶值为1。
然后对cmp结果做一些运算后,计算target。
cmp的结果经过什么handle可以自己去跟一下,我总结一下就是
a1=neg((flag>>1)&1)&addr1
a2=(~neg((bool)a1))&addr2
target=a1+a2
精简过后
input < ‘4’ ? a1 : a2
修改cmp(不是vm_cmp,dnspy修改不了字段的值)的返回值就能改变流程了。
5.方法调用和字段获取
vm虚拟机里会用token获取需要用到的资源,比如字符串
方法体并反射调用
字段等等
由于样本代码太少,所以这部分就没怎么分析,我真的不想去分析壳的虚拟机。
总结
NET环境和普通环境的vm虚拟机大致相同,NET环境的vm虚拟机总体强度比普通环境要弱一些。普通环境的vmp3.x会打散handle表,没有统一的dispatcher,但是NET环境有handle表和dispatcher,也没有普通环境那么强的代码混淆程度,应该是为了稳定做的妥协。不过即使是这般削弱过的vmp,强度其实也足够了。我分析这个小样本就够呛的了,更别说用非人肉方法把vm还原回C#代码,难度很高,不是我这种小菜鸟能够搞定的了,还是收拾一下洗洗睡吧。
附上分析的样本和重命名过的样本,样本本身有点问题,输入一次数字后就会崩溃,这个是vm虚拟机在处理switch结构的时候出了问题。
附件已经更新,重命名版也可以运行了,我在能运行的前提下尽量修改了方法名和字段名。在此感谢wwh1004大佬的指点。
其实重命名有办法运行
https://www.52pojie.cn/forum.php?mod=redirect&goto=findpost&ptid=1005816&pid=27376490
你用VMPDumper把那个最新的样本dump一次,可以解密IL,顺便会自动hook掉CreateFile,默认就是过检测的
重命名之后,写入文件记得选混合模块
保存之后可以运行
wwh1004 发表于 2019-8-13 14:21
那个vmp bug,不知道为什么,用了sdk,加出来的程序就不能运行
这个是vm虚拟机在处理switch结构的时候出了问题。它把读到的字节无脑减去0x31(记为offset),再判断是否大于3,offset>3会跳到default分支处理,其他情况就全交给switch表处理了。其实就是少了一个offset<0的判断,导致(switch+offset)的offset有可能为负数,这样switch会跳转到不可预估的区域,然后就崩了。 精彩分析,难得。 不错学习了 够详细,支持一下! 学习了,,,。 net反破解也越来越强力了 感谢楼主分享谢谢
感谢分享。。。。。。。 厉害了我的哥哥 他jit那边怎么办,总得把IL编译出来吧