Domanda

Devo rilevare se la mia applicazione è in esecuzione all'interno di un'istanza del sistema operativo virtualizzata o meno.

Ho trovato un articolo con alcune utili informazioni sull'argomento. Lo stesso articolo appare in più punti, non sono sicuro della fonte originale. VMware implementa una specifica istruzione x86 non valida per restituire informazioni su se stessa, mentre VirtualPC utilizza un numero magico e una porta I / O con un'istruzione IN.

Questo è fattibile, ma sembra essere un comportamento non documentato in entrambi i casi. Suppongo che una versione futura di VMWare o VirtualPC potrebbe modificare il meccanismo. Esiste un modo migliore? Esiste un meccanismo supportato per entrambi i prodotti?

Allo stesso modo, esiste un modo per rilevare Xen o VirtualBox ?

Non sono preoccupato per i casi in cui la piattaforma sta deliberatamente cercando di nascondersi. Ad esempio, gli honeypot usano la virtualizzazione ma a volte oscurano i meccanismi che il malware userebbe per rilevarla. Non mi interessa che la mia app pensi che non sia virtualizzata in questi honeypot, sto solo cercando un "miglior sforzo" soluzione.

L'applicazione è principalmente Java, anche se mi aspetto di usare il codice nativo più JNI per questa particolare funzione. Il supporto di Windows XP / Vista è molto importante, anche se i meccanismi descritti nell'articolo di riferimento sono funzioni generiche di x86 e non si basano su alcuna particolare funzionalità del sistema operativo.

È stato utile?

Soluzione

Hai mai sentito parlare di pillola blu, pillola rossa? . È una tecnica utilizzata per vedere se si esegue o meno all'interno di una macchina virtuale. L'origine del termine deriva dal il film della matrice in cui a Neo viene offerta una pillola blu o rossa (per rimanere all'interno della matrice = blu o per entrare nel mondo "reale" = rosso).

Di seguito è riportato un codice che rileverà se stai eseguendo o meno la 'matrice':
(codice preso in prestito da questo sito che contiene anche alcune belle informazioni sull'argomento in questione):

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

La funzione restituirà 1 quando si esegue all'interno di una macchina virutale e 0 altrimenti.

Altri suggerimenti

In Linux ho usato il comando: dmidecode (ce l'ho su CentOS e Ubuntu)

dall'uomo:

  

dmidecode è uno strumento per scaricare a   tabella DMI del computer (alcuni dicono SMBIOS)   contenuti in un formato leggibile dall'uomo.

Quindi ho cercato l'output e ho scoperto che probabilmente è 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

Un altro modo è cercare a quale produttore è associato l'indirizzo MAC di eth0: http://www.coffer.com/mac_find /

Se restituisce Microsoft, vmware & amp; ecc. quindi probabilmente è un server virtuale.

VMware ha un Meccanismi per determinare se il software è in esecuzione in una macchina virtuale VMware Articolo della knowledge base che ha del codice sorgente.

Microsoft ha anche una pagina su " Determinare se Hypervisor è installato " . MS chiarisce questo requisito di hypervisor nel TEST IsVM " sezione della loro " Test di convalida della virtualizzazione del server " documento

I documenti VMware e MS menzionano entrambi l'utilizzo dell'istruzione CPUID per controllare il bit presente dell'hypervisor (bit 31 del registro ECX)

Il bugtracker RHEL ne ha uno per " dovrebbe impostare il bit ISVM (ECX: 31) per CPUID leaf 0x00000001 " per impostare il bit 31 del registro ECX sotto il kernel Xen.

Quindi senza entrare nelle specifiche del fornitore sembra che potresti usare il controllo CPUID per sapere se stai funzionando virtualmente o no.

No. Questo è impossibile da rilevare con assoluta precisione. Alcuni sistemi di virtualizzazione, come QEMU , emulano un'intera macchina fino ai registri hardware. Ribaltiamolo: cosa stai cercando di fare? Forse possiamo aiutarti.

Penso che andare avanti, basandosi su trucchi come la virtualizzazione SIDT non funzionante, non sarà davvero d'aiuto poiché l'hardware colma tutti i buchi che l'architettura x86 bizzarra e disordinata ha lasciato. La cosa migliore sarebbe fare pressioni sui provider Vm per un modo standard per dire che sei su una VM - almeno per il caso in cui l'utente lo abbia esplicitamente permesso. Ma se assumiamo che stiamo permettendo esplicitamente il rilevamento della VM, possiamo anche posizionare marcatori visibili lì dentro, giusto? Suggerirei semplicemente di aggiornare il disco sulle macchine virtuali con un file che ti dice che sei su una macchina virtuale, ad esempio un piccolo file di testo nella radice del file system. O ispeziona il MAC di ETH0 e impostalo su una determinata stringa nota.

Su virtualbox, supponendo che tu abbia il controllo sul guest VM e tu abbia dmidecode, puoi usare questo comando:

dmidecode -s bios-version

e tornerà

VirtualBox

Vorrei raccomandare un articolo pubblicato su Usenix HotOS '07, La compatibilità non è trasparenza: miti e realtà di rilevamento VMM , che conclude diverse tecniche per dire se l'applicazione è in esecuzione in un virtualizzato ambiente.

Ad esempio, utilizzare l'istruzione sidt come fa redpill (ma questa istruzione può anche essere resa trasparente dalla traduzione dinamica) o confrontare il runtime di cpuid con altre istruzioni non virtualizzate.

Sotto Linux, puoi riferire su / proc / cpuinfo. Se è in VMware, di solito si presenta in modo diverso rispetto a se si trova su bare metal, ma non sempre. Virtuozzo mostra un passaggio all'hardware sottostante.

Durante l'installazione della nuova Ubuntu ho scoperto il pacchetto chiamato imvirt. Dai un'occhiata a http://micky.ibh.net/~liske/imvirt.html

Questa funzione C rileverà il SO guest VM:

(Testato su Windows, compilato con Visual Studio)

#include <intrin.h>

    bool isGuestOSVM()
    {
        unsigned int cpuInfo[4];
        __cpuid((int*)cpuInfo,1);
        return ((cpuInfo[2] >> 31) & 1) == 1;
    }

Prova leggendo le SMBIOS , in particolare le strutture con BIOS informazioni.

In Linux è possibile utilizzare l'utilità dmidecode per sfogliare le informazioni.

Controlla lo strumento virt-what . Utilizza dmidecode menzionato in precedenza per determinare se ci si trova su un host virtualizzato e il tipo.

Uso questa classe C # per rilevare se il sistema operativo guest è in esecuzione in un ambiente virtuale ( solo 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;
            }
        }

}

Utilizzo:

        if (sysInfo.isVM()) { 
            Console.WriteLine("VM FOUND");
        }

Su Linux systemd fornisce un comando per rilevare se il sistema è in esecuzione come macchina virtuale o meno.

Comando:
$ systemd-detect-virt

Se il sistema è virtualizzato, genera il nome del software / tecnologia virtuslization. In caso contrario, genera none

Ad esempio se il sistema esegue KVM, allora:

$ systemd-detect-virt
kvm

Non è necessario eseguirlo come sudo.

Ho provato un approccio diverso suggerito dal mio amico. Le macchine virtuali eseguite su VMWARE non hanno la proprietà TEMPERATURA CPU. cioè non mostrano la temperatura della CPU. Sto usando l'applicazione termometro CPU per controllare la temperatura della CPU.

(Windows in esecuzione in VMWARE) inserisci qui la descrizione dell'immagine

(Windows in esecuzione su una CPU reale) inserisci qui la descrizione dell'immagine

Quindi codice un piccolo programma C per rilevare il sensore di temperatura

#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.

}

Output su una macchina Vmware inserisci qui la descrizione dell'immagine

Output su una CPU reale inserisci qui la descrizione dell'immagine

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top