在当今信息安全领域,特别是恶意软件分析中,经常需要利用到虚拟机技术,以提高病毒分析过程的安全性以及硬件资源的节约性,因此它在恶意软件领域中是应用越来越来广泛。这里我们所谓的虚拟机(Virtual Machine)是指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。
虚拟机检测
一、VMWare
1.1查找注册表
通过检测注册表“HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0”,在数据项中查找目标数据VMWARE
HKEY_LOCAL_MACHINE_SYSTEM_ControlSet001\Services\VMware Pyhsical Disk Helper Service
1.2搜索特定程序
Vmtoolsd.exe vmacthlp.exe VMwareUser.exe VMwareTray.exe VMUpgradeHelper.exe bool SearchTargetPro(WCHAR* strProName) { PROCESSENTRY32 pe32; pe32.dwSize = sizeof(pe32); HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) { exit(1); } bool bMore = ::Process32First(hProcessSnap, &pe32); while (bMore) { if (wcsstr(pe32.szExeFile, strProName)) { return true; bMore = false; } else { bMore = ::Process32Next(hProcessSnap, &pe32); } } CloseHandle(hProcessSnap); return bMore; }
1.3通过执行特权指令
Vmware为真主机与虚拟机之间提供了相互沟通的通讯机制,它使用“IN”指令来读取特定端口的数据以进行两机通讯,但由于IN指令属于特权指令,在处于保护模式下的真机上执行此指令时,除非权限允许,否则将会触发类型为“EXCEPTION_PRIV_INSTRUCTION”的异常,而在虚拟机中并不会发生异常,在指定功能号0A(获取VMware版本)的情况下,它会在EBX中返回其版本号“VMXH”;而当功能号为0x14时,可用于获取VMware内存大小,当大于0时则说明处于虚拟机中。VMDetect正是利用前一种方法来检测VMware的存在,其检测代码分析如下:
void IsInsideVMWare() { bool rc = true; __try { __asm { push edx push ecx push ebx mov eax, 'VMXh' mov ebx, 0 // 将ebx设置为非幻数’VMXH’的其它值 mov ecx, 10 // 指定功能号,用于获取VMWare版本,当它为0x14时用于获取VMware内存大小 mov edx, 'VX' // 端口号 in eax, dx // 从端口dx读取VMware版本到eax //若上面指定功能号为0x14时,可通过判断eax中的值是否大于0,若是则说明处于虚拟机中 cmp ebx, 'VMXh' // 判断ebx中是否包含VMware版本’VMXh’,若是则在虚拟机中 setz [rc] // 设置返回值 pop ebx pop ecx pop edx } } __except (EXCEPTION_EXECUTE_HANDLER) //如果未处于VMware中,则触发此异常 { rc = false; } if (rc == true) { cout << "In VMWare!" << endl; } else { cout << "Not In VMWare!" << endl; } } void test6(void) { unsigned int a = 0; __try { __asm { // save register values on the stack push eax push ebx push ecx push edx // perform fingerprint mov eax, 'VMXh' mov ecx, 14h mov dx, 'VX' in eax, dx mov a, eax pop edx pop ecx pop ebx pop eax } } __except (EXCEPTION_EXECUTE_HANDLER) {} printf("\n[+] Test 6: VMware \"get memory size\" command\n"); if (a > 0) printf("Result : VMware detected\n\n"); else printf("Result : Native OS\n\n"); }
1.4查找特定的驱动模块
hgfs.sys vmhgfs.sys prleth.sys prlfs.sys prlmouse.sys prlvideo.sys prl_pv32.sys vpc-s3.sys vmsrvc.sys vmx86.sys vmnet.sys
1.5 CPUID
原理介绍:当eax=1时,运行CPUID之后,ecx的高31位可以判断出是否在虚拟机中,如果ecx的高31位为0表示在虚拟机下,否则在主机下
参考代码:
void CheckCPUID() { DWORD dwECX = 0; bool isVM = true; _asm { pushad; pushfd; mov eax, 1; cpuid; mov dwECX, ecx; and ecx, 0x80000000; test ecx, ecx; setz[isVM]; popfd; popad; } if (isVM)//主机下 { cout << "在主机下" << endl; } else//虚拟机下 { cout << "在虚拟机下" << endl; } } 当eax=0x40000000时,运行CPUID之后,ebx+ecx+edx=”VMWareVMWare”; 参考代码: void CheckCPUID() { DWORD dwECX = 0; bool isVM = true; DWORD dwReg[3] = { 0 }; _asm { pushad; pushfd; mov eax, 0x40000000; cpuid; mov dword ptr[dwReg], ebx; mov dword ptr[dwReg + 4], ecx; mov dword ptr[dwReg + 8], edx; popfd; popad; } printf("%s\r\n", dwReg); }
1.6检测系统对象
在WinXP和Win7中都有VMwareToolsQuitEvent_wmsvc和VMwareToolsDumpStateEvent_vmsvc,可以通过检测这两项事件对象是否存在来判断是不是运行在虚拟机里
图:XP下检测结果
图:win7下检测结果
1.7查询csrss.exe内存中的可疑字符
1.8硬件特征
VMWare硬件特征如下所示:
显卡 Name=VMware SVGA II
网卡 Name=VMware Accelerated AMD PCNet Adapter
鼠标 Name=VMware Pointing Device
磁盘驱动器 Caption=VMware Virtual IDE Hard Drive
SCSI控制器 name=VMware VMSCSI Controller
可以通过获取当前系统的硬件信息来判定是否运行在虚拟机中。
二、Virtual PC
2.1使用非法指令:
使用非法指令0x0F,0x3F,0xXX,0xXX。这些指令在VirtualPC上不会产生异常,但是在主机和其他虚拟机中会产生异常。并且需要注册异常处理函数来处理
参考代码:
static DWORD lpOldHandler; typedef LPTOP_LEVEL_EXCEPTION_FILTER(_stdcall *pSetUnhandledExceptionFilter)( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ); pSetUnhandledExceptionFilter lpSetUnhandledExceptionFilter; LONG WINAPI TopUnhandledExceptionFilter( struct _EXCEPTION_POINTERS *ExceptionInfo ) { _asm pushad // lpSetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)lpOldHandler); // ExceptionInfo->ContextRecord->Eip = NewEip;//转移到安全位置 MessageBox(NULL,L"HelloWorld",L"hh",0); _asm popad return EXCEPTION_CONTINUE_EXECUTION; } void CheckOrder() { // TODO: Add your control notification handler code here lpSetUnhandledExceptionFilter = (pSetUnhandledExceptionFilter)GetProcAddress(LoadLibrary((L"kernel32.dll")), "SetUnhandledExceptionFilter"); //当异常没有处理的时候,系统就会调用此函数所设置的异常处理函数,此函数返回以前设置的回调函数 lpOldHandler = (DWORD)lpSetUnhandledExceptionFilter(TopUnhandledExceptionFilter); _asm { //获取这个安全地址 } _asm { __emit 0Fh __emit 3Fh __emit 07h __emit 0Bh } }
2.2检测系统对象
2.3硬件特征
Virtual PC的硬件特征如下:
光驱:Caption=MS C/DVD-ROM Name=MS C/DVD-ROM
硬盘:Caption=Virtual HD Model=Virtual HD
显卡:Caption=Virtual PC Intergration Components S3 Trio32/64
Description=Virtual PC Intergration Components S3 Trio32/64
Name= Virtual PC Intergration Components S3 Trio32/64
InfSection=vpc-s3 VideoProcessor=S3 732
主板:Manufacturer=Microsoft Corporation Product=Virtual Machine
特定指令:CPUID
功能号:0x40000001
返回: eax=“VPC7” ,最后一个数字可变
可以通过获取硬件特征值来进行判定是否运行在虚拟机里
三、VirtualBox
3.1搜索注册表项
搜索特定的注册表项来判断是不是运行在虚拟系统中。
3.2CPUID
原理介绍:当eax=0x40000000时,运行CPUID之后,ebx,ecx,edx不等于0,则运行在虚拟机里,如果等于0表示不在虚拟机里。
实例代码:
BOOL isVirtualBoxBySpecInstruct() { bool res = FALSE; __asm { mov eax,0x40000000 //HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS cpuid cmp ebx,0 //ebx,ecx,edx != 0 in vm other not in vm jne l1 mov res,0 jmp ed l1: mov res,1 ed: } return res; }
3.3硬件特征
VirtualBox的硬件特征如下:
光驱:Caption=VBOX CD-ROM Name=VBOX CD-ROM
硬盘:Caption=VBOX HARDDISK Model=VBOX HARDDISK
显卡:Caption=VirtualBox Graphics Adapter Description=VirtualBox Graphics Adapter
InfSection=VBOXVideo Name=VirtualBox Graphics Adapter
VideoProcessor=VBOXVideo
BIOS:Manufacturer=innotek GmbH SMBIOSVersion=VirtualBox
Version=VBOX – 1
主板:Manufacturer=Oracle Corporation Product=VirtualBox
可以通过获取硬件特征值来进行判定是否运行在虚拟机里
3.4搜索特定进程
在虚拟机里,会有一些虚拟机特有的进程,可以通过检测这些进程是否存在来判断是不是运行在虚拟机里。
VBoxService.exe
VBoxTray.exe
3.5查找底层模块
虚拟机的服务需要有底层模块的支持,一些比较明显的模块有如下几个。
VBoxGuest.sys
VBoxSF.sys
VBoxMouse.sys
VBoxVideo.sys
VBoxDisp.dll
四、SandBox
4.1检测系统对象
Sandbox开启之后,会在会在RPC Control目录下,有一个端口名称:SbieSvcPort
4.2查看当前进程是否包含目标动态库
在当前的进程空间中搜索目标动态库来判断是否运行在沙箱中
Comodo sandbox—–cmdvrt32.dll
Qihoo360 sandbox—-SxIn.dll
Sandboxie sandbox—–SbieDll.dll
参考代码:
void CheckSbieDll() { TCHAR ModuleToFind[MAX_PATH] = L"SbieDll.dll"; HMODULE moduleHandle[1024]; DWORD cbNeeded; unsigned int i; HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,GetCurrentProcessId()); if (hProcess == NULL) { cout << "OpenProcess Error" << endl; } if (EnumProcessModules(hProcess, moduleHandle, sizeof(moduleHandle), &cbNeeded)) { for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { TCHAR moduleName[MAX_PATH]; if (GetModuleFileNameEx(hProcess, moduleHandle[i], moduleName, sizeof(moduleName) / sizeof(TCHAR))) { if (wcsstr(moduleName, ModuleToFind) != nullptr) { cout << "In SandBox" << endl; return; } } } } else { cout << "EnumProcessModules Error" << endl; return; } cout << "Not In SandBox" << endl; return; }
4.3检测SbieDll.dll与API完整性
SandBoxie会注入SBIEDLL.DLL,HOOK应用程序使用的API函数,API函数会先跳转到该DLL。
Sanboxie可能会隐藏该SbieDll.dll,所以另一种方法是检测NTDLL API函数的完整性。
如果要检测要调用的API函数是否被HOOK,可以判断对应函数的前5个字节是不是0xE9 0xXXXXXXXX,如果被HOOK了,可以通过使用枚举进程模块的方法查看是被哪个模块HOOK了。
4.4检测CPU个数
通常情况下,虚拟机或者沙箱中的CPU个数是1,所以通过检测虚拟机的个数也可以检测是否运行在虚拟机中。
4.5可成功提权的进程个数
沙盒提供了与主机环境非常相似的环境,很多恶意软件的分析就是在沙盒中进行的,检测程序是否运行在沙盒当中的方法就是通过对已有进程的提权操作然后进行统计,统计为可以成功提权的进程数小于等于10(这里为统计值)的时候为程序运行在沙盒环境。
图:主机运行结果
图:沙箱运行结果
五、其他(PARALLELS、QEMU、XEN、BOCHS)
5.1 PARALLELS
这是一款运行在Mac电脑上安装windows系统的虚拟机软件,这样就能够在Mac下非常方便的运行Widows操作系统的应用,并且可以轻松切换到苹果的Mac系统,对于苹果电脑用户来说还是很实用的。
检测程序是否运行在PARALLELS中可以通过硬件特征,CPU ID指令和进程特征进行检测
硬件特征:
显卡: Caption= Parallels Video Adapter Description= Parallels Video Adapter
Name= Parallels Video Adapter VideoProcessor= Virtual Adapter
网卡: Caption= Parallels Ethernet Adapter Description= Parallels Ethernet Adapter
Manufacturer= Parallels Name= Parallels Ethernet Adapter
ProductName= Parallels Ethernet Adapter
鼠标: Caption= Parallels Mouse Synchronization Device
Description= Parallels Mouse Synchronization Device
Manufacturer= Parallels Name= Parallels Mouse Synchronization Device
声卡: Caption= Parallels Audio Controller (x32) Manufacturer= Parallels
Description= Parallels Audio Controller (x32)
Name= Parallels Audio Controller (x32)
ProductName= Parallels Audio Controller (x32)
主板: Manufacturer= Parallels Software International Inc.
Product= Parallels Virtual Platform
BIOS: Manufacturer= Parallels Software International Inc.
SerialNumber= Parallels-5E 48 47 9F B5 30 7A 47 84 DB 58 97 C5 AF AB 85
Version= PRLS – 1
进程特征:
coherence.exe prl-tool-service.exe
特殊指令,CPUID,类型如下:
检测结果如下图所示:
5.2 QEMU
QEMU是一款开源的模拟器及虚拟机监管器(Virtual Machine Monitor, VMM)。QEMU主要提供两种功能给用户使用。一是作为用户态模拟器,利用动态代码翻译机制来执行不同于主机架构的代码。二是作为虚拟机监管器,模拟全系统,利用其他VMM(Xen, KVM, etc)来使用硬件提供的虚拟化支持,创建接近于主机性能的虚拟机。
可以使用qemu的硬件特征和CPUID指令来检测程序是否运行在qemu虚拟机里面。
QEMU的硬件特征为
CPU:Name = QEMU Virtual CPU Version
DISK:Caption=QEMU HARDDISK
BIOS:Manufacturer=Seabios
CDROM:Caption=QEMU QEMU DVD-ROM
Name=QEMU QEMU DVD-ROM
特殊指令:CPUID,使用的功能号为eax= 0x80000002,这样的话,CPUID指令将提取处理器商标的字符串,在qemu下面是QEMU Virtual CPU Version
5.3 XEN
硬件特征:
DISK:Caption=XENSRC PVDISK SCSI Disk Device
BIOS:Manufacturer=Xen
CDROM:Caption=QEMU QEMU DVD-ROM ATA Device
Name=QEMU QEMU DVD-ROM ATA Device
SCSI控制器:Catption=Citrix PV Storage Host Adapter
特殊指令:使用CPUID指令,类型如下:
图:检测结果
5.4 BOCHS
Bochs是一个x86硬件平台的开源模拟器。它可以模拟各种硬件的配置。Bochs模拟的是整个PC平台,包括I/O设备、内存和BIOS。
检测方法通过硬件特征和特殊指令
硬件特征:
光驱: Caption=BOCHS Generic CD-ROM Name=BOCHS Generic CD-ROM
BIOS: BiosVersion=BOCHS -1 Manufacturer=The Bochs Project
SMBIOSVersion=Bochs Version=BOCHS -1
特殊指令:CPUID
功能号如下:
执行指令后如果返回值:eax=0x40 ebx=0x40 ecx=0x3 edx=0x20,那么程序运行在虚拟机中。
图:检测结果
声 明
本安全公告仅用来描述可能存在的安全问题,绿盟科技不为此安全公告提供任何保证或承诺。由于传播、利用此安全公告所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,绿盟科技以及安全公告作者不为此承担任何责任。绿盟科技拥有对此安全公告的修改和解释权。如欲转载或传播此安全公告,必须保证此安全公告的完整性,包括版权声明等全部内容。未经绿盟科技允许,不得任意修改或者增减此安全公告内容,不得以任何方式将其用于商业目的。
关于绿盟科技
北京神州绿盟信息安全科技股份有限公司(简称绿盟科技)成立于2000年4月,总部位于北京。在国内外设有30多个分支机构,为政府、运营商、金融、能源、互联网以及教育、医疗等行业用户,提供具有核心竞争力的安全产品及解决方案,帮助客户实现业务的安全顺畅运行。
基于多年的安全攻防研究,绿盟科技在网络及终端安全、互联网基础安全、合规及安全管理等领域,为客户提供入侵检测/防护、抗拒绝服务攻击、远程安全评估以及Web安全防护等产品以及专业安全服务。
北京神州绿盟信息安全科技股份有限公司于2014年1月29日起在深圳证券交易所创业板上市交易,股票简称:绿盟科技,股票代码:300369。
如果您需要了解更多内容,可以
加入QQ群:570982169
直接询问:010-68438880