bootlicker: от firmware-контекста к пользовательскому процессу

Родственная загрузочная цепочка с дополнительными стадиями kernel callback и APC.

Объект и границы атрибуции

README описывает bootlicker как legacy-проект для виртуальных машин VMware. Заголовки исходников указывают GuidePoint Security. В просмотренном коде действительно видна многостадийная архитектура: EFI-вход, обработка передачи к ядру, stager внутри boot driver, kernel-компонент и пользовательская стадия. Но фраза README о независимости от настроек безопасности остаётся авторским заявлением, а не универсальным результатом этого анализа.

В отличие от bootdoor, здесь интересен не только переход UEFI → kernel, но и дальнейшее получение контекста пользовательского процесса. Общность имён файлов и схемы не означает побайтовой идентичности проектов. Для сравнения используются конкретные реализации, зафиксированные в карточках исходников. E33 E34 E36

Две задачи stager

EFI-стадия создаёт runtime-копию и сохраняет путь продолжения исходного firmware driver. Позднее в OslArchTransferToKernel выбирается ACPI.SYS, а stager переносится в его секцию. Первый смысл этого действия — дождаться Windows-контекста. Второй — получить точку вызова, которая связана с обычной последовательностью инициализации загруженных компонентов. E33 E34

DrvMain отображает исходную область kernel payload, выделяет память в nonpaged pool и копирует туда следующую стадию. Затем пытается восстановить состояние промежуточного драйвера. Здесь появляется дополнительное владение памятью: первоначальный буфер и новая kernel-копия не одно и то же. Для forensic-разбора их нельзя учитывать как единственный объект с одной историей. E35

Само выделение nonpaged pool не доказывает допустимость исполнения на современной конфигурации. Разрешения страниц, активная политика Code Integrity и фактический режим виртуализации должны быть измерены отдельно. В частности, правила memory integrity делают переход от «есть байты в памяти» к «их можно исполнять в ядре» отдельным решением. S15

Callback как продолжение, а не отдельное проникновение

KernelMain сохраняет базу ядра, разрешает PsSetCreateThreadNotifyRoutine и регистрирует callback через участок загруженного драйвера. Назначение — получить уведомление, когда появится подходящий поток, и связать следующую стадию с жизненным циклом процесса. E36

Для Blue это подчёркивает ограниченность проверки «адрес callback попадает в диапазон подписанного драйвера». Такая проверка полезна, но недостаточна, если сам участок драйвера изменён. Нужно объяснить содержимое точки входа и дальнейший переход управления. При этом не всякий непрямой переход злонамерен: легитимные trampolines и инструментирование также требуют учёта.

У этой стадии есть и собственные условия корректности: доступность API, пригодность выбранной памяти, регистрация callback и сохранение его окружения после возвращения функции инициализации. Наличие строки регистрации в исходнике подтверждает намерение и маршрут, но не успешный результат на любой сборке Windows.

Фильтр процесса: важная незавершённость снимка

ThreadNotifyRoutine получает сведения о потоке и процессе, запрашивает имя образа и сравнивает его хеш с целевым значением. В исследованном снимке в сравнении стоит ноль. Поэтому нельзя описывать этот файл как готовый выбор конкретного приложения или приписывать ему заранее определённую цель. Это наблюдаемая незаполненная часть цепочки. E37

Здесь особенно опасна привычка «додумывать за автора». Если исследователь сам выбирает цель и изменяет код, результат относится к модифицированному образцу. Такой эксперимент нельзя затем выдавать за свойства исходного снимка. Досье сохраняет различие между архитектурой APC-ветви и её фактической параметризацией.

APC: два адресных пространства и два момента исполнения

В ApcRoutine.c kernel-стадия подготавливает память в текущем процессе, переносит пользовательский фрагмент и ставит следующую APC с пользовательским режимом исполнения. Это отдельный переход через границу процесса. Для него недостаточно просто иметь указатель на пользовательский код в адресном пространстве ядра. E38

С точки зрения расследования появляются новые связи: callback создания потока, объект APC, область памяти процесса и происхождение её содержимого. Но факт постановки APC ещё не гарантирует её исполнения. Исследование должно различать подготовку, постановку в очередь, доставку и начало следующей стадии.

Red: сильный отчёт показывает причинную цепочку с временными отметками для каждой стадии. «Kernel payload запустился» не означает, что пользовательская стадия была доставлена и выполнилась.

Blue: сопоставляйте callback, необычные области процесса и события его жизненного цикла. Проверка только firmware-файла пропустит поздние следы; проверка только процесса не объяснит их происхождение.

Проект для VMware не является гипервизорным rootkit по определению

Выбор виртуальной машины как исследовательской платформы не делает код реализацией гипервизора. В рассмотренной цепочке используются UEFI и Windows kernel-механизмы. Для классификации как VMBR потребовалось бы показать создание или захват слоя виртуализации, управление состоянием гостя и соответствующий monitor. Эти действия не следуют из слова VMware в README. E33 E36

Это различие влияет на модель противника. Возможность изменить firmware image виртуальной машины обычно находится у владельца инфраструктуры или у субъекта с доступом к её конфигурации. Непривилегированный пользователь внутри гостя такой возможностью автоматически не обладает. При оценке риска нужно явно назвать, где расположен исходный контроль.

Сравнение с bootdoor

Измерениеbootdoorbootlicker
Ранний переходExitBootServices и адресная картаEFI-цепочка и ранний boot driver
Промежуточный объектACPI.SYSACPI.SYS со stager
Поздняя логикаПереданная kernel-нагрузкаThread notification и APC-ветвь
НеопределённостьСовместимость и первичный запускТе же вопросы плюс незаданный target hash
Главный Blue-ориентирПроисхождение entrypoint и RAMСвязь callback → процесс → область памяти

Сравнение отражает просмотренные функции, а не результат запуска двух бинарных образцов в одинаковой лаборатории. Оно позволяет выбрать необходимые свидетельства для такой лаборатории, но не назначить победителя по «скрытности» без измерений. Именно поздняя цепочка отличает bootlicker в этом корпусе и делает его полезным для изучения переходов между уровнями.

Источники и исходники

Ссылки E ведут к свидетельствам по локальному коду; S — к первичным внешним публикациям. Диапазон относится к оригинальному файлу. Статическое исследование, без запуска образцов.

E33 / bootlicker-master/bootkit/EfiMain.c

Строки 22–89 · Runtime-копия и сохранение нормального пути firmware driver.

Локальный снимок · файл: 89 строк · ссылка на публичный commit не установлена.

SHA-256 b5d6eacd79891122a0a961322f001ff88e99ab50a5edc95f8bec30466bc95799

E34 / bootlicker-master/bootkit/OslArchTransferToKernel.c

Строки 35–116 · Перенос stager в секцию ACPI.SYS.

Локальный снимок · файл: 116 строк · ссылка на публичный commit не установлена.

SHA-256 4eda7284d8a90bd1cc2c230193803e317b1f7ae2bfd48de6a464d59a0c85e616

E36 / bootlicker-master/kernel/KernelMain.c

Строки 33–81 · Thread notification callback через участок загруженного драйвера.

Локальный снимок · файл: 81 строк · ссылка на публичный commit не установлена.

SHA-256 8179ae360927cab68ab351872abf4c4e170b55039a210d48058f4e4a2e6b6951

E35 / bootlicker-master/bootkit/DrvMain.c

Строки 60–137 · Промежуточное отображение и копия в nonpaged pool, затем kernel payload.

Локальный снимок · файл: 137 строк · ссылка на публичный commit не установлена.

SHA-256 02eb9d591b0154f598fba8e7e2b70b1ee2985261b3c9c8606a7c326d8f1d601e

S15 / Memory integrity and VBS enablement ↗

Microsoft Learn · доступ 12.09.2026. Первичный внешний источник. Доступ: 12.09.2026.

E37 / bootlicker-master/kernel/ThreadNotifyRoutine.c

Строки 119–183 · Фильтрация процесса, нулевой целевой hash в снимке, постановка APC.

Локальный снимок · файл: 190 строк · ссылка на публичный commit не установлена.

SHA-256 0aef1e26340d9e247c1dc880cad912c64fc9df5e38634edaf4518af014e8ef8b

E38 / bootlicker-master/kernel/ApcRoutine.c

Строки 71–148 · Переход от kernel APC к пользовательскому адресному пространству.

Локальный снимок · файл: 148 строк · ссылка на публичный commit не установлена.

SHA-256 9eb9c4bba44d6d5f726c8d17a9c86000f70a5d9020eaa7c1cb9fda59c2b20344

← Предыдущий материалbootdoor: передача управления через границы загрузкиСледующий материал →Insomnia: ранняя модификация системного вызова