Вы — всюду: некий призрак вещий,
Что встарь вставал из лунных мшин!
На всех путях, на каждой вещи —
Клеймо познанья, след машин.
В. Брюсов
Предпосылки
Voltage Glitching (также известный как Power Glitching или VCC Glitch) — это метод аппаратного взлома (класс Fault Injection, FI), при котором намеренно создаются кратковременные искажения (провалы/импульсы) в линии питания процессора.
Цель такой атаки — вызвать просчет в работе внутренней логики чипа на аппаратном уровне. Даже если прошивка или ОС запрещают чтение памяти программно, Voltage Glitching заставляет процессор физически ошибиться и выдать данные, которые он не должен выдавать.
Не очень давно мы уже публиковали статью, в которой решалась проблема с преодолением защиты от чтения на процессоре V850E2, используя данный метод. Уже тогда была написана небольшая программа для Raspberry Pi Pico, которая часто используется для этих задач в силу высокой частоты своего GPIO, ну и, конечно же, стоимости.
В данном эксперименте мы стали заниматься процессором Renesas RH850, подход к преодолению защиты которого отличается от того, что мы делали ранее, при этом хотелось написать что-то условно универсальное, что можно было бы использовать от проекта к проекту. К тому же схема, использованная для чтения процессора V850E2 содержала два устройства, одно из которых работало как USB2UART, а второе - занималось непосредственно glitch атакой.
Мы решили избавиться от USB2UART адаптера и перенести этот функционал также в Pico, таким образом схема упростится, и всё, что нам надо это: транзистор для управления питанием, Raspberry Pi Pico и скрипт на python, реализующий атаку и UART программатор в режиме загрузчика.
Реализация двух портов
Для того чтобы Pico работал как USB2UART устройство, получая команды от программатора, написанного на python, а также получал управляющие команды по другому serial интерфейсу, необходимо было создать двух-портовое устройство. Библиотека TinyUSB обеспечивает эмуляцию двух COM-портов через один USB-соединение, а аппаратный UART Pico используется для физического интерфейса с целевой системой.
Код создает два независимых CDC (Communication Device Class) порта через TinyUSB:
CDC0 (интерфейс 0) - “глитч-порт” для управления и команд
CDC1 (интерфейс 1) - “UART-мост” для передачи данных к целевому процессору
Скорость: настраиваемая (по умолчанию 9600 бод)
Архитектура “моста” между USB CDC и UART Ключевой принцип - создание двухстороннего моста:
CDC1 → UART1: Данные от хоста (компьютера) через CDC1 передаются в целевой процессор через UART1
UART1 → CDC1: Ответы от целевого процессора через UART1 передаются обратно хосту через CDC1
process_cdc0_command()- обрабатывает команды управления глитчем от CDC0process_cdc1_data()- передает потоковые данные от CDC1 в UART1 с поддержкой триггеровСкорость UART может меняться на лету через
tud_cdc_line_coding_cb()при изменении настроек в хостеТриггерные паттерны для UART позволяют детектировать специфичные последовательности байт
Буферизация предотвращает потерю данных при высоких скоростях
Использование
tud_task()для обработки USB событийПроверка доступности буферов перед записью (
tud_cdc_n_write_available())Ожидание готовности UART перед отправкой (
uart_is_writable())Прерывания для приема UART данных (
on_uart1_rx())
Блок для испытаний
От теории - к практике, необходимо было проверить машину в действии.
Под рукой был блок SRS от VOLVO 32246116 с закрытым процессором R7F701330. Блоки достаточно старые, их все уже давно читают и пишут, поэтому было понятно, что проблем с ним не будет.
Штатная система питания ядра (1,2V) построена на основе импульсного стабилизатора с ШИМ-контроллером. В установившемся режиме он обеспечивает низкий уровень пульсаций благодаря замкнутому контуру обратной связи и высокочастотной фильтрации выходными конденсаторами.
Демонтаж сглаживающих конденсаторов приводит к довольно жёсткой “пиле”, которая сама порождает glitch, и приводит к сбою в работе процессора.
Voltage glitch
Для получения чистого, управляемого глитча предлагается полное шунтирование штатного контура питания. Напряжение 1,2V формируется низкошумящим линейным стабилизатором (LDO), включенным последовательно с нагрузкой. В разрыв цепи питания (или на путь GND) устанавливается высокоскоростной МОП-ключ (в наличии имелся IRLML2030). LDO обеспечивает низкое выходное сопротивление и мгновенное восстановление напряжения после спада, что позволяет формировать прямоугольные провалы питания с крутыми фронтами без эффекта «звона» и послесвечения, характерного для дросселей ШИМ.
В наличии имелся LDO LD3985M122R (фиксированный 1.22V).
Сначала попробовали разрыв. В принципе, рабочий (и более безопасный для схемы) вариант, однако есть ньюанс. После закрытия ключа напряжение на ядре падает до уровня ёмкостного делителя (0.6–0.7В) и далее разряжается очень медленно (током ядра). Резистор 10к на землю не помогает, так как разрядка происходит очень медленно, а glitch длится 1-2 микросекунды или менее.

Необходимо всё же “сажать” на землю. Это можно сделать двумя мосфетами:
Глитч с двумя мосфетами:

Но и один транзистор, который сажает на землю, при условии подачи питания от LD3985M122R, работает уж очень эффективно, и глитч, даже в 560нс настолько силён, что “валит” проц, не давая опомниться. Пришлось даже вернуть сглаживающий конденсатор. Хотя запас в 300МГц, до которых удалось разогнать Pico, все ещё позволял увеличивать делитель WIDTHS_DIVIDOR, определяющий какую долю микросекунды считать нашим “тиком”:
uint32_t t_delay = system_status.glitch_delay *
(sysclock / MICROSECOND_SCALE) / WIDTHS_DIVIDOR;
uint32_t t_width = system_status.glitch_width *
(sysclock / MICROSECOND_SCALE) / WIDTHS_DIVIDOR;
Очень соблазнительно выглядит вариант использования драйвера TC4427. В таком случае одним управляющим сигналом можно было бы как прерывать питание, так и ставить линию на землю.
Как выяснилось для разных вариантов нужен как обычный, так и инвертированный сигнал, в случае с двумя транзисторами (такой вариант тоже может быть нужен), и то, и другое. Поэтому прошивка была доработана и повяилось два вывода glitch (GP2, GP1).
Финальная схема для этого процессора была такой:

Триггерный паттерн
Так как флеш процессора закрыт на чтение (bitlock или 0x3F), то и “глитчить” необходимо именно команду чтения. Так как ответ от команды чтения об ошибке (код 0xDA) приходит через 11мкс, окно уязвимости очень невелико. Однако, как понять что сообщение уже послано?

Для этого передаём нашей машине триггерный паттерн, на который “заряжать” глитч. Поскольку весь трафик по UART идёт через наш второй UART интерфейс (CDC1), сделать это не так уж сложно. Однако, дьявол кроется в мелочах.
В частности, пришлось доработать прошивку pico чтобы убедиться, что байты уже отосланы. За это отвечает uart_tx_busy(). К тому же проверять все байты пакета зачастую не требуется, достаточно проверить часть байт, однако отсчёт необходимо вести от последнего байта, поэтому при установке паттерна, мы посылаем два значения: сам паттерн и реальную длину сообщения, на которое мы будем реагировать.
Использовение двух ядер
Так как в Pi Pico есть два ядра, логично процесс работы моста и работу glitch положить в разные ядра. Поэтому процедуру работы glitch запускаем посредстовм multicore_launch_core1().
Назначение пинов для работы с RH850
Пин Pico | Назначение | Описание |
|---|---|---|
GP4 | UART1_TX | Передача данных к процессору RH850 (через FTDI или напрямую) |
GP5 | UART1_RX | Прием данных от процессора RH850 |
GP6 | RESET_PIN | Сброс процессора (активный низкий уровень) |
GP3 | TRIGGER_PIN | Вход триггера для запуска глитча (GPIO или UART) |
GP2 | GLITCH_PIN | Выход глитч-импульса |
GP1 | GLITCH_PIN | Инвертированный выход глитч-импульса |
Создание скрипта для работы с UART Bootloader
Из открытых источников можно почерпнуть принципы работы протокола загрузчика похожего процессора и написать скрипт для выполнения основных команд на python. Затем вписываем в него обращения ко второму порту и получаем скрипт для глитчинга.
class RH850Command(IntEnum):
CMD_INQUIRY = 0x00 # Запрос состояния
CMD_ERASE = 0x12 # Стирание
CMD_WRITE = 0x13 # Запись
CMD_READ = 0x15 # Чтение
CMD_DLM = 0x2C # Проверка защиты
CMD_FREQ = 0x32 # Установка частоты
CMD_BAUDRATE = 0x34 # Установка скорости UART
CMD_DEVTYPE = 0x38 # Получение типа устройства
CMD_SIGNATURE = 0x3A # Чтение Silicon Signature
...
Команда 0x21 возвращает байт состояния защиты. Интерпретация:
0x3F= “Read / Write Disable” (чтение и запись запрещены)0x7F= “Read Disable” (чтение запрещено)0xBF= “Write Disable” (запись запрещена)0x1F= “Erase Disable” (стирание запрещено)
Побочные эффекты
Глитчинг этих процессоров может иметь “побочные эффекты”. Например, один из процессоров имел защиту Serial Disable, при которой протокол по UART частично заблокирован (позволяет выполнить информационные команды). При попытке “прохождении” этой защиты, процессор полностью закрылся 0x1F.
Дальнейшие перспективы
Дальнейшие перспективы проекта - подключение триггера на протоколе JTAG. Этот протокол также часто встречается в различных процессорах, и было бы небезинтересно попробовать подключить глитч-атаку на команды этого протокола. Например, проверку DEBUG password (ADKP). Если получится доработать эту машину до такого состояния, будем писать продолжение этой статьи.
Где код
Обсуждение публикации кода для данных процессоров вызвала недовольство со стороны общественности, поэтому код пока не публикуется. Мы не считаем, что код данной машины представляет собой какую-то ценность, но и не желаем создавать ненужную “конкуренцию” коммерческим продуктам в этой сфере. Спасибо за понимание.

















