Reverse Engineering the Hiboy Scooter BTLE Protocol
If you have a Hiboy S2 Pro scooter, you might have explored whether you can increase its max speed above 20 MPH / 30 KPH. There are resources out there mentioning that you can snip a speed limiter wire, but as far as I can tell they are AI-generated make-believe.
TLDR: You can’t. The top speed is limited by the scooter firmware. But the BTLE protocol that the app uses to communicate with the scooter is very simple and open for experimentation.
To dig into this, I decided to poke into the Hiboy app. After all, it has a slider that lets you change the speed. And then it communicates these changes over Bluetooth Low Energy (BTLE) to the scooter itself.
Capturing BTLE Communication
To capture the app’s BTLE protocol, I enabled Android’s BTLE-HCI snoop log. You can see good documentation on how to do that here. Remember to turn off Bluetooth and then turn it on again after changing the developer debug setting.
I then used the Hiboy app to interact with the scooter for a while. In my case, I changed the speed setting to the slowest (4 MPH) then the fastest (19 MPH) and then back again 10 times. After, I used the adb bugreport
command to create a bug report (which includes the BTLE log). I found the BTLE log under fs\data\bt\log
after unzipping the bug report. You can then open btsnoop_hci.log
in Wireshark.
This log contains all of the BTLE traffic that was happening at the time - your phone’s digitizer pen, your ear buds, etc.
Filtering the Log
To find the right device to filter on, I installed the nRF Connect app. This app also lets you send and receive BTLE commands, which is very useful in our reverse engineering journey. You need to have disconnected the Hiboy app from the scooter in order for the nRF Connect app to be able to connect.
In the nRF Connect app, you should see your scooter as well as its Bluetooth address (in my case, 68:1E:16:03:62:80
).
You can use this address as a filter in Wireshark, as shown by https://nilhcem.com/iot/reverse-engineering-simple-bluetooth-devices. Here you can see the app sending the password to the scooter ("AT+PWD[888888]
"):
After exploring through the data capture a liitle bit, there are packets of length 22 that alternate sending different data values to the scooter:
The app is using the BTLE Write Command
to alternately write the following values to handle 0x0009
(Service UUID 0xf1f0
, UUID 0xf1f1
):
ab000ac2030610049efd
ab000ac203061013def3
Only the last 6 bytes change: 04-9e-fd
and 13-de-f3
. These are in hex. The 04 looks familiar (the scooter’s minimum speed in MPH), and when you convert 13 to decimal you get a very familiar number: 19!
The final two bytes don’t appear to be related to changing the speed - but when you plug the 20 bytes into an online checksum calculator, you can see they are a checksum - CRC16/MODBUS
specifically.
The protocol sends these 0xF3DE
bytes in little-endian order, so DE-F3
.
Replaying Traffic with nRF Connect
To see if we’ve really figured this out, we can use nRF Connect. Once you connect to the scooter (after having disconnected the Hiboy app), you can use its interface to navigate to Unknown Service 0xF1F0
, and click the upward arrow beside Unknown Characteristic 0xF1F1
:
In the Write Value screen that appears, enter or paste one of the 22-byte strings you captured. Under Advanced, make sure to select “Command”.
Removing Hiboy’s Speed Limit?
I was able to replay a few of these packets and voila! I could see the scooter correspondingly change its max speed from very slow to fast!
Now it was time to see if I could send in something higher than what the app allowed.
I changed the value of the last byte to 0x19
(25 MPH), created a new little-endian CRC16/MODBUS for it (5e-f4
), and sent:
ab000ac2030610195ef4
In a cacaphony of sad trombones, however, the scooter would only go to about 15 MPH. It was at this point I remembered an oddity (bug?) the scooter has: the top speed number always represents KPH. (See this Reddit thread: HiBoy S2 Pro stuck at 12 MPH Max Speed : ElectricScooters (reddit.com)).
Setting the scooter to Metric and re-running a data capture for setting its speed to 25 KPH, I was able to capture a value of:
ab000a82030610195f3b
We still have 0x19
for speed, but now there is an 8
for the 7th byte rather than a c
. That is a change of one bit - almost certainly the flag for non-Metric.
I then prepared a series of these, leading all the way up to 38 KPH:
1 KPH: ab000a82030610015f31
5 KPH: ab000a82030610055eF2
15 KPH: ab000a820306100fdef5
25 KPH: ab000a82030610195f3b
30 KPH: ab000a820306101d5ef8
32 KPH: ab000a82030610209f29
35 KPH: ab000a8203061023df28
38 KPH: ab000a82030610261f2b
Speed Limited by Scooter Firmware
After sending them one by one, I am sorry to report that the scooter would max out at around 30 KPH even if the Bluetooth settings protocol told it to max out at 38. The scooter firmware simply ignores speeds outside of spec.
… But an Open / Hackable Future
Although this experiment ended up not bearing fruit when it came to increasing the scooter’s max speed, it did demonstrate that the protocol is open and hackable. If the Hiboy app ever goes to garbage, it would definitely be feasible to create a community one (like several that already exist) through a bit more experimentation with the protocol.
Notably, after downloading the APK for the app and sending it through an APK decompiler, you can see references in the source to Service Mileage and a couple of other interesting things. The official app doesn’t display the scooter’s total mileage although alternatives do. Perhaps other interesting features are available through the BTLE protocol still!