吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7452|回复: 12
收起左侧

[转贴] 快速认识 VMP 3.x 第一部分 壳代码篇

[复制链接]
BeneficialWeb 发表于 2021-12-21 13:51
本帖最后由 BeneficialWeb 于 2021-12-21 14:01 编辑

本帖翻译自r0da的博客 (链接地址)[https://whereisr0da.github.io/blog/posts/2021-01-05-vmp-1/]

大家好,这是我第一次研究VMProtect。VMP是一款非常有名的加壳保护软件,它具有很多功能,其中最主要的功能是代码变异和虚拟化,但是Part 1只涉及VMP中最简单的保护措施。其他保护措施将会在后面的帖子进行讨论。现在我们先关注壳代码和输入表混淆。
20211219133823

壳代码

壳代码主要是对可执行文件的节区进行压缩和加解密,从而防止逆向人员进行静态分析。考虑到这种方式在程序执行阶段代码和节区会被解密出来,因此保护方法一般不是很有成效。
20211219133331
针对这种情况,VMProtect不会将真实原始文件节区信息存储在PE文件头里。这种保护措施听上去很腻害。但是仍然有一些虚拟地址和大小应该始终要存在PE头里,这样Windows内核才能为可执行文件分配正确大小的空间。因此在不考虑地址空间布局随机化的情况下,我们仍然可以需要留心节区大小和一些可能地址。
关于原始文件的内容,几乎全部被放进了.vmp1节区,这个节区包括了被加密的节区内容,壳代码,节区信息等。
唯一没有被保护的节区是.rsrc,因为Windows需要读取它来提取程序图标和其他应用信息用以显示在属性菜单上。VMProctect有一个保护资源的选项,他通过把资源分成两部分,一部分是针对Windows需要而创建的;一部分是程序自身运行时所需的资源信息,只在程序执行过程中被加密和解密。
截图中除了.data节区,其他的节区都是不可写入的。所以VMP将会调用VirtualProtect或者类似的函数来改变节区的属性,然后修改节区内容。VMP 3.x以前,VMP使用VirtulProtect函数,之后它使用了未文档化的内核API函数ZwProtectVirtualMemory来达到同样的目的。
因为ZwProtectVirtualMemory会在PE加载时会被Windows内部被频繁调用,所以我们只在到达PE入口点后,才对其进行下断操作。
20211219133440
可以注意到vmp程序的入口点看起来像是一个VMProtect 虚拟化化后的函数。在VM 2.x以前,VMP的壳代码是未被虚拟化的。我们很容易在单步运行pushret指令后跳转到OEP。
20211219133508
现在我们知道VMP会在解码中会修改两次节区属性,一次用于写入数据,一次是用于恢复节区属性。在一定量的断点命中后,我们应该可以得到ZwProtectVirtualMemory的调用次数。

n = 不可写入的节区数
n+1 (.vmp0): 改变写保护标志的次数
1: 移除拷贝标志位的次数
n+1 (.vmp0) 恢复原始标志位

因此vmp执行脱壳代码的次数为((n+1)*2)+1。这里有一张反映这种操作的动态图,注意观察右边的标志位变化。
44
在壳代码运行完后,我们就可以通过任意工具来dump 转储可执行文件,不过目前还没有修复导入表。
以我对vmp相关研究来看, vmp0节区包含了虚拟化和变异后的程序代码,以及IAT相关的代码。vmp1节区包含了所有与壳机制相关的东西,例如被加密的节区,虚拟化后的壳代码,节区信息等。

寻找OEP

由于壳代码被虚拟化了,因此想通过vmp代码来找到oep相当困难。我们需要学习一些技巧:

  1. 我们可以监视eip寄存器的值变化,尤其是当eip寄存器的值从vmp1切换到其他节区,而不是.vmp0时。这样应该对于寻找OEP来说能起作用。我尝试过编写Qiling脚本来实现这个功能,但是Qiling脚本并没有实现ZwProtectVirtualMemory这个函数,这导致我们的工作无法进展下去。后来我写了一个unicorn Python脚本来实现了这个任务。
  2. 我们也可以通过对.text节区下硬件执行断点来达到同样的结果。在我的例子中,oep是.text节区上的第一个函数,但是这种情况比较少见,不可能所有受vmp保护的程序都满足这种情况。
  3. 你还可以通过查看第一个函数堆栈的cookie来寻找oep。使用vc++编译的程序,他的栈cookie通常是0x2B992DDFA232详细内容请参考这篇优秀文章
    4.你也可以手动寻找oep。通过尝试观察栈底来寻找第一个可能是OEP的返回地址。

IAT 混淆

VMP的IAT混淆是一个可选项,并不是默认设置的。有时你也会遇到vmp保护的程序不会发生重建IAT的情况,原因是开发者不擅长使用vmp加壳。当然,我肯定懂加壳,帖子里说的情况也是开了IAT混淆保护的。
首先,我们会看到原始IAT依旧被保存在了PE文件中,但却不会被使用。
20211219133649
虽然你能看到程序使用了哪些API,却不能通过交叉引用来静态分析,原因是导入地址是运行时动态计算的。当然如果是我来实现IAT保护,我应该是通过导入一个dll的随机函数来实现,而不是保留原来的所有东西;或者干脆完全删除IAT的内容,用LoadLibrary加载每个DLL以后,再解决导入表问题。我们通过查看vmp程序调用API的完整流程,可以注意到相关API调用的代码只是进行了变异操作,而没有进行虚拟化保护。
每一个IAT相关函数的调用都在.text节区,比如说call dword ptr ds:[<&CreateProcessW>], 是6个字节长度的指令。VMP将会把这种原始的API调用改变成这种类型的调用:

push 随机寄存器
call 变异后的api解析器

为了保持代码对齐,这两条指令也是6字节大小的。每一个API 调用都有一个变异后的api解析器函数。这也解释了为什么脚本会有大量的输出,当然也有一部分原因是代码虚拟化。VMP使用一个随机寄存器来传递一个参数给API解析器。
这里给出一个变异后的版本例子。随机寄存器选择为edi。
注意:正如我所说,这个代码在.vmp0节区。

nop
not di
bswap di
jmp ...
pop edi
jmp ...
xchg dword ptr ss:[esp], edi 
push edi
not edi 
xchg di, di 
jmp ...
mov edi, 0x401113
mov edi, dword ptr ds:[edi + 0x2B21E] 
jmp ...
lea edi, dword ptr ds:[edi + 0x724F2141] 
jmp ...
xchg dword ptr ss:[esp], edi
jmp ...  
ret 

化简后的版本(reg代表随机寄存器)

# reg 是被 push 的寄存器
# 下面的代码是得到要调用的返回地址
pop reg
# reg与返回地址交换值
# 因此返回的时候会调用到相应的API
xchg dword ptr ss:[esp], reg 
# 设置未来的返回地址用来跳转到API函数
push reg 
# 计算函数地址
# magic number
mov reg, 0x401113 
# 可理解为获取VMP针对 kernel32.dll 重构后的IAT地址
mov reg, dword ptr ds:[reg + 0x2B21E]
# 获取CreateProcessW地址
lea reg, dword ptr ds:[reg + 0x724F2141]
# put the API function address on stack top, using the "push reg" above
# 将API函数地址放到栈顶
xchg dword ptr ss:[esp], reg  
# 跳转到API函数
ret 

做个总结,vmp使用push建立了一个栈变量,然后通过ret跳转到API函数地址。
地址的计算方式如下:

reg = 0x401113        : magic number
ds:[reg + 0x2B21E]    : VMP针对kernel32.dll重构后的IAT地址
ds:[reg + 0x724F2141] : CreateProcessW的实际地址

我没有足够的时间去编码实现一个导入表修复器,但是这确实可以通过模拟器来实现,比如说unicorn等。
0xnobody, can1357 和 mrxodia 写了一些工具来脱壳和修复64位程序的导入表。
(工具链接地址)[https://github.com/0xnobody/vmpdump]

免费评分

参与人数 6吾爱币 +11 热心值 +6 收起 理由
ZJevon + 2 + 1 我很赞同!
shineroof + 1 谢谢@Thanks!
bullshit + 1 + 1 谢谢@Thanks!
haonanyxp + 1 我很赞同!
AG6 + 1 + 1 我很赞同!
Hmily + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| BeneficialWeb 发表于 2021-12-21 17:42
Hmily 发表于 2021-12-21 14:41
感谢翻译分享,BeneficialWeb可以把图片上传论坛本地,图床打开很慢。

我这边打开挺快的
Hmily 发表于 2021-12-21 14:41
感谢翻译分享,BeneficialWeb可以把图片上传论坛本地,图床打开很慢。
gueijiaochen 发表于 2021-12-21 15:09
ynboyinkm 发表于 2021-12-21 16:00
vm是我的最爱!!!!
plauger 发表于 2021-12-21 16:25
还有第二部分,楼主加油
aonima 发表于 2021-12-21 17:11
感谢翻译
sun12345 发表于 2021-12-23 01:07
感谢感谢
00hlz 发表于 2023-7-22 10:13
感谢分享,有脱壳工具吗?
py66 发表于 2024-1-7 11:25
看也看不懂
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-7 06:46

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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