2010-09-08 67 views
1

我試圖檢測我是否在虛擬環境(虛擬機,虛擬機等)上運行
在Windows上,我使用了幾個ASM,但我不能在Linux中使用它們,主要是因爲該代碼可能被編譯並在32位或64位Linux上運行。在Linux上檢測VMM

下面的代碼可以在Windows 32和64,並在VMWare,VirtualBox和其他虛擬機進行了測試:

#include <stdio.h> 

int idtCheck() 
{ 
    unsigned char m[2]; 
    __asm sidt m; 
    printf("IDTR: %2.2x %2.2x\n", m[0], m[1]); 
    return (m[1]>0xd0) ? 1 : 0; 
} 

int gdtCheck() 
{ 
    unsigned char m[2]; 
    __asm sgdt m; 
    printf("GDTR: %2.2x %2.2x\n", m[0], m[1]); 
    return (m[1]>0xd0) ? 1 : 0; 
} 

int ldtCheck() 
{ 
    unsigned char m[2]; 
    __asm sldt m; 
    printf("LDTR: %2.2x %2.2x\n", m[0], m[1]); 
    return (m[0] != 0x00 && m[1] != 0x00) ? 1 : 0; 
} 

int main(int argc, char * argv[]) 
{ 
    idtCheck(); 
    gdtCheck(); 

    if (ldtCheck()) 
     printf("Virtual Machine detected.\n"); 
    else 
     printf("Native machine detected.\n"); 

    return 0; 
} 

現在,GCC抱怨上的所有功能的__asm。我試着用ASM(),ASM和其他形式,我在過去使用但沒有工作。有任何想法嗎?

+0

我建議你閱讀整個文檔,特別是文本註釋後**:**。那麼你就可以問一個相關的問題或者自己弄清楚。 – jbcreix 2010-09-08 14:58:52

+0

謝謝。看到編輯的問題。 – 2010-09-08 15:12:53

+3

SIDT產生6(32位)或10(64位)字節的結果,不要將其推入一個2字節的字符數組,除非你喜歡覆寫堆的隨機比特。 – bdonlan 2010-09-08 15:18:59

回答

4

嗯,我還沒有拆開機器代碼在那裏,但這裏是一個使用GCC內聯彙編版本:

int redpill() 
{ 
     unsigned char idt_addr[(sizeof(long)==8)?10:6]; 
     __asm__("SIDT (%[ptr])" 
         : "=m" (idt_addr) 
         : [ptr] "r" (&idt_addr)); 
     // examine high order byte 
     return idt_addr[(sizeof(long)==8)?9:5] > 0xd0; 
} 

應該「工作」即使是64位,但我沒有在那裏測試過。

不過!這並不能保證給出你想要的結果,根本就是。首先,它不適用於硬件虛擬化,因爲你看不到真正的IDT。其次,它依賴於VMWare和Virtual PC的實現細節,可能很容易改變。如果您的操作系統決定將其IDT置於高位地址,它甚至可能會引發誤報。所以我不推薦這種方法。

對於使用VMX硬件支持的虛擬機,可能是你最好的選擇將是做一些應該在硬件快,但需要在虛擬機陷阱,並檢查計時。像CPUID就是一個很好的選擇;在虛擬機和真實硬件上進行基準測試(與執行ADD或其他處理不同時鐘速率的虛擬循環進行比較),並查看測試機器與哪個配置文件更加匹配。由於每個CPUID將不得不退出虛擬機以向主機內核詢問它想要呈現的功能,所以它將比在真實硬件上花費更多的時間。 VM將有陷阱,或者用模擬的代碼替換它 -

對於其它類型的虛擬機,你可以簡單地通過加載控制寄存器或調試寄存器做一個類似的定時檢查。如果你的東西像VMware,它可能會取代一些仿真代碼的陷阱 - 在這種情況下,您可能能夠通過定時修改包含控制寄存器或調試寄存器操作代碼來識別它。這將迫使虛擬機使其緩存的代碼無效,這就需要虛擬機出現一個昂貴的陷阱,這將會顯示在您的基準測試中。

請注意,這兩種方法都需要操作系統內核的幫助 - 如果您至少沒有模擬內核的控制權,那麼您很難確定是否存在很難確定。如果虛擬機非常複雜,它可能會造成時序錯亂,此時事情變得非常困難 - 但這往往會導致性能下降,並導致時鐘漂移(如果可以連接到互聯網並查詢時間,則容易識別服務器!),所以大多數商業虛擬機不這樣做。

+0

你確定CPUID嗎?我記得CPUID被緩存。這對於將虛擬機遷移到足夠類似的硬件體系結構中是非常必要的。谷歌的「VMotion CPUID」似乎同意。 – MSalters 2010-09-09 15:14:30

+0

英特爾處理器手冊將CPUID,INVD,GETSEC和XSETBV文檔記錄爲導致VM退出。操作系統可能會在軟件中緩存CPUID,但這仍然需要VM退出,速度足夠慢,應該足夠了。其他說明要麼不被廣泛支持,要麼導致不良的副作用。 – bdonlan 2010-09-09 23:39:42