Привет, Хабр! Меня зовут Сергей, я embedded-разработчик в «Гравитон», моя основная задача в компании — разрабатывать и внедрять системы защиты встраиваемого программного обеспечения.
В современных реалиях, когда число изощренных угроз целостности прошивки, таких как персистентные руткиты, растет (так, согласно исследованию руткит CosmicStrand был внедрен во множество устройств в разных странах), а риск фатальных ошибок при ее обновлении или эксплуатации остается критически высоким, полагаться только на софтверный уровень защиты недостаточно. Поэтому наша команда сделала ставку на аппаратные возможности чипсетов (PCH) и разработала многоуровневую систему защиты.
Сегодня я расскажу, как устроен механизм аппаратной защиты от записи в BIOS-регион SPI Flash, как разработчикам и инженерам безопасности контролировать его, используя доступные инструменты, и покажу, как я применил этот подход на практике и что из этого вышло.
Статья будет полезна embedded-разработчикам, инженерам по безопасности и всем, кто хочет понять, как обеспечивается защита BIOS от несанкционированной записи на аппаратном уровне.
Защита Flash
Обеспечить сохранность содержимого SPI Flash возможно при помощи защиты записи диапазона BIOS (BIOS Range Write Protect) и глобальной защиты записи SPI Flash (Global Flash Write Protection). Сначала расскажу о теоретической части, затем вместе с самыми терпеливыми читателями посмотрим как данный механизм противодействует основному вектору атаки.
Защита записи диапазонов BIOS
В SPI контроллере подопытной платы присутствует пять Protected Range (PR) регистров защиты диапазонов BIOS, с помощью которых можно установить запрет на перезапись памяти.
Пример layout'а физической памяти с защищенными диапазонами:

Установка PR-регистров переопределяет разрешения на чтение и перезапись данных, установленные в Master регионе Flash-дескриптора, тем самым обеспечивая дополнительную защиту регионов.
В общих чертах это работает следующим образом:
SPI контроллер получает запрос,
Контроллер сравнивает адрес операции с базой/лимитом каждого PR,
Если адрес попадает в защищенный диапазон и WP=1, контроллер отвергает операцию, возвращая SPI_CYCLE_STATUS.ERROR.
Данный способ защиты запрещает операции чтения и перезаписи напрямую из Flash и даже во время работы процессора в SMM (System Management Mode). Однако остается вопрос: как убедиться, что упомянутая защита активно работает на реальном железе, блокируя попытки записи даже при максимальных привилегиях? Лучшее решения для такого «аппаратного детектива» — фреймворк Chipsec, он позволяет не только прочитать состояние защитных регистров, но и протестировать их реакцию на попытки несанкционированного доступа. Установка этого инструмента крайне тривиальна, просто доставляем зависимости:
apt install -y build-essential python3-dev python3 gcc linux-headers-$(uname -r) nasm
Клонируем репозиторий:
git clone https://github.com/chipsec/chipsec.git
Ну и запускаем сборку:
python setup.py build_ext -i
Давайте взглянем на практический результат. На скриншоте ниже проведен запуск модуля common.bios_pw на защищенной системе, с помощью команды:
сhipsec_main -m common.bios_pw
Тут проверяется не только наличие Protected Range регистров, но и корректность настройки — то есть действительно ли они покрывают те регионы прошивки, которые должны быть защищены от модификаций.

Регистры защиты диапазонов BIOS — PR0 и PR1 — устанавливают защиту перезаписи двух диапазонов памяти от 0x01000000 до 0x01FFFFFF(значение Write Protect — 1). Тем самым при попытке перепрошить регион BIOS не удастся переписать защищенные области.
Информация о регионах BIOS с не установленными PR-регистрами выглядит следующим образом:

При такой конфигурации PR-регистров появляется возможность перезаписать регион BIOS любыми данными, обойдя глобальную защиту SMM, что приведет к модификации ВПО или полной потере работоспособности, в зависимости от целей злоумышленника. Итак, PR-регистры обеспечивают защиту от перезаписи региона BIOS, но что если продвинутый злоумышленник решит переконфигурировать их? Чтобы избежать этого, в регистре HSFS (Hardware Sequencing Flash Status Register) существует бит FLOCKDN, с помощью которого SPI Controller не позволяет менять значения регистров PR в runtime.
Снова воспользуемся Chipsec для проверки FLOCKDN (Flash Lock Down) бита в SPI-контроллере. Для этого воспользуемся командой:
chipsec_main -m common.spi_lock

Видим, что все в порядке, бит установлен в 1, конфигурация контроллера залочена.
Глобальная защита записи SPI Flash
Глобальная защита SPI Flash применяется ко всему Flash-чипу. Параметры глобальной защиты задаются в управляющем регистре BIOS (BIOS Control Register). Для обеспечения защиты от перезаписи нас интересуют следующие биты:
BIOS Write Enable (BIOSWE) — при установленном значении «1» доступ к региону BIOS предоставляется циклам чтения и записи (Read/Write Cycles), а при значении «0» доступ предоставляется только циклам чтения.
-
BIOS Lock Enable (BLE) — установленное значение «1» активирует генерацию прерываний SMI (System Management Interrupt) при установленном бите BIOSWE, а значение «0» бита BLE отключает генерацию SMI-прерываний при установленном бите BIOSWE.
При срабатывании SMI-прерывания, код обработчика проверяет, была ли попытка установки бита BIOSWE авторизованной. В случае выявления неавторизованного доступа, обработчик сбрасывает значение BIOSWE обратно в «0», тем самым запрещая доступ к региону BIOS циклам записи.
SMM BIOS Write Protect Disable (SMM_BWP) — бит со значением «1» включает SMM защиту региона BIOS, что не предоставляет возможности перезаписывать регион BIOS, пока все процессоры не находятся в SMM (System Management Mode) и бит BIOS Write Enable не имеет значения «1». Установленное значение «0» выключает SMM-защиту региона BIOS, что позволяет обеспечить перезапись региона вне SMM.
Информация о перечисленных битах регистра BIOS_CTRL, которые обеспечивают защиту SPI Flash от перезаписи, может быть получена с помощью команды:
chipsec_main -m common.bios_wp
На скриншоте ниже показан пример правильной конфигурации, обеспечивающей защиту от записи:

А вот пример конфигурации битов регистра BIOS_CTRL, которая не позволяет обеспечивать защиту от перезаписи региона BIOS:

Конфигурация обращений к SPI Flash
Стоит отметить, что эталонная реализация UEFI EDK2 также содержит встроенные механизмы защиты SPI Flash, а именно гарантирует безопасность на уровне SPI-транзакций. При любой операции стирания или записи в регион BIOS происходит автоматическое восстановление защиты по завершении Flash Cycle. Для этого в UefiPayloadPkg существует функция SendSpiCmd, которая в конце обращения возвращает защиту SPI Flash по умолчанию.
///
/// Restore the settings for SPI Prefetching and Caching and enable BIOS Write Protect
///
if ((FlashCycleType == FlashCycleWrite) || (FlashCycleType == FlashCycleErase)) {
EnableBiosWriteProtect (SpiBaseAddress, mSpiInstance->Flags & FLAGS_SPI_DISABLE_SMM_WRITE_PROTECT);
SetSpiBiosControlRegister (SpiBaseAddress, BiosCtlSave);
}
ReleaseSpiBar0 (SpiBaseAddress);
return Status;
Погружение в описанные аппаратные механизмы защиты может показаться сухим и излишне насыщенным, но оправдание этой сложности лежит в изощренности современных угроз.
Возможные атаки, и как не оставить злоумышленникам лазеек
Итак, теоретическая база получена, самое время остановиться и порассуждать, а от чего мы вообще защищаемся?
Успешное внедрение вредоносного кода на уровне прошивки позволяет злоумышленникам получить полный контроль над ВПО, сохраняя при этом невидимость для традиционных антивирусов и средств защиты, которые зачастую работают лишь на уровне операционной системы. В пропатченную прошивку злоумышленники могут внедрить rootkit, backdoor, сетевого агента и прочие неприятные разновидности вредоносного ПО, что позволяет перехватить важные данные, нарушить или обеспечить полный отказ работы системы. Тем не менее, при наличии грамотно реализованных механизмов защиты, такие атаки становятся либо полностью невозможными, либо требуют специфических условий.
Злоумышленник, получивший доступ к устройству, может считать образ прошивки SPI Flash при помощи различных операционных утилит и в результате получит полный образ Flash, готовый для модификации и встраивания вредоносного ПО.
Для реализации такого сценария атакующий может использовать инструменты вроде UEFITool, позволяющие извлекать, модифицировать и собирать обратно образ прошивки, а затем пытаться записать его обратно в SPI. Но не тут то было! Ведь BWE-бит регистра BIOS_CTRL установлен в «0», поэтому для получения возможности записи в область BIOS флеш-памяти SPI необходимо установить его в «1». Но тут на страже стоит BLE-бит, заметит внимательный читатель. Когда он выставлен, механизм должен блокировать попытки изменения бита BWE и оставлять значение равное «0». В теории все выглядит гладко и, кажется, что прошивка под надежной защитой. Однако в действительности это происходит не мгновенно, и когда приходит запрос смены BWE на «1», то он действительно выставляется на «1», и лишь после этого платформа прерывает задачу с помощью SMI. Код обработчика этого SMI выполняет смену бита обратно на «0», что влечет за собой проблемы.
Во-первых, реализация обработчика SMI оставлена на совести разработчиков прошивки, поэтому если в прошивке не реализован этот код, бит BLE оказывается бесполезен, так как назад на «0» BWE-бит выставляться не будет. Во-вторых, в таком случае мы имеем «уязвимость состояния гонки», которая позволяет полностью обойти этот механизм, даже если обработчик SMI реализован корректно. Для применения этой уязвимости атакующему необходимо запустить поток, непрерывно выставляющий BIOSWE на «1», в то время как другой поток должен писать данные в SPI флеш-память. Согласно работе Калленберга и Войтчука, эта атака работает на многоядерных процессорах и также может успешно применяться на одноядерных процессорах с включенной технологией Hyper-Threading.
Для избежания такого состояния и нужен бит SMM BIOS Write Protect Disable(SMM_BWP). При его корректной настройке чипсет обеспечит возможность записи в область BIOS только в том случае, если все ядра работают в режиме System Management Mode и BWE выставлен на значение «1». Это эффективно защищает систему от уязвимости состояния гонки, описанной выше.
Обновление прошивки
Но как обновлять прошивку, которая расположена в сейфе со множеством замков? Как вырваться из этого царства параноидальной инженерии? Действительно, попытка обновления даже с помощью специальных утилит от Intel, например FPT (Flash Programming Tool) не приведет к успеху.

Запуск обновления прошивки можно реализовать через строго контролируемую запись в специальный регистр ACPI — это один из самых защищенных способов инициации системных операций, доступный только на уровне ядра или SMM-оболочки.
Такой подход исключает возможность случайного или злонамеренного запуска обновления, поскольку ACPI-интерфейс защищен от произвольного доступа механизмами операционной системы и чипсета. Более того, все попытки взаимодействия с этим регистром логируются в TPM и могут быть восстановлены даже после аппаратного сброса, что делает любое вмешательство следуемым и верифицируемым.
В общих чертах этот процесс можно описать так:
В качестве способа для запуска обновления можно использовать ACPI-таблицы, где определяются кастомные регистры. Сам интерфейс достаточно подробно описан в стандарте, что не мешает его расширять, создавая свои виртуальные регистры в адресном пространстве IO. Это позволяет инициировать обновление как на уровне ОС, так и до ее загрузки. С их помощью сигнал сохраняется даже после перезагрузки системы в течение достаточно долгого времени, чтобы запустить встроенное ПО, отвечающее за обновление. Для начала обновления необходимо записать в кастомный регистр определенное значение, после чего в системе устанавливается флаг, который BIOS подхватывает и понимает, что настало время для обновления. Он ищет капсулы по определенному пути в файловой системе, и, найдя, проверяет версию образа. Если версия образа будет младше текущей версии, дальше обновление не пойдет.
Также необходимо убедится не была ли нарушена целостность и конфиденциальность образа, чтобы нельзя было добавить вредоносный код или исказить образ до неузнаваемости. Тут никакой экзотики, для защиты используется RSA алгоритм шифрования, которым подписываем как сам образ, так и капсулу с обновлением. В конце, в качестве дополнения ко всем вышеперечисленным тестам добавлено некоторое количество сигнатур и «водяных» знаков, как предохранители от битых прошивок. В случае успеха все проверки образа капсулы пройдены, и начинается обновление.
Конечно, технические подробности скрыты за удобным интерфейсом, поэтому для администратора системы процесс обновления состоит из последовательных шагов:
-
Выбрать пункт меню «Обновление ПО»,
-
Вставить флешку с капсулой «Гравитон», дождаться появления информации о ее содержимом,
-
Дождаться окончания процесса обновления,
Насладиться успехом.

Вывод
В современной индустрии firmware security нередко становится жертвой компромиссов — даже у крупных вендоров порой встречаются решения, где удобство разработки или скорость вывода продукта на рынок берут верх над принципами безопасности (так, по данным из Open Security Training, из 10 тысяч систем только в 6 реализованы описанные механизмы).
Я считаю, что такая продуманная архитектура не только обеспечивает безопасность, но и превращает жесткие ограничения в четкий воркфлоу, где каждый процесс легитимного обновления имеет защищенный, но удобный маршрут. Надеюсь вам понравился материал, буду рад услышать обратную связь и продолжить делиться опытом в следующих материалах.
Полезные материалы:
Комментарии (4)
Agne
30.07.2025 15:17Да помнится , в биос на уже весьма старых сони ноутбуках при определеныых проблемах становился случайный пароль рута на биос . А сони - отвечало меняйте плату. ПРиходилось подключаться к чипу биос программатором и волшебной комбинацией байт сбрасывать биос. Хорошо что остались уязвимости и ключи.
Ilya_JOATMON
30.07.2025 15:17Это вы с интеловскими чипсетами работаете. Документацию к ним свободно с его сайта скачать можно. С АМД все хуже, все под НДА и в свободном доступе жалкие огрызки и что-то древнее старше 10 лет.
Javian
Off Когда-то иза неудачного обновления bios мне пришлось из ноута hp выпаять флеш-память, слить дамп, некой утилитой расшифровать, и часть этого дампа перенести в прошивку с оф сайта. И записать программатором обратно.
Чуть позже неудачно обновил bios на матплате Asus, забывшей после этого что она оверклокерская. В этот раз выпаивать ничего не пришлось благодаря теме на ixbt, где описывалось как собрать прошивку для матплаты и прошить штатными средствами.
С тех пор я избегаю обновлять bios без явной необходимости.
zatim
Да, сейчас с этим намного больше гемора стало. Всякие там МЕ-регионы появились. А еще во флешке может лежать не только биос, а еще прошивка мультиконтроллера (ноутбука). Возможностей для окирпичивания становится еще больше.