2012.04.07_天易love_关于VMP调试插件原理的思考

以超级大牛hkfans“ vmp2.06全过程分析”一文中的NOTEPAD. vmp.exe作为例子,
讲一下我的理解,错误之处请牛人指正!
  1、如何实现retrieve handler info?
    我觉得主要是找到一张虚拟机指令地址入口表,类似于这样:

81 12 FA FE 43 2C FA FE 92 08 FA FE 69 08 FA FE
E1 1C FA FE 76 03 FA FE BB 25 FA FE 31 00 FA FE
E7 17 FA FE 05 08 FA FE 29 11 FA FE 77 1D FA FE
6E 19 FA FE B7 18 FA FE 5A 2C FA FE 75 2C FA FE
FB 19 FA FE 3E 2C FA FE EC 2C FA FE 8F 2B FA FE
FA 2D FA FE 32 24 FA FE 6C 28 FA FE 1F 1E FA FE
AB 06 FA FE E0 08 FA FE 86 1C FA FE EC 26 FA FE
56 2B FA FE 34 0E FA FE 90 06 FA FE C2 17 FA FE
3A 1B FA FE BB 11 FA FE 76 28 FA FE D1 1D FA FE
CA 1C FA FE 90 26 FA FE 7D 04 FA FE 96 11 FA FE
5C 1D FA FE 55 0F FA FE E0 28 FA FE D7 11 FA FE
10 2A FA FE 70 2D FA FE 03 1F FA FE 76 20 FA FE
2C 16 FA FE DF 03 FA FE 77 07 FA FE A4 23 FA FE
23 2A FA FE E7 06 FA FE 14 16 FA FE AD 0F FA FE

   简单解释一下,例如81 12 FA FE就是0xFEFA1281,只要neg 一下,就变成了0x0105ED7F,到地址0x0105ED7F处看看,有一堆垃圾指令,这里直接给出里面的两条有效指令:
//edi是虚拟寄存器的基地址 eax定位其中的哪一个寄存器,这里是取出某个虚拟寄存器的值
0105FF84    8B1438          mov     edx, dword ptr [eax+edi] 
//ebp是VESP,再把这个值压入虚拟栈
01060000    8955 00         mov     dword ptr [ebp], edx  
这条虚拟机指令前人起名叫做 vm_pushdw_regdw
为什么要neg 一下?直接上代码

0105E4AF    8B1485 0EF20501 mov     edx, dword ptr [eax*4+105F20E] //105F20E 表地址
0105E4B6    F9              stc
0105E4B7    F7DA            neg     edx  //看到了吗
0105E4B9    F9              stc
0105E4BA    F5              cmc
0105E4BB    81C2 00000000   add     edx, 0  //等于没加
0105E4C1  ^ E9 33FBFFFF     jmp     0105DFF9

    内存中的一张表0x400字节,去除里面重复的,实际就是前面给出的那张表:
0105F20E  81 12 FA FE 43 2C FA FE 92 08 FA FE 92 08 FA FE  ?C,??
0105F21E  69 08 FA FE E1 1C FA FE 76 03 FA FE BB 25 FA FE  i?v?
0105F22E  31 00 FA FE E1 1C FA FE E7 17 FA FE E7 17 FA FE  1.???
0105F23E  05 08 FA FE 29 11 FA FE 77 1D FA FE 6E 19 FA FE  )wn
0105F24E  B7 18 FA FE 31 00 FA FE 5A 2C FA FE 69 08 FA FE  ?1.Z,i
0105F25E  75 2C FA FE FB 19 FA FE 77 1D FA FE 3E 2C FA FE  u,?w>,
0105F26E  EC 2C FA FE 8F 2B FA FE 3E 2C FA FE FA 2D FA FE  ??>,?
0105F27E  05 08 FA FE 32 24 FA FE 6C 28 FA FE 76 03 FA FE  2$l(v
0105F28E  1F 1E FA FE BB 25 FA FE AB 06 FA FE E0 08 FA FE  ???
0105F29E  69 08 FA FE 86 1C FA FE 6E 19 FA FE 8F 2B FA FE  i?n?
0105F2AE  BB 25 FA FE E7 17 FA FE EC 26 FA FE E0 08 FA FE  ????
0105F2BE  56 2B FA FE EC 26 FA FE 34 0E FA FE 76 03 FA FE  V+?4v
0105F2CE  86 1C FA FE 90 06 FA FE 76 03 FA FE 34 0E FA FE  ??v4
0105F2DE  C2 17 FA FE E1 1C FA FE 76 03 FA FE 86 1C FA FE  ??v?
0105F2EE  34 0E FA FE 5A 2C FA FE FB 19 FA FE 3A 1B FA FE  4Z,?:
0105F2FE  31 00 FA FE BB 11 FA FE 05 08 FA FE 76 03 FA FE  1.?v
0105F30E  76 28 FA FE D1 1D FA FE C2 17 FA FE AB 06 FA FE  v(???
0105F31E  CA 1C FA FE 90 26 FA FE 7D 04 FA FE 96 11 FA FE  ??}?
0105F32E  E0 08 FA FE 3E 2C FA FE 5C 1D FA FE 90 06 FA FE  ?>,\?
0105F33E  3A 1B FA FE 55 0F FA FE 5A 2C FA FE AB 06 FA FE  :UZ,?
0105F34E  29 11 FA FE 76 28 FA FE E1 1C FA FE EC 26 FA FE  )v(??
0105F35E  32 24 FA FE 8F 2B FA FE E0 28 FA FE D7 11 FA FE  2$???
0105F36E  FA 2D FA FE CA 1C FA FE 34 0E FA FE 10 2A FA FE  ??4*
0105F37E  70 2D FA FE 03 1F FA FE C2 17 FA FE B7 18 FA FE  p-??
0105F38E  76 20 FA FE 5C 1D FA FE 2C 16 FA FE BB 11 FA FE  v \,?
0105F39E  34 0E FA FE DF 03 FA FE C2 17 FA FE 8F 2B FA FE  4???
0105F3AE  5C 1D FA FE 5A 2C FA FE E1 1C FA FE 77 1D FA FE  \Z,?w
0105F3BE  77 07 FA FE 76 20 FA FE 90 06 FA FE FB 19 FA FE  wv ??
0105F3CE  56 2B FA FE 55 0F FA FE EC 2C FA FE 96 11 FA FE  V+U??
0105F3DE  76 03 FA FE 76 03 FA FE 5A 2C FA FE 03 1F FA FE  vvZ,
0105F3EE  55 0F FA FE 31 00 FA FE FB 19 FA FE B7 18 FA FE  U1.??
0105F3FE  3E 2C FA FE 92 08 FA FE 34 0E FA FE A4 23 FA FE  >,?4?
0105F40E  86 1C FA FE AB 06 FA FE 3A 1B FA FE 3A 1B FA FE  ??::
0105F41E  E7 17 FA FE BB 11 FA FE E0 28 FA FE 23 2A FA FE  ???#*
0105F42E  1F 1E FA FE 31 00 FA FE 90 26 FA FE 5A 2C FA FE  1.?Z,
0105F43E  BB 25 FA FE 56 2B FA FE 10 2A FA FE 3A 1B FA FE  ?V+*:
0105F44E  E1 1C FA FE E0 08 FA FE 6C 28 FA FE 3E 2C FA FE  ??l(>,
0105F45E  FA 2D FA FE E7 06 FA FE 70 2D FA FE 03 1F FA FE  ??p-
0105F46E  90 06 FA FE 96 11 FA FE 6E 19 FA FE 75 2C FA FE  ??nu,
0105F47E  32 24 FA FE A4 23 FA FE BB 11 FA FE 6E 19 FA FE  2$??n
0105F48E  92 08 FA FE 6E 19 FA FE 7D 04 FA FE E7 17 FA FE  ?n}?
0105F49E  D1 1D FA FE 14 16 FA FE 10 2A FA FE 70 2D FA FE  ?*p-
0105F4AE  31 00 FA FE 3A 1B FA FE 2C 16 FA FE 32 24 FA FE  1.:,2$
0105F4BE  14 16 FA FE B7 18 FA FE 77 07 FA FE FB 19 FA FE  ?w?
0105F4CE  EC 26 FA FE 23 2A FA FE C2 17 FA FE E1 1C FA FE  ?#*??
0105F4DE  05 08 FA FE 70 2D FA FE 32 24 FA FE E7 17 FA FE  p-2$?
0105F4EE  D7 11 FA FE D1 1D FA FE BB 25 FA FE 76 03 FA FE  ???v
0105F4FE  BB 11 FA FE BB 11 FA FE 14 16 FA FE E7 06 FA FE  ???
0105F50E  31 00 FA FE 3E 2C FA FE 86 1C FA FE 90 06 FA FE  1.>,??
0105F51E  81 12 FA FE 43 2C FA FE 86 1C FA FE 05 08 FA FE  ?C,?
0105F52E  81 12 FA FE 43 2C FA FE BB 11 FA FE 5C 1D FA FE  ?C,?\
0105F53E  81 12 FA FE 43 2C FA FE 69 08 FA FE 70 2D FA FE  ?C,ip-
0105F54E  81 12 FA FE 43 2C FA FE 92 08 FA FE 5A 2C FA FE  ?C,?Z,
0105F55E  81 12 FA FE 43 2C FA FE E1 1C FA FE AB 06 FA FE  ?C,??
0105F56E  81 12 FA FE 43 2C FA FE EC 2C FA FE 86 1C FA FE  ?C,??
0105F57E  81 12 FA FE 43 2C FA FE A4 23 FA FE 3E 2C FA FE  ?C,?>,
0105F58E  81 12 FA FE 43 2C FA FE 7D 04 FA FE 75 2C FA FE  ?C,}u,
0105F59E  81 12 FA FE 43 2C FA FE A4 23 FA FE E0 28 FA FE  ?C,??
0105F5AE  81 12 FA FE 43 2C FA FE 55 0F FA FE AB 06 FA FE  ?C,U?
0105F5BE  81 12 FA FE 43 2C FA FE 14 16 FA FE 31 00 FA FE  ?C,1.
0105F5CE  81 12 FA FE 43 2C FA FE 6C 28 FA FE 92 08 FA FE  ?C,l(?
0105F5DE  81 12 FA FE 43 2C FA FE 8F 2B FA FE 90 26 FA FE  ?C,??
0105F5EE  81 12 FA FE 43 2C FA FE EC 26 FA FE AD 0F FA FE  ?C,??
0105F5FE  81 12 FA FE 43 2C FA FE FB 19 FA FE C2 17 FA FE  ?C,??

   至于这张表为什么要有重复的入口地址,我认为可以让不同的虚拟字节码实现同样的功能,
一条实际的指令对应多个字节码,增加了字节码的多样性,目的就是让你的头更大!还有个原因就是凑字数吧,以前写作文不就是这样干的吗?

   归根到底有多少虚拟指令,只要去掉重复的就可以了,化简后的上面那张表就只有56条。

   你要问我怎么找到这个表地址的,答案很简单。在OEP处一直F7就OK了,顶多1分钟吧!
如果你人又懒,水平又高,可以用下面个函数,写个OD插件:
OllyDbg._Readcommand
OllyDbg._Disasm
    从OEP处读一条指令,反汇编一条,周而复始,找到下面这个地方就可以停下来了。先提取出表地址,再从0x400字节中提取出不重复的地址。

0105E4AF    8B1485 0EF20501 mov     edx, dword ptr [eax*4+105F20E] //105F20E 表地址
0105E4B6    F9              stc
0105E4B7    F7DA            neg     edx  
0105E4B9    F9              stc
0105E4BA    F5              cmc
0105E4BB    81C2 00000000   add     edx, 0   
0105E4C1  ^ E9 33FBFFFF     jmp     0105DFF9

    有了这张表,你就可以做一张指令查找表了。前面举例已经讲了第一条,再讲简化表的最后一条,让你彻底搞懂。
AD 0F FA FE 对应0xFEFA0FAD,NEG一下就是0x0105F053,到那里提取出有效指令如下:
0105FA9B    8B45 00         mov     eax, dword ptr [ebp]
0105E706    8B00            mov     eax, dword ptr [eax]
0106013B    8945 00         mov     dword ptr [ebp], eax
    前人取了名字VM_READdw_MEMdw,感觉还要适应!依次类推,做个虚拟指令查找表。

2、如何反汇编虚拟机字节码?

    假如VEIP(esi=010375AC),也就是指向下面7个字节的尾部字节,这个记事本例子中esi是逐渐变小的。

//B1就是010375AC处的虚拟机字节码                   
010375A6  9C A3 36 12 DB B0 B1   

  超级大牛hkfans的VMP插件可以从该处反汇编得到:
010375AC    C9                        pop       r14 
010375AB    58 C0C49CBB       push      BB9CC4C0         
010375A6    40                         add       dword   
    它是怎么来的?

   我们从OD中可以提取到以下有效指令,显示了从B1变为C9的全过程,上一条虚拟指令地址参与了计算。
0105E1B4    30D8            xor     al, bl //al=B1  ebx=010375AD (上一条虚拟指令地址)
0105DA77    FEC8            dec     al     // al=1c-1=1b
0105DD64    D0C0            rol     al, 1  //al=36
0105DD6E    F6D0            not     al     //al=c9
0105E49C    0FB6C0          movzx   eax, al  //eax=000000C9

现在得到:010375AC    C9   
根据计算公式求出虚拟指令入口地址如下: 
0105E4AF    8B1485 0EF20501 mov     edx, dword ptr [eax*4+105F20E] //105F20E 表地址
0105E4B7    F7DA            neg     edx  
虚拟指令入口地址edx=neg([c9*4+105F20E]) =neg(FEFA2C43)=0x0105D3BD
有了这个入口地址,再查一下事先做好的指令表就可以得到虚拟机的汇编指令了。

   这里我们到0105D3BD处提取出有效指令如下:
0105DC99    F6D8            neg     al  //neg(c9)=37
0105DC9D    FEC0            inc     al  //al=38
0105DCA8    24 3C           and     al, 3C  //al=38
0105DCB3    8B55 00         mov     edx, dword ptr [ebp] //虚拟机退栈
01060092    83C5 04         add     ebp, 4
01060096    891438          mov     dword ptr [eax+edi], edx //al=38  保存到虚拟机的寄存器r14中

这里al=0x38  0x38/4=0xe 即保存到r14中,注意r0是第一个虚拟寄存器。
显然我们可以用pop r14来表示上面的操作。
这样反汇编010375AC处的字节码可以得到:
010375AC    C9     pop       r14 

    周而复始,依次类推,反汇编的原理我就只能猜出这么多了,如果你是编程高手,应该可以知道怎么做VMP调试插件了吧?

   至于单步,F4等功能,我想可能在异常处理循环中,判断esi的值,根据断点地址(想要断下时的esi值),可以在那个地方下个内存断点,当虚拟机访问那里取字节码时就可以断下。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值