VMProtect分析-加载器
分析对象为网上流传的VMP源码
源码路径 | 函数名 | 行号 |
---|---|---|
runtime\loader.cc | SetupImage | 884 |
1、反调试
1.1 用户模式
line:17492
通过检测PEB->BeingDebugged,常规手段了,没什么好说。
然后就是通过NtSetInformationProcess
、NtQueryInformationProcess
、NtSetInformationThread
进行反调试,各功能如下:
NtSetInformationProcess:如果是window10则调用,参数二为
ProcessInstrumentationCallback
。这个参数主要是注册一个回调,在Windows系统Vista以及之后的版本中,可以使用KPROCESS->InstrumentationCallback来指定回调函数的地址,每次函数从内核态返回用户态之后系统都会调用指定的回调函数。但是这里VMP设置了一个NULL的值,猜测可能是有人利用了这种机制来进行绕过反调试,因此清空这个位置。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//https://pastebin.com/9TqRGsM5
//https://secrary.com/Random/InstrumentationCallback/
//------64-Bit---------------
extern "C"
{
void DbgBreakPoint();
int __stdcall ZwSetInformationProcess(HANDLE,unsigned long long,unsigned long long*,unsigned long long);
}
void* BeingDebugged()
{
unsigned long long Cano= 0;
ZwSetInformationProcess(GetCurrentProcess(),ProcessInstrumentationCallback,&Cano,0x8);
MessageBox(0,L"Being Debugged\r\n",L"waliedassar",0);
ExitProcess(0);
}
int main()
{
unsigned long long Cano= (unsigned long long)&BeingDebugged;
int ret=ZwSetInformationProcess(GetCurrentProcess(),ProcessInstrumentationCallback,&Cano,0x8);
if(ret==0xC0000061) printf("Expected\r\n");
return 0;
}NtQueryInformationProcess:查询
ProcessDebugPort
、ProcessDebugObjectHandle
NtSetInformationThread:传入
ThreadHideFromDebugger
隐藏线程,也是老常规了。
最后利用异常机制检测反调试。
如果存在调试器则会继续执行__writeeflags
之后的代码,否则会进入自己的异常函数执行。
1.2 内核模式
内核模式本质上还是跟用户模式没什么区别,主要是调用NtQuerySystemInformation
以查询系统为主,拦截双机调试为主。
SystemKernelDebuggerInformation:通过传入
SystemKernelDebuggerInformation
查询DebuggerEnabled
和DebuggerNotPresent
是否有值。SystemModuleInformation:通过判断是否存在一些调试设备。这里可以去看我反调试那篇文章,符号的那一节。
1
2
3
4
5\\.\SICE
\\.\SIWVID
\\.\NTICE
\\.\ICEEXT
\\.\SYSER
1.3 API检测
检测头部是否为0xCC
,对抗软件断点。
1.4 内存检测
VMP会查询整个镜像模块中原可执行的代码是否被设置为了无权限,对抗内存断点。
2、检测虚拟机
2.1 CPUID
老常规,cpuid
首先使用eax=1参数调用cpuid检测ecx的31位是否为1来检测虚拟机。(虚拟机下为1)
然后在进行eax=0x40000000获取CPU的信息,判断字符串是否为正常字符串。
2.3 系统固件
通过EnumSystemFirmwareTables
和GetSystemFirmwareTable
判断原始固件表是否存在虚拟机的名字。
检测的内容有
1 | QEMU |
如果上述函数无法调用,则通过打开设备\\device\\physicalmemory
来检查是否存在上述固件名字
2.4 检测固定DLL
检测SBIEDLL.DLL
是否存在,这个DLL是沙箱(Sandboxie)的一个组件。
总结
只是分析了基于windows反调试和反虚拟机,linux和mac方面的也大吃差不多。至于内存CRC校验的东西就不看啦!
对于检测虚拟机和调试基本上就是比较常规的东西,但还是有意外收货!!!!
一个是KPROCESS->InstrumentationCallback
这个标志位,这个可能在之后编程的时候会用到,觉得非常牛逼,嘎嘎嘎!!!!