Wednesday, August 24, 2022

Reversing the Pokit Meter's Bluetooth Protocol

Travis Goodspeed went to Twitter recently looking for a good BLE voltmeter for some vehicles.

Pokit Meter quickly came up as a possible solution. For around $100 it has all the features you'd expect out of a basic multimeter: voltage, current, resistance, continuity, diode check, and even temperature. The only caveat is that the app is apparently not that good.

Reversing BLE devices like this is the exact sort of thing we specialize in at ICE9, so I thought I'd volunteer my services to take a look at the protocol and see how complex it is. For an overview of the process, see my talk Bluetooth Hacking: Tools and Techniques from 2019.

My usual approach with a device like this that is mainly operated from an app is to install that app on an Android test device and log the Bluetooth communications. This proved to be extremely effective with Pokit. I began by measuring the voltage of a battery and noting the values on the screen. I then tested other functions, always noting what I did and what values were displayed on the screen. Finally, I transferred the log file to my laptop and opened it in Wireshark.

Immediately it became evident that this device uses a very simple command-response protocol. No pairing or encryption are used. On boot, the app subscribes to notifications on a number of characteristics. It then sends a command to put the device into the user-requested mode. Measurements come as notifications from a specific characteristic. From here it was just a matter of comparing the log file to my notes to align which commands referred to which modes and which notifications referred to which measurements.

I observed all commands as write requests on characteristic 0x2f with UUID 53dc9a7a-bc19-4280-b76b-002d0e23b078 and responses were handle value notifications on chracteristic 0x31 with UUID 047d3559-8bee-423a-b229-4417fa603b90. Here is a list of commands I was able to figure out from interacting with the app:

  • 00 ff f4 01 00 00 - disable
  • 01 ff f4 01 00 00 - voltage DC
  • 02 ff f4 01 00 00 - voltage AC
  • 03 ff f4 01 00 00 - current DC
  • 04 ff f4 01 00 00 - current AC
  • 05 ff f4 01 00 00 - resistance
  • 06 00 f4 01 00 00 - diode check
  • 07 00 96 00 00 00 - continuity
  • 08 00 d0 07 00 00 - temperature

I don't know the meaning of the five bytes following the command number. It's possible they may be range related arguments, but there does not appear to be a way to manually specify ranges from the app and I have never observed values other than those above.

The responses for all modes all come in a similar form. Some examples follow, but they clearly are a single byte flag followed by a 32-bit value followed by some more gibberish. The 32-bit value left me stumped for a bit. It was clearly little endian and roughly correlated with the values I had observed, but not exactly. Finally it dawned on me to treat it as a 32-bit float, and there were my measurements, exactly as I recorded from the app.

  • 01 67 b4 cf 3f 01 01 - voltage of 0x3fcfb467: 1.6v
  • 00 00 00 80 7f 07 00 - no continuity, positive infinity
  • 01 b5 18 93 41 07 00 - some continuity (see flag), resistance of 18.4Ω
  • 00 47 35 fe 41 08 00 - temperature measurement of 31.8°C / 89.2°F (it's hot where I did this work!)

That's about all the info you need to communicate with the device. For Mr. Goodspeed's application, leaving a Pokit connected to each vehicle battery and connecting to them once a day (or as often as needed), putting them into voltage DC mode, taking one measurement, and disconnecting solves the problem.

For myself, I think I'll be keeping it as a useful tool in my bag and a handy temperature logger.

I hope this information aids people who are trying to replicate the functionality of the app! As always, if you have any Bluetooth or embedded development or security needs, feel free to reach out to us.

P.S., oscilloscope functions quite a bit differently from the modes listed above, and due to time constraints I did not look into it. Following the process I described above would be a great project for someone looking to get into reverse engineering BLE devices!

P.P.S., I was also able to observe a firmware update from version 1.4 to version 1.6. Extracting the blob from the btsnoop file is quite straightforward. It appears to be encrypted, compressed, or both, and I will not be posting it here.