- PVSM.RU - https://www.pvsm.ru -

Еще немного реверс-инжиниринга UEFI PEI-модулей на другом полезном примере

И снова здравствуйте, уважаемые хабрачитатели.
В рамках борьбы за возможность модификации UEFI на ноутбуках HP пришлось отломать еще одну защиту, на этот раз более современную. Видимо, отдел разработки прошивок в HP догадался, что предыдущая защита была не ахти [1], и потому они решили радикально её улучшить, поэтому метод обхода защиты DXE-тома из предыдущей статьи перестал работать, и мне опять понадобилось вооружаться дизассемблером, разрабатывать конвертер из TE в PE и отвечать на те же вопросы: где находится цифровая подпись, кто именно ее проверяет и как сделать так, чтобы проверка всегда заканчивалась успехом.
Если вас интересуют ответы и описание процесса их поиска — прошу под кат.

Краткая предыстория

Защита, о взломе которой пойдет речь в этом тексте, была введена HP около полутора лет назад, и (насколько мне известно) до сих пор считалась надежной. Пользователи ноутбуков HP с защищенным ей UEFI периодически наведывались на форум bios-mods.com [2] в надежде на помощь в избавлении от белых списков оборудования или открытии скрытых настроек UEFI Setup, но с той же периодичностью получали ответ — защита стойкая и ничего не сделать. В начале лета 2014 года одному из администраторов bios-mods [3] это надоело и он решил взять инициативу по взлому в свои руки. Процесс пошел, но крайне медленно, и результата публичного до сих пор не появилось, а он очень нужен ремонтникам, которые рады бы ставить на эти ноутбуки другие процессоры/видеокарты/модемы, но не могут, т.к. для их правильной работы нужна модификация DXE-драйверов, а после нее прошивка не стартует. В итоге мне эта ерунда надоела и я решил отломать защиту самостоятельно, благо, как выяснилось, ничего радикально сложнее предыдущей защиты HP придумать не смогли.

Ликбеза не будет

Если вам непонятно, что тут происходит, прочтите предыдущую статью [1], там имеется краткое введение в курс дела и список используемых инструментов.

Что дано и что требуется найти

Имеется ноутбук HP, который на любое изменение в DXE-томе отзывается сначала перезагрузкой почти сразу после включения, а затем впадает в бесконечный цикл, моргая при этом лампочками на клавиатуре. Также имеется дамп его прошивки [4] и добрые ребята-ремонтники, готовые потратить время на то, чтобы проверить очередную измененную прошивку на работоспособность.
Конечная цель — прошивка должна работать после модификаций.

Поиски

Снова открываем прошивку в UEFITool [5] и смотрим на панель Messages. Благодаря опыту, полученному в прошлой статье, утилита теперь умеет отображать нестандартные данные в дереве (т.е. не теперь не обязательно распаковывать весь DXE-том, что добраться до них) и сохраняет их при пересборке тома:
Еще немного реверс-инжиниринга UEFI PEI-модулей на другом полезном примере - 1

Как и в прошлый раз, подозрительные данные оказываются в самом конце DXE-тома, но теперь можно достать их непосредственно из дерева, что и делаем, получаем файл key.bin, который затем открываем в Hex-редакторе:
Еще немного реверс-инжиниринга UEFI PEI-модулей на другом полезном примере - 2

И снова перед глазами предстает неизвестный кусок данных размером 100h (похожий на RSA2048 public key), но теперь у него есть сигнатура — $HSS. Как я уже писал, данные такого рода могут быть найдены либо по сигнатуре, либо по смещению внутри тома, либо по абсолютному адресу (с учетом того, что последний байт микросхемы SPI-flash оказывается при старте по адресу FFFFFFFFh). Проверим сначала первый вариант, воспользовавшись поиском текста в UEFITool:
Еще немного реверс-инжиниринга UEFI PEI-модулей на другом полезном примере - 3

Находим 4 вхождения искомой строки, одно из которых мы уже посмотрели (то, которое внутри Non-UEFI data), нужно разобраться с остальными. Первое оказывается в DXE-драйвере по имени BiosImageInterface, но он сам находится в томе, который призван проверять, так что наличие там основной проверки весьма маловероятно. Если в других местах не найдем — надо будет к нему вернуться.
Последние же два вхождения указывают две копии одного и того же PEI-модуля, первая из которых находится в упакованной копии PEI-тома (она может использоваться для автоматического восстановления поврежденного PEI-тома), а другая — в «настоящем» PEI-томе. Вот и наш подозреваемый, все указывает на то, что целостность проверяет именно он, и нужно достать его содержимое в файл hss.bin для дальнейшего анализа.

В прошлый раз на этом месте мы загрузили полученный файл в IDA и начали анализировать его, но в данном случае так смогут сделать только обладатели IDA 6.7 и выше, т.к. именно в 6.7 появилась нативная поддержка формата Terse Executable [6], в котором и хранится наш PEI-модуль. Формат этот разработан авторами спецификации UEFI PI для экономии места в кэше процессора, по факту это PE32 с сильно обрезанным заголовком, от которого оставили только жизненно необходимые для правильной загрузки образа поля. Более того, большая часть производителей использует в фазе PEI крайне примитивный загрузчик исполняемых файлов, который не поддерживает relocation'ы, и потому его базовый адрес должен совпадать с физическим адресом. Все это замечательно, конечно, но нам нужен не непонятный TE, а понятный PE32, поэтому пришлось написать конвертер из TE в PE [7], который пытается восстановить заголовок PE-файла по тем данным, которые получилось найти в TE-файле. Утилита писалась за полчаса и под конкретный файл, так что за правильность конвертирования любого наперед заданного TE-образа поручиться не могу.
Вот теперь у нас есть файл pe.bin и можно открывать его в IDA и вести анализ. В этот раз пойдем немного другим путем и будем начинать не с точки входа, а с того места, где встречается сигнатура $HSS. Идем в Search -> Text... (или нажимаем Alt+T), вводим $HSS, ставим галку Find all occurences и… ничего не находим. Думаем немного и понимаем, что у нас LittleEndian-машина, и $HSS при загрузке в регистр будет выглядеть как SSH$ или 53534824h. Ищем этот вариант и вуаля, одно вхождение:
Еще немного реверс-инжиниринга UEFI PEI-модулей на другом полезном примере - 4

Переходим двойным щелчком на сообщении и попадаем вот сюда:
Еще немного реверс-инжиниринга UEFI PEI-модулей на другом полезном примере - 5

А вот и проверка на то, что по адресу из EBX лежит 53534824h, и если оно там действительно лежит — в переменную на стеке сохраняется EBX + 20h, т.е. как раз адрес первого байта ключа, а если не лежит — к EBX прибавляется 10h и проверяется снова. Видно также, что из другой ветки кода в ту же переменную может попасть значение FFF3DF00h, которое является физическим адресом первого байта ключа. Можно это проверить, для чего достаточно от 100000000h отнять FFF3DF00h и отступить полученные C2100h байт от конца файла — как и предполагалось, мы оказываемся точно на начале блока с ключом. Будет ли ключ найден по сигнатуре или абсолютному адресу — зависит от BootMode. Если текущий режим 20h, т.е. BOOT_IN_RECOVERY_MODE [8] — ключ будет найден по абсолютному адресу, иначе — по сигнатуре.
Смотрим дальше:
Еще немного реверс-инжиниринга UEFI PEI-модулей на другом полезном примере - 6

А дальше происходит вызов функции из какого-то специфичного для HP PPI, которая и осуществляет проверку. Если эта функция вернула 0 (т.е. EFI_SUCCESS), то мы уходим с этого экрана вниз на return, если же проверка не удалась, все опять зависит от BootMode, в случае BOOT_IN_RECOVERY_MODE происходит вызов функции из другого PPI (которая, я подозреваю, постарается восстановить DXE-том из Recovery-образа). Затем уже независимо от BootMode вызывается его одна функция из второго PPI, после чего в стек кладутся 6 и 0CF9h и выполняется вызов коротенькой функции, в нашем случае выглядящей так:

mov al, 6
mov dx, 0CF9h
out dx, al

Если вдруг не узнали в гриме — это самый распространенный ныне способ hard reset'а через IO-порты. А если ресет вдруг не случился, случится бесконечный цикл, который сразу за ним.
Ну вот, с причинами ресета разобрались, теперь надо его обойти, причем так, чтобы вернуть EFI_SUCCESS в EAX из той функции, в которой это все происходит. На мой взгляд, самый простой способ достичь желаемого — поменять первый text eax, eax на xor eax, eax, в результате и в EAX появится 0, и JGE сработает в 100% случаев, а ресет станет мертвым кодом.

Тестирование и заключение

Сказано-сделано, меняем 85 C0 -> 31 C0, записываем вместо ключа нули, собираем прошивку (не забыв, что у нас две копии этого файла и заменить нужно обе) и отправляем нашим ремонтникам на тестирование. Через 5 минут приходит сообщение: «запускается и работает, большое спасибо». Вот теперь можно снова садиться и писать статью про крутые вендорские защиты, которые сначала держатся полтора года, а потом снимаются за полтора часа.
Спасибо за внимание, удачных вам прошивок и модификаций.

P.S. В качестве бонуса, фиговенькое фото запущенного ноутбука с замененным Boot Logo, хранящимся в DXE-томе. Показывает, что защита действительно снята.

Еще немного реверс-инжиниринга UEFI PEI-модулей на другом полезном примере - 7

Автор: CodeRush

Источник [9]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/uefi/81983

Ссылки в тексте:

[1] предыдущая защита была не ахти: http://habrahabr.ru/post/249655/

[2] форум bios-mods.com: https://www.bios-mods.com/forum/

[3] одному из администраторов bios-mods: http://donovan6000.blogspot.de/

[4] дамп его прошивки: https://www.dropbox.com/s/e2zn9yeo7hflwwc/PCH.zip?dl=0

[5] UEFITool: https://github.com/LongSoft/UEFITool/releases/latest

[6] формата Terse Executable: http://wiki.phoenix.com/wiki/index.php/Terse_Executable_Format

[7] пришлось написать конвертер из TE в PE: https://github.com/NikolajSchlej/TE2PE

[8] BOOT_IN_RECOVERY_MODE : http://feishare.com/edk2doxygen/d9/d44/_include_2_boot_mode_8h_source.html

[9] Источник: http://habrahabr.ru/post/249939/