Abyss: две жизни одного bootkit

Загрузочная цепочка Windows, отдельный DXE runtime-компонент и границы заявлений об обходе защиты.

Главный результат

В исследованном снимке Abyss имеет две различимые плоскости исполнения. Первая меняет ход загрузки Windows: начинает с UEFI-приложения, наблюдает загрузку образов, доходит до внутренних функций winload и подготавливает вмешательство в ядро. Вторая оформлена отдельным DXE runtime-драйвером и использует интерфейс переменных прошивки как вход для операций после смены фазы. Склеивать эти ветви в утверждение «любой UEFI-код автоматически живёт под Windows» неправильно: у них разные точки входа, память и условия вызова. E01 E07

Этот вывод основан на статическом чтении локального снимка. Он подтверждает устройство ветвей, но не совместимость готового бинарного файла с конкретной прошивкой, выпуском Windows или включённым VBS. Динамического прогона, проверки подписи собранного EFI и воспроизведения обхода Secure Boot в этом исследовании нет.

Конфигурация задаёт достижимое поведение

UefiMain сначала получает зашифрованную конфигурацию, инициализирует её поля и последовательно вызывает настройку окружения, дополнительных компонентов и runtime-ветви. Только после этого отдельное условие разрешает перехват LoadImage. Поэтому наличие функции в дереве не означает, что она сработает при каждой загрузке. Для воспроизводимого отчёта нужны не только хеш исходника, но и конфигурация конкретного экземпляра. E01

Это существенное различие между архитектурой и наблюдением. В отчёте «найден компонент с возможностью модификации CI» нельзя незаметно заменять на «CI была отключена на машине». Между ними стоят решение конфигурации, достижимость точки перехвата, совпадение структуры образа, успешная запись и дальнейшая загрузка ОС. Каждый переход требует самостоятельного свидетельства.

Где проходит цепочка управления

Модуль обработки winload читает версию PE, ищет секции и устанавливает перехваты OslFwpKernelSetupPhase1 и, при дополнительном условии, BlImgAllocateImageBuffer. Первая точка удобна автору тем, что уже доступен LoaderBlock со списком загруженных компонентов. Вторая используется для подготовки памяти под следующую стадию. Это не обычный вызов документированного Windows API: выбор точки опирается на внутреннее устройство загрузчика. E02 E04 E05

В обработчике фазы ядро ищется по списку модулей. Если нужный объект не найден, есть возврат к исходной функции. Если включена ветвь mapper и подготовлены необходимые объекты, выбирается целевой boot driver. Отдельно вызывается обработка ntoskrnl. Таким образом, «нашёл ядро», «подготовил память», «изменил драйвер» и «выполнил нагрузку» — четыре разных состояния, а не один факт наличия bootkit. E04

Для Blue это даёт полезную последовательность анализа: сопоставить PE на диске и его образ в памяти, определить владельцев указателей, проверить структуру LoaderBlock в соответствующей фазе и объяснить происхождение исполняемых областей. Сравнение требует учёта релокаций и законных изменений загрузчика; побайтовое различие всего образа само по себе не является диагнозом.

DSE: изменение политики и изменение наблюдаемого состояния

В исследованной функции обработки ядра вмешательство в DSE находится под двумя условиями конфигурации. Модуль защиты анализирует инструкции вокруг импорта CiInitialize и отдельно изменяет участок, связанный с запросом состояния Code Integrity. Это показывает две цели: повлиять на решение механизма и повлиять на то, как его состояние будет представлено наблюдателю. E03 E06

Из этого нельзя вывести универсальный обход HVCI. При memory integrity решение о допустимости исполняемых страниц опирается на изолированную среду VBS. Изменение кода или ответа в обычном ядре не доказывает, что изменилось решение более привилегированного компонента. Документация Microsoft описывает такую границу как отдельную часть модели защиты. S15

Red: доказательная гипотеза здесь — достижение изменяемого объекта до того, как независимый механизм начнёт обеспечивать его целостность. Одной строки «DSE disabled» в журнале для подтверждения недостаточно.

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

Runtime: интерфейс, память и авторизация

Второй компонент регистрирует события ExitBootServices и изменения виртуальной карты, сохраняет исходные указатели runtime services и устанавливает обёртки. Обработчик изменения карты конвертирует адреса и выставляет признак перехода; второй обработчик фиксирует завершение boot services. Командная ветвь SetVariable проверяет оба признака. Это явная попытка учесть жизненный цикл, которой нет у примитивной идеи «оставить указатель на EFI-функцию». E07 E08

Многие обёртки просто вызывают оригинал. Основной интерес представляет SetVariable: внутри специальной ветви проверяются имя, указатель VendorGuid и размер структуры. В показанном участке ненулевой GUID не сравнивается с ожидаемым значением, а совпадение имени проверяется по префиксу. Это проверка формы сообщения, но не самостоятельное доказательство права инициатора на операцию. Полную доступность канала из непривилегированного процесса этот участок также не устанавливает: выше остаётся политика ОС на вызов firmware variables. E09

Отдельный вопрос — время жизни объектов. В точке входа runtime-драйвера структура протокола объявлена локальной переменной и её адрес передаётся установке интерфейса. Такой контракт заслуживает проверки lifetime: регистрация указателя сама по себе не продлевает жизнь локального объекта. Это статически наблюдаемая зона риска, а не сообщение о воспроизведённом падении. E07

Что считать устойчивостью

UEFI различает boot services и runtime services; первые недоступны после успешного завершения ExitBootServices, вторые имеют отдельный контракт. Но даже корректное сохранение runtime-кода означает лишь резидентность в текущем сеансе. Для повторного запуска после выключения нужен источник повторной активации: файл, запись загрузки, изменённый firmware image или иной механизм. Сам обработчик SetVariable не доказывает, какой из этих вариантов использован. S24

Для расследования необходимо отдельно зафиксировать изменённый носитель и текущую память. Наличие только EFI-файла показывает возможность старта; наличие только необычной runtime-области показывает состояние сеанса. Восстановление одного слоя без проверки другого может оставить причину повторного появления.

Наблюдаемость и пределы вывода

НаблюдениеЧто оно поддерживаетЧего оно не доказывает
Указатель runtime service ведёт в нетипичную областьИзменён маршрут вызоваЗлонамеренность без атрибуции владельца
В памяти изменён участок CIВмешательство в конкретный образОбход VTL1 и всех политик VBS
В ESP присутствует дополнительный EFIИзменён состав загрузочной средыЧто файл реально исполнялся
Успешно получен TPM quoteПодписан выбранный набор измеренийОтсутствие последующей модификации RAM

Полезнейший результат разбора Abyss — не список названий перехватов, а карта зависимостей. Конфигурация, версия загрузчика, память, состояние runtime и политика авторизации определяют поведение совместно. Без этой карты и атакующий эксперимент, и защитный отчёт рискуют измерять совсем не тот механизм, который указан в заголовке.

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

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

E01 / Abyss-main/AbyssBootkitPkg/Bootkit1_Boot_UEFIApplication/AbyssBootkit1UEFIApplication.c

Строки 115–307 · Конфигурация, отдельная runtime-ветвь, условный LoadImage hook и продолжение загрузки.

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

SHA-256 1da000a7e64bc718fbe3f2114ef07ef43e74635749c2c4a2fdbd8002ad0b14f0

E07 / Abyss-main/AbyssBootkitPkg/Bootkit2_Runtime_DXERuntimeDriver/AbyssBootkit2DXERuntimeDriver.c

Строки 94–241 · Регистрация протокола и событий; установка обёрток runtime services.

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

SHA-256 3635521999b4afbb803817e49d190b9cc7edb5acca910d51e3439079460de91b

E02 / Abyss-main/AbyssBootkitPkg/Bootkit1_Boot_UEFIApplication/Modules/Module1_BootWindows0_Hookings/Functions/Functions02PatchHookWindowsOSLoader.c

Строки 95–345 · Поиск секций и двух внутренних функций winload; зависимость от сигнатур.

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

SHA-256 bdd55213712a181c7631d195a8c16f99fb50202b195813128b924547fb0811a6

E04 / Abyss-main/AbyssBootkitPkg/Bootkit1_Boot_UEFIApplication/Modules/Module1_BootWindows0_Hookings/Functions/Hooks/Hooks02WinloadEfi1OslFwpKernelSetupPhase1.c

Строки 88–155 · LoaderBlock, поиск ядра, условный mapper, возврат к оригинальной функции.

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

SHA-256 6c49e2ef6fed75d6faaf147a382932b5efcfa00698560e29fa28f0c68a33e900

E05 / Abyss-main/AbyssBootkitPkg/Bootkit1_Boot_UEFIApplication/Modules/Module1_BootWindows0_Hookings/Functions/Hooks/Hooks02WinloadEfi2BlImgAllocateImageBuffer.c

Строки 105–144 · Отдельное состояние выделения памяти для mapper; ошибка обнуляет указатель.

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

SHA-256 df2fd7028fb2d3c94efe9da8f3a2424d052487b282cf3051ead2dc10e1485a0a

E03 / Abyss-main/AbyssBootkitPkg/Bootkit1_Boot_UEFIApplication/Modules/Module1_BootWindows0_Hookings/Functions/Functions03PatchHookWindowsKernel.c

Строки 99–200 · Изменение политики DSE включается отдельными конфигурационными условиями.

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

SHA-256 ba7582db96b626131e7c5c952c7cecb1239f8f70a91bee195b8c4350770f4d89

E06 / Abyss-main/AbyssBootkitPkg/Bootkit1_Boot_UEFIApplication/Modules/Module1_BootWindows0_Hookings/Functions/Protections/Protections01DriverSignatureEnforcement.c

Строки 117–247 · Разбор инструкций вокруг импорта CI и отдельная правка запроса состояния; не доказательство взлома VTL1.

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

SHA-256 3e6cfd1742de6be8beecbbeb13a244bbf072fa45cf5f6468625674552663ee11

S15 / Memory integrity and VBS enablement ↗

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

E08 / Abyss-main/AbyssBootkitPkg/Bootkit2_Runtime_DXERuntimeDriver/Functions/Hooks/Hooks01RuntimeServices.c

Строки 123–207 · Конвертация адресов и два признака смены фазы.

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

SHA-256 a1cc7b2f9fe84dd171831dfd28f26b0b00b1d428d55ac90fc75dad86db4ffd1b

Посмотреть фрагмент исходника · строки 157–162
 157  	Global_HooksRuntimeServices_VirtualAddressChangeEvent = NULL;
 158  
 159  
 160  	// ---------------------------------------------------------------------------------------------------------------------
 161  	// We are now working in virtual address-space
 162  	Global_HooksRuntimeServices_VirtualMemoryActivated = TRUE;

E09 / Abyss-main/AbyssBootkitPkg/Bootkit2_Runtime_DXERuntimeDriver/Functions/Hooks/Hooks01RuntimeServices.c

Строки 378–424 · Командная ветвь SetVariable; часть проверок формы запроса без доказательства авторизации.

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

SHA-256 a1cc7b2f9fe84dd171831dfd28f26b0b00b1d428d55ac90fc75dad86db4ffd1b

S24 / UEFI 2.11: Runtime Services ↗

UEFI Forum · 2.11. Первичный внешний источник. Доступ: 12.09.2026.

← Предыдущий материалКак читать этот выпуск и проверять его выводыСледующий материал →Benthic: шесть способов исказить картину Windows