首页
社区
课程
招聘
10
[原创]如何分析虚拟机(1):新手篇VMProtect 1.81 Demo
发表于: 2018-3-18 18:45 22703

[原创]如何分析虚拟机(1):新手篇VMProtect 1.81 Demo

2018-3-18 18:45
22703

序言

关于 VMProtect,从其诞生到现在已经十几年。无数人投入精力进行研究,虚拟机基本结构已经基本明确了。

 

相关资料可以参考:
[专题][Fight Against Big Four]汇集所有能帮助你对抗强壳的知识(VMP、SE、THEMIDA、Enigma)

 

顺便推一下我整理的一份虚拟化保护相关资料的列表,放在了Github上,https://github.com/lmy375/awesome-vmp 。

 

对于 VMProtect 和 Themida 的虚拟机结构,许多文章已经说的得很清楚。然而却少有文章具体的分析方法。
[翻译]手把手静态分析FinSpy 系列文章有细致介绍作者分析FinSpy VM 的分析过程与思考过程,是非常值得参考的。)
假如我们面对野生样本中的未知虚拟机,该如何入手,一步一步弄清虚拟机结构,提取字节码,进行代码还原?

 

本系列会分析多个不同类型的虚拟机样本(VMProtet, Code Virtualizer 甚至更多有趣的 VM 保护样本),向大家展示我自己针对虚拟机保护代码的分析方法。
本文是系列的第1篇,内容上没有什么很新的东西,主要是展示一下完整的分析过程。

 

本文中通过 Trace 提取虚拟指令的部分我个人觉得还算有趣,对虚拟机已经有了解的读者可以跳过其他废话直接看那一部分。

虚拟机简介

对于大多数虚拟机来说,其结构是相似的。

  • VM_DATA 是虚拟机字节码,是虚拟机要解释执行的指令。
  • VM_EIP,也可以叫 VPC 或者 vEIP ,比如 VMProtect 中的 ESI 寄存器。一般是指向 VM_DATA 中的某个地址,虚拟机每次从这里取出指令,并执行。
  • VM_CONTEXT 虚拟机上下文,实际就是虚拟机寄存器数组。比如 VMProtect 中的 EDI 寄存器的地址,就是虚拟机寄存器数组的起始地址。
  • VM_STACK 虚拟栈,栈式虚拟机实现起来方便,膨胀倍数高,是虚拟机保护的首选。虚拟栈就是临时进行数据交换。VMProtect 的 EBP 寄存器就是虚拟栈的栈顶指针。

一般虚拟机保护代码的执行过程是这样的:

  1. 初始化虚拟机。保存物理寄存器到虚拟机CONTEXT中。
  2. 从 VM_EIP 处取出指针,根据指令的 Opcode 跳转到 Handler 代码中
  3. 执行 Handler,每条 Handler 完成不一样的功能,代表不同的指令操作。 一般来说是操作虚拟寄存器或虚拟栈,进行一些算术运算等。
  4. 执行完 Handler 后,VM_EIP 会向后移动,指向下一条指令。回到第2步,解释执行下一条指令。
  5. 执行完全部字节码后,虚拟机退出,将虚拟寄存器的值还原到物理寄存器中。

所以在分析虚拟机保护的过程,把握如下几个关键要素:

  1. 关键数据结构的位置:虚拟栈在哪?虚拟寄存器在哪儿?
  2. 解释循环位置:VM_EIP 在哪儿?如何取指令?如何跳向 Handler?
  3. Handler 分析:有多少条 Handler?每条 Handler 都要完成什么样的工作?

实例分析 VMProtect 1.81 Demo

下面实例分析一个虚拟机保护的样本,展示一下分析思路。

 

为什么选这么古老的版本,而且还是 Demo 版。因为这个版本虚拟机的主体代码没有混淆,保留了完整且清晰的虚拟机结构,适合入门分析。

 

样本是对如下代码进行 VM 得到的。

1
2
3
4
5
6
7
sub_401000 proc near
mov     eax, dword_403000
add     eax, 12345678h
sub     eax, 12345678h
mov     dword_403000, eax
retn
sub_401000 endp

经验丰富的话应该对 VMProtect 虚拟机结构已经比较熟悉,这里并不会介绍新的东西,只是展示一下思路,给新人一点参考。

1. 初步结构

IDA 打开加保护后的文件,定位到0x401000位置,这是我们进行保护的代码位置。经过虚拟机保护,原本的代码已经不在了。

 

新的代码如下:

1
2
.text:00401000                 push    offset byte_404781
.text:00401005                 call    sub_40472C

CALL的目的地址已经不在.text节中,在新加的.vmp0中。也就是虚拟机新加入的代码了。

 

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.vmp0:0040472C                 push    esi ; 依次保存寄存器
.vmp0:0040472D                 push    edi
.vmp0:0040472E                 push    esp
.vmp0:0040472F                 push    ebx
.vmp0:00404730                 push    eax
.vmp0:00404731                 push    edx
.vmp0:00404732                 push    ebp
.vmp0:00404733                 pushf
.vmp0:00404734                 push    ecx
.vmp0:00404735                 push    ds:dword_404649  ; 重定位偏移
.vmp0:0040473B                 push    0
.vmp0:00404740                 mov     esi, [esp+30h]   ; 前面 push 的 offset byte_404781
.vmp0:00404744                 mov     ebp, esp
.vmp0:00404746                 sub     esp, 0C0h     ; 分配一下栈空间
.vmp0:0040474C                 mov     edi, esp      ; 栈顶位置赋值给 edi
.vmp0:0040474E
.vmp0:0040474E loc_40474E:                          
.vmp0:0040474E                 add     esi, [ebp+0]  ; 重定位
.vmp0:00404751
.vmp0:00404751 loc_404751:                           
.vmp0:00404751                                       
.vmp0:00404751                 mov     al, [esi]   ; 从 esi 取出 1 字节
.vmp0:00404753                 movzx   eax, al   
.vmp0:00404756                 inc     esi         ; esi 字节
.vmp0:00404757                 jmp     ds:off_40409C[eax*4]  ; 根据 esi 取出字节进行跳转

这段代码首先保存当前寄存器的值。(这与前面介绍了虚拟机初始化的过程是一致的) 然后进行分配栈空间,初始化 esi, edi, ebp 寄存器。这三个寄存器都是作什么的?

 

mov al, [esi]从 esi 地址取出 1 字节,并根据这一字节进行跳转jmp ds:off_40409C[eax*4]。这一过程很像前面介绍的虚拟机执行过程的第2步。

 

继续分析验证推断, esi 的值实际来自前面的 mov esi, [esp+30h],进一步追溯实际来自push offset byte_404781。IDA 查看一下 byte_404781 位置:

1
2
3
4
5
6
7
.vmp0:00404781 byte_404781     db 0Eh, 0E8h, 81h      
.vmp0:00404784                 dd 5C765DA9h, 3E0A1A1Eh, 3A36262Eh, 602122Ah, 3000E822h
.vmp0:00404784                 dd 16790040h, 34567869h, 1E7A1412h, 5678E836h, 97341234h
.vmp0:00404784                 dd 5C066B4Dh, 1121973Eh, 4C3C0622h, 0EB161121h, 1E11F7EAh
.vmp0:00404784                 dd 326B2020h, 78081577h, 36325C32h, 30006904h, 0ED0040h
.vmp0:00404784                 dd 4382010h, 8342C24h, 0E1001Ch, 8 dup(0)
.vmp0:00404800                 dd 200h dup(?)

初始有值的数据,且位于 .vmp0 节内。这很有可能就是 VM_DATA 也就是虚拟机字节码的内容(实际也确实是这样的)。那么 esi 寄存器的作用也就明确了,就是VM_EIP
edi 和 ebp 是指向栈上的内存,具体是什么还不明确,继续分析。
前面那个jmp ds:off_40409C[eax*4]跳转是个很典型的switch结构,IDA可以查看CFG图如下:
ida

 

图中蓝色线条最为密集的部分就是 0x0404751 的代码,这部分代码前面已经分析过,是 esi 取字节并跳转。

 

可以看到跳转的目标很多,共有41个跳转目标。这时我们有充分的理由认为这个41个跳转目标就是 Handler 代码。

2. Handler 分析

接下来是比较枯燥的过程,要逐条分析每个 Handler。

 

因为要考虑地址寄存器宽度1字节、2字节、4字节,所以41条Handler中有许多指令功能是一致的,只是数据宽度不同。取几条比较典型的指令说明:

  1. 立即数压栈

    1
    2
    3
    4
    5
    6
    7
    .vmp0:0040462B vPushImm4:                            
    .vmp0:0040462B                                       
    .vmp0:0040462B                 mov     eax, [esi]
    .vmp0:0040462D                 sub     ebp, 4
    .vmp0:00404630                 lea     esi, [esi+4]
    .vmp0:00404633                 mov     [ebp+0], eax
    .vmp0:00404636                 jmp     loc_40400F

    这条指令从 esi 地址取出 4 字节,然后 ebp - 4 后写入 [ebp] 内存处。 esi 指向的地方是 VM_DATA,因此取出的部分是指令中的固定数,即虚拟指令中的立即数。 ebp - 4 后再赋值的操作很像栈操作,先抬高栈顶,再写值。通过分析其他指令可以发现许多加减 ebp 然后读写值的情况。那么可以认定 ebp 就是虚拟栈栈顶指针。

  2. 寄存器压栈

    1
    2
    3
    4
    5
    6
    7
    .vmp0:004045AF vPushReg4:                            
    .vmp0:004045AF                                     
    .vmp0:004045AF                 and     al, 3Ch
    .vmp0:004045B2                 mov     edx, [edi+eax]
    .vmp0:004045B5                 sub     ebp, 4
    .vmp0:004045B8                 mov     [ebp+0], edx
    .vmp0:004045BB                 jmp     loc_40400F

    这条指令取 al 的后几位,作为 edi 寄存器的偏移,取出值后压入栈顶。al 是之前从 esi 地址中取出的值,也是指令的一部分。由该值作索引,从 edi 寻址取值。可以猜测 edi 就是 VM_CONTEXT。这里是将虚拟寄存器中值压入虚拟栈中。

  3. 计算

    1
    2
    3
    4
    5
    6
    7
    .vmp0:00404000 vAdd4:                                
    .vmp0:00404000                                       
    .vmp0:00404000                 mov     eax, [ebp+0]
    .vmp0:00404003                 add     [ebp+4], eax
    .vmp0:00404006                 pushf
    .vmp0:00404007                 pop     dword ptr [ebp+0]
    .vmp0:0040400A                 jmp     loc_404751

    这是一条比较明显的计算指令(加法指令)。
    ebp + 0 是栈顶, ebp + 4 是次栈顶。 二者相加,保存在 [ebp + 4]。 eflag 值保存在 [ebp + 0]。
    即先从栈中弹出两个数,相加后将结果压入栈中,再将eflag值压入栈中。

  4. 其他
    我们已经确定了:

  • esi 取出的值来自指令,因此是立即数或者寄存器下标
  • edi 指向VM_CONTEXT,读写就是操作虚拟寄存器
  • ebp 指向虚拟栈顶,读写就是压栈、弹栈
    根据这几点,很容易就可以将所有 Handler 的作用分析清楚。

3. 还原字节码

分析完所有 Handler 之后,就可以提取分析字节码了。


[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!

最后于 2018-4-9 18:12 被穆恩编辑 ,原因:
上传的附件:
收藏
免费 10
支持
分享
赞赏记录
参与人
雪币
留言
时间
心游尘世外
为你点赞!
2025-1-23 05:28
東陽不列山
为你点赞!
2025-1-19 06:53
一路南寻
感谢你的贡献,论坛因你而更加精彩!
2025-1-18 01:37
飘零丶
为你点赞!
2024-9-8 05:37
shinratensei
为你点赞!
2024-9-5 02:23
YiGod
感谢你分享这么好的资源!
2024-7-21 16:20
PLEBFE
为你点赞~
2022-7-27 02:06
mb_yrvsqudt
为你点赞~
2020-11-16 16:16
Sinner_Dusk
为你点赞~
2020-4-27 10:13
零加一
为你点赞~
2019-4-3 16:51
最新回复 (41)
雪    币: 6541
活跃值: (3610)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
向大牛学习
2018-3-18 19:31
0
雪    币: 9934
活跃值: (2554)
能力值: ( LV6,RANK:87 )
在线值:
发帖
回帖
粉丝
3
好文章,先收藏了
2018-3-18 20:30
0
雪    币: 2067
活跃值: (1767)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
精贴
2018-3-18 20:51
0
雪    币: 79
活跃值: (1844)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
5
楼主对vm的还原研究坚持这么久,很有毅力啊
2018-3-18 21:30
0
雪    币: 153
活跃值: (818)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
向大牛学习
2018-3-18 21:50
0
雪    币: 58
活跃值: (1210)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
好东西
2018-3-18 22:52
0
雪    币: 775
活跃值: (2342)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
8
膜观大牛,mark学习
2018-3-18 23:07
0
雪    币: 13245
活跃值: (4819)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
9
好文~~感谢分享~~
2018-3-19 00:41
0
雪    币: 3853
活跃值: (707)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
10
谢谢楼主分享
2018-3-19 09:15
0
雪    币: 3712
活跃值: (1546)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
11
文章写的很好,感谢楼主分享
2018-3-19 09:33
0
雪    币: 375
活跃值: (246)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
感谢大牛分享,期待后续大作。
2018-3-19 09:37
0
雪    币: 439
活跃值: (1528)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
13
期待后续大作
2018-3-19 09:57
0
雪    币: 0
活跃值: (175)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
mark
2018-3-19 10:27
0
雪    币: 2348
活跃值: (127)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
15
期待后续大作,谢谢楼主分享  谢谢
2018-3-19 10:34
0
雪    币: 41
活跃值: (1038)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
期待后续的佳作!
2018-3-19 10:45
0
雪    币: 3906
活跃值: (4172)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
17
顶!
2018-3-19 10:52
0
雪    币: 84
活跃值: (4578)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
18
感谢分享  mark 
2018-3-19 16:18
0
雪    币: 576
活跃值: (1163)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
19
又是一波VMP小高潮
2018-3-19 17:37
0
雪    币: 36
活跃值: (1151)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
20
感谢分享    mark
2018-3-19 18:51
0
雪    币: 622
活跃值: (282)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
21
hkfans 又是一波VMP小高潮
哈哈  都是hk大佬六七年前分析过的东西 
2018-3-19 19:03
0
雪    币: 622
活跃值: (282)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
22
淡淡的荧光 楼主对vm的还原研究坚持这么久,很有毅力啊[em_12]
个人兴趣
2018-3-19 19:17
0
雪    币: 6818
活跃值: (153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
2018-3-19 22:57
0
雪    币: 8235
活跃值: (2145)
能力值: ( LV8,RANK:122 )
在线值:
发帖
回帖
粉丝
24
感谢大牛分享
2018-3-20 11:45
0
雪    币: 225
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
感谢大牛分享。坚持就是胜利。
2018-3-20 15:04
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册