2012-04-10 118 views
9

我想開發一個應用程序,檢測程序是否在虛擬機內運行。64位窗口VMware檢測

對於32位Windows,已經有方法下面的鏈接解釋說: http://www.codeproject.com/Articles/9823/Detect-if-your-program-is-running-inside-a-Virtual

我試圖適應有關在64位Windows操作系統的Virtual PC和VMware檢測代碼。對於VMware,代碼可以在Windows XP 64位操作系統中成功檢測到。但是,當我在本機系統(Windows 7 64位操作系統)中運行它時,程序崩潰。

我將代碼放在.asm文件中,並使用ml64.exe文件定義自定義生成步驟。 64位Windows的彙編代碼是:

IsInsideVM proc 

     push rdx 
     push rcx 
     push rbx 

     mov rax, 'VMXh' 
     mov rbx, 0  ; any value but not the MAGIC VALUE 
     mov rcx, 10 ; get VMWare version 
     mov rdx, 'VX' ; port number 

     in  rax, dx ; read port 
         ; on return EAX returns the VERSION 
     cmp rbx, 'VMXh'; is it a reply from VMWare? 
     setz al   ; set return value 
     movzx rax,al 

     pop rbx 
     pop rcx 
     pop rdx 

     ret 
IsInsideVM endp 

我在一個CPP文件調用此部分,如:提前

__try 
{ 
returnValue = IsInsideVM(); 
} 
__except(1) 
{ 
    returnValue = false; 
} 

感謝。

+1

嗯,是的,試圖訪問硬件端口,這是一種特權操作,將陷阱的用戶代碼。您需要使用SEH捕獲異常。它看起來像你正在嘗試,但你沒有顯示(1)編譯器選項或(2)調試器跟蹤。 – 2012-04-10 14:03:18

回答

4

紅色藥丸Joanna可能工作:random backup page of invisiblethings.org blog

吞嚥紅丸或多或少等效於以下代碼(返回非零時在矩陣):

int swallow_redpill() { 
    unsigned char m[2+4], rpill[] = "\x0f\x01\x0d\x00\x00\x00\x00\xc3"; 
    *((unsigned*)&rpill[3]) = (unsigned)m; 
    ((void(*)())&rpill)(); 
    return (m[5]>0xd0) ? 1 : 0; 
} 

該代碼的核心實際上是SIDT指令(編碼爲0F010D [addr]),它將目標操作數中的中斷描述符表寄存器(ID​​TR)的內容存儲在目標操作數中,該操作數實際上是一個內存位置。 SIDT指令的特別之處在於,它可以在非特權模式下執行(ring3),但它返回敏感寄存器的內容,由操作系統在內部使用。

由於只有一個IDTR寄存器,但至少有兩個OS同時運行(即主機和來賓操作系統),VMM需要將來賓的IDTR重新安置在安全的地方,以便它不會與主持人之一。不幸的是,VMM無法知道在客戶OS中運行的進程是否(以及何時)執行SIDT指令,因爲它沒有特權(並且不會產生異常)。因此該進程獲取IDT表的重定位地址。據觀察,在VMWare上,IDT的重定位地址位於地址0xffXXXXXX處,而在虛擬PC上則是0xe8XXXXXX。這已在運行於Windows XP主機操作系統上的VMWare Workstation 4和Virtual PC 2004上進行了測試。

注:我沒有自己測試過,但看起來它使用了非特權方法。如果它在x64上首先不起作用,則可能會有所幫助。

另外,剛剛發現與內容的問題,可以幫助你:Detecting VMM on linux

0

我的猜測是,你的函數corrups寄存器。

在真實硬件(非VM)上運行應該可能在「in rax,dx」中觸發異常。如果發生這種情況,那麼控制權將傳遞給您的異常處理程序,該處理程序會設置結果,但不會恢復寄存器這種行爲將完全被調用者意想不到的。例如,它可以將某些內容保存到EBX/RBX寄存器中,然後調用你的asm代碼,你的asm代碼執行「mov RBX,0」,它執行,捕獲異常,設置結果,返回 - 然後調用者突然意識到他保存的數據不再是EBX/RBX了!如果在EBX/RBX中存儲了一些指針 - 您將很難崩潰。任何事情都可能發生。

當然,你的彙編代碼保存/恢復寄存器,但這種情況只有在不發生異常。即如果你的代碼在虛擬機上運行。然後你的代碼執行正常的執行路徑,不會引發異常,寄存器將正常恢復。但是如果有異常 - 您的POP將被跳過,因爲執行將被傳遞給異常處理程序。

正確的代碼也許應該做俯臥撐/持久性有機污染物的嘗試外/ except塊,而不是內部。

+0

也許'setjmp'和'longjmp'可以用來強制保護寄存器和堆棧指針(全局變量可以用來使結果生存的longjmp) – 2015-05-22 04:10:44

+0

也許你可以使用SetUnhandledExceptionFilter捕獲錯誤,撥弄PEXCEPTION_POINTERS到調整「繼續」地址,然後返回EXCEPTION_CONTINUE_EXECUTION。 – 2015-05-22 09:55:41