下面资料比较老了,记录下只为增加下了解
虚拟机后门检测(IN)
__try
{
__asm
{
push edx
push ecx
push ebx
mov eax, 'VMXh'
mov ebx, 0 // 将ebx设置为非幻数’VMXH’的其它值
mov ecx, 10 // 指定功能号,用于获取VMWare版本,当它为x14时用于获取VMware内存大小
mov edx, 'VX' // 端口号
in eax, dx // 从端口dx读取VMware版本到eax
//若上面指定功能号为x14时,可通过判断eax中的值是否大于,若是则说明处于虚拟机中
cmp ebx, 'VMXh' // 判断ebx中是否包含VMware版本’VMXh’,若是则在虚拟机中
setz [rc] // 设置返回值
pop ebx
pop ecx
pop edx
}
rc = true;
}
__except(EXCEPTION_EXECUTE_HANDLER) //如果未处于VMware中,则触发此异常
{
rc = false;
} 虚拟机中IN读取指定端口不会异常,如果异常了为真实机。
时间戳指令检测
__asm
{
push eax
RDTSC
mov ifirst,eax
RDTSC
mov isecond,eax
pop eax
}
isub = isecond - ifirst;
if (isub > 0x0ff) //判断两次之差是否大于0xff
{
MessageBox(L"IN VM",L"Check VM",MB_OK);
}
else
{
MessageBox(L"Not in VM",L"Check VM",MB_OK);
}
MAC地址检测
虚拟机中MAC地址的头两个字节是000c或者0005
ULONG uInfo = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
pMac01 = (BYTE)pAdapterInfo->Address[0];
pMac02 = (BYTE)pAdapterInfo->Address[1];
if (pMac01 == 0x00 && (pMac02 == 0x0c || pMac02 == 0x05) )
MessageBox(L"IN VM",L"Check VM",MB_OK);
else
MessageBox(L"Not in VM",L"Check VM",MB_OK);
进程检测
vmtoolsd.exe,vmtoolsd.exe,VMwareTray.exe,vmacthlp.exe,VMUpgradeHelper.exe虚拟机中存在的进程。
枚举方式可以有多种:
1.创建进程快照(CreateToolhelp32Snapshot)
2. 枚举进程和枚举进程模块,
EnumProcesses和EnumProcessModules
3.通过WMI接口查询进程。
文件检测
通过打开虚拟机相关的文件进行判断
例如:
C:\\Program Files\\VMware\\VMware Tools\\vmtoolsd.exe
char *szFile = "C:\\Program Files\\VMware\\VMware Tools\\vmtoolsd.exe";
HANDLE hVmFile = CreateFileA(szFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
if (hVmFile != INVALID_HANDLE_VALUE)
MessageBox(L"In VM",L"Check VM",MB_OK);
else
MessageBox(L"Not In VM",L"Check VM",MB_OK);
CloseHandle(hVmFile);
注册表检测
注册表里对应的虚拟机的信息非常多,由此可以操作判断虚拟机。
HKEY hKey = NULL;
WCHAR * szSubKey = L"SOFTWARE\\VMware, Inc.\\VMware Tools";
ULONG uReg=RegOpenKeyEx(HKEY_LOCAL_MACHINE,szSubKey ,0,KEY_READ,&hKey);
if (uReg == ERROR_SUCCESS)
MessageBox(L"In VM",L"Check VM",MB_OK);
else
MessageBox(L"Not In VM",L"Check VM",MB_OK);
RegCloseKey(hKey);
磁盘型号Model Number
Disk Serial Number : "WD-WMA9N2077672“
Disk Model Number : "WDC WD80EB-28CGH1 “
Disk Serial Numbe : 硬盘序列号
Disk Model Number : 硬盘型号
我本机的Model Number是:ST350041CC66
虚拟机中的Model Number:VMware,VMware Virtual S1.0
显示卡检测
虚拟机的显示卡名称是VMware SVGA II
if (EnumDisplayDevices(NULL, nDeviceIndex, &DispDev, 0))
{
hr = StringCchCopy((STRSAFE_LPWSTR)lpszMonitorInfo, 0x100, (STRSAFE_LPWSTR)DispDev.DeviceString);
if (FAILED(hr))
{
return FALSE;
}
}
else
{
bRet = FALSE;
}
系统设备检测
虚拟机中存在通讯接口设备和磁盘设备
VMware VMCI Bus Device
VMware, VMware Virtual S SCSI Disk Device
通过枚举系统所有设备信息
如果发现VMCI Device或者DISK Device就是在虚拟机中了
IDT基址检测
typedef struct
{
WORD IDTLimit; // IDT的大小
WORD LowIDTbase; // IDT的低位地址
WORD HiIDTbase; // IDT的高位地址
} IDTINFO;
Redpill作者(?不是bulepill么)在VMware上发现虚拟机系统上的IDT地址通常位于0xFFXXXXXX,而Virtual PC通常位于0xE8XXXXXX,而在真实主机上位于0x80xxxxxx。Redpill仅仅是通过判断执行SIDT指令后返回的第一字节是否大于0xD0,若是则说明它处于虚拟机,否则处于真实主机中。
typedef struct
{
WORD IDTLimit; // IDT的大小
WORD LowIDTbase; // IDT的低位地址
WORD HiIDTbase; // IDT的高位地址
} IDTINFO;
Redpill作者在VMware上发现虚拟机系统上的IDT地址通常位于0xFFXXXXXX,而Virtual PC通常位于0xE8XXXXXX,而在真实主机上位于0x80xxxxxx。Redpill仅仅是通过判断执行SIDT指令后返回的第一字节是否大于0xD0,若是则说明它处于虚拟机,否则处于真实主机中。
LDT和GDT基址检测
在保护模式下,所有的内存访问都要通过全局描述符表(GDT)或者本地描述符表(LDT)才能进行。这些表包含有段描述符的调用入口。各个段描述符都包含有各段的基址,访问权限,类型和使用信息,而且每个段描述符都拥有一个与之相匹配的段选择子,各个段选择子都为软件程序提供一个GDT或LDT索引(与之相关联的段描述符偏移量),一个全局/本地标志(决定段选择子是指向GDT还是LDT),以及访问权限信息。 若想访问段中的某一字节,必须同时提供一个段选择子和一个偏移量。段选择子(寄存器)为段提供可访问的段描述符地址(在GDT 或者LDT 中)。 GDT的线性基址被保存在GDT寄存器(GDTR)中,而LDT的线性基址被保存在LDT寄存器(LDTR)中。
当LDT基址位于0x0000(只有两字节)时为真实主机,否则为虚拟 机,而当GDT基址位于0xFFXXXXXX时说明处于虚拟机中,否则为真实主机
unsigned short ldt_addr = 0;
unsigned char ldtr[2] = {0};
__asm
{
sldt ldtr
}
ldt_addr = *((unsigned short *)&ldtr);
if(ldt_addr != 0x0000)
{
MessageBox(L"IN VM",L"Check VM",MB_OK);
}
else
{
MessageBox(L"Not in VM",L"Check VM",MB_OK);
}
GDT基址位于0xFFXXXXXX处于虚拟机中,真实机在x80XXXXXX
unsigned int gdt_addr = 0;
unsigned char gdtr[4];
_asm sgdt gdtr
gdt_addr = *((unsigned int *)&gdtr[2]);
printf("GDT BaseAddr:0x%x\n", gdt_addr);
if((gdt_addr >> 24) == 0xff)
{
MessageBox(L"IN VM",L"Check VM",MB_OK);
}
else
{
MessageBox(L"Not in VM",L"Check VM",MB_OK);
}
STR检测
在保护模式下运行的所有程序在切换任务时,对于当前任务中指向TSS的段选择器将会被存储在任务寄存器中,TSS中包含有当前任务的可执行环境状态,包括各种寄存器状态等等,当任务再次被执行时,处理器就会保存原先的任务状态。每项任务均有其自己的TSS,而我们可以通过STR指令来获取指向当前任务中TSS的段选择器。这里STR(Store task register)指令是用于将任务寄存器 (TR) 中的段选择器存储到目标操作数,目标操作数可以是通用寄存器或内存位置,使用此指令存储的段选择器指向当前正在运行的任务的任务状态段 (TSS)。在虚拟机和真实主机之中,通过STR读取的地址是不同的,当地址等于0x0040xxxx时,说明处于虚拟机中,否则为真实主机。
Str将任务寄存器(TR) 中的段选择器存储到目标操作数
当地址等于x0040xxxx时,说明处于虚拟机中,否则为真实机
unsigned char mem[2] = {0};
__asm str mem;
if ( (mem[0]==0x00) && (mem[1]==0x40))
{
MessageBox(L"IN VM",L"Check VM",MB_OK);
}
else
{
MessageBox(L"Not in VM",L"Check VM",MB_OK);
}