web-dev-qa-db-fra.com

Détecter le système d'exploitation virtualisé d'une application?

J'ai besoin de détecter si mon application s'exécute dans une instance de système d'exploitation virtualisé ou non.

J'ai trouvé n article avec quelques informations utiles sur le sujet. Le même article apparaît à plusieurs endroits, je ne suis pas sûr de la source d'origine. VMware implémente une instruction x86 particulière non valide pour renvoyer des informations sur lui-même, tandis que VirtualPC utilise un nombre magique et un port d'E/S avec une instruction IN.

Ceci est réalisable, mais semble être un comportement non documenté dans les deux cas. Je suppose qu'une future version de VMWare ou VirtualPC pourrait changer le mécanisme. Y a-t-il une meilleure façon? Existe-t-il un mécanisme pris en charge pour l'un ou l'autre produit?

De même, existe-t-il un moyen de détecter Xen ou VirtualBox ?

Je ne suis pas préoccupé par les cas où la plate-forme tente délibérément de se cacher. Par exemple, les pots de miel utilisent la virtualisation mais masquent parfois les mécanismes que les logiciels malveillants utiliseraient pour les détecter. Peu m'importe que mon application pense qu'elle n'est pas virtualisée dans ces pots de miel, je cherche juste une solution "au mieux".

L'application est principalement Java, bien que je m'attende à utiliser du code natif plus JNI pour cette fonction particulière. La prise en charge de Windows XP/Vista est la plus importante, bien que les mécanismes décrits dans l'article référencé soient des fonctionnalités génériques de x86 et ne dépendent d'aucune installation de système d'exploitation particulière.

64
DGentry

Avez-vous entendu parler de pilule bleue, pilule rouge? . C'est une technique utilisée pour voir si vous utilisez ou non une machine virtuelle. L'origine du terme provient de le film matriciel où Neo se voit offrir une pilule bleue ou rouge (pour rester à l'intérieur de la matrice = bleu, ou pour entrer dans le monde 'réel' = rouge).

Ce qui suit est un code qui détectera si vous exécutez à l'intérieur de `` la matrice '' ou non:
(code emprunté à ce site qui contient également de belles informations sur le sujet traité):

 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 fonction renverra 1 lorsque vous exécutez à l'intérieur d'une machine virutale et 0 sinon.

66
sven

Sous Linux, j'ai utilisé la commande: dmidecode (je l'ai à la fois sur CentOS et Ubuntu)

de l'homme:

dmidecode est un outil pour vider le contenu d'une table DMI d'un ordinateur (certains disent SMBIOS) dans un format lisible par l'homme.

J'ai donc recherché la sortie et découvert son probablement 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

Une autre façon consiste à rechercher à quel fabricant l'adresse MAC de eth0 est liée: http://www.coffer.com/mac_find/

S'il retourne Microsoft, vmware & etc .. alors c'est probablement un serveur virtuel.

24
michaelbn

Non. Cela est impossible à détecter avec une précision totale. Certains systèmes de virtualisation, comme QEMU , émulent une machine entière jusqu'aux registres matériels. Tournons cela: qu'est-ce que vous essayez de faire? Peut-être que nous pouvons aider avec ça.

12
Kirk Strauser

VMware a Mécanismes pour déterminer si le logiciel s'exécute dans une machine virtuelle VMware Article de la base de connaissances qui contient du code source.

Microsoft a également une page sur "Déterminer si l'hyperviseur est installé" . MS énonce cette exigence d'un hyperviseur dans la section IsVM TEST "de leur " Server Virtualization Validation Test " document

Les documents VMware et MS mentionnent tous deux l'utilisation de l'instruction CPUID pour vérifier le bit présent de l'hyperviseur (bit 31 du registre ECX)

Le bugtracker RHEL en a un pour "devrait définir le bit ISVM (ECX: 31) pour la feuille CPUID 0x00000001" pour définir le bit 31 du registre ECX sous le noyau Xen.

Donc, sans entrer dans les détails du fournisseur, il semble que vous pouvez utiliser la vérification CPUID pour savoir si vous utilisez virtuellement ou non.

12
David

Je pense qu'à l'avenir, s'appuyer sur des astuces comme la virtualisation SIDT cassée ne va pas vraiment aider car le matériel bouche tous les trous que l'architecture étrange et désordonnée x86 a laissé. Le mieux serait de faire pression sur les fournisseurs Vm pour une façon standard de dire que vous êtes sur un VM - au moins pour le cas où l'utilisateur l'a explicitement autorisé. Mais si nous supposons que nous autorisons explicitement la détection de VM, nous pouvons tout aussi bien y placer des marqueurs visibles, non? Je suggérerais simplement de mettre à jour le disque sur vos machines virtuelles avec un fichier vous indiquant que vous êtes sur un VM - un petit fichier texte à la racine du système de fichiers, par exemple. Ou inspectez le MAC d'ETH0, et définissez-le sur une chaîne connue donnée.

11
jakobengblom2

Sur virtualbox, en supposant que vous avez le contrôle sur l'invité VM et que vous avez dmidecode, vous pouvez utiliser cette commande:

dmidecode -s bios-version

et il reviendra

VirtualBox
8
icasimpan

Je voudrais recommander un article publié sur Usenix HotOS '07, La compatibilité n'est pas la transparence: mythes et réalités de détection VMM, qui conclut plusieurs techniques pour dire si l'application s'exécute dans un environnement virtualisé.

Par exemple, utilisez l'instruction sidt comme le fait redpill (mais cette instruction peut également être rendue transparente par une traduction dynamique), ou comparez le temps d'exécution de cpuid avec d'autres instructions non virtualisées.

7
ZelluX

Sous Linux, vous pouvez créer un rapport sur/proc/cpuinfo. Si c'est dans VMware, il se présente généralement différemment que s'il est sur du métal nu, mais pas toujours. Virtuozzo montre une transmission au matériel sous-jacent.

5
warren

Essayez en lisant les structures SMBIOS , en particulier les structures avec les informations BIOS .

Sous Linux, vous pouvez utiliser l'utilitaire dmidecode pour parcourir les informations.

5
Jonas Gulle

Lors de l'installation de la nouvelle Ubuntu, j'ai découvert le paquet appelé imvirt. Jetez-y un œil sur http://micky.ibh.net/~liske/imvirt.html

5
Pavlo Svirin

Cette fonction C détectera VM OS invité:

(Testé sous Windows, compilé avec Visual Studio)

#include <intrin.h>

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

Vérifiez l'outil virt-what . Il utilise le dmidecode mentionné précédemment pour déterminer si vous êtes sur un hôte virtualisé et le type.

4
Rickard von Essen

Sous linux, systemd fournit une commande pour détecter si le système fonctionne comme une machine virtuelle ou non.

Commander:
$ systemd-detect-virt

Si le système est virtualisé, il génère le nom du logiciel/technologie de virtuslisation. Sinon, il génère none

Par exemple, si le système fonctionne KVM alors:

$ systemd-detect-virt
kvm

Vous n'avez pas besoin de l'exécuter en tant que Sudo.

3
Amiy

J'utilise ce C# classe pour détecter si l'OS invité s'exécute dans un environnement virtuel (Windows uniquement):

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

}

tilisation:

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

J'ai essayé une approche différente suggérée par mon ami. Les machines virtuelles exécutées sur VMWARE n'ont pas de propriété CPU TEMPERATURE. c'est-à-dire qu'ils ne montrent pas la température du CPU. J'utilise une application de thermomètre CPU pour vérifier la température du CPU.

(Windows fonctionnant sous VMWARE) enter image description here

(Windows fonctionnant sur un vrai processeur) enter image description here

J'ai donc codé un petit programme C pour détecter le capteur de température

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

}

Sortie sur une machine Vmware enter image description here

Sortie sur un vrai processeur enter image description here

0
Mohit Dabas