• В этом разделе размещаются статьи из интернета.
    Для публикации своих авторских статей используйте Блоги.

Чтиво Как обнаруживают виртуальные машины

Взято с
Если не актуально или не совсем верно, дополняйте.

Как распознать виртуальную машину?
Во-первых, любая виртуальная машина несет на своем борту какое-нибудь специфическое оборудование. Это касается видео адаптера, жесткого диска, идентификатора процессора, версии BIOS, MAC-адреса сетевой карты.

Во-вторых, виртуальные машины оставляют следы в системе в виде запущенных вспомогательных процессов, драйверов и других специфических объектов.

В-третьих, если как следует покопаться в реестре виртуальной машины, там можно найти много всяких интересных ключей, характерных только для виртуальных машин.

Ну и в-четвертых, некоторые производители специально оставляют возможности, позволяющие обнаружить их продукты.

Что же касается общих признаков наличия виртуальной машины, предложенных в свое время госпожой Рутковской (характерное расположение таблиц IDT, GDT и LDT, а также время выполнения операций процессором), то в настоящий момент все эти признаки трудно поддаются анализу и приведению к какому-нибудь общему знаменателю, главным образом из-за многоядерности и многоликости современных процессоров.

Анализируем оборудование
Начнем, пожалуй, с жесткого диска. Если посмотреть идентификатор жесткого диска в диспетчере устройств на виртуальной машине, то в его составе можно увидеть интересные строчки:

DiskVirtual для VirtualPC
DiskVBOX_HARDDISK для Virtual Box
Prod_VMware_Virtual для VMware Workstation
Самый простой способ узнать наименование жесткого диска — прочитать значение ключа с именем «0» в ветке реестра HKLM\HARDWARE\SYSTEM\CurrentControlSet\Services\Disk\Enum.

В этом месте перечисляются все дисковые накопители в системе, и первым, как раз в ключе с именем «0», будет тот диск, с которого произошла загрузка системы.

1.jpg

Идентификатор жесткого диска VirtualBox в реестре
Как читать реестр, я думаю, ты знаешь. Используем сначала API RegOpenKeyEx для открытия нужного ключа, далее с помощью RegQueryValueEx читаем значение. Выглядеть это должно примерно вот так:

...
// Открывем нужный ключ реестра
RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"HARDWARE\\SYSTEM\\
CurrentControlSet\\
Services\\Disk\\Enum",
0,
KEY_QUERY_VALUE,
&rKey);
// Читаем значение
RegQueryValueExA(rKey,
"0",
NULL,
&Type,
(LPBYTE)RegKey,
&RegPath);
// Закрываем все, что открыли ранее
RegCloseKey(rKey);
...
Далее все просто — используем strstr для поиска нужных нам строк в считанном значении и, в зависимости от результата сравнения, делаем вывод. Версия BIOS содержится в ключе «SystemProductName» в ветке HKLM\HARDWARE\DESCRIPTION\System\BIOS. К примеру, для VMware там будет лежать строка «VMware Virtual Platform», а для VirtualBox — «VBOX –1».

Прочитать это все можно с помощью все тех же API — RegOpenKeyEx и RegQueryValueEx.

2.jpg

Версия BIOS Parallels Workstation в реестре
Данные о видеоадаптере можно подглядеть в HKLM\System\CarrentControlSet\Enum\PCI. В этой ветке перечислено все, что подключено к шине PCI, в том числе и видеокарта. Для VirtualPC это строчка вида VEN_5333&DEV_8811&SUBSYS_00000000&REV_00, которая определяет видеоадаптер S3 Trio 32/64, эмулируемый виртуалкой от Microsoft — на реальном железе такое оборудование нынче днем с огнем не сыскать (а у меня такая была в конце прошлого века. — Прим. ред.). Для VirtualBox видеокарта описана последовательностью VEN_80EE&DEV_BEEF&SUBSYS_00000000&REV_00, что расшифровывается как «VirtualBox Display», а у Parallels Workstation — строка VEN_1AB8&DEV_4005&SUBSYS_04001AB8&REV_00 определяет видеоадаптер «Parallels Display».

Помимо этого, в VirtualBox можно найти строку VEN_80EE&DEV_CAFE&SUBSYS_00000000&REV_00, определяющую некий «VirtualBox Device», а у Parallels Workstation строки VEN_1AB8&DEV_4000&SUBSYS_04001AB8&REV_00 и VEN_1AB8&DEV_4006&SUBSYS_04061AB8&REV_00, определяющие «Parallels Tools Device» и «Parallels Memory Controller» соответственно.

Алгоритм действий следующий: пытаемся открыть нужный нам ключ, и если он открывается успешно, то оборудование, описанное этим ключом, в наличии и можно делать вывод о присутствии какой-либо виртуальной машины:

...
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\
Enum\\PCI\\VEN_5333&DEV_8811&
SUBSYS_00000000&REV_00",
0,
KEY_QUERY_VALUE,
&rKey) == ERROR_SUCCESS)
{
RegCloseKey(rKey);
// Мы под VirtualPC
return true;
}
...
Идентификатор процессора определяется с помощью команды cpuid. Благодаря ей можно получить много всякой полезной информации об установленном процессоре. Вид выдаваемой этой командой информации зависит от содержимого регистра EAX. Результат работы команды записывается в регистры EBX, ECX и EDX. Подробно про эту команду можно почитать в любой книге по программированию на ассемблере. Для наших целей мы будем использовать эту инструкцию, предварительно положив в регистр EAX значение 0x40000000:

...
_asm
{
mov eax, 0x40000000
cpuid
mov ID_1, ebx
mov ID_2, ecx
mov ID_3, edx
}
...
После выполнения этого кода на VMware Workstation в переменных ID_1, ID_2 и ID_3 будут записаны значения 0x61774d56, 0x4d566572 и 0x65726177 соответственно (в символьном представлении это не что иное, как «VMwareVMware»), на VirtualBox в ID_1 и в ID_2 будет лежать значение 0x00000340, а на Parallels Workstation в ID_1 0x70726c20, в ID_2 — 0x68797065 и в ID_3 — 0x72762020 (что соответствует строке «prl hyperv»).

Использование MAC-адреса для идентификации производителя сетевой карты, конечно, не самый надежный способ (ибо MAC-адрес довольно-таки просто поменять), но тем не менее его вполне можно применить для детекта виртуальных машин в качестве дополнительной проверки.

Ты наверняка знаешь, что первые три байта MAC-адреса сетевой карты определяют ее производителя. Производители виртуальных машин в этом плане не исключение:

VMware (VMware Workstation)
00:05:69
00:0c:29
00:1c:14
00:50:56
Microsoft (Virtual PC)
00:03:ff
00:0d:3a
00:50:f2
7c:1e:52
00:12:5a
00:15:5d
00:17:fa
28:18:78
7c:ed:8d
00:1d:d8
00:22:48
00:25:ae
60:45:bd
Dc:b4:c4
Oracle (VirtualBox)
08:00:20
Parallels (Parallels Workstation)
00:1c:42
Вытащить эти первые три байта из MAC-адреса нам поможет API-функция GetAdaptersInfo:

// Подключаем либу, в которой
// содержится нужная нам функция
#include <iphlpapi.h>
#pragma comment(lib, "IPHLPAPI.lib")
...
// Определяем размер буфера под данные,
// возвращаемые функцией
GetAdaptersInfo(AdapterInfo, &OutBufLen);
// Выделяем память под данные об адаптере
AdapterInfo = (PIP_ADAPTER_INFO) new(char[OutBufLen]);
// Получаем информацию об адаптере
GetAdaptersInfo(AdapterInfo, &OutBufLen);
// Сравниваем первые три байта MAC-адреса
// с 00:1c:42 (Parallels Workstation)
if (((BYTE)AdapterInfo->Address[0] == 0x00) &&
((BYTE)AdapterInfo->Address[1] == 0x1c) &&
((BYTE)AdapterInfo->Address[2] == 0x42))
{
delete(AdapterInfo);
// Мы под Parallels Workstation
return true;
}
else
{
delete(AdapterInfo);
return false;
}
...
Вспомогательные процессы, окна и другие «подозрительные» объекты
Для нормальной работы практически все виртуальные машины требуют установки дополнений к гостевой операционной системе, например VBoxGuestAddition для VirtualBox или Parallels Tools для Parallels Workstation. Без этих дополнений работа с виртуальной машиной несколько затруднительна (ни тебе нормального разрешения экрана и полноэкранного режима, ни взаимодействия с USB-девайсами, ни нормальной настройки сетевых подключений). В общем, все производители виртуалок не рекомендуют использовать их без этих дополнений. А эти самые дополнения оставляют очень заметный след в виде запущенных процессов:

VirtualBox
VBoxTray.exe
VBoxService.exe
Parallels Workstation
prl_cc.exe
prl_tools.exe
SharedIntApp.exe
Virtual PC
vmusrvc.exe
vmsrvc.exe
VMware Workstation
vmtoolsd.exe
Для поиска процесса по имени мы воспользуемся функциями CreateToolhelp32Snapshot, Process32First и Process32Next:

#include <Tlhelp32.h>
...
...
// К примеру, ищем процесс vmtoolsd.exe
wchar_t VMwareProcessName[] = {L"vmtoolsd.exe"};
PROCESSENTRY32 pe;
HANDLE hSnapShot;
hSnapShot = CreateToolhelp32Snapshot
(TH32CS_SNAPPROCESS, 0);
ZeroMemory (&pe, sizeof(PROCESSENTRY32W));
pe.dwSize = sizeof(PROCESSENTRY32W);
Process32First(hSnapShot, &pe);
do
{
if (memcmp(pe.szExeFile, VMwareProcessName, 24) == 0)
// Мы под VMware
return true;
}
while (Process32Next(hSnapShot, &pe));
...

Помимо непосредственно самих процессов, демаскирующим признаком могут стать окна, открытые этими процессами. Окон в каждой из рассматриваемых виртуальных машин может быть довольно много, и все их мы перечислять не будем, а ограничимся одним или двумя. Итак:

VirtualBox
VBoxTrayToolWndClass
Parallels Workstation
CPInterceptor
DesktopUtilites
Virtual PC
{0843FD01-1D28-44a3-B11D-E3A93A85EA96}
VMware Workstation
VMSwitchUserControlClass


3.jpg

Открытые окна для VMware (красным выделено окно класса VMSwitchUserControlClass)
Найти окно по имени класса очень просто — для этого есть функция FindWindow:

...
// К примеру, ищем окно для VMware
HWND VMwareWindow = FindWindowA("VMSwitchUserControlClass", NULL);
if(VMwareWindow != NULL)
// Мы под VMware Workstation
return true;
...


Помимо процессов и окон, указывающих на наличие ВМ, можно найти и другие «подозрительные» объекты — например, если покопаться в гостевой ОС виртуальной машины утилитой WinObj или какой-нибудь аналогичной, то можно найти вот такие объекты:

VirtualBox
\Device\VBoxMiniRdrDN
\Device\VBoxGuest
Parallels Workstation
\Device\prl_pv
\Device\prl_tg
\Device\prl_time
\Device\PrlMemDev
\Device\PrlMemDevPci
\Device\PrlMemDev
Virtual PC
\Device\VirtualMachineServices


4.jpg

«Подозрительные» объекты в VirtualBox
Проверить наличие «подозрительного» объекта очень просто, достаточно попытаться открыть его с помощью CreateFile:

...
// К примеру, проверяем VirtualBox
if ((CreateFile(L"\\\\.\\VBoxMiniRdrDN",
0,0,0,OPEN_EXISTING,0,0)
!=INVALID_HANDLE_VALUE)||
(CreateFile(L"\\\\.\\VBoxGuest",
0,0,0,OPEN_EXISTING,0,0)
!=INVALID_HANDLE_VALUE))
// Мы под VirtualBox
return true;
...


Что еще «подозрительного» можно найти в реестре?
Помимо признаков наличия специфического оборудования, в реестре можно увидеть и другие следы, оставляемые виртуальными машинами. Некоторые из них базируются в ветке HKLM\HARDWARE\ACPI\DSDT. Достаточно в этом месте проверить наличие таких вот ключей:

VirtualBox
VBOX__
Parallels Workstation
PRLS__
Virtual PC
AMIBI
VMware Workstation
PTLTD__


Проверку реализуем так же, как мы проверяли наличие определенного оборудования. Просто делаем попытку открыть нужный нам ключ и, в случае успеха, делаем вывод о наличии ВМ.

5.jpg

Ключ PRLS__ в реестре Parallels Workstation
Возможности, заложенные производителем
Некоторые производители (в частности, VMware и Microsoft) специально реализуют возможности управления своими продуктами, которые можно использовать для наших целей.

В Virtual PC используются инвалидные (не «инвалидные», а «альтернативно одаренные». И вообще-то они «недействительные». — Прим. ред.) команды процессора с опкодами 0x0F, 0x3F, 0x07 и 0x0B, попытка выполнения которых на реальном процессоре вызовет исключение, в то время как на Virtual PC все пройдет нормально. С помощью этих команд можно достаточно просто задетектить виртуалку от Microsoft:

...
__try
{
__asm
{
xor ebx, ebx
mov eax, 1
__emit(0x0F)
__emit(0x3F)
__emit(0x07)
__emit(0x0B)
}
// Мы под Virtual PC
return true;
}
__except(EXCEPTION_EXECUTE_HANDLER)
return false;
...


В VMware Workstation для взаимодействия гостевой и основной ОС реализован небольшой бэкдор в виде порта с номером 0x5658. Для его использования необходимо в EAX положить «магическое» число 0x564d5868 (в символьном представлении — «VMXh»), а в ECX записать одну из команд взаимодействия гостевой и основной ОС (например, команда 0x0A возвращает версию установленной VMware Workstation). Короче, выглядит все это приблизительно так:

...
__try
{
__asm
{
mov eax, 0x564d5868
mov ecx, 0x0A
mov edx, 0x5658
in eax, dx
}
// Мы под VMware
return true;
}
__except(EXCEPTION_EXECUTE_HANDLER)
return false;
...
 

Похожие темы

Сверху