Главная » Хабрахабр » [Перевод] Взлом дешёвого фитнес-браслета

[Перевод] Взлом дешёвого фитнес-браслета

Это перевод. Статья опубликована 27 мая 2018 года


Фитнес-трекер до и после разборки

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

  • действительно маленький форм-фактор (примерно 15×40 мм);
  • Bluetooth low energy (BLE);
  • OLED-дисплей (96×32 пикселя);
  • аккумулятор;
  • USB-зарядка;
  • акселерометр;
  • вибромотор;
  • цена около $10 (!).

Снаружи на задней панели единственный идентификатор — это наклейка «FCC ID: 2AHFTID115». Если погуглить, то это вроде как соответствует устройству ID115 и можно даже найти несколько фотографий его внутренностей. Оглядываясь назад, на одной из этих фотографий, если сильно постараться, можно разглядеть название самой крупной интегральной схемы (IC): N51822. Это говорит о том, что здесь может быть микроконтроллер (MCU) nRF51822 от Nordic, 32-битный процессор ARM M0 со встроенной поддержкой BLE, который теоретически достаточно легко запрограммировать на другие вещи, которые должен делать браслет.

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

Чёрная пластиковая крышка приклеена к серому заднику. Открыть корпус оказалось не так-то просто. После вскрытия я убедился, что там действительно nRF51822. Я попробовал фен, чтобы размягчить клей, и терпеливо резал его маленьким ножичком, стараясь не слишком повредить пластик. Имейте в виду, что есть варианты. Позже я купил практически идентичный браслет с MCU от Texas Instrument.


nRF51822 и шариковая ручка для масштаба

В документации говорится, что чип можно запрограммировать/отладить с помощью двухконтактного интерфейса ARM Serial Wire Debug (SWD). Если мы хотим установить канал коммуникации с чипом, то это означает две вещи:

  • Нам понадобится программатор SWD (например, Segger J-Link).
  • Нам понадобится доступ к двум контактам SWD на микроконтроллере, а именно SWDIO (данные) и SWDCLK (тактовые импульсы).

К счастью, на плате есть несколько доступных контактных площадок. Хотя их существование явно объясняется необходимостью отладки, тестирования и проверки, я предпочитаю думать, что какой-то классный инженер оставил их там как маленькие подарки для таких как мы. Не все они должным образом помечены, поэтому предлагаю такие коды:

Шариковая ручка для масштаба и полупроизвольные названия для открытых контактных площадок
Передняя и обратная стороны печатной платы.

С помощью такого же дешёвого USB-микроскопа я сделал несколько снимков передней и обратной сторон платы и попытался отследить дорожки от микроконтроллера до контактных площадок.


Дорожки к контактам SWDIO и SWDCLK на передней и задней сторонах платы

По этим фотографиям можно отследить дорожки от контактов SWDIO и SWDCLK на чипе до контактных площадок IO и CLK. Обратите внимание, что это многослойная печатная плата со сквозными отверстиями, поэтому следует проверять дорожки с обеих сторон платы. Теперь можно подготовить нашу первую таблицу сопоставления: Так мы убедимся, что пометка CLK на плате соответствует SWDCLK на MCU, а непомеченный контакт — это вывод SWDIO.

Вывод nRF51822

Площадка

Описание

SWDIO

IO

Штырь данных для программирования SWD

SWDCLK

CLK

Штырь тактовой частоты для программирования SWD

Получив доступ к двум контактным площадкам SWD, я припаял очень тонкие проводки к ним и ко всем остальным доступным контактам.

Следующая задача — попытаться запрограммировать устройство на какую-нибудь задачу. Чтобы запустить простейшую программу, мы должны убедиться в следующем:

  • Мы правильно отследили контакты SWDIO/SWDCLK.
  • Программатор SWD работает, и компьютер может подавать команды.
  • Мы можем скомпилировать программу Arm и корректно использовать Nordic SDK.
  • Мы можем прошить скомпилированную программу в чип.
  • Чип правильно работает и загружает нашу программу.

В качестве “hello, world” в данном случае может выступить программа, включающая и выключающая светодиод. И даже это не элементарно, потому что на плате нет встроенного светодиода, а если добавить внешний, то всё равно нужно выяснить, к чему его подключать. Это добавляет ещё одно измерение в пространственную модель проблемы. Согласно теореме об отсутствии бесплатного сыра я просто подключил два светодиода на контакты P1 и P2 с надеждой, что мы сможем добраться до этих контактных площадок с MCU.


День плохих проводов

Если вы на macOS и используете Homebrew, то ищите формулу Cask в caskroom/drivers/segger-jlink. Драйверы и программы командной строки для программатора J-Link SWD лежат на сайте Segger. Связь с программатором SWD устанавливается из утилиты командной строки JLinkExe.

3. Затем я скачал Nordic nRF5 SDK (я использую версию 12. Из примеров SDK понятно, что нам понадобится компилятор, способный компилировать программы Arm. 0). Поэтому я установил ещё gcc-arm-embedded (тоже доступный на Homebrew).

SDK предварительно сконфигурирован для нескольких вариантов таких плат. Изучив документацию SDK и форумы разработчиков Nordic, я выяснил, что их SDK чаще всего используют с платами разработки вроде этой. Поскольку мы контачим непосредственно с контроллером, то придётся настроить некоторые параметры SDK.

На видео показаны два мигающих светодиода. Я потратил много времени на понимание экосистемы nRF5, но в конце концов всё-таки смог запустить программу на чипе! Одним из самых главных секретов стало то, что на самом деле есть несколько вариантов nRF51822, а в моём всего лишь 16 КБ памяти. На данном этапе я создал репозиторий Github и сбросил туда программу с рабочим Makefile. Так что пришлось ещё подправить скрипт компоновщика.

Как я уже говорил, задача с миганием светодиодов предусматривала некоторые надежды и метод тыка, какие из контактов MCU ведут к P1 и P2, где подключены светодиоды. Простейшая стратегия — подключать все штырьки по очереди и поочередно подавать высокое и низкое напряжение. К моему удивлению, оба светодиода загорелись! Ещё больше я удивился, когда заработал вибромотор!

Итак, метод тыка дополнил таблицу:

Вывод nRF51822

Площадка

Описание

P0.30

P1

Цифровой ввод-вывод общего назначения

P0.00

P2

Цифровой ввод-вывод общего назначения

P0.01

-

Вибродвигатель

Способность передавать данные на компьютер незаменима при отладке. Программатор J-Link поддерживает передачу в реальном времени (RTT) как для отправки, так и для получения данных с чипа. Чтобы использовать RTT, нужно сделать #include "SEGGER_RTT.h" и вызвать SEGGER_RTT_WriteString(). Для получения данных на компьютере вызовите интерфейс командной строки jlinkrttlogger, который поставляется в комплекте J-Link.
Ещё одна сложная задача — заставить работать OLED. В самых распространённых OLED на рынке работает драйвер/контроллер ssd1306, и обычно коммуникация с MCU осуществляется по последовательному интерфейсу, используя или SPI, или I²C. Вот пример от Adafruit.

И размер 96×32 у него нестандартный. Я не нашёл такой дисплей ни в одном из обычных магазинов. Поиск по идентификатору QT1316P01A на дисплее выдаёт китайские сайты типа Aliexpress, но там нет никакой документации, кроме наименований штырей:


Именования штырей OLED с Aliexpress

Если дорожки между тремя выводами nRF51822 и этими тремя выводами OLED, то мы сделаем шаг вперёд. Если список не врёт, то контакты SCL, SDA и RES# указывают нам, что это вариант I²C. Вернёмся к микроскопу.


Дорожки контактов данных OLED

Обновляем таблицу соответствий:

Вывод nRF51822

Площадка

Описание

P0.21

-

Вывод OLED SDA

P0.22

-

Вывод OLED SCL

P0.24

-

Вывод OLED RES#

Протокол I²C гораздо более продвинутый, чем какой-нибудь простой последовательный протокол вроде UART. Одно из преимуществ в том, что он поддерживает по несколько устройств master и slave на одной шине. Это немного усложняет дело: как минимум, нужно сказать MCU, для какого slave подаются команды. Так что на высоком уровне кроме физических контактов есть ещё «логический» адрес OLED-дисплея.

Он опрашивает со все возможные логические адреса и сообщает, если там что-то установлено. К счастью, один из примеров в nRF5 SDK — это сканер I²C. Он выдаёт такой лог: Моя модифицированная версия здесь.

$ make
# ...
$ make flash
# ...
$ make log
# ...
TWI scanner.
TWI device detected at 0x3c.

У нас есть веские основания полагать, что дисплей правильно идентифицирован и это действительно вариант I²C. Отличная новость! Поиск в гугле говорит, что 0x3c — типичный адрес для таких устройств.

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

Именно на это ушла львиная часть времени в данном проекте. Для правильной конфигурации я изучил библиотеку ssd1306 от Adafruit и попытался эмулировать подобные команды. Тем не менее, оно работает! Узнать все детали оказалось весьма трудоёмким занятием, и всё равно некоторые вещи я не могу объяснить.


Отображение жёстко закодированного растрового рисунка

Код этого примера здесь.

Так что страницы по 8 пикселей в высоту. С такими настройками дисплей делится на 4 строки (страницы) и 96 столбцов. Второй байт займёт второй столбец, затем третий и так далее, вплоть до 96-го столбца, когда он возвращается и начинает с первого столбца на второй странице. Первый отправленный байт расположится «вертикально» в первом столбце первой страницы.

Как показано на видео, наблюдаемое поведение отличается: сначала заполняются нечётные столбцы, затем чётные, и только потом он возвращается ко второй странице. Таково ожидаемое поведение.

В конце концов, я проглотил свою гордость и всё-таки реализовал в программе такую странную логику рендеринга, чтобы закончить на этом. Я потратил немало времени, чтобы понять причину столь глупого поведения дисплея, а затем ещё некоторое время на настройку конфигурации, чтобы исправить это.

Копаясь в библиотеке ssd1306 от Adafruit для Arduino, я всё время думал, что хорошо бы иметь способ «имитации» специфичных битов Arduino, чтобы протестировать их на nRF51822. Оказывается, гораздо более опытные люди тоже думали на эту тему — именно это делает удивительный проект sandeepmistry/arduino-nRF5. Он реализует основные библиотеки Arduino с помощью nRF5 SDK.

Я форкнул проект и добавил поддержку платы из нашего браслета. С помощью этого проекта мы можем открыть Arduino IDE, выбрать плату nRF5 — и использовать богатую экосистему Arduino. Его можно выбрать в раскрывающемся меню Tools > Board > ID115 Fitness Bracelet (nRF51822).


Библиотека ssd1306 от Adafruit в оригинальном виде (вверху) и с патчем (внизу)

К моему удивлению и облегчению, произошло то же самое странное поведение с заполнением сначала нечётных, а потом чётных столбцов OLED! Это также означает, что теперь мы можем использовать библиотеку OLED от Adafruit. По сравнению с низкоуровневым подходом, теперь у нас есть доступ к разнообразным классным абстракциям, например, выводу текста: Я с удовольствием форкнул библиотеку и внедрил тот же хак.


Более привычный “Hello, world!”

Кроме цифровых сигналов «включить/выключить», у nRF51822 есть 10 контактов для аналогового ввода. Это полезно, например, для чтения текущего заряда аккумулятора. Судя по документации, чтение аналоговых контактов выдаёт 10-битное значение. Поэтому если на входе находится 0V, то мы прочитаем 0, а если там VCC, мы прочитаем 1023 с промежуточными значениями между ними.

Я периодически считывал значения аналоговых входов и составил графики самых интересных сигналов:


Эффект встряхивания платы и зарядки аккумулятора по данным с аналоговых входов

05 относится к заряду аккумулятора, потому что значение увеличивается и уменьшается по мере зарядки и разрядки. Я убеждён, что контакт P0. 26 подключен к одному из выходов акселерометра, поскольку он сходит с ума при встряхивании платы. Подозреваю, что контакт P0. 03 и P0. Контакты P0. Например, на первом графике обратите внимание, как уровень заряда батареи (вывод 5) изменяется, когда акселерометру требуется больше энергии. 04 тоже могут быть подключены к различным выходам акселерометра, но здесь на сигнал со входа скорее всего накладывается некий эффект второго порядка. Это пример эффекта второго порядка.

Исходные данные и скрипт построения графика здесь. Код можно найти в этом наброске. Теперь можно добавить несколько строк в нашу таблицу соответствия:

Вывод nRF51822

Площадка

Описание

P0.05

-

Аналоговый вход — связан с зарядом батареи

P0.26

-

Аналоговый вход — одна ось акселерометра

P0.03

-

Аналоговый вход — одна ось акселерометра (вероятно)

P0.04

-

Аналоговый вход — одна ось акселерометра (вероятно)

В оригинальной прошивке прикосновение к браслету в определённой точке включает дисплей. При удержании этой точки запускается хронометр, если я правильно помню. Это не физическая кнопка, а какая-то ёмкостная сенсорная штука, которая работает на удивление хорошо. Используя тот же подход, что для поиска цифровых выходов, я нашёл место подключения к MCU (видео).

Код лежит здесь.

Вывод nRF51822

Площадка

Описание

P0.10

-

Цифровой вход — встроенная кнопка

Функциональность BLE на чипах nRF5 реализована через нечто под названием SoftDevice. Это предварительно скомпилированный двоичный файл со стеком BLE. Он прошивается независимо от приложения. Есть много версий SoftDevice, в зависимости от версии SDK и версии чипа.

Она показывает, с какой SDK поставляются разные версии чипа — и какая там стоит версия SoftDevice. В документации приводится некая матрица зависимости (к сожалению, на неё нельзя поставить прямую ссылку). В нашем случае на чипе стоит отметка QFAAH0, у этой микросхемы 256 КБ флэш-памяти, 16 КБ оперативной памяти и заявлена совместимость с SoftDevice s130.

3 уже содержит несколько примеров использования SoftDevice s130. Мой SDK версии 12. После загрузки и инициализации двоичный файл SoftDevice перейдёт к этому адресу и передаст управление нашей программе. По сравнению с предыдущими программами, которые прямо зашиваются в микросхемы с адреса 0x0, теперь нужно прошить SoftDevice с адреса 0x0, а саму программу — с адреса 0x1b000. Наблюдаемое поведение не изменилось, разве что следует заранее прошить SoftDevice: Чтобы проиллюстрировать, я взял тот же пример с морганием светодиодов, но изменил его для прошивки SoftDevice (код).

$ make
# ...
$ make flash-softdevice
# ...
$ make flash
# ...
$ make log
# ...
Hello, world!

Устройство только транслирует своё присутствие. Пожалуй, самое простое приложение для Bluetooth — превращение устройства в маячок. Он предполагает, что SoftDevice s130 уже прошит. Один из таких примеров есть в SDK под названием ble_app_beacon.

Кроме настройки размера оперативной памяти (это знание тяжко мне далось в примере со светодиодами), выявилась ещё одна трудно отслеживаемая проблема. Здесь тоже низкоуровневая коммуникация с чипом всё усложняет по сравнению с программированием через SDK. В примерах SDK предполагается наличие внешнего кварцевого генератора. Как оказалось, для выполнения чувствительных ко времени задач стек BLE использует генератор тактовой частоты. Исходный код маячка здесь. Когда я это понял после тысяч попыток printf, то изменил флаг конфигурации на использование синтетического генератора тактовых импульсов, и проблема решилась.

Когда пример BLE заработал с nRF5 SDK, зная о ловушках с оперативной памятью и генератором, я снова посмотрел на среду Arduino. И опять там оказался славный проект sandeepmistry/arduino-BLEPeripheral (от того же парня, что и arduino-nRF5!), который обеспечивает отличные абстракции поверх внутренней настройки BLE.

Автор проекта arduino-nrf5 потратил время и добавил конфигурацию всех плат и настроек, так что теперь выбор правильного генератора тактовых импульсов для SoftDevice сводится к простому выбору из выпадающего меню Tools > Low Frequency Clock > Synthesized. К моему удивлению, не пришлось даже форкать библиотеку. Я по-быстрому написал пример с включением зелёного светодиода по Bluetooth (с этим приложением). Потрясающе. Его работа показана на видео.

После возни с этой платой бесчисленные часы в течение нескольких недель у меня чешутся руки засунуть её подальше за стиральную машину и забыть на некоторое время.


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

«Противостояние» на PHDays 8 — взгляд со стороны SOC

В мае этого года прошла конференция Positive Hack Days 8, на которой мы вновь поучаствовали в роли SOC в уже традиционном Противостоянии (The Standoff). Атакующие — молодцы! В этом году организаторы учли прошлые ошибки и Противостояние началось в срок. Нападали ...

Погружение в AD: разбираем продвинутые атаки на Microsoft Active Directory и способы их детекта

Изображение: Pexels Участники рассказывают о новых векторах и своих изобретениях, но не забывают и о советах, как можно их обнаружить и предотвратить. За последние четыре года ни один Black Hat или DEF CON не обошелся без докладов на тему атак ...