9

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

32 ビット Windows の場合、次のリンクで説明されている方法が既にあります

64 ビット Windows オペレーティング システムでの Virtual PC および VMware 検出に関するコードを適応させようとしています。VMware の場合、コードは Windows XP 64 ビット OS で正常に検出できます。しかし、ネイティブ システム (Windows 7 64 ビット OS) で実行すると、プログラムがクラッシュします。

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

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

前もって感謝します。

4

2 に答える 2

4

ジョアンナの古い赤い丸薬が機能する可能性があります: invisiblethings.org ブログのランダム バックアップ ページ:

赤い丸薬を飲み込むことは、次のコードとほぼ同等です (Matrix ではゼロ以外を返します)。

 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] としてエンコード) であり、割り込み記述子テーブル レジスタ (IDTR) の内容をデスティネーション オペランド (実際にはメモリ ロケーション) に格納します。SIDT 命令の特別で興味深い点は、非特権モード (リング 3) で実行できますが、オペレーティング システムによって内部的に使用される機密レジスタの内容を返すことです。

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

注: 自分でテストしたことはありませんが、特権のないアプローチを使用しているようです。x64 で最初に動作しない場合は、微調整が役立つ場合があります。

また、役立つコンテンツを含む質問を見つけました: Linux での VMM の検出

于 2012-04-11T01:22:09.893 に答える
0

私の推測では、関数がレジスタを破損していると思います。

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

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

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

于 2015-05-22T03:43:03.613 に答える