《虚拟机去虚拟化及检测技术攻防(共30页).docx》由会员分享,可在线阅读,更多相关《虚拟机去虚拟化及检测技术攻防(共30页).docx(30页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、精选优质文档-倾情为你奉上在当今信息安全领域,特别是恶意软件分析中,经常需要利用到虚拟机技术,以提高病毒分析过程的安全性以及硬件资源的节约性,因此它在恶意软件领域中是应用 越来越来广泛。这里我们所谓的虚拟机(VirtualMachine)是指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算 机系统。通过虚拟机软件(比如VMware,VirtualPC,VirtualBox),你可以在一台物理计算机上模拟出一台或多台虚拟的计算机, 这些虚拟机完全就像真正的计算机那样进行工作,例如你可以安装操作系统、安装应用程序、访问网络资源等等。攻击者为了提高恶意程序的隐蔽性以及破坏真实
2、主 机的成功率,他们都在恶意程序中加入检测虚拟机的代码,以判断程序所处的运行环境。当发现程序处于虚拟机(特别是蜜罐系统)中时,它就会改变操作行为或者 中断执行,以此提高反病毒人员分析恶意软件行为的难度。本文主要针对基于IntelCPU的虚拟环境VMware中的WindowsXPSP3系统 进行检测分析,并列举出当前常见的几种虚拟机检测方法。方法一:通过执行特权指令来检测虚拟机 Vmware为真主机与虚拟机之间提供了相互沟通的通讯机制,它使用“IN”指令来读取特定端口的数据以进行两机通讯,但由于IN指令属于特权指令,在 处于保护模式下的真机上执行此指令时,除非权限允许,否则将会触发类型为“EXC
3、EPTION_PRIV_INSTRUCTION”的异常,而在虚拟机中 并不会发生异常,在指定功能号0A(获取VMware版本)的情况下,它会在EBX中返回其版本号“VMXH”;而当功能号为0x14时,可用于获取 VMware内存大小,当大于0时则说明处于虚拟机中。VMDetect正是利用前一种方法来检测VMware的存在,其检测代码分析如下:代码:boolIsInsideVMWare() boolrc=true;_try_asmpushedxpushecxpushebxmoveax,VMXhmovebx,0/将 ebx设置为非幻数VMXH的其它值movecx,10/指定功能号,用于获取VMWa
4、re版本,当它为0x14时用于 获取VMware内存大小movedx,VX/端口号ineax,dx/从端口dx读取 VMware版本到eax/若上面指定功能号为0x14时,可通过判断eax中的值是否大于0,若是则说明处于虚拟机 中cmpebx,VMXh/判断ebx中是否包含VMware版本VMXh,若是则在虚拟机 中setzrc/设置返回 值popebxpopecxpopedx_except(EXCEPTION_EXECUTE_HANDLER)/ 如果未处于VMware中,则触发此异常rc=false;returnrc;测试结果:图1如图1所示,VMDetect成功检测出VMWare的存在。方
5、法二:利用IDT基址检测虚拟机 利用IDT基址检测虚拟机的方法是一种通用方式,对VMware和VirtualPC均适用。中断描述符表 IDT(InterruptDescriptorTable)用于查找处理中断时所用的软件函数,它是一个由256项组成的数据,其中每一中断对应一 项函数。为了读取IDT基址,我们需要通过SIDT指令来读取IDTR(中断描述符表寄存器,用于IDT在内存中的基址),SIDT指令是以如下格式来存 储IDTR的内容:代码:typedefstructWORDIDTLimit;/IDT的大小WORDLowIDTbase;/IDT的低位地址WORDHiIDTbase;/IDT的高
6、位地址IDTINFO; 由于只存在一个IDTR,但又存在两个操作系统,即虚拟机系统和真主机系统。为了防止发生冲突,VMM(虚拟机监控器)必须更改虚拟机中的IDT地址,利 用真主机与虚拟机环境中执行sidt指令的差异即可用于检测虚拟机是否存在。著名的“红丸”(redpill)正是利用此原理来检测VMware的。 Redpill作者在VMware上发现虚拟机系统上的IDT地址通常位于0xFFXXXXXX,而VirtualPC通常位于0xE8XXXXXX, 而在真实主机上正如图2所示都位于0x80xxxxxx。Redpill仅仅是通过判断执行SIDT指令后返回的第一字节是否大于0xD0,若是则说明它
7、 处于虚拟机,否则处于真实主机中。Redpill的源码甚是精简,源码分析如下:代码:#includeintmain()unsignedcharm2+4,rpill=x0f x01x0dx00x00x00x00xc3;/相当于SIDTadrr,其中addr用于保存IDT地址* (unsigned*)&rpill3)=(unsigned)m;/将sidtaddr中的addr设为m的地 址(void(*)()&rpill)();/执行SIDT指令,并将读取后IDT地址保存在数组m 中printf(idtbase:%#xn,*(unsigned*)&m2);/由于前2字节为IDT大 小,因此从m2开始
8、即为IDT地 址if(m50xd0)printf(InsideMatrix!n,m5);/当IDT基址大于 0xd0xxxxxx时则说明程序处于VMware中elseprintf(NotinMatrix.n);return0;测试结果如图2所示: 图2 利用此IDT检测的方法存在一个缺陷,由于IDT的值只针对处于正在运行的处理器而言,在单CPU中它是个常量,但当它处于多CPU时就可能会受到影响 了,因为每个CPU都有其自己的IDT,这样问题就自然而然的产生了。针对此问题,OffensiveComputing组织成员提出了两种应对方法, 其中一种方法就是利用Redpill反复地在系统上循环执行任
9、务,以此构造出一张当前系统的IDT值变化统计图,但这会增加CPU负担;另一种方法就是 windowsAPI函数SetThreadAffinityMask()将线程限制在单处理器上执行,当执行此测试时只能准确地将线程执行环境限制在 本地处理器,而对于将线程限制在VM处理器上就可能行不通了,因为VM是计划在各处理器上运行的,VM线程在不同的处理器上执行时,IDT值将会发生变 化,因此此方法也是很少被使用的。为此,有人提出了使用LDT的检测方法,它在具有多个CPU的环境下检测虚拟机明显优于IDT检测方法,该方法具体内容 参见下节内容。 方法三:利用LDT和GDT的检测方法 在Intel64andIA
10、- 32ArchitectureSoftwareDevelopersManualVolume3A:SystemProgrammingGuide 第二章的Vol.32-5一页(我的Intel开发手册是2008版的)中对于LDT和GDT的描述如下(以下内容为个人翻译):在 保护模式下,所有的内存访问都要通过全局描述符表(GDT)或者本地描述符表(LDT)才能进行。这些表包含有段描述符的调用入口。各个段描述符都包含有 各段的基址,访问权限,类型和使用信息,而且每个段描述符都拥有一个与之相匹配的段选择子,各个段选择子都为软件程序提供一个GDT或LDT索引(与之相 关联的段描述符偏移量),一个全局/本地
11、标志(决定段选择子是指向GDT还是LDT),以及访问权限信息。 若想访问段中的某一字节,必须同时提供一个段选择子和一个偏移量。段选择子为段提供可访问的段描述符地址(在GDT或者LDT中)。通过段描述符, 处理器从中获取段在线性地址空间里的基址,而偏移量用于确定字节地址相对基址的位置。假定处理器在当前权限级别(CPL)可访问这个段,那么通过这种机制 就可以访问在GDT或LDT中的各种有效代码、数据或者堆栈段,这里的CPL是指当前可执行代码段的保护级别。 GDT的线性基址被保存在GDT寄存器(GDTR)中,而LDT的线性基址被保存在LDT寄存器(LDTR)中。 由于虚拟机与真实主机中的GDT和LD
12、T并不能相同,这与使用IDT的检测方法一样,因此虚拟机必须为它们提供一个“复制体”。关于GDT和LDT的基 址可通过SGDT和SLDT指令获取。虚拟机检测工具Scoopysuite的作者TobiasKlein经测试发现,当LDT基址位于 0x0000(只有两字节)时为真实主机,否则为虚拟机,而当GDT基址位于0xFFXXXXXX时说明处于虚拟机中,否则为真实主机。具体实现代码如 下: 代码:#includevoidLDTDetect(void)unsignedshortldt_addr=0;unsignedcharldtr2;_asmsldtldtrldt_addr=*(unsignedsho
13、rt*)&ldtr);printf(LDTBaseAddr:0x%xn,ldt_addr);if(ldt_addr=0x0000)printf(NativeOSn);elseprintf(InsideVMwaren);voidGDTDetect(void)unsignedintgdt_addr=0;unsignedchargdtr4;_asmsgdtgdtrgdt_addr=*(unsignedint*)&gdtr2);printf(GDTBaseAddr:0x%xn,gdt_addr);if(gdt_addr24)=0xff)printf(InsideVMwaren);elseprintf(
14、NativeOSn);intmain(void)LDTDetect();GDTDetect();return0;测试结果如图3所示: 图3方法四:基于STR的检测方法 在保护模式下运行的所有程序在切换任务时,对于当前任务中指向TSS的段选择器将会被存储在任务寄存器中,TSS中包含有当前任务的可执行环境状态,包括 通用寄存器状态,段寄存器状态,标志寄存器状态,EIP寄存器状态等等,当此项任务再次被执行时,处理器就会其原先保存的任务状态。每项任务均有其自己的 TSS,而我们可以通过STR指令来获取指向当前任务中TSS的段选择器。这里STR(Storetaskregister)指令是用于将任务寄存
15、器(TR)中的段选择器存储到目标操作数,目标操作数可以是通用寄存器或内存位置,使用此指令存储的段选择器指向当前正在运行的任务的任务状态 段(TSS)。在虚拟机和真实主机之中,通过STR读取的地址是不同的,当地址等于0x0040xxxx时,说明处于虚拟机中,否则为真实主机。实现代 码如下:代码:#includeintmain(void) unsignedcharmem4=0;inti;_asmstrmem;printf(STRbase:0x);for(i=0;i& lt;4;i+)printf(%02x,memi);if(mem0=0x00)& amp;&(mem1=0x40)printf(nI
16、NSIDEMATRIX! n);elseprintf(nNativeOS!n);return0;测试结果如图4所示:图4方法五:基于注册表检测虚拟机 在windows虚拟机中常常安装有VMwareTools以及其它的虚拟硬件(如网络适配器、虚拟打印机,USB集线器),它们都会创建任何程序 都可以读取的windows注册表项,因此我们可以通过检测注册表中的一些关键字符来判断程序是否处于虚拟机之中。关于这些注册表的位置我们可以通过在注 册表中搜索关键词“vmware”来获取,下面是我在VMware下的WinXP中找到的一些注册表项:项名:HKEY_CLASSES_ROOTApplicationsV
17、MwareHostOpen.exe项名:HKEY_CLASSES_ROOTInstallerProductsC2A6F2EFEC940B2B12CF170FEProductName键值“VMwareTools”项名:HKEY_CLASSES_ROOTInstallerProductsC2A6F2EFEC940B2B12CF170FESourceListPackageName键值:VMwareTools.msi项名:HKEY_CURRENT_USERPrintersDeviceOld键值:_#VMwareVirtualPrinter,winspool,TPVM:项名:HKEY_LOCAL_MAC
18、HINEHARDWAREDEVICEMAPScsiScsiPort0ScsiBus0TargetId0LogicalUnitId0Identifier键值:VMwareVirtualIDEHardDrive项名:HKEY_LOCAL_MACHINEHARDWAREDEVICEMAPScsiScsiPort1ScsiBus0TargetId0LogicalUnitId0Identifier键值:NECVMWarVMwareIDECDR10项名:HKEY_LOCAL_MACHINESOFTWAREClassesInstallerProductsC2A6F2EFEC940B2B12CF170FEPr
19、oductName键值:VMwareTools项 名:HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionInstaller UserDataS-1-5-18ProductsC2A6F2EFEC940B2B12CF170FEInstallPropertiesDisplayName键值:VMwareTools项名:HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionReinstall0002DeviceDesc键值:VMwareSVGAII项名:HKEY_LOCAL_MACHI
20、NESOFTWAREMicrosoftWindowsNTCurrentVersionNetworkCards2Description键值:VMwareAcceleratedAMDPCNetAdapter项名:HKEY_LOCAL_MACHINESOFTWAREVMware,Inc.VMwareTools项名:HKEY_LOCAL_MACHINESYSTEMControlSet001ControlClass4D36E968-E325-11CE-BFC1-08002BE103180000DriverDesc键值:VMwareSVGAII项名:HKEY_LOCAL_MACHINESYSTEMCont
21、rolSet001ControlClass4D36E968-E325-11CE-BFC1-08002BE103180000ProviderName键值:VMware,Inc.项名:HKEY_LOCAL_MACHINESYSTEMControlSet001ControlClass4D36E972-E325-11CE-BFC1-08002bE103180001DriverDesc键值:VMwareAcceleratedAMDPCNetAdapter项名:HKEY_LOCAL_MACHINESYSTEMControlSet001ControlClass4D36E97B-E325-11CE-BFC1-
22、08002BE103180000DriverDesc键值:VMwareSCSIController项名:HKEY_LOCAL_MACHINESYSTEMControlSet001ControlPrintMonitorsThinPrintPrintPortMonitorforVMWare补充另外一处 具体代码如下:cpp1. BOOLDetectVM()2. 3. HKEYhKey;4. 5. charszBuffer64;6. 7. unsignedlonghSize=sizeof(szBuffer)-1;8. 9. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,HAR
23、DWAREDESCRIPTIONSystemBIOS,0,KEY_READ,&hKey)=ERROR_SUCCESS)10. 11. RegQueryValueEx(hKey,SystemManufacturer,NULL,NULL,(unsignedchar*)szBuffer,&hSize);12. 13. if(strstr(szBuffer,VMWARE)14. 15. RegCloseKey(hKey);16. 17. returnTRUE;18. 19. 20. 21. RegCloseKey(hKey);22. 23. 24. 25. returnFALSE;26. 27. 除以
24、上这些表项之外,还有很多地方可以检测,特别是虚拟机提供的虚拟化软硬件、服务之类,比如文件共享服务,VMware物理磁盘助手服 务,VMwareEthernetAdapterDriver,VMwareSCSIController等等的这些信息都可作为检测虚拟机的 手段。这里我们就以其中某表项为例编程举例一下,其它表项检测方法同理,具体代码如下:代码:.386.modelflat,stdcalloptioncasemap:noneincludewindows.incincludeuser32.incincludekernel32.incincludeadvapi32.incincludelibus
25、er32.libincludelibkernel32.libincludelibadvapi32.lib.dataszCaptiondbVMwareDetector,0szInsidedbInsideVMware!,0szOutsidedbNativeOS!,0szSubKeydbsoftwareVMWare,Inc.VMwaretools,0hKeydd?.codestart:invokeRegOpenKeyEx,HKEY_LOCAL_MACHINE,addrszSubKey,0,KEY_WRITEorKEY_READ,addrhKey.ifeax=ERROR_SUCCESSinvokeMe
26、ssageBox,NULL,addrszInside,addrszCaption,MB_OK.elseinvokeMessageBox,NULL,addrszOutside,addrszCaption,MB_OK.endifinvokeRegCloseKey,hKeyinvokeExitProcess,NULLendstart测试结果如图5所示:图5方法六:基于时间差的检测方式 本方法通过运行一段特定代码,然后比较这段代码在虚拟机和真实主机之中的相对运行时间,以此来判断是否处于虚拟机之中。这段代码我们可以通过RDTSC指 令来实现,RDTSC指令是用于将计算机启动以来的CPU运行周期数存放到E
27、DX:EAX里面,其中EDX是高位,而EAX是低位。下面我们以 xchgecx,eax一句指令的运行时间为例,这段指令在我的真实主机windows7系统上的运行时间为E,如图6所 示: 图6而该指令在虚拟机WinXP下的运行时间为,如图7所示:图7两者之间的运行时间明显差别很多,在虚拟机中的运行速度远不如真实主机的,一般情况下,当它的运行时间大于0xFF时,就可以确定它处于虚拟机之中了,因此不难写出检测程序,具体实现代码如下: 代码:.586p.modelflat,stdcalloptioncasemap:noneincludewindows.incincludekernel32.incinc
28、ludeuser32.incincludelibkernel32.libincludelibuser32.lib.dataszTitledbVMDetectWithRDTSC,0hszInsideVMdbInsideVMware!,0hszOutsideVMdbNativeOS!,0h.codestart:RDTSCxchgecx,eaxRDTSCsubeax,ecxcmpeax,0FFhjgDetectedinvokeMessageBox,0,offsetszOutsideVM,offsetszTitle,0retDetected:invokeMessageBox,0,offsetszIns
29、ideVM,offsetszTitle,0retendstart测试结果如图8所示:图8 方法七:利用虚拟硬件指纹检测虚拟机利 用虚拟硬件指纹也可用于检测虚拟机的存在,比如VMware默认的网卡MAC地址前缀为“00-05-69,00-0C-29或者00-50-56”,这 前3节是由VMware分配的唯一标识符OUI,以供它的虚拟化适配器使用。在我的VMWareWinXP下的MAC地址为00-0C-29-5B- D7-67,如图9所示:图9 但由于这些可经过修改配置文件来绕过检测。另外,还可通过检测特定的硬件控制器,BIOS,USB控制器,显卡,网卡等特征字符串进行检测,这些在前面使用注册表检
30、测方法中已有所涉及。另外之前在看雪论坛上也有朋友提到通过检测硬盘ModelNumber是否含有“vmware”或“virtual”等字样来实现检测虚拟机的功能,具体转载如下:cpp1. 小试antivmware2. 今天偶然看到一款绿色版的硬盘专业工具,突然发现可以利用其中的一项功能来实现antivmware。3. 今日事今日毕,那就在今晚12:00之前把这个想法实现吧,letsgo!4. 我的想法就是检测硬盘的modelnumber,具体什么是modelnumber自己网上搜吧,反正不是硬盘序列号。难点就是在多种操作系统下都要能起到antivmware的效果。程序在xp、2k、2003下都可
31、以检测到vmware的运行。5. 直接贴代码了,如果看不懂也没关系,我也是逆了人家的代码写出来的。Delphi也可以当汇编语言开发工具用,难道不是吗?6. unitUnit1;7. interface8. uses9. Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,10. Dialogs,StdCtrls,Buttons;11. type12. TForm1=class(TForm)13. BitBtn1:TBitBtn;14. procedureBitBtn1Click(Sender:TObject);1
32、5. procedureFormClose(Sender:TObject;varAction:TCloseAction);16. private17. Privatedeclarations18. public19. Publicdeclarations20. end;21. 22. var23. Form1:TForm1;24. hDeviceHandle:Thandle;25. 26. implementation27. 28. $R*.dfm29. 30. procedureTForm1.BitBtn1Click(Sender:TObject);31. var32. InBuffer:a
33、rray0.$8fofbyte;33. cb:Cardinal;34. tmp:Pchar;35. begin36. hDeviceHandle:=CreateFile(.PHYSICALDRIVE0,$C,$3,nil,OPEN_EXISTING,$,0);37. ZeroMemory(InBuffer,sizeof(InBuffer);38. asm39. pushad40. leaebx,InBuffer41. xorecx,ecx42. moval,$2c43. MOVebx,al44. MOVEAX,$200c000045. MOVebx+4,eax46. moval,$0147.
34、MOVebx+8,al48. moval,$4049. MOVebx+$c,al50. MOVEAX,$0001a5E051. MOVebx+$10,eax52. moval,$3053. MOVebx+$18,al54. moval,$1255. MOVebx+$1c,al56. moval,$4057. MOVebx+$20,al58. addecx,ebx59. addecx,$5060. MOVebx+$14,ecx61. popad62. end;63. 64. 65. ifDeviceIoControl(hDeviceHandle,$4D014,InBuffer,$50,InBuf
35、fer,$50,cb,nil)then66. begin67. asm68. pushad69. leaebx,InBuffer70. addebx,$5871. movtmp,ebx72. popad73. end;/asm74. 75. if(pos(vmware,LowerCase(tmp)0)or(pos(virtual,LowerCase(tmp)0)then76. showmessage(检测到VMwareWorkstation!)77. else78. showmessage(请在VMware中测试!);79. 80. end;81. end;82. 83. procedureT
36、Form1.FormClose(Sender:TObject;varAction:TCloseAction);84. begin85. closehandle(hDeviceHandle);86. end;87. 88. end.89. 90. 代码很短,但是效果不错。截图几张,留作纪念! C+代码实现如下:cpp1. 通过IOCTL_STORAGE_QUERY_PROPERTY2. 3. typedefenum_STORAGE_QUERY_TYPEPropertyStandardQuery=0,PropertyExistsQuery,PropertyMaskQuery,PropertyQue
37、ryMaxDefinedSTORAGE_QUERY_TYPE,*PSTORAGE_QUERY_TYPE;4. 5. typedefenum_STORAGE_PROPERTY_IDStorageDeviceProperty=0,StorageAdapterPropertySTORAGE_PROPERTY_ID,*PSTORAGE_PROPERTY_ID;6. 7. typedefstruct_STORAGE_PROPERTY_QUERY8. 9. STORAGE_PROPERTY_IDPropertyId;10. 11. STORAGE_QUERY_TYPEQueryType;12. 13. U
38、CHARAdditionalParameters1;14. 15. 16. 17. STORAGE_PROPERTY_QUERY,*PSTORAGE_PROPERTY_QUERY;18. 19. typedefstruct_STORAGE_DEVICE_DESCRIPTOR20. 21. ULONGVersion;22. 23. ULONGSize;24. 25. UCHARDeviceType;26. 27. UCHARDeviceTypeModifier;28. 29. BOOLEANRemovableMedia;30. 31. BOOLEANCommandQueueing;32. 33.
39、 ULONGVendorIdOffset;34. 35. ULONGProductIdOffset;36. 37. STORAGE_DEVICE_DESCRIPTOR,*PSTORAGE_DEVICE_DESCRIPTOR;38. 39. 40. 41. #defineIOCTL_STORAGE_QUERY_PROPERTYCTL_CODE(IOCTL_STORAGE_BASE,0x0500,METHOD_BUFFERED,FILE_ANY_ACCESS)42. 43. 44. 45. boolIsSandboxed()46. 47. 48. 49. HANDLEhPhysicalDriveIOCTL=0;50. 51. intj=0,k=0;52. 53. charszModel128,szBuffer128;54. 55. char*szDrives=56. 57. qemu,58. 59. virtual,60. 61. vmware,