虚拟机检测技术剖析Word下载.docx
《虚拟机检测技术剖析Word下载.docx》由会员分享,可在线阅读,更多相关《虚拟机检测技术剖析Word下载.docx(14页珍藏版)》请在冰豆网上搜索。
true;
__try
__asm
push
edx
ecx
ebx
mov
eax,
'
VMXh'
ebx,
0
//
将ebx设置为非幻数’VMXH’的其它值
ecx,
10
指定功能号,用于获取VMWare版本,当它为0x14时用于获取VMware内存大小
edx,
VX'
端口号
in
dx
从端口dx读取VMware版本到eax
//若上面指定功能号为0x14时,可通过判断eax中的值是否大于0,若是则说明处于虚拟机中
cmp
判断ebx中是否包含VMware版本’VMXh’,若是则在虚拟机中
setz
[rc]
设置返回值
pop
}
__except(EXCEPTION_EXECUTE_HANDLER)
//如果未处于VMware中,则触发此异常
false;
return
rc;
测试结果:
图1
如图1所示,VMDetect成功检测出VMWare的存在。
方法二:
利用IDT基址检测虚拟机
利用IDT基址检测虚拟机的方法是一种通用方式,对VMware和Virtual
PC均适用。
中断描述符表IDT(Interrupt
Descriptor
Table)用于查找处理中断时所用的软件函数,它是一个由256项组成的数据,其中每一中断对应一项函数。
为了读取IDT基址,我们需要通过SIDT指令来读取IDTR(中断描述符表寄存器,用于IDT在内存中的基址),SIDT指令是以如下格式来存储IDTR的内容:
typedef
struct
WORD
IDTLimit;
IDT的大小
LowIDTbase;
IDT的低位地址
HiIDTbase;
IDT的高位地址
}
IDTINFO;
由于只存在一个IDTR,但又存在两个操作系统,即虚拟机系统和真主机系统。
为了防止发生冲突,VMM(虚拟机监控器)必须更改虚拟机中的IDT地址,利用真主机与虚拟机环境中执行sidt指令的差异即可用于检测虚拟机是否存在。
著名的“红丸”(redpill)正是利用此原理来检测VMware的。
Redpill作者在VMware上发现虚拟机系统上的IDT地址通常位于0xFFXXXXXX,而Virtual
PC通常位于0xE8XXXXXX,而在真实主机上正如图2所示都位于0x80xxxxxx。
Redpill仅仅是通过判断执行SIDT指令后返回的第一字节是否大于0xD0,若是则说明它处于虚拟机,否则处于真实主机中。
Redpill的源码甚是精简,源码分析如下:
#include
<
stdio.h>
int
main
()
unsigned
char
m[2+4],
rpill[]
"
\x0f\x01\x0d\x00\x00\x00\x00\xc3"
;
//相当于SIDT[adrr],其中addr用于保存IDT地址
*((unsigned*)&
rpill[3])
(unsigned)m;
//将sidt[addr]中的addr设为m的地址
((void(*)())&
rpill)();
//执行SIDT指令,并将读取后IDT地址保存在数组m中
printf
("
idt
base:
%#x\n"
m[2]));
//由于前2字节为IDT大小,因此从m[2]开始即为IDT地址
if
(m[5]>
0xd0)
Inside
Matrix!
\n"
m[5]);
//当IDT基址大于0xd0xxxxxx时则说明程序处于VMware中
else
Not
Matrix.\n"
);
0;
测试结果如图2所示:
图2
利用此IDT检测的方法存在一个缺陷,由于IDT的值只针对处于正在运行的处理器而言,在单CPU中它是个常量,但当它处于多CPU时就可能会受到影响了,因为每个CPU都有其自己的IDT,这样问题就自然而然的产生了。
针对此问题,Offensive
Computing组织成员提出了两种应对方法,其中一种方法就是利用Redpill反复地在系统上循环执行任务,以此构造出一张当前系统的IDT值变化统计图,但这会增加CPU负担;
另一种方法就是windows
API函数SetThreadAffinityMask()将线程限制在单处理器上执行,当执行此测试时只能准确地将线程执行环境限制在本地处理器,而对于将线程限制在VM处理器上就可能行不通了,因为VM是计划在各处理器上运行的,VM线程在不同的处理器上执行时,IDT值将会发生变化,因此此方法也是很少被使用的。
为此,有人提出了使用LDT的检测方法,它在具有多个CPU的环境下检测虚拟机明显优于IDT检测方法,该方法具体内容参见下节内容。
方法三:
利用LDT和GDT的检测方法
在
《Intel®
64
and
IA-32
Architecture
Software
Developer’s
Manual
Volume
3A:
System
Programming
Guide》第二章的Vol.3
2-5
一页(我的Intel开发手册是2008版的)中对于LDT和GDT的描述如下(以下内容为个人翻译):
在保护模式下,所有的内存访问都要通过全局描述符表(GDT)或者本地描述符表(LDT)才能进行。
这些表包含有段描述符的调用入口。
各个段描述符都包含有各段的基址,访问权限,类型和使用信息,而且每个段描述符都拥有一个与之相匹配的段选择子,各个段选择子都为软件程序提供一个GDT或LDT索引(与之相关联的段描述符偏移量),一个全局/本地标志(决定段选择子是指向GDT还是LDT),以及访问权限信息。
若想访问段中的某一字节,必须同时提供一个段选择子和一个偏移量。
段选择子为段提供可访问的段描述符地址(在GDT
或者LDT
中)。
通过段描述符,处理器从中获取段在线性地址空间里的基址,而偏移量用于确定字节地址相对基址的位置。
假定处理器在当前权限级别(CPL)可访问这个段,那么通过这种机制就可以访问在GDT
或LDT
中的各种有效代码、数据或者堆栈段,这里的CPL是指当前可执行代码段的保护级别。
……
GDT的线性基址被保存在GDT寄存器(GDTR)中,而LDT的线性基址被保存在LDT寄存器(LDTR)中。
由于虚拟机与真实主机中的GDT和LDT并不能相同,这与使用IDT的检测方法一样,因此虚拟机必须为它们提供一个“复制体”。
关于GDT和LDT的基址可通过SGDT和SLDT指令获取。
虚拟机检测工具Scoopy
suite的作者Tobias
Klein经测试发现,当LDT基址位于0x0000(只有两字节)时为真实主机,否则为虚拟机,而当GDT基址位于0xFFXXXXXX时说明处于虚拟机中,否则为真实主机。
具体实现代码如下:
void
LDTDetect(void)
short
ldt_addr
ldtr[2];
_asm
sldt
ldtr
*((unsigned
*)&
ldtr);
printf("
LDT
BaseAddr:
0x%x\n"
ldt_addr);
if(ldt_addr
==
0x0000)
Native
OS\n"
else
VMware\n"
GDTDetect(void)
gdt_addr
gdtr[4];
sgdt
gdtr
gdtr[2]);
GDT
gdt_addr);
if((gdt_addr
>
24)
0xff)
main(void)
LDTDetect();
GDTDetect();
测试结果如图3所示:
图3
方法四:
基于STR的检测方法
在保护模式下运行的所有程序在切换任务时,对于当前任务中指向TSS的段选择器将会被存储在任务寄存器中,TSS中包含有当前任务的可执行环境状态,包括通用寄存器状态,段寄存器状态,标志寄存器状态,EIP寄存器状态等等,当此项任务再次被执行时,处理器就会其原先保存的任务状态。
每项任务均有其自己的TSS,而我们可以通过STR指令来获取指向当前任务中TSS的段选择器。
这里STR(Store
task
register)指令是用于将任务寄存器
(TR)
中的段选择器存储到目标操作数,目标操作数可以是通用寄存器或内存位置,使用此指令存储的段选择器指向当前正在运行的任务的任务状态段
(TSS)。
在虚拟机和真实主机之中,通过STR读取的地址是不同的,当地址等于0x0040xxxx时,说明处于虚拟机中,否则为真实主机。
实现代码如下:
mem[4]
{0};
i;
__asm
str
mem;
STR
0x"
for
(i=0;
i<
4;
i++)
%02x"
mem[i]);
(
(mem[0]==0x00)
&
(mem[1]==0x40))
\n
INSIDE
MATRIX!
!
OS!
测试结果如图4所示:
图4
方法五:
基于注册表检测虚拟机
在windows虚拟机中常常安装有VMware
Tools以及其它的虚拟硬件(如网络适配器、虚拟打印机,USB集线器……),它们都会创建任何程序都可以读取的windows注册表项,因此我们可以通过检测注册表中的一些关键字符来判断程序是否处于虚拟机之中。
关于这些注册表的位置我们可以通过在注册表中搜索关键词“vmware”来获取,下面是我在VMware下的WinXP中找到的一些注册表项:
项名:
HKEY_CLASSES_ROOT\Applications\VMwareHostOpen.exe
HKEY_CLASSES_ROOT\Installer\Products\C2A6F2EFE6910124C940B2B12CF170FE\ProductName
键值“VMware
Tools”
HKEY_CLASSES_ROOT\Installer\Products\C2A6F2EFE6910124C940B2B12CF170FE\SourceList\PackageName
键值:
VMware
Tools.msi
HKEY_CURRENT_USER\Printers\DeviceOld
_#VMwareVirtualPrinter,winspool,TPVM:
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\Scsi\Scsi
Port
0\Scsi
Bus
0\Target
Id
0\Logical
Unit
0\Identifier
Virtual
IDE
Hard
Drive
1\Scsi
NECVMWar
CDR10
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Products\C2A6F2EFE6910124C940B2B12CF170FE\ProductName
Tools
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\C2A6F2EFE6910124C940B2B12CF170FE\InstallProperties\DisplayName
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Reinstall\0002\DeviceDesc
SVGA
II
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\NetworkCards\2\Description
Accelerated
AMD
PCNet
Adapter
HKEY_LOCAL_MACHINE\SOFTWARE\VMware,
Inc.\VMware
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4D36E968-E325-11CE-BFC1-08002BE10318}\0000\DriverDesc
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4D36E968-E325-11CE-BFC1-
08002BE10318}\0000\ProviderName
VMware,
Inc.
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0001\DriverDesc
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4D36E97B-E325-11CE-BFC1-08002BE10318}\0000\DriverDesc
SCSI
Controller
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Print\Monitors\ThinPrint
Print
Monitor
VMWare
除以上这些表项之外,还有很多地方可以检测,特别是虚拟机提供的虚拟化软硬件、服务之类,比如文件共享服务,VMware
物理磁盘助手服务,VMware
Ethernet
Adapter
Driver,VMware
Controller等等的这些信息都可作为检测虚拟机的手段。
这里我们就以其中某表项为例编程举例一下,其它表项检测方法同理,具体代码如下:
.386
.model
flat,
stdcall
option
casemap:
none
include
windows.inc
user32.inc
kernel32.inc
advapi32.inc
includelib
user32.lib
kernel32.lib
advapi32.lib
.data
szCaption
db
Detector
0
szInside
VMware!
szOutside
szSubKey
software\VMWare,
tools"
hKey
dd
?
.code
start:
invoke
RegOpenKeyEx,
HKEY_LOCAL_MACHINE,
addr
szSubKey,
0,\
KEY_WRITE
or
KEY_READ,
hKey
.if
eax
ERROR_SUCCESS
MessageBox,
NULL,addr
szInside,
szCaption,
MB_OK
.else
szOutside,
.endif
RegCloseKey,hKey
ExitProcess,NULL
end
start
测试结果如图5所示:
图5
方法六:
基于时间差的检测方式
本方法通过运行一段特定代码,然后比较这段代码在虚拟机和真实主机之中的相对运行时间,以此来判断是否处于虚拟机之中。
这段代码我们可以通过RDTSC指令来实现,RDTSC指令是用于将计算机启动以来的CPU运行周期数存放到EDX:
EAX里面,其中EDX是高位,而EAX是低位。
下面我们以xchg
一句指令的运行时间为例,这段指令在我的真实主机windows
7系统上的运行时间为0000001E,如图6所示:
图6
而该指令在虚拟机WinXP下的运行时间为00000442,如图7所示:
图7
两者之间的运行时间明显差别很多,在虚拟机中的运行速度远不如真实主机的,一般情况下,当它的运行时间大于0xFF时,就可以确定它处于虚拟机之中了,因此不难写出检测程序,具体实现代码如下:
.586p
szTitle
VMDetect
With
RDTSC"
0h
szInsideVM
szOutsideVM
RDTSC
xchg
eax
RDTSC
sub
0FFh
jg
Detected
0,
offset
szOutsideVM,
szTitle,
ret
Detected:
szInsideVM,
r