首页
论坛
专栏
课程

[原创]vmp3.0.9全保护拆分解析

2018-5-1 14:31 18066

[原创]vmp3.0.9全保护拆分解析

2018-5-1 14:31
18066

图片描述
以下为了避免插件干扰,故采用x64dbg原版进行分析。

 

图片描述
首先我通过检测到调试器的弹窗进行栈回溯,定位到该关键点:
CALL eax

 

由于才接触Vmp,所以是把各个保护拆分开来进行的分析,会比较简单一些,不过全保护其实也就是凑在一起罢了,只要注意顺序就行啦。

 

本帖只是分析基础保护反调试反虚拟机等,不涉及还原VM和分析VM代码的部分。属于新手贴一类,适合萌新观看,大佬轻喷,有错漏之处,敬请指正,谢谢。

 

EverEdit编辑器是加的一个vmp的壳子,虽然特征和这里分析的不太一致,但是反调试路子大致一样的,而且虽然是vmp但是通过trace跟踪和分析也是可以暴力破解的,可以拿来练手,这里推荐一下。

一、反调试保护

1.调用IsDebuggerPresent,判断返回值eax==1被调试,eax==0没有调试。

图片描述

 

图片描述

2.CheckRemoteDebuggerPresent,判断buffer返回值是0还是1,1被调试,0没有调试。

图片描述

3.NtQueryInformationProcess,ProcessInfoClass=0x1E来获取调试句柄,判断是否被调试,调试句柄返回0且eax的返回值是0xC0000353

图片描述

 

图片描述

4.NtSetInformationThread,ThreadInfoClass=0x11,这个不是检测调试,而是设置不把调试信息发送到调试器,可以直接把0x11修改为0x3或者其它数值就可以了。

图片描述

5.ZwQuerySystemInformation,SystemInfoClass=0x23(MACRO:SystemKernelDebuggerInformation),返回值是2字节的bool值,设置为0即可。

图片描述

6.ZwQuerySystemInformation,SystemInfoClass=0xB(MACRO:SystemModuleInformation),会去遍历内核模块,然后进行判断,第一次是获取需要存储的buffer长度,第二次才是真正获取信息,只要把buffer都置为0,就检测不到调试了,至于buffer的位置会在第一次调用后使用LocalAlloc申请空间来存储

图片描述

 

图片描述

7.CloseHandle反调试,如果被调试了,那么KiRaiseUserExceptionDispatcher函数会被调用,走异常处理流程;如果是不被调试的状态,不会走向异常流程。

图片描述

8.检测硬件断点,是通过SEH异常来处理的

首先在SEH链中对当前模块的SEH头下一个软件断点

图片描述

然后把图示中的Dr0、Dr1、Dr2、Dr3、Dr6、Dr7调试寄存器都修改为0

图片描述

然后F9再次到CALL eax的时候如果是GetpRrocessAffinityMask函数调用,说明反调试已经顺利通过。

PS:上面对CALL eax下的是硬件断点,注意不要下软件断点,因为前面ZwSetInformationThread后(User-mode反调试)或者第三次最后一次NtQuerySystemInformation后(Kernel-mode)反调试会有如下图所示的软件断点检测,其实vmp的内存保护一部分的原理和这个一致,代码特征几乎都一样,取出来的HEX字节也是存放在esi寄存器中。所以为了方便,最好下硬件断点,因为硬件断点检查触发的时机都是在SEH函数中,很好拦截。

图片描述

二、反虚拟机

1.CPUID判断ECX最高位31位是否为1,如果是1那么就是在虚拟机中,如果是0那就是在宿主机上。我自己加壳的这个样本有两个CPUID检测点,等它执行后修改ecx最高位为0就行。
不过下面的贴图演示的是使用修改虚拟机的.vmx配置文件的方式,更加方便。

图片描述

2.使用GetSystemFirewareTable获取系统固件信息,判断其中有无下列字符串:VMware、VirtualBox、Parallels。注意大小写,只需要等GetSystemFirewareTable执行完成后对内存搜索VMware字符串(因为我用的VMware虚拟机),然后填充为0就可以过虚拟机检测了。下面我会贴一个脚本配合OD+StrondOD+DrxProtect使用的,主要就是填充VMware字符串。

三、IAT解密

1.我没有分析它是如何加密的,只是简单的分析了调用函数的解密过程,其实十分简单:进入解密函数后单步f7,当看到类似:lea register,dword ptr[register+imm](register:寄存器,imm:立即数)的语句,在执行完成后register中就是函数,再跟踪几步通过ret一类的就去执行真正的函数了
2.不知有无遗漏。。。

四、内存保护

1.内存保护和上面分析的软件断点几乎一样,对你修改的内存下硬件访问断点,就可以看到在取HEX字节然后运算,不再贴图了,只要把取出来的esi的数值替换为原来的数值就行了

2.不知有无遗漏。。。



[推荐]看雪企服平台,提供安全分析、定制项目开发、APP等级保护、渗透测试等安全服务!

最后于 2018-5-1 14:36 被cat喵编辑 ,原因:
上传的附件:
上一主题 下一主题
最新回复 (39)
PYGame 2018-5-1 15:20
2
0
消灭0回复  标题有些夸张了... 在VMPCALL的地方下断点, 都是在对一些函数和异常做介绍  不过能看出来写的非常认真
Yecate 2018-5-1 16:11
3
0
卡不懂
sisess 1 2018-5-1 16:31
4
0
厉害厉害
wx_咖啡_552099 2018-5-1 17:04
5
0
厉害!
pxhb 2 2018-5-1 17:25
6
0
感谢分享
ZwTrojan 2018-5-1 17:34
7
0
我使用SharpOD插件可以过掉反调试,但是在IsDebuggerPresent上下断就会被检测到,意思是VM还会检测API入口的1个字节判断是否为0xCC来进行反调试吗.
cat喵 1 2018-5-1 18:44
8
0
谢谢,正在新手村任务中
cat喵 1 2018-5-1 18:45
9
0
ZwTrojan 我使用SharpOD插件可以过掉反调试,但是在IsDebuggerPresent上下断就会被检测到,意思是VM还会检测API入口的1个字节判断是否为0xCC来进行反调试吗.
是的,有软件断点的检测,使用硬件断点就可以的
cat喵 1 2018-5-1 18:45
10
0
cat喵 是的,有软件断点的检测,使用硬件断点就可以的
上面帖子的软件断点检测有说到
jgs 2018-5-1 20:33
11
0
普及贴收藏,谢谢楼主提供
nig 4 2018-5-2 13:43
12
0
顶一下,希望把工作坚持  下去。
xiaohang 3 2018-5-3 12:19
13
0
支持,整理的很全啊
StriveXjun 2018-5-3 14:27
14
0
离脱壳还很远
cat喵 1 2018-5-4 20:37
15
0
StriveXjun 离脱壳还很远
哈哈,是的,这就是一篇总结贴,而且属于适合新手的,vm还原部分我也还在分析中,不同版本的特征感觉也不太一致,所以没办法快速还原。
如果您有相关资料,也请分享或指教一个方向谢谢
cat喵 1 2018-5-4 20:46
16
0
cat喵 哈哈,是的,这就是一篇总结贴,而且属于适合新手的,vm还原部分我也还在分析中,不同版本的特征感觉也不太一致,所以没办法快速还原。 如果您有相关资料,也请分享或指教一个方向谢谢
大神请教个问题,你写的SharpOD的Atti_Atti  Attach的原理是使用的挂钩DbgUiIssueRemoteBreakin,DbgUiConnectToDbg,DbgUiDebugActiveProcess这几个函数来实现的吗?
JAS白乌鸦 2018-5-5 10:57
17
0
cat喵 大神请教个问题,你写的SharpOD的Atti_Atti Attach的原理是使用的挂钩DbgUiIssueRemoteBreakin,DbgUiConnectToDbg,DbgUiDebugActi ...
我也在研究这个,sharpod的Atti_Atti    Attach和scyllahide的kill  anti  attach都可以绕过一些TMD的反附加.不过我挂钩这几个函数失败了,打算直接用修复的方法,把地址改成原版ntdll中的地址.
函数的话,我搜到的有DbgUiIssueRemoteBreakin,DbgUiConnectToDbg,DbgUiDebugActiveProcess你说的这几个,还有DbgBreakPoint,DbgUserBreakPoint这两个.
cat喵 1 2018-5-5 12:40
18
0
JAS白乌鸦 我也在研究这个,sharpod的Atti_Atti Attach和scyllahide的kill anti attach都可以绕过一些TMD的反附加.不过我挂钩这几个函数失败了,打算直接用修复的方法 ...
期待你完成后的分享,这方面的思路提供的内容多一些,但是具体实现还没去试过,准备考试啦
StriveXjun 2018-5-7 10:11
19
0
cat喵 大神请教个问题,你写的SharpOD的Atti_Atti Attach的原理是使用的挂钩DbgUiIssueRemoteBreakin,DbgUiConnectToDbg,DbgUiDebugActi ...
我也是使用的SOD的方法,  attach进程的时候,在目标进程会创建一个线程,这个线程的起始地址就是DbgUiIssueRemoteBreakin,但你先挂钩进程的  LdrInitializeThunk的话在直接  int  3  接管调试断点,就不会走到那几个API那去了。
lookzo 2018-5-8 19:46
20
0
栈回硕就能找到call  ebx?难道是最新版的没旧版强度大了?
MistHill 6 2018-5-9 10:51
21
0
lookzo 栈回硕就能找到call ebx?难道是最新版的没旧版强度大了?
Call  R32  在vCall里。
VMP3的vCall与VMP2有很大不同,VMP2的vCall只能调用虚拟子程序/函数,VMP3的vCall可以直接调用API,比较方便。感觉VMP3的vCall  handler是从Oreans(TMD/WL/CV)“抄”来的!
vCall中,解码vEIP一字节为参数个数,然后将vESP(EBP)处的参数依次入栈,最后Call  R32完成调用,返回结果EAX保存在[EBP]。
而且VMP3  vCall的入口有好多个,这些vCall  handler解码算法也有差异;VMP2时只有一个vCall。

另外,ZwQuerySystemInformation[SystemInformationClass::SystemModuleInformation]取得系统模块列表后,将模块名与解密后的字符串"sice.sys"、"siwvid.sys"、"ntice.sys"、"iceext.sys"和"syser.sys"进行比较,来完成检测。
awfssfn 2018-5-9 11:17
22
0
受教了,谢谢楼主分享。
JAS白乌鸦 2018-5-9 15:05
23
0
StriveXjun 我也是使用的SOD的方法, attach进程的时候,在目标进程会创建一个线程,这个线程的起始地址就是DbgUiIssueRemoteBreakin,但你先挂钩进程的 LdrInitializeThun ...
大佬,这句"在直接    int    3    接管调试断点"是什么意思.没有理解.是直接钩取LdrInitializeThunk然后在Fake_LdrInitializeThunk里面自己写int  3吗
cat喵 1 2018-5-11 15:13
24
0
MistHill Call R32 在vCall里。 VMP3的vCall与VMP2有很大不同,VMP2的vCall只能调用虚拟子程序/函数,VMP3的vCall可以直接调用API,比较方便。感觉VMP3的vCall ...
谢谢,说的好详细。想问下vCALL在3.x版本下不止一个,但是一直没明白为啥这个检测基本上检测函数的调用在一个地方就能过,我是把所有的保护都有勾选的?
cat喵 1 2018-5-11 15:23
25
0
谢谢大佬的分析
MistHill 6 2018-5-14 09:56
26
0
cat喵 谢谢,说的好详细。想问下vCALL在3.x版本下不止一个,但是一直没明白为啥这个检测基本上检测函数的调用在一个地方就能过,我是把所有的保护都有勾选的?
你这个样本是有点特殊:
API调用总是在这个vCall上;通常不应该“固定”在某个vCall上。

我在“一个反调试有特色的CrackMe”里提到看过的两个VMP3的样本v301和v309,外壳部分(vmp1)都各有11个vCall,按入口地址依次标记为vCall1~vCallB。
从壳的入口到第一个vGetHash(v301是一个GetHash函数)之间,所有vCall的记录都为12次,但不是总在同一个vCall上:
v301样本
 1)     vCall6  kernel32.LocalAlloc                     ; size 0xA4; for anti data!
 2)     vCallA  kernel32.GetCurrentProcess
 3)     vCall5  kernel32.IsDebuggerPresent
 4)     vCallB  kernel32.CheckRemoteDebuggerPresent
 5)     vCall2  ntdll.ZwQueryInformationProcess         ; ProcessDebugPort
 6)     vCall8  kernel32.GetCurrentThread
 7)     vCallB  ntdll.ZwSetInformationThread
 8)     vCall4  ntdll.ZwQuerySystemInformation          ; SystemDebuggerInfo
 9)     vCall5  ntdll.ZwQuerySystemInformation          ; SystemModuleInfo, get buffer size
10)     vCall8  kernel32.LocalAlloc                     ; alloc buf
11)     vCall4  ntdll.ZwQuerySystemInformation          ; SystemModuleInfo, query
12)     vCall2  kernel32.LocalFree                      ; free buf
v309样本
 1)     vCall1  kernel32.LocalAlloc                     ; size 0xA4; for anti data!
 2)     vCall3  kernel32.GetCurrentProcess
 3)     vCall4  kernel32.IsDebuggerPresent
 4)     vCall7  kernel32.CheckRemoteDebuggerPresent
 5)     vCall4  ntdll.ZwQueryInformationProcess         ; ProcessDebugPort
 6)     vCall4  kernel32.GetCurrentThread
 7)     vCall7  ntdll.ZwSetInformationThread
 8)     vCall8  ntdll.ZwQuerySystemInformation          ; SystemDebuggerInfo
 9)     vCall7  ntdll.ZwQuerySystemInformation          ; SystemModuleInfo, get buffer size
10)     vCall1  kernel32.LocalAlloc                     ; alloc buf
11)     vCall6  ntdll.ZwQuerySystemInformation          ; SystemModuleInfo, query
12)     vCallA  kernel32.LocalFree                      ; free buf

这两个样本在vmp0段解密后,它的vCall都各多达110个!即壳代码部分VM的handler数要远远少于用户代码保护部分VM的handler。
我对VMP3研究得还不多,也许您可以把样本放上来大家看看。
xingbing 2018-5-18 14:24
27
0
强,收藏学习了。
风过果落 2018-5-19 11:59
28
0
收藏学习了。
BlackJZero 2018-5-30 07:46
29
0
Zonee 2018-6-1 19:16
30
0
厉害了,收下谢谢分享
严启真 2018-6-13 16:45
31
0
好,正需要,学习中,谢谢分享
wolovbm 2018-6-14 15:16
32
0
谢谢楼主分享。
lookzo 2018-7-17 15:21
33
0
MistHill Call R32 在vCall里。 VMP3的vCall与VMP2有很大不同,VMP2的vCall只能调用虚拟子程序/函数,VMP3的vCall可以直接调用API,比较方便。感觉VMP3的vCall ...
感谢mist
Alfik 2018-7-29 20:33
34
0
新版本3.2改进了反调试 
严启真 2018-8-3 21:26
35
0
很详细,谢谢
chkds 2018-8-12 23:13
36
0
感觉挺适合新手的,讲的比较浅显易懂,谢谢
少昊 2018-11-16 20:10
37
0
蹲个未来大佬
菜鸟级X 2 2018-12-6 00:12
38
0
mark
阿亮 2018-12-6 08:47
39
0
不错,学习一下
唯独 2019-2-9 03:36
40
0
之前debug的程序都没有anti-debugger,刺客信条枭雄上了vmp,学习一下
游客
登录 | 注册 方可回帖
返回