Reverse engineering Bluetooth LE - device sends weird responses back - bluetooth

I recently aquired a Segway Ninebot ES2 electric scooter. I can connect to the scooter via Bluetooth LE and grab information such as battery status, current mileage, temperature, and so on. This is all done through an application.
On my Android device, I've successfully extraceted the HCI log file, which I imported into Wireshark. I can see all the requests and commands send back and forth between my phone and the scooter. However, the requests and responses are all garbage and I have no idea how to interpret them.
Example of a sent command (info says Sent Write Command, Handle: 0x000e (Nordic UART Service: Nordic UART Tx))
Example of the received value I got right after (info says Rcvd Handle Value Notification, Handle: 0x000b (Nordic UART Service: Nordic UART Rx))
How am I supposed to interpret these responses? If the battery status was 59%, I would expect it to return something like 0x3b (0x3b hex is 59 decimal). But honestly, I have no idea how this works. Maybe they're returning a bunch of data in a data type only their app knows how to interpret? Like JSON for web.
Here's an example from the nRF Connect for Mobile application, where I hit the down arrow on all the characteristics: https://i.imgur.com/hREDomP.jpg (large image)
And probably more important: How do I replicate a request or command in nRF Connect? I've tried sending a byte array that looks like 0x {02410011000d.....} (from the Write Command) in the application, but I have no idea how to read the response.

If someone is still interested, I did the same research for this scooter.
That's standart BLE communacation, device offers BLE "services" and "characteristics". Service can contain one or more characteristics, by which you communicate with device. Each charateristic can allow different types of interaction with it: writing into it, reading from it, subscribing to notifications (so you dont have to to manually read, it kinda pushes data to your app), and more (read here, for example)
Take a look at your wireshark screenshot: you can see Service UUID, Handle UUID (the characteristic), and handle ID. You can communicate with device via uuid or id, depending on your programming language or library (more about uuids).
In this particular scooter there are two characteristics, one allows writing into it, another - allows subscribing to it. Together, they act like RX and TX wires in UART: you write data into one and read from another. So, to begin communication with scooter you must establish connection to it, subscribe for notifications from one ch, and write data to another.
As for protocol: look again at she screenshots, "UART Tx" is the actual payload that was sent to scooter and "UART Rx" was the response. Yes, it's binary data, that only app would understand. Luckily, protocol has been reverse engineered and is well documented. In your example app requests serial number, and it's returned in response - "N2GWX...". In order to request battery percentage you must build another payload according to protocol.

I'm not sure if it's still relevant, but at least for those, who will be interested in the topic.
You can try the following to understand how to interpret response from the device.
An option to consider is to fetch manufacturer's mobile app (apk) either by adb or from sites like apkmirror, etc.
Then apply some reverse-eng tool like JADX.
If you're lucky and the code is somewhat readable, then search for smth that has to do with response (like ResponseParser) and try to find algo that is used to interpret the response.
However, the very first attemp should always be to search on github/google if smb did it already for your device, unless it's very niche.

Related

HM-10 BLE Module - connect to other Devices

first of all: What i am trying to do is only for private interest.
I'd like to connect a AT-09/HM-10 BLE-Module with Firmware 6.01 to another device which provides also a BLE Module, which it is not based on the CC254X-Chip,
I am able to communicate with this Device using my Laptop with integrated Bluetooth, Linux and the bluepy-helper. I am also able to make a connection using the HM10 through a USB-RS232-Module and "Hterm", but after that quite Stuck in my progress.
By "reverse-engineering" the Android-Application for controlling this particular device i found a set of Commands, stored as Strings in Hex-Format. The Java-Application itself sends out the particular Command combined with a CRC16-Modbus-Value in addition with a Request (whatever it is), to a particular Service and Characteristic UUID.
I also have a Wireshark-Protocol pulled from my Android-Phone while the application was connected to the particular device, but i am unable to find the commands extracted from the .apk in this protocol.
This is where i get stuck. After making a connection and sending out the Command+CRC16-Value i get no response at all, so i am thinking that my intentions are wrong. I am also not quite sure how the HM-10-Firmware handles / maps the Service and Char-UUIDs from the destination device.
Are there probably any special AT-Commands which would fit my need?
I am absolutely not into the technical depths of Bluetooth and its communication layer at all. The only thing i know is that the HM-10 connects to a selected BLE-Device and after that it provides a Serial I/O and data flows between the endpoints.
I have no clue how and if it can handle Data flow to certain Service/Char UUIDs from the destination endpoint, althrough it seems to have built-in the GATT , l2cap-Services and so on. Surely it handles all the neccessary communication by itself, but i don´t know where i get access to the "front-end" at all.
Best regards !

Send data using over bluetooth using different protocols

I have an app that communicates with a bluetooth device, and I'm trying to replace that app with some code.
I tried using C# InTheHand nuget, Microsoft's Bluetooth LE Explorer, python's sockets and others to send data and see what happens.
But there's something I still don't understand - in each way using different libraries I saw in wireshark a different protocol: ATT, RFCOMM, L2CAP...
When I sniffed my bluetooth traffic from my phone using the app mentioned before, I saw mostly HCI_CMD protocol traffic.
How can I choose the protocol I want to send? Is there a simple package for that? something to read?
Do I need to build the packet myself? including headers and such?
Thank you!
Update:
Using Microsoft's Bluetooth LE Explorer I was able to send a packet that lit up my lamp, starting with 02010e10000c00040012(data)
Using bleak I was able to send a packet starting with 02010e10000c00040052(data)
the difference makes the lamp not ligh up and I'm not sure if I can change it via bleak as it's not part of the data I send
I think what you are showing is that bleak does a write without response while MS BLE Explorer does a write_with_response.
Looking at the Bleak documentation for write_gatt_char that seems to be consistent as response is False by default
write_gatt_char Parameters:
char_specifier (BleakGATTCharacteristic, int, str or UUID). The characteristic to write to, specified by either integer handle, UUID
or directly by the BleakGATTCharacteristic object representing it.
data (bytes or bytearray) – The data to send.
response (bool) – If write-with-response operation should be done. Defaults to False.
I would expect the following to have the desired effect:
await client.write_gatt_char(LIGHT_CHARACTERISTIC, b"\x55\xaa\x03\x08\x02\xff\x00\xff\xf5", True)

Communicating with LeLink OBD-II BLE device in Nissan Leaf with Core Bluetooth

Hi this OBD BLE device (https://www.amazon.com/LELink-Bluetooth-Energy-OBD-II-Diagnostic/dp/B00QJRYMFC) is the one I'm using to connect over bluetooth my own iPhone. I have been able to find the right service and the characteristic to write to and to set notify value to true. However, I'm very confused as to what kind of commands I'm supposed to be sending to it. There's a list of mixed instructions online about how ELM327 devices are supposed to receive "PIDs" but also I'm confused if I should be using the list of AT commands.
First time I sent "DP\r" (an AT command) to the write characteristic and got back "DP ?" so I'm guessing it was not understood by the device.
Second time, I was following one PDF which said I should send in Mode followed by PID number so I sent in "01 00\r" which was replied with "NO DATA". I'm guessing this second command might have been better because at least I received something back instead of "?".
Would anybody know what to do in this situation? Thank you
I'm also searching for information regarding the same thing. While surfing on the internet I got a PDF with the command list to be sent to ELM327 devices and another site with info on how to use those commands in simple. So as for the details in this site "DP\r" would not work instead you would need to send "ATDP\r" as every command starts with "AT".
and I suppose that this also will be a useful PDF.

Changing the connection interval in a Bluez-based GATT-oriented application

We are currently working on an application on linux (a.o. RasPi running latest Debian Jessie) that connects to a BLE device (developed by us). This tool has evolved from cherry-picking files from the bluez (5.46) stack and adding an application layer on top. This all works quite nicely, except for the fact that connecting is incredibly slow. From the output of our tool, I understand that a truckload of messages need to be exchanged to communicate GATT services and characteristics, and each of those costs one connection interval of time. Since it is a low power device, we want the connection interval to be relatively high, and thus the high delay.
When connecting with Android BLE Scanner, I see (on the device side) that BLE Scanner manipulates the connection interval to a low value, gets all the requested data, and then sets the connection interval back to its original value. Note, btw, that neither BLE Scanner nor our Bluez-derived application take the preferred connection parameters into account.
Now I want to have our application do the same: set the connection interval to 8ms, get all info about characteristics and services, and set the connection interval back. In the Bluez stack I even find a nice function in the HCI layer for this: hci_le_conn_update.
But now the challenge: the rest of the application is built on top of the GATT functionality and even though the BLE specification defines a hierarchy between those two (with some layers in between), in code they seem absolutely independent of each other.
There are two parameters to the hci_le_conn_update function that are HCI specific: 'dd' (file descriptor to device) and 'handle' (some value that identifies the connection). The hcitool tells me that when I create a connection, the first handle is 64, so I tried with that value. For 'dd' I used hci_dev_open to get a file descriptor for the device. This worked. Sort of.
As I said before, the min/max values are not entirely taking into account. So when I set it to 6/10, I get 11 and when I set it to 6/50, I get 60. This is a bit too undeterministic for my taste, and I would prefer a function that directly changes the connection interval instead of giving a range that is mostly ignored anyway. Also the fact that I have to use a hardcoded magic number 64 gives me a bad itch. I can actually control the connection interval on the embedded device's side, but I want the control at the side of the client application.
The goal is to update the connection interval in a Bluez-GATT-based application. Within certain limits, I do not mind that much how I get there. Any suggestions?
In the official dbus API, there is no method to change connection parameters. (See https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/gatt-api.txt and https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/device-api.txt). The key is therefore to send the Connection Parameter Update Request from the peripheral side. You can of course experiment with sending a raw hci command but that is a bit "hacky" and has no guarantees to not mess up the BlueZ daemon.
If you would like to discuss the features of BlueZ such as an connection parameter update request api, you should do that on the BlueZ mailing list (http://www.bluez.org/contact/) rather than here.

How to receive incoming SMS notification in linux?

I have programmed a D-Link GSM modem on a windows machine to send and receive SMS, for testing I used Hyperterminal.
In windows the connection manager initiates the COMx ports, modem uses one unlisted COMx port through which I can send an SMS, and through a listed NMEA port I receive incoming SMS, calls like +CMTI: "ME", 11 or RING +CLIP: XXXXXXXXXXXX
I'm successfully interpreting the message and programming it to my requirements in windows. While trying the same in linux(Fedora), I see the modem initialises /dev/ttyUSB0 and /dev/ttyUSB1 as the two newly identified devices. I use minicom to set the device ports and communicate AT commands to the same.
In both the devices (/dev/ttyUSB0 and /dev/ttyUSB1) I'm not receiving unsolicited AT result code like +CMTI indication whenever I'm expecting a new SMS. FYI I've set the CNMI setting according to the manual and several other combinations.
A strange thing is that I'm able to see RING when I'm calling but not +CLIP: <callerinfo>. Similarly I'm not getting ++PSBEARER: XX, Y or +CMTI: "ME", XX
The only alternative solution is to poll the UNREAD messages at regular intervals, which is generally a bad design. Please tell me if I'm doing anything wrong with regards to the configuration, should I change some thing else apart from these?
RING is the only UR code you can assume that will always come without any specific configuration (just because this is such an old relic that it just behaves that way...). For all other UR codes, you must explicit enable each and every one of them, e.g. AT+CLIP=1, etc, otherwise they will not be enabled. And enabling those are per serial interface, e.g. running AT+CLIP=1 on /dev/ttyUSB0 will not make +CPLIP: ... be printed on /dev/ttyUSB1.
So when you get them on windows the connection manager, it must be because it has those included in it init strings. Minicom I think defaults to no init string or possibly just a very classical one like ATS0=0 E1Q0V1.

Resources