宝峰科技

 找回密码
 注册

QQ登录

只需一步,快速开始

智能终端设备维修查询系统注册会员邮箱认证须知!
查看: 4973|回复: 0

VMP之反VM(还原代码)初探

[复制链接]

该用户从未签到

破解狼人 发表于 2010-10-31 22:40:53 | 显示全部楼层 |阅读模式

欢迎您注册加入!这里有您将更精采!

您需要 登录 才可以下载或查看,没有账号?注册

x
VMP之还原VMP初探
作者:小娃崽[CUG]

这应该是一篇菜鸟一看就懂,高手不用看就懂的帖子。不知道为什么,前段时间老是在想VMP这个东西,可能是因为太闲的原因吧。突然想到 如果虚拟了 MOV EAX,1这个指令最终结果还会是令EAX这个寄存器中的数据为1的。这两天休息,就下了VMP1.08回来虚拟了几个小程序,F8从头到尾把程序跑了一趟。累啊,以下是一点心得,先记录下来,免得以后忘记了。
【1】总的纲领:
汇编中操作数主要分为三类:寄存器操作数,内存操作数,立即操作数。CPU指令执行的最终结果还是改变寄存器或者内存中的数据。
  比如 :
  MOV EAX,1
  mov [10000000],eax
  使EAX=1,[10000000]=1
  也可以变换一种形式改变EAX的值,
  比如:
  push 1
  pop  eax
  不管怎样,最终结果还是一样的,只是换了个形式,VMP也一样,只是跑了N条等价的伪指令,晃点我们的眼睛而已。

【2】VMP是堆栈机:
它有自己的"寄存器",有自己的伪指令,它对数据的操作都是通过堆栈进行的,从它的伪指令可以看出,伪指令太多了,我只看了几十条,其他的就看不下去了。
  如【1】所述,指令的结果只是改变数据.
   pop     dx
   pop     ax
   pop     cx
   div     cx
   push    ax
   push    dx
   JMP     vm_execute //字除法,并把商和余数压入堆栈 v_divw

   pop     ecx
   add     dword ptr [esp], ecx
   jmp     vm_execute           //可以看做是V_ADD

   lods    byte ptr [esi]
   add     al, bl
   sub     al, 0C6
   ror     al, 1
   not     al
   ror     al, 3
   add     bl, al
   cbw
   cwde
   push    eax
   jmp     vm_execute          //可以看做是V_PUSH


   pop     eax
   pop     dword ptr [eax]   
   jmp     vm_execute         //可以看做是和MOV [XXXXXXXX],reg 等价的伪指令


。。。。。。。。。。。。
没猜想错的话,在虚拟机内部,VMP对数据的操作转换到了VM_COMTEXT,堆栈当中,只是通过伪指令进行而已。
在论坛里还看到前辈们总结的 ,这个或那个再或那个等于异或什么的,还画有图,应该是精华部分吧,没看,因为我觉得我看不懂,以后用的上的话在看吧。
【3】VMP的构造:
    猜想进入VMP之前和退出VMP之后,堆栈的情况应该差不多的,改变不了多少。于是对VM入口下了硬件访问断点。
00404313    58              pop     eax
00404314    61              popad                     //F9几下来到这里 和VMP的入口刚好匹配得上 应该就是传说中的VM出口了。
00404315    9D              popfd
00404316    C3              retn                      //还有一条差不多的,只是这里是retnf
   F8按了好久,于是干脆就写了几句脚本,专门查看EAX的值,发现大体结构都是差不多的。

VM_START:
00401000 > $  68 EB4C4000   push    00404CEB             //把PCODE压入堆栈
00401005   .- E9 A63A0000   jmp     00404AB0

VM_EXECUTE:

00404AB0    9C              pushfd
00404AB1    60              pushad                       
00404AB2    68 00000000     push    0
00404AB7    8B7424 28       mov     esi, dword ptr [esp+28]
00404ABB    FC              cld
00404ABC    BF 00404000     mov     edi, 00404000
00404AC1    89F3            mov     ebx, esi
00404AC3    033424          add     esi, dword ptr [esp]
00404AC6    AC              lods    byte ptr [esi]
00404AC7    00D8            add     al, bl
00404AC9    FEC0            inc     al
00404ACB    F6D0            not     al
00404ACD    C0C0 07         rol     al, 7
00404AD0    34 D3           xor     al, 0D3
00404AD2    00C3            add     bl, al
00404AD4    0FB6C0          movzx   eax, al
00404AD7    FF2485 DD404000 jmp     dword ptr [eax*4+4040DD]    //开始执行伪指令

0040404F    AC              lods    byte ptr [esi]
00404050    00D8            add     al, bl
00404052    34 4A           xor     al, 4A
00404054    FEC8            dec     al
00404056    C0C8 05         ror     al, 5
00404059    FEC8            dec     al
0040405B    00C3            add     bl, al
0040405D    8F0487          pop     dword ptr [edi+eax*4]       //把之前PUSH的寄存器保存到VM_COMTEXT,10次,V_SaveToVMContext
00404060    E9 610A0000     jmp     00404AC6

。。。。。。。。。。。。。。。。。N条伪指令

00404B32    AC              lods    byte ptr [esi]
00404B33    00D8            add     al, bl
00404B35    34 4A           xor     al, 4A
00404B37    FEC8            dec     al
00404B39    C0C8 05         ror     al, 5
00404B3C    FEC8            dec     al
00404B3E    00C3            add     bl, al
00404B40    FF3487          push    dword ptr [edi+eax*4]     //把数据压入堆栈 ,10次,V_VMContextToStack
00404B43  ^ E9 7EFFFFFF     jmp     00404AC6

004045B6    58              pop     eax
004045B7    61              popad
004045B8    9D              popfd                            //再把堆栈的数据压入到真实的寄存器
004045B9    C3              retn

N条伪指令下来,最终执行了几条等价的汇编指令而已。以下是我自己总结的VMP大概构造:

Vm_Start
VM_Execute
V_SaveToVMContext
N条伪指令
V_VMContextToStack
V_RETN  
  
【4】验证与猜想:
  回到MOV EAX,1这条指令上来,我就虚拟了这个指令而已,然后在VM的出口下断,发现最终的结果就是EAX=1,其他寄存器与没VM之前的变化不大。以下是代码片段,我可是完整的F8几回才看到了点真相。
  
   V_SaveToVMContext  10次
   。。。。。。。。。。。。。
   00404421    AC              lods    byte ptr [esi]
   00404422    00D8            add     al, bl
   00404424    2C C6           sub     al, 0C6
   00404426    D0C8            ror     al, 1
   00404428    F6D0            not     al
   0040442A    C0C8 03         ror     al, 3
   0040442D    00C3            add     bl, al
   0040442F    66:50           push    ax
   00404431    E9 57060000     jmp     00404A8D             //V_PUSH 5
   。。。。。。。。。。。。
   00404B17    AC              lods    byte ptr [esi]
   00404B18    00D8            add     al, bl
   00404B1A    C0C0 07         rol     al, 7
   00404B1D    FEC0            inc     al
   00404B1F    34 3E           xor     al, 3E
   00404B21    04 2D           add     al, 2D
   00404B23    00C3            add     bl, al
   00404B25    8F0487          pop     dword ptr [edi+eax*4]  //V_SaveToVMContext对应的V_EAX被改变
   00404B28  ^ E9 60FFFFFF     jmp     00404A8D
   。。。。。。。。。。。。
   V_VMContextToStack 10次
   V_RETN    //退出VM
【5】还原VMP的一点感悟
  知道了事情的真相,感觉人肉还原VMP还是可行的,需要的只是时间和毅力,N条伪指令下来,才还原成几条汇编指令,我才不干!我想VMP强大的地方应该数PUSH,POP操作了太多次,有的负责解码,但大多是的时候我都觉得它们跟花指令差不多。而且HANDLE与PCODE可是随机组合的,同一段程序会VM出不同的版本。
如果  MOV EAX,1  VM后的结果是 :
     V_SaveToVMContext  
     V_PUSH 5
     V_SaveToVMContext
     V_VMContextToStack
     V_RETN   
我想还原起来可就不费力了。
可以从VM的外部着手,观察和猜测这段VM的大体功能,像高手们说的,把它看成是一个函数,有时候不用跟进VM就能看出个大概了,比如一个虚拟了的MessageBoxA,接着进入VM内部,注意观察VM_COMTEXT,堆栈的数据变化,把无效的PUSH,POP给剔除,精简出有效的伪指令,再还原。而且对数据操作的指令(ADD,MUL,DIV之类的)在VMP内部都有等效的伪指令,而且不难看出。

【总结】:
   终于理解了什么是VM,高兴
您需要登录后才可以回帖 登录 | 注册

本版积分规则

免责声明

本站中所有被研究的素材与信息全部来源于互联网,版权争议与本站无关。本站所发布的任何软件编程开发或软件的逆向分析文章、逆向分析视频、补丁、注册机和注册信息,仅限用于学习和研究软件安全的目的。全体用户必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。学习编程开发技术或逆向分析技术是为了更好的完善软件可能存在的不安全因素,提升软件安全意识。所以您如果喜欢某程序,请购买注册正版软件,获得正版优质服务!不得将上述内容私自传播、销售或者用于商业用途!否则,一切后果请用户自负!

QQ|Archiver|手机版|小黑屋|联系我们|宝峰科技 ( 滇公网安备 53050202000040号 | 滇ICP备09007156号-2 )

Copyright © 2001-2023 Discuz! Team. GMT+8, 2024-12-22 16:31 , File On Powered by Discuz! X3.49

快速回复 返回顶部 返回列表