VMProtect(简称 VMP)想必大家都很熟悉。随着其版本的不断迭代,高版本 VMP 的分析难度日益增加。
我的好朋友 R-R 之前曾推出过"VMP Anti-Debug"系列教程,其中详细讲述了基于 TitanHide 的反反调试驱动方案。了解 TitanHide 的朋友应该都知道,它是一款基于 Ring 0 层、通过 HOOK SSDT 方式实现的开源反反调试驱动。
那么,VMP 究竟是依据什么来检测 TitanHide 的呢?又是如何完成这一检测过程的?在深入分析之前,我们先简单回顾一下 TitanHide 的基本原理。
1. 检测原理:设备符号检测
许多用户可能已经用过或了解过 TitanHide。在分析过程中我发现,VMP 主要是通过对 TitanHide 的驱动设备符号(Device Symbol)进行检测来实现识别的。
核心代码如下:
HANDLE hDevice = CreateFileA("\\\\.\\TitanHide", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
起初我在分析 VMP 时,误以为它检测了其他特征,甚至尝试重新编写了一个驱动来规避,但最终确认其检测点正是上述的设备名称。
2. 逆向分析:字符串的动态构造
为了规避静态字符串扫描,VMP 采用了在栈上动态构造字符的方式。以下是具体的汇编逻辑:
2.1 栈上动态构造字符
VMP 逐字节将字符串 \\?\TitanHide 写入栈内存:
mov ecx, 5C
mov word ptr ss:[ebp-1D0], cx
mov edx, 3F
mov word ptr ss:[ebp-1CE], dx
mov eax, edx
mov word ptr ss:[ebp-1CC], ax
mov word ptr ss:[ebp-1CA], cx
mov edx, 54
mov word ptr ss:[ebp-1C8], dx
mov eax, 69
mov word ptr ss:[ebp-1C6], ax
mov ecx, 74
mov word ptr ss:[ebp-1C4], cx
mov edx, 61
mov word ptr ss:[ebp-1C2], dx
mov eax, 6E
mov word ptr ss:[ebp-1C0], ax
mov ecx, 48
mov word ptr ss:[ebp-1BE], cx
mov edx, 69
mov word ptr ss:[ebp-1BC], dx
mov eax, 64
mov word ptr ss:[ebp-1BA], ax
mov ecx, 65
mov word ptr ss:[ebp-1B8], cx
xor edx, edx
mov word ptr ss:[ebp-1B6], dx
2.2 构造 UNICODE_STRING 结构体
随后,代码计算字符串长度并构建 UNICODE_STRING 结构:
lea eax, dword ptr ss:[ebp-1D0]
lea ecx, dword ptr ds:[eax+2]
mov dx, word ptr ds:[eax]
add eax, 2
cmp dx, bx
jne 3.vmp
sub eax, ecx
sar eax, 1
add eax, eax
2.3 填充 UNICODE_STRING 结构体
接着完成结构体的具体字段填充:
mov word ptr ss:[ebp-16C], ax
mov ecx, dword ptr ss:[ebp-16C]
add ecx, 2
mov word ptr ss:[ebp-16A], cx
lea edx, dword ptr ss:[ebp-1D0]
mov dword ptr ss:[ebp-168], edx
2.4 构造 OBJECT_ATTRIBUTES 结构体
最后,构建用于文件操作的 OBJECT_ATTRIBUTES 结构:
mov dword ptr ss:[ebp-320], 18
mov dword ptr ss:[ebp-31C], ebx
mov dword ptr ss:[ebp-314], ebx
lea eax, dword ptr ss:[ebp-16C]
mov dword ptr ss:[ebp-318], eax
mov dword ptr ss:[ebp-310], ebx
mov dword ptr ss:[ebp-30C], ebx
3. 核心调用与判断
跳过繁琐的结构初始化细节,直接关注最关键的部分:VMP 直接使用 syscall 指令调用 NtOpenFile API。
push 60
lea ecx, dword ptr ss:[ebp-364]
push ecx
lea edx, dword ptr ss:[ebp-320]
push edx
push C0100080
lea eax, dword ptr ss:[ebp-140]
push eax
mov ecx, dword ptr ss:[ebp-30]
or ecx, 0
syscall
调用结束后,通过返回值判断是否成功打开了设备句柄,从而确定是否存在 TitanHide:
test eax, eax
jl 3.exe
mov dword ptr ss:[ebp-2E8], 2
如果 eax 非负(即成功打开设备),则判定检测到 TitanHide,并执行相应的反调试逻辑。
结语
值得一提的是,目前 TitanHide 的作者已经更新了版本,修复了此类检测问题,用户无需再手动修改驱动即可规避该检测。
声明:本文仅供安全研究人员学习与参考,聚焦于技术原理探讨。文中未包含任何恶意代码或可直接利用的攻击载荷,严禁用于非法目的。