
How NASA’s Hackathon Schoolchildren Reverse Engineering a Fitness Bracelet to Control a Drone
- Transfer

A year ago, I purchased a SONY SmartBand SWR10 fitness tracker. Like most other fitness trackers, the gadget did not play a big role in my life, its main occupation was lying on my table. However, this is an interesting electronic device, and when a friend invited me to join his team at the NASA Space Apps hackathon , I decided to use the tracker. We selected the Do Not Crash My Drone section, where we needed to create a solution for controlling the drone. It was decided to use this tracker to control the drone.

As soon as the hackathon began, I began to look for the API of my bracelet or tools for developers, but nothing was found. Some forum users said that SONY has a proprietary SDK, which is given to developers who decided to cooperate with the company, but under the terms of the hackathon, only open-source solutions could be used. So I decided it was time to create my own drone control interface. I launched the tracker application and turned on the “Bluetooth HCI snoop log” function. This feature allowed you to sniff traffic and save the dump to the SD card.
I found the log:
~ adb shell echo $ EXTERNAL_STORAGE
/ sdcard
~ adb pull /sdcard/btsnoop_hci.log
and opened it in WireShark:

It seems that the data transfer was carried out using the Bluetooth Low Energy protocol, or, more precisely, via the GATT protocol . This is a two-way data transfer, where the phone acts as a server, “GATT Server”, and peripherals receive “GATT characteristics”, which can contain any binary data.
I selected the first UUID (00000208–37cb-11e3–8682–0002a5d5c51b), and searched it on Google. I was expecting to find the usual standardized GATT service, but found something more interesting .
I decided that we discovered someone's Git repository created by a person who reverse-engineered the protocol. And this was partially true: the project contained several working functions, including connecting, responding to hand movements, reading battery status, and keeping the connection active. But the implementation of the accelerometer was strange. I added the accelerometer data to MPAndroidChart , and I got this:

Although the information on the slopes was correct, the values were not displayed. After studying the function code, it turned out that the 32-bit single-precision number contained three 10-bit values. This makes sense, since most accelerometers work with 10-bit accuracy (like most ADCs, analog-to-digital converters). Here is the source data, pay attention to the first two bits:
acc data: 0b00101110 0b10110101 0b10111100 0b10111000
acc data: 0b00111010 0b11110001 0b00011101 0b11101011
acc data: 0b00111110 0b01110110 0b10100110 0b10011001
acc data: 0b00001011 0b11011101 0b10111101 0b00111001
But parsing data as the three 10-bit values was quite strange, every few degrees of tilt changed value 511 to -512, and the offset did not change (moreover, there was no integer overflow problem here). So I decided that SONY might use some kind of proprietary binary packaging method, or the company would use arithmetic coding and compression.
I tried Protobuf, MsgPack, Thrift and several parsers, but nothing worked. I had only a day to connect my device to the drone’s Wi-Fi. Already desperate, I tried DEX decompiling the company’s application, and after half an hour it turned out this:
// 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;
The first half [0, 512] was inverted, and therefore the situation described above arose. I fixed it using regular XOR and it worked out. I added the gravity factor, with the result [-1.1] for ± 1 g, and all that needed to be done next was to use the accelerometer data to control the drone.