私は仮想マシンの世界の初心者で、ちょっとした質問があります。ソフトウェアが VM (VMware Player など) で実行されている場合、それが VM にインストールされていることをどのように認識しますか? ソフトウェアはオペレーティング システムから情報を取得しますか、それともソフトウェアとハードウェア (VMware Player) の間で直接通信しますか? 前もって感謝します
2 に答える
残念ながら、唯一の答えはありません。各仮想マシンには、使用できる一種のブリッジがありますが、検出する VM ごとに特定のチェックを記述する必要があります (例は VC++ 固有ですが、コンパイラに簡単に適応させることができます)。理論的には、VM の下で実行しているかどうかを判断できないことに注意してください。
VMウェア
VMWare はIN
命令を使用して、ゲストからホストへの通信を処理します。通常、この命令はユーザーモードでは使用できず、例外がスローされますが、VM が処理します。例外をキャッチすると、VMWare で実行されていない (またはIN
命令を実行する権限がある) ことがわかります。特権があるかどうか、または WMWare で実行しているかどうかを判断するための 2 番目のテストはほとんど役に立ちませんが、これは標準的な検出コードであり、完全を期すためにここに記述します (レジスタ内の予想される文字列 VMXh
をチェックするだけEBX
です。必要な値でいくつかのレジスタを初期化する必要があることに注意してください)。 .)
bool IsRunningInsideVmWare()
{
bool flag = true;
__try
{
__asm
{
push edx
push ecx
push ebx
mov eax, 'VMXh'
mov ebx, 0
mov ecx, 10
mov edx, 'VX'
in eax, dx
cmp ebx, 'VMXh'
setz [flag]
pop ebx
pop ecx
pop edx
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
flag = false;
}
return flag;
}
仮想 PC
ゲストは、存在しない命令0f3f070b
を使用してホストと通信できます。次に、そのような命令を発行できます。VM はそれを正しく解釈しますが、物理 CPU は例外をスローします (問題のある命令をキャッチしてジャンプすることができます)。この例EBX
では、例外ハンドラーで既知の値に設定すると、このシナリオを検出できます。
DWORD __forceinline VpcExceptionFilter(LPEXCEPTION_POINTERS ep)
{
ep->ContextRecord->ctx->Ebx = -1;
ep->ContextRecord->ctx->Eip += 4;
return EXCEPTION_CONTINUE_EXECUTION;
}
bool IsRunningInsideVpc()
{
bool flag = false;
__try
{
_asm
{
push ebx
mov eax, 1
mov ebx, 0
__emit 0Fh
__emit 3Fh
__emit 07h
__emit 0Bh
test ebx, ebx
setz [flag]
pop ebx
}
}
__except(VpcExceptionFilter(GetExceptionInformation()))
{
}
return flag;
}
VirtualBox
VirtualBox を検出するのは非常に簡単で、疑似デバイス\\.\VBoxMiniRdrDN
が存在するかどうかを確認するだけです。
bool IsRunningInsideVirtualBox()
{
HANDLE handle = CreateFile("\\\\.\\VBoxMiniRdrDN", GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle != INVALID_HANDLE_VALUE)
{
CloseHandle(handle);
return true;
}
return false;
}
WMI と次のクエリを使用して、もう少し一般的なことを行うことができます (Windows で実行していると仮定します)。
- との
Win32_BaseBoard
試合Name
で。(?i)(Hyper-V|Virtual Machine|Microsoft|VMware|VirtualBox|Parallels Virtual)
Win32_ComputerSystem
試合Model
とManufacturer
対戦(?i)(Hyper-V|Virtual Machine|VMware|VirtualBox)
で。- との
Win32_VideoController
試合Name
で。(?i)Hyper-V
CPUID
手順も役立ちます (これらの値がサポートされている場合)。
EAX
0 ( Get vendor ID ) に設定すると、 と、CPU ベンダー名を含む ASCII 文字列が取得されます(EBX
一覧EDX
についてECX
はWikipediaを参照してください)。もちろん、VM は偽の名前を返すか、不明な VM である可能性があります。
VM で実行している場合、1 に設定すると ( Processor Info and Feature Bits ) ( hypervisor )のEAX
ビット31ECX
が1に設定されます。ここでも、VM は偽の結果を返す場合があります (一部の VM はこのビットを尊重しません)。
この問題に対処しなければならなかったとき、VM でサポートされていないハードウェアトリック/機能 (USB レガシー サポートなど)もチェックしようとしましたが、本番環境で使用するには信頼性が十分ではないことがわかりました。
コメントで、あなたは Android で実行していると言いました。それはまったく別の話ですが、一般的な手法は、WMI (または上記の組み合わせ) について述べたことと似ています。一般的な方法は、よく知られているエミュレーターのデバイス名文字列を確認することです。Android 7 以降では、特定のフラグがありro.kernel.qemu
ます。
それらの値を偽造できますか? はい、例を参照してください。エミュレーターで ro.kernel.qemu を 0 に設定する方法はありますか? . エミュレーションでの使用を阻止しようとする適切なアプリケーションは、複数の検出手法も使用することに注意してください ( Android: Get Hardware Information Programmaticallyも参照してください)。