アプリケーションが仮想化されたOSインスタンス内で実行されているかどうかを検出する必要があります。
記事 トピックに関するいくつかの有用な情報が見つかりました。同じ記事が複数の場所に掲載されていますが、元のソースはわかりません。 VMware は、自身に関する情報を返す特定の無効なx86命令を実装しますが、 VirtualPC は、IN命令でマジックナンバーとI/Oポートを使用します。
これは実行可能ですが、どちらの場合も文書化されていない動作のようです。 VMWareまたはVirtualPCの将来のリリースでメカニズムが変更される可能性があると思います。もっと良い方法はありますか?どちらの製品でもサポートされているメカニズムはありますか?
同様に、 Xen または VirtualBox を検出する方法はありますか?
プラットフォームが意図的に自分自身を隠そうとしているケースについては心配していません。たとえば、ハニーポットは仮想化を使用しますが、マルウェアがそれを検出するために使用するメカニズムをあいまいにすることがあります。私のアプリがこれらのハニーポットで仮想化されていないと思うかどうかは気にしません。ただ、「ベストエフォート」ソリューションを探しています。
アプリケーションの大部分はJavaですが、この特定の機能にはネイティブコードとJNIを使用する予定です。参照記事に記載されているメカニズムはx86の一般的な機能であり、特定のOS機能に依存しないものの、Windows XP/Vistaのサポートは最も重要です。
青い錠剤、赤い錠剤? について聞いたことがありますか。これは、仮想マシン内で実行しているかどうかを確認するために使用される手法です。用語の起源は、 マトリックスムービー に由来します。ここで、Neoには青色または赤色の錠剤が提供されます(マトリックス内にとどまる=青、または「現実」の世界=赤を入力する)。
以下は、「マトリックス」内で実行されているかどうかを検出するコードです。
( このサイト から借用したコードには、現在のトピックに関するいくつかの素敵な情報も含まれています):
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;
}
この関数は、仮想マシン内で実行している場合は1を返し、そうでない場合は0を返します。
Linuxでは、次のコマンドを使用しました:dmidecode(CentOSとUbuntuの両方にあります)
男から:
dmidecodeは、コンピューターのDMI(SMBIOSなどとも呼ばれます)テーブルの内容を人間が読める形式でダンプするためのツールです。
だから私は出力を検索し、おそらくMicrosoft Hyper-Vを見つけました
Handle 0x0001, DMI type 1, 25 bytes
System Information
Manufacturer: Microsoft Corporation
Product Name: Virtual Machine
Version: 5.0
Serial Number: some-strings
UUID: some-strings
Wake-up Type: Power Switch
Handle 0x0002, DMI type 2, 8 bytes
Base Board Information
Manufacturer: Microsoft Corporation
Product Name: Virtual Machine
Version: 5.0
Serial Number: some-strings
別の方法は、eth0のMACアドレスがどのメーカーに関連するかを検索することです: http://www.coffer.com/mac_find/
Microsoft、vmwareなどを返す場合は、おそらく仮想サーバーです。
いいえ。これを完全に正確に検出することは不可能です。 [〜#〜] qemu [〜#〜] などの一部の仮想化システムは、ハードウェアレジスタまでマシン全体をエミュレートします。これを変えましょう:あなたが何をしようとしているのですか?たぶん私たちはそれを手伝うことができます。
VMwareには、ソフトウェアがVMware仮想マシンで実行されているかどうかを判断する メカニズムがあります いくつかのソースコードがあるナレッジベース記事。
Microsoftには、 「ハイパーバイザーがインストールされているかどうかの判断」 のページもあります。 MSは "Server Virtualization Validation Test" ドキュメントのIsVM TEST "セクションでハイパーバイザーのこの要件を詳しく説明しています。
VMwareおよびMSの両方のドキュメントでは、CPUID命令を使用してハイパーバイザー存在ビット(レジスタECXのビット31)を確認することに言及しています。
RHELバグトラッカーには、 「CPUIDリーフ0x00000001にISVMビット(ECX:31)を設定する必要があります」 があり、Xenカーネルの下でレジスタECXのビット31を設定します。
そのため、ベンダーの詳細に触れることなく、CPUIDチェックを使用して、仮想的に実行しているかどうかを確認できるように見えます。
ハードウェアが奇妙で乱雑なx86アーキテクチャに残されたすべての穴を塞いでしまうので、今後、壊れたSIDT仮想化のようなトリックに頼ることは、実際には役に立たないと思います。最良の方法は、少なくともユーザーが明示的に許可している場合にVM-にいることを確認する標準的な方法でVmプロバイダーにロビー活動を行うことです。 VMの検出を明示的に許可しているので、そこに可視マーカーを配置することもできますよね?VMのディスクを更新することをお勧めします。 on a VM-たとえば、ファイルシステムのルートにある小さなテキストファイル。または、ETH0のMACを検査し、既知の文字列に設定します。
Virtualboxでは、VMゲストを制御でき、dmidecodeがある場合、次のコマンドを使用できます。
dmidecode -s bios-version
そして、それは戻ります
VirtualBox
Usenix HotOS '07、Compatibility is Not Transparency:VMM Detection Myths and Realitiesに投稿された論文をお勧めします。仮想化環境。
たとえば、redpillのようにsidt命令を使用します(ただし、この命令は動的変換によって透過的にすることもできます)、またはcpuidのランタイムを他の非仮想化命令と比較します。
Linuxでは、/ proc/cpuinfoでレポートできます。 VMwareの場合、通常はベアメタル上にある場合とは異なりますが、常にではありません。 Virtuozzoは、基盤となるハードウェアへのパススルーを示します。
[〜#〜] smbios [〜#〜] 構造、特に [〜#〜] bios [〜#〜] 情報を持つ構造を読んでみてください。
Linuxでは、 dmidecode ユーティリティを使用して情報を参照できます。
新しいUbuntuのインストール中に、imvirtというパッケージを発見しました。 http://micky.ibh.net/~liske/imvirt.html でご覧ください
このC関数は、VMゲストOS:
(Windowsでテスト、Visual Studioでコンパイル)
#include <intrin.h>
bool isGuestOSVM()
{
unsigned int cpuInfo[4];
__cpuid((int*)cpuInfo,1);
return ((cpuInfo[2] >> 31) & 1) == 1;
}
ツールを確認してください virt-what 。前述のdmidecodeを使用して、仮想化されたホストとタイプにいるかどうかを判断します。
Linuxでは、systemdはシステムが仮想マシンとして実行されているかどうかを検出するコマンドを提供します。
コマンド:$ systemd-detect-virt
システムが仮想化されている場合、仮想化ソフトウェアまたは技術の名前が出力されます。そうでない場合は、none
を出力します
たとえば、システムが実行されている場合KVM then:
$ systemd-detect-virt
kvm
Sudoとして実行する必要はありません。
私はこれを使用しますC#
ゲストOSが仮想環境内で実行されているかどうかを検出するクラス(windows only):
sysInfo.cs
using System;
using System.Management;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
public class sysInfo
{
public static Boolean isVM()
{
bool foundMatch = false;
ManagementObjectSearcher search1 = new ManagementObjectSearcher("select * from Win32_BIOS");
var enu = search1.Get().GetEnumerator();
if (!enu.MoveNext()) throw new Exception("Unexpected WMI query failure");
string biosVersion = enu.Current["version"].ToString();
string biosSerialNumber = enu.Current["SerialNumber"].ToString();
try
{
foundMatch = Regex.IsMatch(biosVersion + " " + biosSerialNumber, "VMware|VIRTUAL|A M I|Xen", RegexOptions.IgnoreCase);
}
catch (ArgumentException ex)
{
// Syntax error in the regular expression
}
ManagementObjectSearcher search2 = new ManagementObjectSearcher("select * from Win32_ComputerSystem");
var enu2 = search2.Get().GetEnumerator();
if (!enu2.MoveNext()) throw new Exception("Unexpected WMI query failure");
string manufacturer = enu2.Current["manufacturer"].ToString();
string model = enu2.Current["model"].ToString();
try
{
foundMatch = Regex.IsMatch(manufacturer + " " + model, "Microsoft|VMWare|Virtual", RegexOptions.IgnoreCase);
}
catch (ArgumentException ex)
{
// Syntax error in the regular expression
}
return foundMatch;
}
}
}
使用法:
if (sysInfo.isVM()) {
Console.WriteLine("VM FOUND");
}
友人が提案した別のアプローチを試しました。VMWAREで実行される仮想マシンにはCPU温度プロパティがありません。つまり、CPUの温度を表示しません。 CPU温度の確認にCPU温度計アプリケーションを使用しています。
そこで、温度センサーを検出する小さなCプログラムをコーディングします
#include "stdafx.h"
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
int main(int argc, char **argv)
{
HRESULT hres;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
hres = CoInitializeSecurity(
NULL,
-1, // COM authentication
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
if (FAILED(hres))
{
cout << "Failed to initialize security. Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *)&pLoc);
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object."
<< " Err code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (for example, Kerberos)
0, // Context object
&pSvc // pointer to IWbemServices proxy
);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// For example, get the name of the operating system
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t(L"SELECT * FROM Win32_TemperatureProbe"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres))
{
cout << "Query for operating system name failed."
<< " Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 7: -------------------------------------------------
// Get the data from the query in step 6 -------------------
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if (0 == uReturn)
{
break;
}
VARIANT vtProp;
// Get the value of the Name property
hr = pclsObj->Get(L"SystemName", 0, &vtProp, 0, 0);
wcout << " OS Name : " << vtProp.bstrVal << endl;
VariantClear(&vtProp);
VARIANT vtProp1;
VariantInit(&vtProp1);
pclsObj->Get(L"Caption", 0, &vtProp1, 0, 0);
wcout << "Caption: " << vtProp1.bstrVal << endl;
VariantClear(&vtProp1);
pclsObj->Release();
}
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
CoUninitialize();
return 0; // Program successfully completed.
}