74

アプリケーションが仮想化された OS インスタンス内で実行されているかどうかを検出する必要があります。

このトピックに関する有益な情報が記載された記事を見つけました。同じ記事が複数の場所に表示されますが、元のソースはわかりません。VMwareは特定の無効な x86 命令を実装して自身に関する情報を返しますが、VirtualPCはマジック ナンバーと I/O ポートを IN 命令で使用します。

これは実行可能ですが、どちらの場合も文書化されていない動作のようです。VMWare または VirtualPC の将来のリリースでは、メカニズムが変更される可能性があると思います。より良い方法はありますか?いずれかの製品でサポートされているメカニズムはありますか?

同様に、XenまたはVirtualBoxを検出する方法はありますか?

プラットフォームが故意に自分自身を隠そうとするケースについては心配していません。たとえば、ハニーポットは仮想化を使用していますが、マルウェアがそれを検出するために使用するメカニズムがわかりにくい場合があります。私のアプリがこれらのハニーポットで仮想化されていないと思うかどうかは気にしません。「ベスト エフォート」ソリューションを探しているだけです。

アプリケーションはほとんどが Java ですが、この特定の機能にはネイティブ コードと JNI を使用する予定です。Windows XP/Vista のサポートは最も重要ですが、参照記事で説明されているメカニズムは x86 の一般的な機能であり、特定の OS 機能に依存していません。

4

16 に答える 16

75

青い錠剤、赤い錠剤について聞いたことがありますか?. これは、仮想マシン内で実行しているかどうかを確認するために使用される手法です。この用語の起源は、ネオが青または赤の錠剤を提供されるマトリックス映画に由来します (マトリックス内にとどまる = 青、または「現実の」世界に入る = 赤)。

以下は、「マトリックス」内で実行しているかどうかを検出するコードです: (このサイト
から借用したコードには、目前のトピックに関するいくつかの優れた情報も含まれています):

 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 を返します。

于 2008-09-30T17:59:12.380 に答える
24

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

もう 1 つの方法は、eth0 の MAC アドレスが関連するメーカーを検索することです: http://www.coffer.com/mac_find/

Microsoft、vmware などを返す場合は、おそらく仮想サーバーです。

于 2010-11-28T22:36:45.587 に答える
14

VMware には、ソフトウェアが VMware 仮想マシンで実行されているかどうかを判断するメカニズムがあり、ソース コードが記載されているナレッジベース記事があります。

Microsoft には、「ハイパーバイザーがインストールされているかどうかの判断」に関するページもあります。MS は、 「サーバー仮想化検証テスト」ドキュメントの「IsVM TEST」セクションで、ハイパーバイザーのこの要件を詳しく説明しています。

VMware と MS の両方のドキュメントでは、CPUID 命令を使用してハイパーバイザー存在ビット (ECX レジスタのビット 31) を確認することが言及されています。

RHEL バグトラッカーには、Xen カーネルで ECX レジスタのビット 31 を設定するための「CPUID リーフ 0x00000001 の ISVM ビット (ECX:31) を設定する必要がある」というものがあります。

したがって、ベンダーの詳細に入ることなく、CPUID チェックを使用して、仮想的に実行しているかどうかを知ることができるようです。

于 2010-08-16T18:32:49.970 に答える
12

将来的には、壊れたSIDT仮想化のようなトリックに頼ることは、ハードウェアが奇妙で乱雑なx86アーキテクチャーが残したすべての穴を塞ぐので、実際には役に立たないと思います。最善の方法は、VMを使用していることを知らせる標準的な方法について、Vmプロバイダーに働きかけることです。少なくとも、ユーザーが明示的に許可している場合はそうです。しかし、VMの検出を明示的に許可していると仮定すると、そこに表示可能なマーカーを配置することもできますよね?VM上のディスクを、VM上にいることを通知するファイル(たとえば、ファイルシステムのルートにある小さなテキストファイル)で更新することをお勧めします。または、ETH0のMACを調べて、それを特定の既知の文字列に設定します。

于 2008-10-02T06:58:56.117 に答える
12

いいえ。これを完全に正確に検出することは不可能です。QEMUなどの一部の仮想化システムは、マシン全体をハードウェア レジスタまでエミュレートします。これをひっくり返してみましょう。何をしようとしているのですか? 多分私たちはそれを手伝うことができます。

于 2008-09-30T17:52:44.750 に答える
7

Usenix HotOS '07に投稿された論文をお勧めします。互換性は透明性ではありません:VMM検出の神話と現実。これは、アプリケーションが仮想化環境で実行されているかどうかを判断するためのいくつかの手法をまとめたものです。

たとえば、redpillと同じようにsidt命令を使用するか(ただし、この命令は動的変換によって透過的にすることもできます)、cpuidの実行時間を他の非仮想化命令と比較します。

于 2009-05-28T13:21:14.977 に答える
6

この 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;
    }
于 2015-08-14T14:39:13.940 に答える
6

newes Ubuntu のインストール中に、imvirt というパッケージを発見しました。http://micky.ibh.net/~liske/imvirt.htmlでそれを見てください。

于 2010-01-14T23:34:09.757 に答える
5

Linux では、/proc/cpuinfo でレポートできます。VMware にある場合は通常、ベア メタルにある場合とは異なる方法で起動しますが、常にそうとは限りません。Virtuozzo は、基盤となるハードウェアへのパススルーを示しています。

于 2008-09-30T17:45:18.123 に答える
5

SMBIOS構造体、特にBIOS情報を含む構造体を読み取ってみてください。

Linux では、dmidecodeユーティリティを使用して情報を参照できます。

于 2008-09-30T17:48:55.947 に答える
4

友人が提案した別のアプローチを試してみました。VMWARE で実行される仮想マシンには、CPU TEMPERATURE プロパティがありません。つまり、CPU の温度は表示されません。CPU温度を確認するためにCPU温度計アプリケーションを使用しています。

(VMWARE で実行されている Windows) ここに画像の説明を入力

(実際の CPU で動作する Windows) ここに画像の説明を入力

そこで、温度センサーを検出する小さな 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.

}

VMware マシンでの出力 ここに画像の説明を入力

実際の CPU での出力 ここに画像の説明を入力

于 2016-10-12T09:18:10.897 に答える
3

このC#クラスを使用して、ゲスト OS が仮想環境 ( Windows のみ)内で実行されているかどうかを検出します。

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");
        }
于 2015-09-07T02:22:40.737 に答える
2

たった 1 行のコードであらゆる種類の Windows 仮想マシンを検出する普遍的な方法を思いつきました。win7--10 をサポートしています (xp はまだテストされていません)。

なぜ普遍的な方法が必要なのですか?

最も一般的に使用される方法は、win32 からベンダー値を検索して一致させることです。しかし、1000 以上の VM メーカーがある場合はどうなるでしょうか? 次に、1000 以上の VM シグネチャに一致するコードを作成する必要があります。しかし、それは時間の無駄です。しばらくすると、他の新しい VM が起動され、スクリプトが無駄になります。

バックグラウンド

私は何ヶ月もそれに取り組みました。多くのテストを行った結果、 VMでは win32_portconnectorが常に null で空であることがわかりました。完全なレポートをご覧ください

//asked at: https://stackoverflow.com/q/64846900/14919621
what win32_portconnector is used for ? This question have 3 parts.
1) What is the use case of win32_portconnector ?    //https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-portconnector
2) Can I get state of ports using it like Mouse cable, charger, HDMI cables etc ?
3) Why VM have null results on this query : Get-WmiObject Win32_PortConnector ?

VM で:

PS C:\Users\Administrator> Get-WmiObject Win32_PortConnector

実際の環境では:

PS C:\Users\Administrator> Get-WmiObject Win32_PortConnector
Tag                         : Port Connector 0
ConnectorType               : {23, 3}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 2

Tag                         : Port Connector 1
ConnectorType               : {21, 2}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 9

Tag                         : Port Connector 2
ConnectorType               : {64}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 16

Tag                         : Port Connector 3
ConnectorType               : {22, 3}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 28

Tag                         : Port Connector 4
ConnectorType               : {54}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 17

Tag                         : Port Connector 5
ConnectorType               : {38}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 30

Tag                         : Port Connector 6
ConnectorType               : {39}
SerialNumber                :
ExternalReferenceDesignator :
PortType                    : 31

コードを見せて

これらのテストに基づいて、Windows VM を検出できる小さなプログラムを作成しました。

//@graysuit
//https://graysuit.github.io
//https://github.com/Back-X/anti-vm
using System;
using System.Windows.Forms;

public class Universal_VM_Detector
{
    static void Main()
    {
        if((new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_PortConnector")).Get().Count == 0)
        {
            MessageBox.Show("VM detected !");
        }
        else
        {
            MessageBox.Show("VM NOT detected !");
        }
    }
}

コードを読んだり、コンパイルされた実行可能ファイルを取得したりできます。

安定

多くの環境でテストされており、非常に安定しています。

  • Visrtualbox を検出します
  • VMware を検出します
  • Windows サーバーを検出します
  • RDP を検出します
  • Virustotal を検出
  • any.runなどを検出し ます...
于 2021-03-13T17:12:22.070 に答える