彩票走势图

代码保护软件VMP逆向分析虚拟机指令:分析VMP的一些细节

转帖|使用教程|编辑:杨鹏连|2021-06-30 09:25:48.143|阅读 669 次

概述:​看了网上大神们写了好多的vmp 虚拟代码的分析 ,但是在对实在项目时,插件总是提示不对或者未知版本,一直对vm代码的还原有质疑,于是就萌发了具体分析这个vm代码是怎么回事,若有错误,欢迎指出,能力有限只能分析皮毛,只谈vm的代码。

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

VMProtect是一种很可靠的工具,可以保护应用程序代码免受分析和破解,但只有在应用程序内保护机制正确构建且没有可能破坏整个保护的严重错误的情况下,才能实现最好的效果。

VMProtect通过在具有非标准体系结构的虚拟机上执行代码来保护代码,这将使分析和破解软件变得十分困难。除此之外,VMProtect还可以生成和验证序列号,限制免费升级等等。

下载VMProtect最新试用版

VMProtect正版授权在线订购享受最低价,仅售801元起!还不赶紧加入你的订购清单?>>更多详情可点击咨询购买

相关链接:

代码保护软件VMP逆向分析虚拟机指令:初步认识与环境搭建(一)

代码保护软件VMP逆向分析虚拟机指令:VMP代码的提取(二)

代码保护软件VMP逆向分析虚拟机指令详细分析(三)

代码保护软件VMP逆向分析虚拟机指令:分析那4条汇编被VM的VM指令

五、分析VM的一些细节

我们差不多讲完基础分析是吧,基本上可以说是可以动手分析了,但是在那之前我们有些东西好像还没讲清楚,一些细节。

1、VM的栈问题

有个地方我们还没讲 ,就是如果压栈时 , 如果超出了栈大小 (就目前我们看到的还没有超栈的情况),占用到了vm_context怎么办下面是我截取的汇编, 所以你看到地址有时候很奇怪 。我们来分析一下如果压栈超出了栈空间怎么办

00433391    8D4424 60       lea eax,dword ptr ss:[esp+0x60]
00433395    F6C5 65         test ch,0x65
00433398    3BC9            cmp ecx,ecx
0043339A    66:81FD EA79    cmp bp,0x79EA
0043339F    3BE8            cmp ebp,eax
004333A1    E9 0F3A0000     jmp vmptest_.00436DB5
00436DB5   /0F87 F2C80200   ja vmptest_.004636AD ;看到这里我们之前都是跳了 我们追踪代码
00436DBB   |8BC4            mov eax,esp          ;的时候下面的代码就被跳过了,直接到了
00436DBD   |8ACB            mov cl,bl            ;vmtest_.004636AD 接下来我们重点讲没跳
00436DBF   |B9 40000000     mov ecx,0x40         ;过的这部分代码
00436DC4   |0FC0F6          xadd dh,dh
00436DC7   |8D5425 80       lea edx,dword ptr ss:[ebp-0x80]
00436DCB   |3BFF            cmp edi,edi
00436DCD  ^|E9 101CFEFF     jmp vmptest_.004189E2
004189E2    81E2 FCFFFFFF   and edx,0xFFFFFFFC
004189E8    F9              stc
004189E9    66:F7C7 8465    test di,0x6584
004189EE    2BD1            sub edx,ecx
004189F0  ^ E9 38D1FFFF     jmp vmptest_.00415B2D
00415B2D    8BE2            mov esp,edx
00415B2F    57              push edi
00415B30    66:BF CD59      mov di,0x59CD
00415B34    0FBFF8          movsx edi,ax
00415B37    E9 FA590400     jmp vmptest_.0045B536
0045B536    56              push esi
0045B537  ^ E9 058AFEFF     jmp vmptest_.00443F41
00443F41    9C              pushfd
00443F42    66:0FCE         bswap si
00443F45    8BF0            mov esi,eax
00443F47    66:0F46FB       cmovbe di,bx
00443F4B    8BFA            mov edi,edx
00443F4D    E9 490E0400     jmp vmptest_.00484D9B
00484D9B    FC              cld
00484D9C  ^ E9 9513F9FF     jmp vmptest_.00416136
00416136    F3:A4           rep movs byte ptr es:[edi],byte ptr ds:[esi]
00416138    C1E6 B0         shl esi,0xB0
0041613B    C1C7 FA         rol edi,0xFA
0041613E    66:0FBAFF 16    btc di,0x16
00416143    9D              popfd
00416144    5E              pop esi
00416145    66:0FCF         bswap di
00416148    8BFB            mov edi,ebx
0041614A    5F              pop edi
0041614B    E9 5DD50400     jmp vmptest_.004636AD
004636AD    FFE7            jmp edi
我们先去混淆一下看看,按之前的方法
00433391    8D4424 60       lea eax,dword ptr ss:[esp+0x60]
0043339F    3BE8            cmp ebp,eax                     ;比较栈顶 与vm_context末尾位置
00436DB5   /0F87 F2C80200   ja vmptest_.004636AD            ;如果栈顶 大于 vm_context最末尾位置 证明栈还没有顶到vm_context
00436DBB   |8BC4            mov eax,esp                     ;eax记录一下vm_context位置
00436DBF   |B9 40000000     mov ecx,0x40
00436DC7   |8D5425 80       lea edx,dword ptr ss:[ebp-0x80]
004189E2    81E2 FCFFFFFF   and edx,0xFFFFFFFC              ;让后2位为0 地址对齐
004189EE    2BD1            sub edx,ecx                     ;其实就是栈顶 -0xC0
00415B2D    8BE2            mov esp,edx                     ;把vm_context 与栈底 拉高0xC0个字节 主要是栈底不动 vm_context动
00415B2F    57              push edi                        ;这一方面也是看出来为什么每次都要和esp+0x60比较
0045B536    56              push esi                        -------------------------------------
00443F41    9C              pushfd                          ;备份 edi 、esi、和eflags值
00443F45    8BF0            mov esi,eax
00443F4B    8BFA            mov edi,edx
00416136    F3:A4           rep movs byte ptr es:[edi],byte ptr ds:[esi] ;然后把旧vm_context线上值 拷贝到新vm_context上
00416143    9D              popfd                           ---------------------------------------
00416144    5E              pop esi                         ;还原 edi、esi、和eflags值
0041614A    5F              pop edi                         
004636AD    FFE7            jmp edi
然后你发现了什么问题, 在最后的rep movs中, 我们是拷贝byte为单位, 拷贝的长度是由ecx决定的,但是ecx=0x40, 而我们之前很早之前说 esp+0x60我们推出寄存器有 0x60/4=0x18 个, 芜湖!!!!!!!那么我们现在怎么解释呢? 这里我们应该可以看出来 vm_context应该只有16个寄存器。 即0x10个寄存器而多出来的 0x20个byte(8 int32) 应该是给压栈时缓冲用的, 比如像这里他是先压栈, 在判断栈是否报栈了 ,那么如果爆栈了, 假如vm_context是0x18个寄存器, 他就会覆盖到第0x17编号寄存器,那么他就没办法回缩 还原vm_context上被感染的寄存器值(如果要能还原 带价太大) 所以这里多出的8 int32 应该是缓冲用的。

所以说分析问题 往往都是 ,从假设开始 ,你之前看到的可能 会被后面的又重新定义 ,然后你会发现
你之前的好像不太严谨 ,往后看这个就严谨了 ,好像一切 就 豁然开朗了。

2、寄存器轮转机制

VM_PushImm32 0x00002222         ;执行下面的VM_Add后  | dwResult 0x00005555
VM_PushReg32 vm_context->0x00   ;0x00003333          | eflags   0x00000206
VM_Add
VM_PopReg32  vm_context->0x1C   ;0x00000206 EFLAGS
VM_PopReg32  vm_context->0x1C   ;0x00005555
VM_PushImm32 0x00001010
VM_PushReg32 vm_context->0x1C   ;0x00005555 dwResult 上一次Add的结果
VM_PushReg32 vm_context->0x1C   ;0x00005555
VM_Nand                         ;执行后 [ESP] = EFLAGS = 0x286  [ESP+4]=0xFFFFAAAA
VM_PopReg32  vm_context->0x00   ;0x286 弹出这个后 现在栈上应该是[ESP]=0xFFFFAAAA [ESP+4]=0x0x00001010
VM_Add                          ;执行这个这里后  [ESP] = EFLAGS = 0x282    [ESP+4]=0xFFFFBABA
VM_PopReg32  vm_context->0x0C   ;0x282 eflags
VM_PushReg32 vm_esp             ;现在[ESP] = ESP+4 即保存这个地址 这个地址对应的值是 0xFFFFBABA 没问题吧
VM_SSReadMemSS                  ;把栈顶的值当mem读 值返回到自身 [ESP]=[[ESP]] = [ESP + 4] = 0xFFFFBABA
VM_Nand                         ;还没运行这个指令时[ESP]=0xFFFFBABA [ESP+4]=0xFFFFBABA
VM_PopReg32  vm_context->0x20   ;0x202  eflags
VM_PopReg32  vm_context->0x10   ;0x00004545  到这里 可以说这4句汇编已经运行完毕了
我们可以看到 0x2222 + 0x3333 = 0x5555 如果按我们的那4句汇编来的话, 这个0x5555应该是在eax寄存器上,如果说vm_context 的某个偏移值与我们物理机的寄存器是绝对对应关系的话, 那么往下走得到的最终结果应该也是在 0x5555所在的这个寄存器上即 vm_context->0x1C, 但是我们发现不是了, 而是vm_context + 0x10上。这就是VMP所谓的寄存器轮转机制, 这个轮转是在程序编译期间有一张表, 所以现在你是无法看到这个对应关系的转变。

3、同一条指令的不同比较

-------------------------------------------------------------------------------------------
VM_PushReg32  vm_context->0x1C                      VM_PushReg32  vm_context->0x1C     
/------------------------------------------------------------------------------------------
0042E1A7  LEA ESI,DWORD PTR DS:[ESI-1]              0043B877  SUB ESI,1                  
0042E1AD  MOVZX EAX,BYTE PTR DS:[ESI]              0043B87D  ROL EAX,CL                  
0042E1B0  SHR DX,CL                                0043B87F  MOVSX ECX,DX                
0042E1B3  MOVZX EDX,BX                             0043B882  MOVZX EAX,BYTE PTR DS:[ESI] 
0042E1B6  CDQ                                      0043B885  BTC CX,BX                    
0042E1B7  XOR AL,BL                                0043B889  BTS ECX,EBX
0042E1B9  ADD ECX,605116AB                         0043B88C  OR DH,64
0042E1BF  CMP DH,87                                0043B88F  XOR AL,BL                    
0042E1C2  ADD AL,19                                0043B891  ADD AL,19                    
0042E1C4  ROR AL,1                                 0043B893  MOVZX CX,DH                  
0042E1C6  CMOVNB EDX,ESI                           0043B897  ROR AL,1                    
0042E1C9  XCHG CX,DX                               0043B899  JMP vmptest_.0045256F
0042E1CC  MOV EDX,EBP                              0045256F  INC AL                     
0042E1CE  INC AL                                   00452571  XOR AL,49                    
0042E1D0  AND DX,53E2                              00452573  ROR DH,CL
0042E1D5  XOR AL,49                                00452575  XOR BL,AL                    
0042E1D7  BSF CX,BX                                00452577  MOVSX EDX,SP                
0042E1DB  SBB ECX,EBP                              0045257A  BTR ECX,ESP                  
0042E1DD  XOR BL,AL                                0045257D  SUB EDX,1D2A7287            
0042E1DF  SAR DX,CL                                00452583  MOV EDX,DWORD PTR SS:[ESP+EAX]
0042E1E2  MOV EDX,DWORD PTR SS:[ESP+EA             00452586  NOT ECX                      
0042E1E5  MOV CL,1A                                00452588  LEA EDI,DWORD PTR DS:[EDI-4]  
0042E1E7  RCR CH,CL                                0045258E  MOV DWORD PTR DS:[EDI],EDX
0042E1E9  MOVSX ECX,CX                             00452590  SUB ESI,4                    
0042E1EC  LEA EDI,DWORD PTR DS:[EDI-4]             00452596  DEC CX                        
0042E1F2  MOV DWORD PTR DS:[EDI],EDX               00452599  JMP vmptest_.00410D3E
0042E1F4  XOR CH,0A4                               00410D3E  MOV ECX,DWORD PTR DS:[ESI]    
0042E1F7  BTS ECX,EBX                              00410D40  CMC
0042E1FA  SUB ESI,4                                00410D41  STC
0042E200  MOV ECX,DWORD PTR DS:[ESI]               00410D42  CLC
0042E202  STC                                      00410D43  XOR ECX,EBX                  
0042E203  TEST DH,DH                               00410D45  CMP EDI,ESP
0042E205  XOR ECX,EBX                              00410D47  NOT ECX                      
0042E207  CLC                                      00410D49  CMP DL,0F7
0042E208  CMC                                      00410D4C  STC
0042E209  NOT ECX                                  00410D4D  ADD ECX,1B2352AE              
0042E20B  CLC                                      00410D53  BSWAP ECX                    
0042E20C  ADD ECX,1B2352AE                         00410D55  TEST ESP,4D941F4C
0042E212  CMC                                      00410D5B  XOR ECX,26A7DD4              
0042E213  CLC                                      00410D61  STC
0042E214  BSWAP ECX                                00410D62  XOR EBX,ECX                  
0042E216  TEST EDI,EDI                             00410D64  CLC
0042E218  STC                                      00410D65  CMP BP,11E1
0042E219  XOR ECX,26A7DD4                          00410D6A  CMC
0042E21F  CMP CX,BX                                00410D6B  ADD EBP,ECX                  
0042E222  XOR EBX,ECX                              00410D6D  JMP vmptest_.0047F0F3
0042E224  STC                                      0047F0F3  JMP vmptest_.00472E41
0042E225  TEST ECX,ESI                             00472E41  LEA EDX,DWORD PTR SS:[ESP+60]
0042E227  ADD EBP,ECX                              00472E45  TEST DH,AL
0042E229  JMP vmptest_.00409E73                    00472E47  CLC
00409E73  JMP vmptest_.00472E41                    00472E48  CMP EDI,EDX
00472E41  LEA EDX,DWORD PTR SS:[ESP+60]            00472E4A  JMP vmptest_.0046EE86
00472E45  TEST DH,AL                               0046EE86  JA vmptest_.00480A05
00472E47  CLC                                      00480A05  JMP EBP
00472E48  CMP EDI,EDX
00472E4A  JMP vmptest_.0046EE86
0046EE86  JA vmptest_.00480A05
00480A05  JMP EBP
\---------------------------------------------------------------------------------
指令与压哪个寄存器无关,我这里只是恰巧找了两个压了相同VM寄存器的。 你看他们的主要代码是不是一样的, 去混淆一下, 就发现是一模一样的, 解密都一样,不过可能存在乱序(在不影响经结果的情况下), 而每次vmp加壳同一个程序这些同vm指令解密都不一样。去混淆我就不去了, 很简单 1-2min的事情 从vm的环境去提取关键汇编就可以了。不过我相信现在你用肉眼就已经看出来了。那么我们上面分析的东西材料我都放在demo文件夹下了。

六、简单总结一下过程
总结就是 :
1.VM_Entry 进入虚拟机
2.VM_Init 物理环境映射虚拟机
3.VM_Init_bytescode vm的代码解析环境初始化
4.执行VM的代码
5.VM_Destroy 虚拟机环境压栈
6.VM_Exit 物理环境从栈上弹出

在整个过程中我们并没有看到有一个大循环, 心脏去驱动 去取指令, 然后解析指令是吧。 这个就是vmp3与vmp1和vmp2的最大区别,解析bytescode不在由VMDispatcher 分发下一个指令执行什么了(每个指令记为一个handle) 而是有vm_bytescode掌管,执行上一个指令才能得到下一个指令地址 这样一来代码的膨胀可想而知。在VM_Instruct内部应该是没有CALL指令的。

如果您对该加密/解密软件感兴趣,欢迎加入vmpQQ交流群:740060302


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn

文章转载自:

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP