相關部落格:http://bbs.pediy.com/thread-119969.htm
通過查找磁盤中是否存在特定的檔案夾或檔案,判斷目前是否在虛拟機中。VMware虛拟機中通常會有路徑C:\Program Files\VMware\VMware Tools\;VirtualBox虛拟機中通常會有路徑C:\Program Files\Oracle\VirtualBox Guest Additions\。
通過程序快照讀取目前程序資訊,查找是否存在虛拟機中特有的程序,如VMware中的vmware.exe和VirtualBox中的VBoxService.exe。
通過擷取主機目前具有VMware特性的服務資訊,判斷目前主機是否為虛拟機。在VMware中通常會存在VMware實體磁盤助手服務和VMware Tools服務等;在VirtualBox中通常會存在VirtualBox Guest Additions Service服務等。
通過讀取主機具有虛拟機特性的系統資料庫位置來判斷是否處于虛拟機環境中。針對VMware可以判斷系統資料庫項HKEY_CLASSES_ROOT\\Applications\\VMwareHostOpen.exe;針對VirtualBox可以判斷系統資料庫項HKEY_LOCAL_MACHINE\\SOFTWARE\\Oracle\\VirtualBox Guest Additions。當然,系統資料庫中能被檢測出的位置很多,這裡隻是舉個例子。
Vmware為真主機與虛拟機之間提供了互相溝通的通訊機制,它使用“IN”指令來讀取特定端口的資料以進行兩機通訊,但由于IN指令屬于特權指令,在處于保護模式下的真機上執行此指令時,除非權限允許,否則将會觸發類型為“EXCEPTION_PRIV_INSTRUCTION”的異常,而在虛拟機中并不會發生異常,在指定功能号0A(擷取VMware版本)的情況下,它會在EBX中傳回其版本号“VMXH”;而當功能号為0x14時,可用于擷取VMware記憶體大小,當大于0時則說明處于虛拟機中。VMDetect正是利用前一種方法來檢測VMware的存在,其檢測代碼分析如下:
利用IDT基址檢測虛拟機的方法是一種通用方式,對VMware和Virtual PC均适用。中斷描述符表IDT(Interrupt Descriptor Table)用于查找進行中斷時所用的軟體函數,它是一個由256項組成的資料,其中每一中斷對應一項函數。為了讀取IDT基址,我們需要通過SIDT指令來讀取IDTR(中斷描述符表寄存器,用于IDT在記憶體中的基址),SIDT指令是以如下格式來存儲IDTR的内容:
由于隻存在一個IDTR,但又存在兩個作業系統,即虛拟機系統和真主機系統。為了防止發生沖突,VMM(虛拟機監控器)必須更改虛拟機中的IDT位址,利用真主機與虛拟機環境中執行sidt指令的差異即可用于檢測虛拟機是否存在。著名的“紅丸”(redpill)正是利用此原理來檢測VMware的。Redpill作者在VMware上發現虛拟機系統上的IDT位址通常位于0xFFXXXXXX,而Virtual PC通常位于0xE8XXXXXX,而在真實主機上正如圖2所示都位于0x80xxxxxx。Redpill僅僅是通過判斷執行SIDT指令後傳回的第一位元組是否大于0xD0,若是則說明它處于虛拟機,否則處于真實主機中。
利用此IDT檢測的方法存在一個缺陷,由于IDT的值隻針對處于正在運作的處理器而言,在單CPU中它是個常量,但當它處于多CPU時就可能會受到影響了,因為每個CPU都有其自己的IDT,這樣問題就自然而然的産生了。針對此問題,Offensive Computing組織成員提出了兩種應對方法,其中一種方法就是利用Redpill反複地在系統上循環執行任務,以此構造出一張目前系統的IDT值變化統計圖,但這會增加CPU負擔;另一種方法就是windows API函數SetThreadAffinityMask()将線程限制在單處理器上執行,當執行此測試時隻能準确地将線程執行環境限制在本地處理器,而對于将線程限制在VM處理器上就可能行不通了,因為VM是計劃在各處理器上運作的,VM線程在不同的處理器上執行時,IDT值将會發生變化,是以此方法也是很少被使用的。為此,有人提出了使用LDT的檢測方法,它在具有多個CPU的環境下檢測虛拟機明顯優于IDT檢測方法,該方法具體内容參見下節内容。
在 《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時說明處于虛拟機中,否則為真實主機。
在保護模式下運作的所有程式在切換任務時,對于目前任務中指向TSS的段選擇器将會被存儲在任務寄存器中,TSS中包含有目前任務的可執行環境狀态,包括通用寄存器狀态,段寄存器狀态,标志寄存器狀态,EIP寄存器狀态等等,當此項任務再次被執行時,處理器就會其原先儲存的任務狀态。每項任務均有其自己的TSS,而我們可以通過STR指令來擷取指向目前任務中TSS的段選擇器。這裡STR(Store task register)指令是用于将任務寄存器 (TR) 中的段選擇器存儲到目标操作數,目标操作數可以是通用寄存器或記憶體位置,使用此指令存儲的段選擇器指向目前正在運作的任務的任務狀态段 (TSS)。在虛拟機和真實主機之中,通過STR讀取的位址是不同的,當位址等于0x0040xxxx時,說明處于虛拟機中,否則為真實主機。實作代碼如下:
在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 Id 0\Identifier
鍵值:VMware Virtual IDE Hard Drive
項名:HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\Scsi\Scsi Port 1\Scsi Bus 0\Target Id 0\Logical Unit Id 0\Identifier
鍵值:NECVMWar VMware IDE CDR10
項名:HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Products\C2A6F2EFE6910124C940B2B12CF170FE\ProductName
鍵值:VMware 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
鍵值:VMware SVGA II
項名:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards\2\Description
鍵值:VMware Accelerated AMD PCNet Adapter
項名:HKEY_LOCAL_MACHINE\SOFTWARE\VMware, Inc.\VMware Tools
項名: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
鍵值:VMware SCSI Controller
項名:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Print\Monitors\ThinPrint Print Port Monitor for VMWare
除以上這些表項之外,還有很多地方可以檢測,特别是虛拟機提供的虛拟化軟硬體、服務之類,比如檔案共享服務,VMware 實體磁盤助手服務,VMware Ethernet Adapter Driver,VMware SCSI Controller等等的這些資訊都可作為檢測虛拟機的手段。這裡我們就以其中某表項為例程式設計舉例一下,其它表項檢測方法同理
本方法通過運作一段特定代碼,然後比較這段代碼在虛拟機和真實主機之中的相對運作時間,以此來判斷是否處于虛拟機之中。這段代碼我們可以通過RDTSC指令來實作,RDTSC指令是用于将計算機啟動以來的CPU運作周期數存放到EDX:EAX裡面,其中EDX是高位,而EAX是低位。下面我們以xchg ecx, eax 一句指令的運作時間為例,這段指令在我的真實主機windows 7系統上的運作時間為0000001E,
兩者之間的運作時間明顯差别很多,在虛拟機中的運作速度遠不如真實主機的,一般情況下,當它的運作時間大于0xFF時,就可以确定它處于虛拟機之中了,是以不難寫出檢測程式,具體實作代碼如下:
利用虛拟硬體指紋也可用于檢測虛拟機的存在,比如VMware預設的網卡MAC位址字首為“00-05-69,00-0C-29或者00-50-56”,這前3節是由VMware配置設定的唯一辨別符OUI,以供它的虛拟化擴充卡使用。在我的VMWare WinXP下的MAC位址為00-0C-29-5B-D7-67,
總結
國外SANS安全組織的研究人員總結出目前各種虛拟機檢測手段不外乎以下四類:
· 搜尋虛拟環境中的程序,檔案系統,系統資料庫;
· 搜尋虛拟環境中的記憶體
· 搜尋虛拟環境中的特定虛拟硬體
· 搜尋虛拟環境中的特定處理器指令和功能
因為現代計算系統大多是由檔案系統,記憶體,處理器及各種硬體元件構成的,上面提到的四種檢測手段均包含了這些因素。縱觀前面各種檢測方法,也均在此四類當中。除此之外,也有人提出通過網絡來檢測虛拟機,比如搜尋ICMP和TCP資料通訊的時間差異,IP ID資料包差異以及資料包中的異常頭資訊等等。随着技術研究的深入,相信會有更多的檢測手段出現,與此同時,虛拟機廠商也會不斷進化它們的産品,以增加anti-vmware的難度,這不也正是一場永無休止的無煙戰争!