Зачем вообще этим заморачиваться?

Некоторые образцы 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, то именно это мы и увидим:

cimwin32.dll
cimwin32.dll

Возможно, первым делом вы бы решили воспользоваться хуками DLL и пропатчить cimwin32. Но надо мыслить масштабнее, чем мы и займёмся.

Тип 27

Тип 27 SMBIOS в System Management BIOS Reference Specification определяется как Cooling Device:

Cooling Device (Type 27) structure
Структура Cooling Device (типа 27)

Можно получить дамп данных 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

Ссылки

Комментарии (7)


  1. NickDoom
    30.06.2025 09:29

    Это прекрасно :) Главное, чтобы враги не научились обороты сверять с реалистичной физической моделью! Хотя всегда можно и пробросить, и заэмулировать, и пустить закольцованную запись…


  1. huder
    30.06.2025 09:29

    Не будет ли сам факт вызова программой кода на проверку кулера ред флагом? Мало какому софту это реально нужно


    1. shteyner
      30.06.2025 09:29

      Он может просто запросить сводку системы, в той же винде это не привилегированная информация, многие программы, которые собирают данные об использовании, ее снимают.

      Те ту информацию, которую ты в powershell можешь получить через Get-ComputerInfo там уже будет достаточно информации для анализа.


  1. usrsse2
    30.06.2025 09:29

    Тогда для защиты от такого вредоносного ПО стоит на реальной системе эмулировать отсутствие кулера.



    1. Rubilnik
      30.06.2025 09:29

      ПК с пассивным охлаждением оказались в большей безопасности...