转帖|使用教程|编辑:杨鹏连|2021-06-22 10:00:51.233|阅读 373 次
概述:看了网上大神们写了好多的vmp 虚拟代码的分析 ,但是在对实在项目时,插件总是提示不对或者未知版本,一直对vm代码的还原有质疑,于是就萌发了具体分析这个vm代码是怎么回事,若有错误,欢迎指出,能力有限只能分析皮毛,只谈vm的代码。
# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>
VMProtect是一种很可靠的工具,可以保护应用程序代码免受分析和破解,但只有在应用程序内保护机制正确构建且没有可能破坏整个保护的严重错误的情况下,才能实现最好的效果。
VMProtect通过在具有非标准体系结构的虚拟机上执行代码来保护代码,这将使分析和破解软件变得十分困难。除此之外,VMProtect还可以生成和验证序列号,限制免费升级等等。
VMProtect正版授权在线订购享受最低价,仅售801元起!还不赶紧加入你的订购清单?>>更多详情可点击咨询购买
相关链接:
三、详细分析
我们先分析一下头和尾,那我们怎么知道哪里才是一个VM指令的开始和结束呢?记得jmp reg 和 push + ret 没,我们就由这两个去确定一个VM指令的范围
VM_Entry ---------------------------------------------------------------- 0044A580 Main PUSH 83819110 ; Key 你可以看做一个密文经过解密 压栈1 Key 0044A585 Main CALL vmptest_.0042FA52 ; Key 经过解密后就是bytescode 压找2 压返回地址 0042FA52 Main PUSH EDX ; 压栈3 EDX 0042FA53 Main JMP vmptest_.0042BF92 0042BF92 Main PUSHFD ; 压栈4 eflags符号寄存器 0042BF93 Main TEST CX,SI 0042BF96 Main CMC 0042BF97 Main PUSH ECX ; 压栈5 ECX 0042BF98 Main SHLD CX,SI,0BA 0042BF9D Main ADD CL,97 ; ECX=00000097 0042BFA0 Main PUSH EBX ; 压栈6 EBX 0042BFA1 Main MOV CL,DL ; ECX=00000008 0042BFA3 Main SHR EBX,CL ; EBX=007FFDF0 0042BFA5 Main PUSH EBP ; 压栈7 EBP 0042BFA6 Main PUSH ESI ; 压栈8 ESI 0042BFA7 Main PUSH EAX ; 压栈9 EAX 0042BFA8 Main PUSH EDI ; 压栈10 EDI 0042BFA9 Main ADD ECX,173475C8 ; ECX=173475D0 0042BFAF Main MOV EAX,0 0042BFB4 Main XOR ESI,239C226E ; ESI=239C226E 0042BFBA Main PUSH EAX ; 压栈11 0x00000000 0042BFBB Main SETLE BH ; EBX=007F00F0 0042BFBE Main MOV ESI,DWORD PTR SS:[ESP+28] ; ESI=83819110 取ESP+0x28地址的值 0x28/4= 10 往上数第10个 0042BFC2 Main LEA ESI,DWORD PTR DS:[ESI+D093E2F1] ; ESI=54157401 从0开始数 你看看是不是取到了Key的值 注意 0042BFC8 Main NEG ESI ; ESI=ABEA8BFF 注意这个 [ESP + 0x28]这个特征 现在赋值给ESI 0042BFCA Main BTS BP,BX ; EBP=0012FF95 0042BFCE Main JMP vmptest_.00430A03 00430A03 Main ROR ESI,1 ; ESI=D5F545FF 00430A05 Main INC ESI ; ESI=D5F54600 00430A06 Main ADD EBP,64941F8C ; EBP=64A71F21 00430A0C Main ADC CX,SP ; ECX=17347530 00430A0F Main BTR EDI,73 00430A13 Main BSWAP ESI ; ESI=0046F5D5 00430A15 Main CMOVPE EBX,ESI ; EBX=0046F5D5 00430A18 Main BTC BP,8C ; EBP=64A70F21 00430A1D Main ADD ESI,EAX 00430A1F Main MOV EBP,ESP ; EBP=0012FF60 ;注意这里EBP的赋值 记住这里现在ebp是上面压的栈顶 00430A21 Main SUB ESP,0C0 ; 和这里esp的开栈 其实这里是给vm_context开空间 00430A27 Main MOV EBX,ESI ;和给vm_ss开空间 00430A29 Main MOV ECX,0 ; ECX=00000000 ;注意这里有个mov ebx,esi 解密因子 我接下来就不 00430A2E Main OR EDI,EBP ; EDI=0012FF60 ;会去多提他 如果你要运行程序你就要注意他 这个解密因子 往上看是不是Key解密而来的 00430A30 Main SUB EBX,ECX ;分析好几个vm 分析ebx一直指向这个vm_decryptfactor 00430A32 Main ROL CX,CL ;我不知道这样叫他对不对 不过这不是重点 00430A35 Main LEA EDI,DWORD PTR DS:[430A35] ; EDI=00430A35 ;知道他是干什么的就可以了 00430A3B Main SUB CX,SI ; ECX=00000A2B ;看到这里的LEA 本身这个指令上一个地址 没错他就是vm_JumpBase 相对谁去跳到下一个地址 肯定是当前 00430A3E Main OR CL,0D5 ; ECX=00000AFF 00430A41 Main ROL CX,23 ; ECX=000057F8 00430A45 Main MOV ECX,DWORD PTR DS:[ESI] ; ECX=B0D37F60 ;到这里 经过解密之后ESI才是真正的vm_bytescode 00430A47 Main ADD ESI,4 ; ESI=0046F5D9 ;你或者叫他(ESI)为跳转间隔 好像也没什么错 00430A4D Main TEST EDI,EBX ; 取值后 ESI +=4 往后移 00430A4F Main XOR ECX,EBX ; ECX=B0958AB5 00430A51 Main JMP vmptest_.00439FEC 00439FEC Main LEA ECX,DWORD PTR DS:[ECX+DEFE95D9] ; ECX=8F94208E 00439FF2 Main CMP AX,25AD 00439FF6 Main TEST BH,90 00439FF9 Main NOT ECX ; ECX=706BDF71 00439FFB Main TEST AL,DL 00439FFD Main CMC 00439FFE Main CMP SP,7CB8 0043A003 Main NEG ECX ; ECX=8F94208F 0043A005 Main LEA ECX,DWORD PTR DS:[ECX+A504E271] ; ECX=34990300 0043A00B Main JMP vmptest_.00416562 00416562 Main BSWAP ECX ; ECX=00039934 00416564 Main XOR EBX,ECX ; EBX=00456CE1 00416566 Main CMP SI,130B 0041656B Main ADD EDI,ECX ; EDI=0046A369 ;上面说到了取bytescode链上的值 0041656D Main JMP vmptest_.0045F2B5 ; 经过解密后 与JumpBase相加得到下一个指令的地址 0045F2B5 Main PUSH EDI ; 然后把这个地址压栈 RET反弹给物理机EIP 0045F2B6 Main RETN ;或者这里你可能也会遇到jmp edi 他们是一样的功能
上面这个我们没有去混淆,我们直接分析了。那么肯定是有技巧的是吧,从上往下看,push 和pushfd肯定要保留,这个是重要的,然后从下往上分析,EDI是重要的,然后看到谁影响了EDI一直这样往上找去,有关的提取出来。另外关于ESP寄存器的要保留下来,主要是ESP减0xC0这个开VM栈空间和VM_REG空间,还有ESP在减0xC0之前把值给了谁,谁就是VM_ESP即vm栈顶(栈底),当然给的这个寄存器不在传递给其他寄存器的话才行,但目前我并没有遇到还在传递的情况。我们是看了开始,我们在看看紧跟着的VM指令:
VM_PopReg32 vm_context->0x10 --------------------------------------------------------------------------------------------- 0046A369 Main MOV EAX,DWORD PTR SS:[EBP] ;返回上面看看我们说EBP是上面压的物理环境的栈顶 0046A36D Main STC ; 0046A36E Main ROR DL,CL ; EDX=00401080 0046A370 Main LEA EBP,DWORD PTR SS:[EBP+4] ; EBP=0012FF64 ;这里EBP = EBP + 4 栈回缩是不 那不就是出栈的意思 0046A376 Main MOVZX EDX,BYTE PTR DS:[ESI] ; EDX=0000008D ;注意这种取1byte的指令类似这个 0046A379 Main CMP CX,BP 0046A37C Main ADD ESI,1 ; ESI=0046F5DA ;ESI+1 刚刚说了esi是bytescode 他也保存了寄存器 0046A382 Main CMP CX,4F65 ;编号 我们不是之前叫他跳转间隔吗 噢见鬼了 0046A387 Main CMP ECX,EBX ;反正我们知道他有这样的能力就可以 这里ESI+=1 0046A389 Main XOR DL,BL ; EDX=0000006C ;有可能他不是正向走 可能是-1 那上面的也对应-4 0046A38B Main TEST DI,5D07 ;这没什么好争论的不是吗 具体看汇编就出来了 0046A390 Main STC ;为什么会这么说 是以为我之前有遇到是反向增长 0046A391 Main NOT DL ; EDX=00000093 ;看到上面的 xor dl,bl 记得我说的EBX是解密因子了没 0046A393 Main CMP DI,2768 0046A398 Main JMP vmptest_.0043EDAF 0043EDAF Main SUB DL,8B ; EDX=00000008 0043EDB2 Main CMC 0043EDB3 Main ROR DL,1 ; EDX=00000004 0043EDB5 Main DEC DL ; EDX=00000003 0043EDB7 Main JMP vmptest_.00413DC1 00413DC1 Main NOT DL ; EDX=000000FC 00413DC3 Main CMP SP,6B29 00413DC8 Main JMP vmptest_.00416D48 00416D48 Main ADD DL,14 ; EDX=00000010 00416D4B Main STC 00416D4C Main XOR BL,DL ; EBX=00456CF1;而这里我们主要关心EDX的值不是吗 这里是0x10 00416D4E Main MOV DWORD PTR SS:[ESP+EDX],EAX ; 发现EDX是从上面去esi地址1byte值经过变化而来的 00416D51 Main AND DH,0F7 ; 而我们之前说的什么ESP指向的是vm_context是吧 00416D54 Main NEG DX ; EDX=0000FFF0;在结合我们上面的分析 这应该是一个出栈的操作 00416D57 Main MOV EDX,DWORD PTR DS:[ESI] ; EDX=E45184BF;在次取ESI (bytescode)的值 关键 这个是跳转间隔密文 00416D59 Main CMP ESI,EDI 00416D5B Main CMC 00416D5C Main JMP vmptest_.00419F08 00419F08 Main ADD ESI,4 ; ESI=0046F5DE;ESI += 4 00419F0E Main STC 00419F0F Main XOR EDX,EBX ; EDX=E414E84E 00419F11 Main TEST DH,36 00419F14 Main XOR EDX,29474E33 ; EDX=CD53A67D 00419F1A Main TEST ESP,EDX 00419F1C Main ADD EDX,64682765 ; EDX=31BBCDE2 00419F22 Main JMP vmptest_.00472890 00472890 Main NEG EDX ; EDX=CE44321E 00472892 Main TEST SI,BX 00472895 Main STC 00472896 Main ADD EDX,44017C67 ; EDX=1245AE85 0047289C Main JMP vmptest_.00463068 00463068 Main ROR EDX,1 ; EDX=8922D742 0046306A Main CMP CX,DI 0046306D Main STC 0046306E Main CMP DI,358A 00463073 Main NEG EDX ; EDX=76DD28BE 00463075 Main JMP vmptest_.0047F903 0047F903 Main BSWAP EDX ; EDX=BE28DD76 0047F905 Main INC EDX ; EDX=BE28DD77 0047F906 Main STC 0047F907 Main XOR EDX,41D507D0 ; EDX=FFFDDAA7 0047F90D Main XOR EBX,EDX ; EBX=FFB8B656;注意这里解密因子 ebx 改变 每一个vm指令都有这个 0047F90F Main CMP SP,BP 0047F912 Main TEST EDX,29E10AB5 ;解密因子的参与 接下来我就不多提他了 记得每个指令都有 0047F918 Main STC ;而且每运行一个vm指令 他都会变 0047F919 Main ADD EDI,EDX ; EDI=00447E10;跳转间隔经过解密后 与JumpBase相加 0047F91B Main JMP vmptest_.00420B9F 00420B9F Main PUSH EDI 00420BA0 Main RETN ;跳转到下一条指令地址 -------------------------------------------------------------------------------------------------然后针对VM指令非入口和出口的分析,也有方法,当然可能这些方法这是适用我们当前遇到的指令(即目前这个demo)。看到第一条指令是取VM_ESP位置的uint32_t值 ,然后VM_ESP回缩4byte,第一反应就是这个应该是pop操作,在往下看看,能不能看到MOV [ESP + REG1],REG2 这个样子的汇编,OK能找到,那么明显就是栈中弹数据到VM_REG中了。在往下看是取VM_Bytescode中的值然后解密与VM_JumpBase相加。无疑是VM_PopReg32了,但是那个寄存器呢?看到
00416D4E Main MOV DWORD PTR SS:[ESP+EDX],EAX ;往上看到EDX的值 看右边的追踪结果 EDX=0x10所以我们这里应该翻译为VM_PopReg32 vm_context->0x10 或者 VM_PopReg32 DwReg4 (0x10/4=4) 可能名字和别人不一样,差不多就是这个意思。注意看看这个EDX的值也是从VM_Bytescode中得到解密出来的。然后紧跟着的几条重要的VM指令我就不一一分析了,和上面是同理的,我直接贴分析出的VM指令
[---------VM_Init--------] 这里我们可以又把这几条vm指令解释为VM_Init 主要是把物理环境反弹到虚拟机里面 /---------------------------------------------------------------------- VM_PopReg32 vm_context->0x10 0x00000000 VM_PopReg32 vm_context->0x2C VM_PopReg32 vm_context->0x18 VM_PopReg32 vm_context->0x28 VM_PopReg32 vm_context->0x20 0x0012FF94 VM_PopReg32 vm_context->0x08 0x7FFDF000 VM_PopReg32 vm_context->0x24 0x00000000 VM_PopReg32 vm_context->0x3C 0x00000246 VM_PopReg32 vm_context->0x30 0x00401008 VM_PopReg32 vm_context->0x14 0x0044A58A 那我们很早之前说的上面压栈是保存物理机环境就不太对了 VM_PopReg32 vm_context->0x0C 0x83819110 应该说是 物理机环境映射到虚拟机的一个过渡 \-------------------------------------------------------------------------把物理环境弹入VM寄存器环境后,重新调整vm_bytescode的指向和之前的VM_REG乱序,就比如上面这个vm_context->0x14是push + call 中call的下一个地址 ,经过调整后vm_context->0x14也就不是这个地址了(这个地址并不是退出VM后仅跟着的执行真实汇编的地址),再比如EBP是vm_bytescode,变换后EBP可能就不是了,可能是EBX或者EAX等。我就不贴代码了,之后会有整理。
VM_Exit /------------------------------------------------------------------------------ 0047A839 Main MOV ESP,EDI ;虚拟机栈给物理机esp栈 没错了这里应该是要 0047A83B Main OR AX,CX ; EAX=0000EFEA;返回物理机了 0047A83E Main POP ECX ; ECX=00000000;弹栈 ECX 0047A83F Main ROR DX,CL ;看到这么多pop 看来是真的要还原到物理机了 0047A842 Main CMP DH,DL ;在看看我们的进度条 也到底了 终于分析完了 0047A844 Main POP EBP ; EBP=0012FF94;弹栈 EBP 0047A845 Main POP EAX ; EAX=00004545;弹栈 EAX 0047A846 Main POP EBX ; EBX=7FFDF000;弹栈 EBX 0047A847 Main OR DI,73E7 ; EDI=0012FFEF 0047A84C Main ADC DI,6287 ; EDI=00126276 0047A851 Main CMOVO SI,DI 0047A855 Main POP EDI ; EDI=00000000;弹栈 EDI 0047A856 Main CWD ; EDX=00120000 0047A858 Main POPFD ;弹栈 EFLAGS 符号寄存器 0047A859 Main POP ESI ; ESI=00000000;弹栈 ESI 0047A85A Main POP EDX ; EDX=00401008;弹栈 EDX 0047A85B Main RETN ;返回物理机 Breakpoint at vmptest_.00401040 00401040 Main PUSH EAX ; <%04X> = 4545 返回物理机第一条汇编 Run trace closed我们可以看到ESP寄存器的值被EDI赋值了,然后从栈中弹出值到物理机(真实环境)的寄存器中。那么这个EDI应该是被安排了真实环境的值,很可能他就是VM_ESP是吧。我们在往上分析一下看看,我直接贴关键的VM指令
[---------VM_Destroy----------] 下面的这几句你可以各类为新的vm指令 他其实就是准备退出虚拟机时把 处理后的物理环境压栈 /---------------------------------------------------------------------------------------- VM_PushImm32 0x00401040 retAddr VM_PushReg32 vm_context->0x14 0x00401008 VM_PushReg32 vm_context->0x30 0x00000000 VM_PushReg32 vm_context->0x18 0x00000202 VM_PushReg32 vm_context->0x24 0x00000000 VM_PushReg32 vm_context->0x04 0x7FFDF000 VM_PushReg32 vm_context->0x10 0x00004545 我们要的最终值 VM_PushReg32 vm_context->0x3C 0x0012FF94 VM_PushReg32 vm_context->0x28 0x00000000 \-------------------------------------------------------------------------------------------这里我就不展示EDI是VM_ESP了,我可以告诉你他是的。看看这个返回地址他是由VM_Bytescode中得到的,还记得我们VM_Entry进来时压的那个push + call 中 call指令后面的地址吗,不是返回仅跟着CALL后面地址的位置,所以我们往往在那个地方下断点就没作用。
如果您对该加密/解密软件感兴趣,欢迎加入加密/解密QQ交流群:740060302
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn
文章转载自: