Как определить, запущено ли приложение из-под виртуальной машины?

Именно такой вопрос сегодня встал передо мной. Google говорит, что информации много. Стал смотреть.

Первое, что попалось, было это(EN). Статья на сайте хорошая, приложение из комплекта даже работает, если его просто запустить, да и мне кажется, что это наиболее правильный метод определения, но к сожалению… После добавления библиотеки мое приложение перестало работать нормально и вылетало с ошибкой «не является приложением Win32» (Could not load file or assembly ‘VmDetectLibrary.dll’ or one of its dependencies.  is not a valid Win32 application. (Exception from HRESULT: 0x800700C1))

Ошибка времени выполнения

Оказывается, что эта ошибка связана с тем, что проект запускается на Windows 8 x64. Ну не работает этот код под x64 совсем, даже если пересобрать Dll.

Далее, так как мне в первую очередь нужна vmware, нахожу статью в их базе знаний

Как я ни пытался, пример их кода:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int cpuid_check()
{
        unsigned int eax, ebx, ecx, edx;
        char hyper_vendor_id[13];
 
        cpuid(0x1, &eax, &ebx, &ecx, &edx);
        if  (bit 31 of ecx is set) {
                cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
                memcpy(hyper_vendor_id + 0, &ebx, 4);
                memcpy(hyper_vendor_id + 4, &ecx, 4);
                memcpy(hyper_vendor_id + 8, &edx, 4);
                hyper_vendor_id[12] = '\0';
                if (!strcmp(hyper_vendor_id, "VMwareVMware"))
                        return 1;               // Success - running under VMware
        }
        return 0;
}
int cpuid_check()
{
        unsigned int eax, ebx, ecx, edx;
        char hyper_vendor_id[13];

        cpuid(0x1, &eax, &ebx, &ecx, &edx);
        if  (bit 31 of ecx is set) {
                cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
                memcpy(hyper_vendor_id + 0, &ebx, 4);
                memcpy(hyper_vendor_id + 4, &ecx, 4);
                memcpy(hyper_vendor_id + 8, &edx, 4);
                hyper_vendor_id[12] = '\0';
                if (!strcmp(hyper_vendor_id, "VMwareVMware"))
                        return 1;               // Success - running under VMware
        }
        return 0;
}

Мне так и не удалось запустить. Не находило функцию cpuid и сбоило в условии, не видя слово bit. На MSDN нашел описание подобной функции, но она принимала другие параметры. В Википедии есть похожая реализация, но она мне не понравилась. Код, который написан на чистом си так и не запустился (тоже ошибка компиляции). Так я и оставил эту статью.

Нашел ответ на StackOverflow.com. Там дается несколько кодов, для определения vmware и Virtual PC. Взял один из них и сделал библиотечку, которую можно скачать тут Метод взят такой:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static bool DetectVirtualMachine()
        {
            const string MICROSOFTCORPORATION = "microsoft corporation";
            const string VMWARE = "vmware";
 
            foreach (var item in new ManagementObjectSearcher("Select * from Win32_ComputerSystem").Get())
            {
                string manufacturer = item["Manufacturer"].ToString().ToLower();
                // Check the Manufacturer (eg: vmware, inc)
 
                if (manufacturer.Contains(MICROSOFTCORPORATION) || manufacturer.Contains(VMWARE))
                {
                    return true;
                }
                // Also, check the model (eg: VMware Virtual Platform)
                if (item["Model"] != null)
                {
                    string model = item["Model"].ToString().ToLower();
                    if (model.Contains(MICROSOFTCORPORATION) || model.Contains(VMWARE))
                    {
                        return true;
                    }
                }
            }
            return false;
        }
public static bool DetectVirtualMachine()
        {
            const string MICROSOFTCORPORATION = "microsoft corporation";
            const string VMWARE = "vmware";

            foreach (var item in new ManagementObjectSearcher("Select * from Win32_ComputerSystem").Get())
            {
                string manufacturer = item["Manufacturer"].ToString().ToLower();
                // Check the Manufacturer (eg: vmware, inc)

                if (manufacturer.Contains(MICROSOFTCORPORATION) || manufacturer.Contains(VMWARE))
                {
                    return true;
                }
                // Also, check the model (eg: VMware Virtual Platform)
                if (item["Model"] != null)
                {
                    string model = item["Model"].ToString().ToLower();
                    if (model.Contains(MICROSOFTCORPORATION) || model.Contains(VMWARE))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

Для работы требуется сборка System.Management.

Так же я написал тестовое приложение для проверки работы DLL. Скачать можно тут. Так же есть проект для Visual Studio 2012

Код самого приложения простой (консольное приложение):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using vmDetect;
 
namespace VM_Detect
{
    class Program
    {
        static void Main(string[] args)
        {
            if (VMDetect.DetectVirtualMachine())
            {
                Console.WriteLine("it's run on the Virtual Machine");
            }
            else
            {
                Console.WriteLine("it's run on Host Machine or on unknown Virtual Machine");
            }
            Console.ReadKey();
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using vmDetect;

namespace VM_Detect
{
    class Program
    {
        static void Main(string[] args)
        {
            if (VMDetect.DetectVirtualMachine())
            {
                Console.WriteLine("it's run on the Virtual Machine");
            }
            else
            {
                Console.WriteLine("it's run on Host Machine or on unknown Virtual Machine");
            }
            Console.ReadKey();
        }
    }
}

Получается, что мы подгружаем DLL (в References) и прописываем using, а дальше обращаемся к методу внутри нее, который возвращает true, если приложение запущено в виртуальной машине, и false в любом другом случае. (если это неизвестная виртуальная машина или хост например)

Запуск на моем хосте:

Приложение запушено на реальной машине, Windows 8

Запуск на виртуальной машине vmware workstation 9 (Windows XP Professional как гостевая ОС)

Примечания:

Добавить комментарий