2012-04-10 9 views
9

プログラムが仮想マシン内で実行されているかどうかを検出するアプリケーションを開発しようとしています。64ビットWindows VMware検出

は、32ビットWindowsの場合は、方法は次のリンクで説明既に存在している:私は、64ビットのWindowsオペレーティングシステムの仮想PCとVMware検出に関するコードを適応しようとしています http://www.codeproject.com/Articles/9823/Detect-if-your-program-is-running-inside-a-Virtual

。 VMwareの場合、コードはWindows XP 64ビットOSで正常に検出できます。しかし、ネイティブシステム(Windows 7の64ビットOS)でプログラムを実行すると、プログラムがクラッシュします。

コードを.asmファイルに置き、ml64.exeファイルでカスタムビルドステップを定義します。 64ビットWindows用のasmコードは次のとおりです。事前に

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

ありがとう:

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ファイルでこの部分を呼び出します。

Joannaから古い 赤色ピルが動作できる
+1

いいえ、特権操作であるハードウェアポートにアクセスしようとすると、ユーザーコードがトラップされます。 SEHを使用して例外をキャッチする必要があります。試しているようですが、(1)コンパイラオプションや(2)デバッガトレースが表示されていません。 –

答えて

4

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; 
} 

このコードの中心は、実際にはデスティネーションオペランド(実際にはメモリ位置)に割り込みディスクリプタテーブルレジスタ(IDTR)の内容を格納するSIDT命令(0F010D [addr]としてエンコードされています)です。 SIDT命令に関して特別で興味深いのは、非特権モード(ring3)で実行できますが、オペレーティングシステムによって内部的に使用される機密レジスタの内容を返します。

IDTRレジスタは1つしかありませんが、少なくとも2つのOS(つまりホストとゲストOS)が同時に実行されているため、VMMはゲストのIDTRを安全な場所に再配置する必要があります。ホストのもの。残念ながら、VMMは、ゲストOSで実行中のプロセスがSIDT命令を実行するかどうかを(それが特権を持たない(例外を生成しないので))知ることができません。したがって、プロセスはIDTテーブルの再配置されたアドレスを取得します。 VMWareでは、IDTの再配置されたアドレスはアドレス0xffXXXXXXにあり、Virtual PCでは0xe8XXXXXXであることが確認されました。これは、VMWare Workstation 4とVirtual PC 2004でテストされています。どちらもWindows XPホストOSで動作しています。

注:私は自分でテストしていませんが、特権のないアプローチを使用しています。最初にx64で動作しない場合は、いくつかの調整が役に立ちます。私の推測では、あなたの関数がレジスタをcorrupsことですDetecting VMM on linux

0

また、ちょうどあなたを助けるかもしれないコンテンツとの質問を行いました。

実際のハードウェア(非VM)で実行すると、おそらく "in rax、dx"で例外が発生するはずです。これが発生した場合、制御は例外ハンドラに渡されます。例外ハンドラは結果を設定しますが、レジスタは復元しません。この動作は、呼び出し元によって完全に予期しないものになります。たとえば、何かをEBX/RBXレジスタに保存してからasmコードを呼び出し、asmコードが "mov RBX、0"を実行し、例外をキャッチして結果を返し、呼び出し元がsundently自分の保存データもうEBX/RBXにはありません!EBX/RBXにいくつかのポインタが格納されていれば、あなたは激しくクラッシュするでしょう。何でも起れる。

確かに、あなたのasmコードはレジスタを保存/復元しますが、これは例外が発生しない場合にのみ発生します。私。コードがVM上で実行されている場合その後、コードは通常の実行パスを実行し、例外は発生せず、レジスタは正常に復元されます。しかし例外がある場合、実行は例外ハンドラに渡されるため、POPはスキップされます。

正しいコードは、try/exceptブロックの外側でPUSH/POPを実行する必要があります。

+0

おそらく、 'setjmp'と' longjmp'を使ってレジスタとスタックポインタを強制的に保存することができます(グローバル変数を使用して結果をlongjmpに残すことができます) –

+0

SetUnhandledExceptionFilterを使用してPEXCEPTION_POINTERS 'continue'アドレスを調整し、EXCEPTION_CONTINUE_EXECUTIONを返します。 –

関連する問題