Как команда школьников на хакатоне НАСА выполнила реверс-инжиниринг фитнес-браслета для управления беспилотником

в 12:26, , рубрики: diy или сделай сам, sony, гаджеты, дроны, Моддинг, мультикоптеры, Носимая электроника, реверс-инжиниринг, фитнес-трекеры

Как команда школьников на хакатоне НАСА выполнила реверс-инжиниринг фитнес-браслета для управления беспилотником - 1

Год назад я приобрел фитнес-трекер SONY SmartBand SWR10. Как и большинство других фитнес-трекеров, гаджет не играл большой роли в моей жизни, его основным занятием было лежать на моем столе. Тем не менее, это интересное электронное устройство, и когда друг пригласил меня присоединиться к его команде в хакатоне NASA Space Apps — я решил использовать трекер. Мы выбрали секцию «Не разбей мой дрон», где требовалось создать решение для управления беспилотником. Было решено использовать этот трекер для управления дроном.

Как команда школьников на хакатоне НАСА выполнила реверс-инжиниринг фитнес-браслета для управления беспилотником - 2

Как только хакатон начался, я стал искать API своего браслета или инструменты для разработчиков, но ничего не нашлось. Некоторые пользователи форума сообщили, что у SONY есть проприетарный SDK, который дается разработчикам, решивших сотрудничать с компанией, но по условиям хакатона можно было использовать только open-source решения. Поэтому я решил, что пришло время создать собственный интерфейс по управлению дроном. Я запустил приложение для трекера, и включил функцию “Bluetooth HCI snoop log”. Эта функция позволила сниффать трафик и сохранять дамп на SD-карту.

Я нашел лог:
~ adb shell echo $EXTERNAL_STORAGE
/sdcard
~ adb pull /sdcard/btsnoop_hci.log

И открыл его в WireShark:

Как команда школьников на хакатоне НАСА выполнила реверс-инжиниринг фитнес-браслета для управления беспилотником - 3

Похоже, что передача данных велась по протоколу Bluetooth Low Energy, а если точнее, то по протоколу GATT. Это двухсторонняя передача данных, где телефон выступает в роли сервера, «GATT Server», а периферийные устройства получают “GATT characteristics”, которые могут содержать любые двоичные данные.

Я выбрал первый UUID (00000208–37cb-11e3–8682–0002a5d5c51b), и поискал его в Google. Я ожидал обнаружить обычный стандартизированный GATT сервис, но нашел что-то более интересное.

Я решил, что мы обнаружили чей-то Git-репозиторий, созданный человеком, который осуществил реверс-инжиниринг протокола. И это было частично так: проект содержал несколько работающих функций, включая подключение, отклик на движение руки, считывание статуса батареи и сохранение подключения активным. Но вот реализация акселерометра была странной. Я добавил данные по акселерометру в MPAndroidChart, и получил вот это:

Как команда школьников на хакатоне НАСА выполнила реверс-инжиниринг фитнес-браслета для управления беспилотником - 4

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

acc data: 0b00101110 0b10110101 0b10111100 0b10111000
acc data: 0b00111010 0b11110001 0b00011101 0b11101011
acc data: 0b00111110 0b01110110 0b10100110 0b10011001
acc data: 0b00001011 0b11011101 0b10111101 0b00111001

Но парсинг данных как трех 10-битных значений был довольно странным, каждые несколько градусов наклона меняли значение с 511 до -512, и смещение этого не меняло (причем проблемы целочисленного переполнения здесь не было). Поэтому я решил, что SONY может использовать какой-то собственный метод бинарной упаковки, или же компания использует арифметическое кодирование и сжатие.

Я опробовал Protobuf, MsgPack, Thrift и несколько парсеров, но ничего не сработало. У меня был всего день для подключения своего устройства к Wi-Fi дрона. Уже отчаявшись, я попробовал DEX-декомпиляцию приложения компании, и через полчаса получилось вот что:

// Roughly
1: iconst_0 512 iconst_1 1023
2: r1 xor iconst_0
3: istore_0
4: iload_0
5: ifneq 8
6: r1 xor iconst_1
7: istore_0

if ((data & 0x200) != 0) {
data = -((data ^ 1023) + 1);
}
return (((float) (-data)) * 15.625f) / GRAVITY_FACTOR;

Первая половина [0, 512] была инвертирована, поэтому и возникла ситуация, описанная выше. Я исправил это, использовав обычный XOR, и все получилось. Я добавил фактор гравитации, с результатом [-1,1] для ±1 г, и все, что нужно было сделать дальше — использовать данные акселерометра для управления дроном.

Автор: marks

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js