[Перевод] Обратное проектирование дисплея e-ink

2d0254eace268773eb3e18033296681a.jpg
Этот ценник, но чёрно-белый, без красного цвета

Одному из членов нашего сообщества удалось приобрести на eBay несколько дисплеев e-ink. Эти дисплеи используют в магазинах, где на них указывается цена товаров, которые можно купить. По сравнению с бумажными ценниками такой дисплей имеет два ключевых преимущества: текст на e-ink дисплеях может обновляться автоматически и может иметь более замысловатую графику. От обычных ЖК-экранов e-ink отличается тем, что энергия расходуется только при изменении содержимого. Это позволяет оснастить ценники батареей небольшой ёмкости и работать без замены батареи несколько лет.

Человек, который купил эти ценники, хотел использовать их в проекте, но не нашёл никакой документации о том, как общаться с ними, чтобы выводить что-либо на экран. Они подарили три устройства Zeus с условием наладить связь и изобразить что-либо на экране. Согласно книге Эндрю Хуана The Hardware Hacker, это идеальное количество устройств. 1:


Самым больши́м препятствием на пути к хакингу часто является страх, что вы что-нибудь сломаете, продвигаясь вслепую. Но вы не пожарите омлет, не разбив яиц. Точно так же, чтобы взломать систему, нужно быть готовым пожертвовать устройствами. К счастью, приобрести несколько копий серийно выпускаемого оборудования очень просто. Чтобы получить образцы устройств для исследовательских целей, я часто собираю отработанные девайсы или просматриваю объявления. Обычно я стараюсь приобрести три экземпляра: один, чтобы разобрать на части и больше не собирать, один для исследования и один для поддержания в относительно первозданном виде.

После аккуратной разборки корпуса печатную плату удалось рассмотреть поближе. На этой печатной плате находились экран e-ink и аккумулятор, подключённый к ней. Батарея была немедленно отсоединена (в качестве меры предосторожности, чтобы ничего не замкнуть). Затем были сделаны фотографии передней и задней частей печатной платы, пояснения по элементной базе.

1033d7547455bd7712bdbd3cc957b802.jpg
Передняя сторона платы

9470870586177eec7278280293f934da.jpg
Задняя сторона платы

Это SES-imagotag G1 2.7 BW NFC, код продукта — B27N02003. На плате есть текст: RFRTx002D и KIM 1514 (наверное, это обозначения элементов внутри платы), а также (скорее всего) кодовое обозначение даты: 09 17 (сентябрь 2017). Сама печатная плата имеет очень профессиональную конструкцию с большим количеством тестовых точек и площадок для программатора. К экрану прикреплена NFC-метка, содержащая идентификатор платы.

На плате установлен микроконтроллер CC2510. Он может обмениваться данными на частоте 2,4 ГГц, и очевидно, что эта функция в продукте используется: на плате присутствует контур антенны. Вполне вероятно, что обновление изображения происходит по беспроводной связи через эту антенну. Остается только выяснить, как выглядит протокол связи. К сожалению, у нас нет сопутствующего устройства, которое выводит изображение на экран, поэтому перехват беспроводной связи невозможен. Но возможно прочитать код микроконтроллера и посмотреть, чего он ожидает.

Изображения печатной платы были преобразованы и наложены друг на друга в GIMP. Передний и задний слои печатной платы были помещены в разные слои GIMP, чтобы можно было легко переключаться между разными видами без потери позиционирования.


Поскольку разные уровни разводки, как правило, имеют разную структуру дорожек и элементов, при навигации между слоями ориентироваться визуально трудно и необходимо оставаться ровно в тех же координатах.

При маршрутизации сигналов между участками платы разработчикам печатных плат иногда приходится использовать так называемые сквозные межуровневые контакты (vias) с передней на заднюю сторону платы. Из маркировки »1 TOP» и »4 BOT» становится ясно, что плата — четырёхслойная. «Слоёный пирог» включает два видимых уровня разводки и ещё два между ними. К счастью для меня, кто-то другой уже протравил и сошлифовал плату до скрытых уровней.


Под via обычно подразумевают столбики контактов, соединяющие все уровни металлизации в схеме в противоположность внутренним контактам (contacts), например, к поликремниевым затворам

Это, правда, была немного другая версия, но бо́льшая часть элементной базы находится более или менее на тех же местах.

Прочитав техописание (datasheet) CC2510, я уяснил, что это интерфейс отладки. С помощью такого отладчика можно передавать код на плату, прогонять код пошагово при отладке.и даже выводить код. У отладчика два сигнальных вывода: для того, чтобы задать тайминг хоста с микроконтроллера, и для двустороннего обмена данными. При запуске отладчика на таймер подаётся два импульсных сигнала при низком логическом состоянии вывода сброса. То есть в общей сложности к плате нужно подключить 5 проводов: тайминг отладки (debug clock), данные для отладки (debug data), сброс (reset), а затем заземление и питание 3,3 В для запитки самой платы.

b664ca50cbc98518706a09c8d60d031c.jpg
Плата на держателе, распечатанном на 3D-принтере, отладочные выводы подключены к плате Pi Pico. Батарея на заднем плане отключена.

В микроконтроллере CC2510 стоит 8051-е процессорное ядро. Оно имеет довольно-таки старый 8-битный набор инструкций, изначально созданный Intel, но используемый во многих встроенных схемах. Большинство функций в этом отладчике реализовано довольно нетривиально


В этой статье автор пишет о странностях подхода TI к реализации этой платы — удачных и не очень — больше, но в более эмоциональных выражениях: http://we.easyelectronics.ru/part/soc-cc2510.html: вместо отдельной реализации записи, чтения, верификации и прочего есть инструкция DEBUG_INSTR. Эта инструкция отладки получает от одного до трёх байтов аргумента и исполняет их как инструкции для 8051-го процессора. Наконец, она передаёт значение из накопительного регистра (ACC/A) обратно через отладчик. Считывание из памяти представляет собой цикл установки адреса, который нужно считать, и передачу значения по этому адресу в регистр ACC.

f749088a7bd564493c96aef9ee8c0dc5.png
Таблица 45 — Команды отладки

Мы подключили выводы CC2510 к микроконтроллеру Raspberry Pi Pico и написали небольшую программку на базе ESP_CC_Flasher для сообщения с отладчиком микроконтроллера. Но вскоре открылось одно досадное обстоятельство: микросхема имела алгоритм блокировки отладки (debug lock): по замыслу производителя после программирования прошивки микроконтроллера интерфейс отладки отключался.

Таким образом, активной осталась лишь очень малая часть инструкций отладки. Работали только READ_STATUS (по которой мы, как и все остальные, могли увидеть, что микросхема заблокирована), GET_CHIP_ID (по которой мы могли узнать тип микросхемы) и CHIP_ERASE (для стирания разрядов защиты от отладки и всего остального кода). Никаких функций о том, как можно прочитать плату, мы не нашли. Тогда мы задались новой целью — обойти защиту от считывания кода.

Изначально мы хотели дать команду CHIP_ERASE и тут же отключить питание платы в надежде, что биты блокировки отладки будут сброшены раньше, чем сотрётся вся flash-память. Увы, это не сработало. Подозреваю, что после подачи команды CHIP_ERASE во flash записывается бит, который указывает, что подан запрос на стирание. Этот бит, как я понимаю, проверяется где-то в процедуре запуска, после чего вся прошивка стирается до тех пор, пока не сотрётся этот злополучный бит. Я, конечно, слегка расстроился, что стёр плату и превратил её в бесполезный кирпич. Но потом вспомнил совет Эндрю о том, что нужно иметь под рукой заведомо неработающее устройство. Эта стёртая плата ещё пригодилась мне, чтобы протестировать другие эксплойты, не боясь случайно стереть или сломать её, ведь она уже была стёрта.

После первой неудачи мы попробовали другой способ — «заглючить» схему скачками напряжения. Это эксплойт, при котором вы на очень короткое время меняете напряжение микросхемы. Иногда это приводит к неожиданному поведению, например пропуску определённых инструкций в программе или загрузке из памяти другого значения. Мы надеялись, что, поменяв напряжение в нужный момент, сможем обойти защиту и при этом выполнить инструкцию отладки, которая блокируется. Для разработки такого эксплойта обязательно внимательно изучить техописание микросхемы, ведь иногда там можно найти подсказки о том, что делать дальше. В данном случае мы нашли несколько интересных моментов:


Note that after the Debug Lock bit has changed due to a Flash Information Page write or a flash mass erase, a HALT, RESUME, DEBUG_INSTR, STEP_INSTR, or STEP_REPLACE command must be executed so that the Debug Lock value returned by READ_STATUS shows the updated Debug Lock value. For example a dummy NOP DEBUG_INSTR command could be executed. The Debug Lock bit will also be updated after a device reset so an alternative is to reset the chip and reenter debug mode.

Это означает, что для каждой «интересной» отладочной инструкции микросхема, вероятно, сначала извлекает из flash-памяти бит блокировки, а затем проверяет, разрешена ли такая команда. Для READ_STATUS используется значение последней инструкции отладки. Это очень полезно: если мы «глючим» инструкцию отладки, то сможем вызвать команду READ_STATUS и посмотреть, всё ли у нас получилось. Если эта команда покажет, что микросхема разблокирована, мы будем знать, что предыдущая инструкция выполнена успешно. К сожалению, это означает для нас и то, что для каждой инструкции отладки нужно успешно «глючить» плату. Это усложняет задачу, ведь велик риск перезагрузить этими скачками напряжения микроконтроллер, что сведёт к нулю весь прогресс в играх с напряжением. Таким образом, нам пришлось сосредоточиться на считывании данных наименьшим числом последовательных инструкций, и все они должны сработать успешно.

752ed2f5cbdd7a51425f4374eff9f239.png
Цоколёвка CC2510

На схеме цоколёвки обращает на себя внимание один конкретный вывод, DCOUPL:


DCOUPL: Power decoupling: 1.8 V digital power supply decoupling. DCOUPL: Развязка по питанию: 1,8 В развязка источника питания с цифровым управлением.

Микросхема запитывается от 3,3 В. Ни у одного внешнего вывода нет логических уровней, соответствующих 1,8 В. Поэтому на первый взгляд кажется странным, что у этой схемы есть питание на 1,8 В. На самом же деле это довольно частое явление: 1,8 В, скорее всего, нужны узлам внутренней логической схемы микроконтроллера (ЦП, RAM, flash и др.) Для сглаживания внешнего питания 1,8 В вывод DCOUPL должен быть подключён к наружному конденсатору. То есть у нас есть прямое подключение к внутреннему источнику питания, что очень удобно.


Развязывающий конденсатор сглаживает пульсации переменного тока источника, то есть его роль в схеме противоположна роли транзистора, которым заменит его автор. Освободившееся при этом место параллельного подключения рядом с источником идеально подходит для задачи, которую поставил себе автор.

Чтобы «заглючить» микроконтроллер, понадобятся умения ювелира: мы выпаяем развязывающий конденсатор и подключим «быстрый» полевой МОП-транзистор (в качестве цифрового ключа) к выводам DCOUPL и заземления. При включении МОП питание 1,8 В «закоротится на землю» и чип «заглючит». Успешный «глитч» становится вопросом точной синхронизации скачка напряжения и включения МОП-транзистора на нужное время. Синхронизация должна быть очень точной, вплоть до наносекунд. По сути, внутри последовательности отладки нам нужно на очень короткое время подтянуть вывод в высокое логическое состояние.

e36fe037ecbe9628842df9f70d9db07f.jpg
Микроконтроллер крупным планом. Конденсатор DCOUPL, который нужно выпаять, отмечен оранжевым.

6c76cfd4ac39a976e73198d51166774b.jpg
Микроконтроллер крупным планом после подключения МОП-транзистора к выводу DCOUPL

До этого мы использовали для сообщения с платой Raspberry Pi Pico. Для синхронизации скачков напряжения используем свойство PIO (programmable IO) микросхемы Pi Pico RP2040. Эта крутая микроконтроллерная плата позволяет задавать выводам тактовую частоту микросхемы. То есть мы можем получить сигнал с частотой 125 МГц. Мы можем подать сигнал на периферию PIO при помощи прямого доступа к памяти (DMA). Так можно делать что-то другое в тот момент, когда фоном будет подаваться наш глитч-сигнал. При этом весь буфер вывода, на который мы его подаём, за исключением позиции с парой последовательных единиц, заполняется нулями.

Для большей эффективности взлома идею пришлось слегка доработать:


  • Повышение тактовой частоты Pi Pico с начальных 125 до 250 МГц. При этом длина глитч-сигнала и длительность его подачи задаются вдвое точнее.
  • Pi Pico выполняет последовательный обмен данными через программный software USB. Иногда прерывания на стороне USB сбивают тайминг, поэтому стек USB работает при нуле на ядро (core 0), а наш код — при единице на ядро (core 1), с блокировкой прерываний.
  • Силу управляющего тока на выводе питания мы установили равной 12 мА, а скорость изменения сигнала (slew rate) — в значение fast (по умолчанию slow). Таким образом, внутренняя ёмкость затворного оксида МОП-транзистора будет меняться с достаточной скоростью, чтобы фронт глитч-сигнала получался красивым и резким.
  • Перезапускаем плату с полным сбросом после каждой попытки «заглючить» её. Для этого подключаем вход питания на 3,3 В к выводу GPIO на Pi Pico. Микроконтроллер CC2510 использует так мало, что МОП-транзистор ему не нужен. Мы можем просто запитать плату напрямую от вывода GPIO.

Теперь нужно составить набор отладочных инструкций так, чтобы «запрещённых» инструкций было как можно меньше, ведь каждая из них связана с риском перезагрузки платы. Это сводилось к изучению набора инструкций для 8051-го ядра и поиску наборов инструкций, которые загружают данные с определённого адреса в накопительный регистр (который возвращал данные после каждой инструкции). В конечном счёте задача была сведена к двум инструкциям:

MOV DPTR,#data16 (загружает 16-битную постоянную по адресу DPTR/указателя данных)

MOVX A,@DPTR (загружает из памяти DPTR в накопительный регистр)

Тогда полная побайтная последовательность отладки будет выглядеть так:


  1. DEBUG_INSTR — 3 байта, аргумент операционного кода.
  2. MOV DPTR,#data16 — операционный код.
  3. #data16 — старший байт.
  4. #data16 — младший байт.
  5. Ответ микроконтроллера: накопительный регистр.
  6. READ_STATUS.
  7. Ответ микроконтроллера: действует ли блокировка отладки.
  8. DEBUG_INSTR, 1 байт, аргумент операционного кода.
  9. MOVX A,@DPTR.
  10. Ответ микроконтроллера: накопительный регистр.
  11. READ_STATUS.
  12. Ответ микроконтроллера: действует ли блокировка отладки.

360aa7084c089e3813d77b7e01dd1ec2.png
Вид последовательности отладки в логическом анализаторе. Инструкции отладки разделены оранжевыми линиями, время подачи глитч-сигнала показано красными линиями.

Развёртка параметров по всей временной шкале последовательности отладки и по длительности глитча помогла нам найти уязвимость DEBUG_INSTR: если подать питание сразу после DEBUG_INSTR, иногда блокировка отладки обходится, что приводит к выполнению DEBUG_INSTR и «правильному» ответу накопительного регистра.

Последующая инструкция READ_STATUS показывает, что блокировка снята. Однако, если мы дадим ещё одну DEBUG_INSTR, микроконтроллер снова будет заблокирован и эта инструкция не пройдёт. Таким образом, для считывания одного байта данных нам нужно два успешных глитча, а по ответам READ_STATUS мы узнаем, сработал ли наш взлом.

Чтобы увеличить шансы на успех такой атаки, нужно точно настроить параметры. Эта настройка очень чувствительна к паразитным эффектам


Под паразитными элементами обычно понимают неустранимые паразитные полупроводниковые приборы, которые постоянно действуют в схеме вопреки планам конструктора и влияют на её нормальную работу, такие как, например, тиристорный эффект или паразитная ёмкость. В данном случае речь идёт о паразитных эффектах, которые возникают спонтанно: в данном случае — за счёт воздействия статического электричества человеческого тела и других объектов, а также изменения положения платы, поэтому авторскую формулировку «паразитные элементы» (в оригинале — parasitic elements) считаю неуместной

Если слегка коснуться платы или чуть сдвинуть её с места, настройка параметров сбивается и калибровку параметра глитча приходится начинать заново. Лучший процент успешных попыток на один глитч, которого нам удалось достичь, это около 5%, но после длительной работы он стремительно падает, вероятно, из-за нагрева. Для успешного чтения байта нужно два успешных глитч-сигнала, поэтому процент успешных попыток чтения будет всего 5% * 5% = 0,25% (если считать попытки глитча взаимонезависимыми). В секунду можно провести 35 попыток, таким образом, за каждые 20 секунд можно прочитать 1 байт. На считывание всего объёма данных flash-памяти 32 Kб уйдёт около 4 дней. Атака разрабатывалась и тестировалась на стёртой плате. При этом было подтверждено, что считываются корректные данные.

a2be5b98434213d349b8afc08d968f27.png
Гистограмма количества успешных глитчей на 10000 попыток. По оси X отложено смещение глитча по времени, длительность глитча составляет 8.

Чтобы атака была более практичной, скрипты были перенесены на сервер в подвале здания Zeus WPI. Запуск глитч-скриптов осуществлялся в рамках сессии tmux, поэтому атака могла проходить в фоновом режиме, а мы наблюдали за ней. Через пару дней скорость считывания данных значительно снизилась, и потребовалась повторная настройка параметров.

Считывание данных с микросхемы проходит довольно медленно. Это связано с нашими приоритетами: во-первых, экономия (общая цена всего «железа» составляет всего 10 евро), а во-вторых, простота и воспроизводимость. Процент успешных попыток можно повысить несколькими способами:


  • Более точная синхронизация и длительность глитча.
  • Замыкание МОП-транзистора на «землю» (0 В) — это, вероятно, не лучший выбор напряжения. Более высокое или более низкое напряжение короткого замыкания, вероятно, даст лучший результат.
  • Теперь форма глитч-сигнала — меандр. Авторы этой статьи2 предлагают разные формы глитч-сигналов и, судя по всему, тоже добиваются повышения процента успешных попыток.
  • Вместо глитча можно использовать другие способы внесения неисправностей, которые также могут быть успешными (например, сбой тайминга (clock glitching) или электромагнитные наводки (electromagnetic fault injection))

Некоторые другие РЧ-микросхемы Texas Instruments используют тот же протокол отладки (ChipCon) и встроенное 8051-е процессорное ядро. Их шифр (part number) имеет вид CCxxxx. Эти микросхемы, вероятно, уязвимы к тем же атакам. Вот их неполный список:


  • CC1110.
  • CC2430.
  • CC2431.
  • CC2510.
  • CC2511.

Компании Texas Instruments об этой уязвимости не сообщалось, поскольку у них уже есть инструкция по безопасности (security advisory), где учтены атаки методом внесения неисправностей (fault injection attacks) во все микросхемы: она находится по адресу TI-PSIRT-2021–100116, озаглавлена Physical Security Attacks Against Silicon Devices и опубликована 31 января 2022. Там есть раздел Affected products and versions:


  • Если для той или иной схемы Texas Instruments не задокументированы методы защиты от конкретной физической атаки, оно может быть к ней уязвимо.
  • Если же схема Texas Instruments имеет задокументированные средства защиты от конкретной физической атаки и компания подтверждает наличие в ней соответствующей уязвимости, TI раскрывает некоторые факты об этом (specific disclosure).

Когда они говорят, что каждое устройство уязвимо, если нет заявлений об обратном, и что они даже не обязаны писать о неустранённых уязвимостях в техописаниях и в инструкциях по безопасности, это звучит неубедительно. Поскольку маловероятно, что против рассматриваемой аппаратной атаки есть какая-то защита, кроме изменения топологии, едва ли Texas Instruments выпустит хотя бы инструкцию по безопасности по этому поводу.


В оригинале — «silicon revision». Подразумевается, что понадобятся не поверхностные изменения, например в разварке, а внесение изменений (вероятно, дорогостоящих и неактуальных для рассматриваемой сферы применения) в топологическую структуру кремниевого кристалла, но, поскольку термин «silicon revision» применим, во-первых, к другим полупроводниковым составам (и, возможно, даже к материалу платы), а во-вторых, к изменениям во frontend-структурах (например, в металлизации кристалла), формально не затрагивающие кремневую подложку, в переводе употреблен более общий термин,

На момент написания этой статьи удалось считать 30,19% от 32 Kб flash-памяти ценника e-ink. Эта память была загружена в Ghidra (фреймворк декомпиляции), с помощью которой мы подтвердили, что слитый нами код является корректным и значимым кодом 8051-го ядра. В следующей статье (надеюсь) будет подробнее написано об обратном проектировании протокола и о том, как общаться с ценниками e-ink. Весь хакерский код доступен в этом репозитории.

Спасибо pcy за ответы на многие вопросы и опасения по поводу глитч-атак.

Если у вас остались вопросы, комментарии или неясности, пишите мне на почту (j@zeus.ugent.be).

rz4hnexx9lidivxbzuaheff5usq.png


Краткий каталог курсов

Data Science и Machine Learning

Python, веб-разработка

Мобильная разработка

Java и C#

От основ — в глубину

А также


© Habrahabr.ru