
Зачем вообще этим заморачиваться?
Некоторые образцы malware выполняют различные проверки, чтобы определить, запущены ли они в виртуальной машине. Один из самых частых способов — проверка наличия определённых аппаратных компонентов, обычно не эмулируемых в виртуальных средах. Один из таких компонентов — кулер процессора. Например, malware может проверять наличие кулера процессора, поискав в WMI класс Win32_Fan
:
wmic path Win32_Fan get *
Они делают это, чтобы не запускаться в виртуальных машинах, усложнив таким образом процесс анализа для исследователей безопасности.
Зловредное ПО может определять, запущено ли оно в виртуальной машине, множеством разных способов. Есть различные классы WMI, позволяющие обнаружит присутствие виртуальной машины, например, Win32_CacheMemory
, Win32_VoltageProbe
и множество других.
В этом посте я расскажу о кулере процессора. Мне просто понравилась идея убедить виртуальную машину, что он у неё есть. Однако такой же подход можно применить к другим аппаратным компонентам и классам WMI.
Как компьютер узнаёт, что в нём есть кулер процессора?
Компьютер узнаёт об этом, считывая данные SMBIOS.
Откуда я это знаю? Загуглил.
Экземпляры
Win32_Fan
предоставляютсяWindows\System32\wbem\cimwin32.dll
. Если дизассемблировать библиотеку, можно увидеть, что для получения информации о кулере она считывает данные SMBIOS (в частности, записи с типом 27).
И в самом деле, если дизассемблировать cimwin32.dll
, то именно это мы и увидим:

Возможно, первым делом вы бы решили воспользоваться хуками DLL и пропатчить cimwin32
. Но надо мыслить масштабнее, чем мы и займёмся.
Тип 27
Тип 27 SMBIOS в System Management BIOS Reference Specification определяется как Cooling Device:

Можно получить дамп данных SMBIOS при помощи утилиты dmidecode
:
root@host:/# dmidecode -t27 -u
# dmidecode 3.3
Getting SMBIOS data from sysfs.
SMBIOS 3.4 present.
Handle 0x1B00, DMI type 27, 15 bytes
Header and Data:
1B 0F 00 1B 00 1C 65 00 00 DD 00 00 E0 15 01
Strings:
43 50 55 20 46 61 6E 00
CPU Fan
По умолчанию утилита dmidecode
интерпретирует данные и отображает их в более удобном для чтения формате:
root@host:/# dmidecode -t27
# dmidecode 3.3
Getting SMBIOS data from sysfs.
SMBIOS 3.4 present.
Handle 0x1B00, DMI type 27, 15 bytes
Cooling Device
Temperature Probe Handle: 0x1C00
Type: Chip Fan
Status: OK
OEM-specific Information: 0x0000DD00
Nominal Speed: 5600 rpm
Description: CPU Fan
Задаём произвольные данные SMBIOS в Xen
На момент написания моей статьи единственным найденным мной источником о создании произвольных данных SMBIOS в Xen был пост mcnewton, которому уже почти десяток лет. Рекомендую прочитать его, потому что в нём описываются как раз те мучения, которые испытывал я.
Если говорить вкратце, то можно задавать произвольные данные SMBIOS в Xen, присвоив опции smbios_firmware
в файле конфигурации домена значение пути к файлу, содержащему данные SMBIOS.
Давайте создадим файл smbios.bin
со следующим байтовым содержимым:
1B 0F 00 1B 00 1C 65 00 00 DD 00 00 E0 15 01 43
50 55 20 46 61 6E 00 00
Обратите внимание, что содержимое его такое же, как показанный выше вывод dmidecode -t27 -u
, но с дополнительным байтом 00
в конце, потому что он требуется по спецификации SMBIOS.
В документации по файлу конфигурации домена Xen можно также найти следующее:
Так как структуры SMBIOS не указывают свой общий размер, каждому элементу в файле должно предшествовать 32-битное целое число, определяющее размер последующей структуры.
Наша структура имеет длину 24 байт, поэтому перед содержимым нужно указать 18 00 00 00
(24 в формате little-endian):
18 00 00 00 1B 0F 00 1B 00 1C 65 00 00 DD 00 00
E0 15 01 43 50 55 20 46 61 6E 00 00
Теперь мы можем присвоить опции smbios_firmware
в файле конфигурации домена Xen значение пути к этому файлу:
smbios_firmware = "/path/to/smbios.bin"
Сохраним файл конфигурации и запустим домен Windows.
root@host:/# xl create /path/to/windows/domain.cfg
Проверим теперь наличие кулера процессора в Windows VM:
PS C:\> wmic path Win32_Fan get *
No Instance(s) Available.
Ой-ёй. Что-то пошло не так.
Предательство
Я упустил в документации одну важную подробность об опции smbios_firmware
:
smbios_firmware=”STRING”
Указывает путь к файлу, содержащему дополнительную прошивку SMBIOS… Переопределению подлежат не все заранее заданные структуры, а только следующие типы: 0, 1, 2, 3, 11, 22, 39. Файл также может …
Если честно, на самом деле, я не упустил этот фрагмент, а просто надеялся, что мои действия не считаются «переопределением» заранее заданной структуры.
Потому что Xen (или, скорее, hvmloader
) не определяет её.
Поэтому, прежде чем определять её самостоятельно, я попробовал узнать, возможно, какой-то бедняга пытался сделать то же самое до меня. К моему разочарованию, он нашёлся. Прямо в архиве патчей xen-devel.
Почему к разочарованию? Потому что после прочтения ответа на патч я ощутил раздражение автора. Но это уже другая история.
Как бы то ни было, патч отклонили, однако он маленький и простой, поэтому его легко можно самостоятельно применить к исходному коду Xen.
И тип 28 тоже
Применив патч и перекомпилировав Xen, я всё равно продолжал видеть ошибку No Instance(s) Available
при попытках запросить класс Win32_Fan
.
Мне это показалось совершенно нелогичным, поэтому я сдампил данные SMBIOS из VM, чтобы проверить наличие типа 27 (dmidecode
есть и для Windows!):
PS C:\> .\dmidecode -t27
# dmidecode 3.5
SMBIOS 2.4 present.
Handle 0x1B00, DMI type 27, 15 bytes
Cooling Device
Temperature Probe Handle: 0x1C00
Type: Chip Fan
Status: OK
OEM-specific Information: 0x0000DD00
Nominal Speed: 5600 rpm
Description: CPU Fan
Он там есть! Но почему он не отображается в WMI? Я заметил следующую строку:
Temperature Probe Handle: 0x1C00
Она указывает на то, что охлаждающее устройство (CPU fan) связано с датчиком температуры, то есть другим типом SMBIOS (28). Однако датчик температуры не был определён в данных SMBIOS:
PS C:\> .\dmidecode -t28
# dmidecode 3.5
SMBIOS 2.4 present.
Вот и оно.
Нам нужно подделать ещё одну таблицу.
Отключим VM и сдампим данные типа 28 с хоста:
root@host:/# dmidecode -t28
# dmidecode 3.3
Getting SMBIOS data from sysfs.
SMBIOS 3.4 present.
Handle 0x1C00, DMI type 28, 22 bytes
Temperature Probe
Description: CPU Thermal Probe
Location: Processor
Status: OK
Maximum Value: 0.0 deg C
Minimum Value: 0.0 deg C
Resolution: 0.000 deg C
Tolerance: 0.0 deg C
Accuracy: 0.00%
OEM-specific Information: 0x0000DC00
Nominal Value: 0.0 deg C
И снова просмотрим их в байтовом представлении:
root@host:/# dmidecode -t28 -u
# dmidecode 3.3
Getting SMBIOS data from sysfs.
SMBIOS 3.4 present.
Handle 0x1C00, DMI type 28, 22 bytes
Header and Data:
1C 16 00 1C 01 63 00 00 00 00 00 00 00 00 00 00
00 DC 00 00 00 00
Strings:
43 50 55 20 54 68 65 72 6D 61 6C 20 50 72 6F 62
65 00
CPU Thermal Probe
Следовательно, это содержимое нужно добавить в файл smbios.bin
(снова не стоит забывать о дополнительном байте 00
в конце):
1C 16 00 1C 01 63 00 00 00 00 00 00 00 00 00 00
00 DC 00 00 00 00 43 50 55 20 54 68 65 72 6D 61
6C 20 50 72 6F 62 65 00 00
А, и ещё нам нужно указать перед ними размер структуры, на этот раз 41 байт (0x29 в шестнадцатеричном виде):
29 00 00 00 1C 16 00 1C 01 63 00 00 00 00 00 00
00 00 00 00 00 DC 00 00 00 00 43 50 55 20 54 68
65 72 6D 61 6C 20 50 72 6F 62 65 00 00
Итак, готовое содержимое файла smbios.bin
должно выглядеть так:
18 00 00 00 1B 0F 00 1B 00 1C 65 00 00 DD 00 00
E0 15 01 43 50 55 20 46 61 6E 00 00 29 00 00 00
1C 16 00 1C 01 63 00 00 00 00 00 00 00 00 00 00
00 DC 00 00 00 00 43 50 55 20 54 68 65 72 6D 61
6C 20 50 72 6F 62 65 00 00
Закидываем невод в N-ный раз
Сохраним файл и снова запустим домен Windows:
root@host:/# xl create /path/to/windows/domain.cfg
Проверим, есть ли теперь кулер процессора в виртуальной машине Windows:
PS C:\> wmic path Win32_Fan get Description,Status
Description Status
Cooling Device OK
Ура! Виртуалка теперь думает, что в ней есть кулер!
Если вы задаётесь вопросом, почему я не использовал *
в команде wmic
, то отвечу, что это вызвано тем, что класс Win32_Fan
имеет множество свойств, а я хотел, чтобы вывод был коротким и удобным. Вполне бы также подошла команда wmic path Win32_Fan get *
.
Задаём произвольные данные SMBIOS в QEMU/KVM
Если вместо Xen вы используете QEMU/KVM, то жизнь ваша будет намного проще, вам не нужно ничего патчить. Можно задавать произвольные данные SMBIOS при помощи опции -smbios
:
qemu-system-x86_64 ... -smbios file=/path/to/smbios.bin
Или, если вы пользуетесь libvirt, то так:
<qemu:commandline>
<qemu:arg value='-smbios'/>
<qemu:arg value='file=/path/to/smbios.bin'/>
</qemu:commandline>
Однако вспомним о том, что Xen требовал 32-битных чисел, указывающих размеры структур. В QEMU они не требуются, поэтому можно просто использовать сырые данные, не указывая предварительно их размер:
1B 0F 00 1B 00 1C 65 00 00 DD 00 00 E0 15 01 43
50 55 20 46 61 6E 00 00 1C 16 00 1C 01 63 00 00
00 00 00 00 00 00 00 00 00 DC 00 00 00 00 43 50
55 20 54 68 65 72 6D 61 6C 20 50 72 6F 62 65 00
00
Вот и всё! QEMU автоматически обработает остальные важные записи SMBIOS.
Однако если вы задаётесь вопросом, можно ли просто взять данные SMBIOS хоста и использовать их в виртуальной машине, то да. Можете попробовать самостоятельно:
cat /sys/firmware/dmi/tables/DMI > /path/to/smbios.bin
Ссылки
Синтаксис файла конфигурации домена Xen: https://xenbits.xen.org/docs/unstable/man/xl.cfg.5.html
Заметки mcnewton — Setting custom SMBIOS data in Xen DomUs:
https://notes.asd.me.uk/2015/12/04/setting-custom-smbios-data-in-xen-domus/[XEN PATCH] tools/firmware/hvmloader/smbios.c: Add new SMBIOS tables (7,8,9,26,27,28):
https://old-list-archives.xen.org/archives/html/xen-devel/2022-01/msg00725.htmlSystem Management BIOS Reference Specification:
https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.1.pdfQEMU Anti Detection patches:
https://github.com/zhaodice/qemu-anti-detection
Комментарии (7)
huder
30.06.2025 09:29Не будет ли сам факт вызова программой кода на проверку кулера ред флагом? Мало какому софту это реально нужно
shteyner
30.06.2025 09:29Он может просто запросить сводку системы, в той же винде это не привилегированная информация, многие программы, которые собирают данные об использовании, ее снимают.
Те ту информацию, которую ты в powershell можешь получить через Get-ComputerInfo там уже будет достаточно информации для анализа.
usrsse2
30.06.2025 09:29Тогда для защиты от такого вредоносного ПО стоит на реальной системе эмулировать отсутствие кулера.
NickDoom
Это прекрасно :) Главное, чтобы враги не научились обороты сверять с реалистичной физической моделью! Хотя всегда можно и пробросить, и заэмулировать, и пустить закольцованную запись…