Creating a Python module for the Beurer BM 65 blood pressure monitor (Part II)

In my last blog post, I reverse engineered most of the USB protocol of the Beurer BM 65 blood pressure monitor. The only thing left was the first byte in each 9-bytes-measurement. I figured it was probably some status bits about detected cardiac arrhythmia. But that just isn’t good enough. I want total knowledge of the protocol, damn it!

We could perhaps reverse engineer the meaning of this byte too by trying all possible values of the first byte against the data downloader in Beurer Health Manager. Then it would be a simple comparison between the byte-value and the reaction. We already know that 0xAC means a normal reading. But what about the other 255 possibilities?

I came up with a few different ways of determining this:

  • Fake/make a measurement with cardiac arrhythmia using the actual device. I just don’t know how easy it is to fool it. And even if we succeed, we would still have incomplete knowledge about the first byte.
  • Use API Monitor to intercept the relevant ReadFile API call and change 0xAC to something else. This is the simplest approach, but very manual and tedious.
  • Program an Arduino to simulate the device. Remember that the Health Manager program spams all COM ports until it gets a response. A fun fact here is that while the program does check for the presence of the Prolific 2303 driver, it’ll happily try any old COM port. And an Arduino would be easy to program in such a way that it reacts like the real device. Besides, this approach would also yield the most Blogosphere points..
  • Implement a fake virtual COM port in Windows. With this, one can simulate the device in software.
  • Use a decompiler to inspect the code within Health Manager itself. All this reverse engineering would have been easier altogether if I’d just done this in the first place. But it feels like cheating. Let’s get back to this one later..

After a bit of consideration, I chose the approach with the virtual COM port. However, instead of creating a virtual COM port driver from scratch, I’m using the com0com project. It creates two virtual COM ports and links them, acting like a null-modem. Then I can code the actual logic in plain Python.

Virtual null-modem between virtual COM ports

Virtual null-modem between virtual COM ports

By default, Windows 7 x64 requires signed kernel-mode drivers, and the com0com driver is only test signed. Fortunately, this security limitation can be easily removed. I then linked the virtual COM ports 5 and 6. Health Manager will try them in ascending order, so by attaching my Python code to COM6, I could fool Health Manager into believing there’s a blood pressure monitor on COM5.

And now for a bit of good news followed by a bit of bad news.. The good news is that my scheme of setting up this virtual null-modem works like a charm! Health Manager is easily fooled into believing that it’s communicating with a real device on COM5. However, the bad news is that after iterating through all combinations for the first byte in the 9-byte measurements, my Python script only triggered a new reaction from Health Manager with the value 0xA9 (169). And this reaction was to reject the entire data transfer! Not a single cardiac arrhythmia-indicating result was reported. Hmm.. That’s unexpected..

Finally, I succumbed to my curiosity and disassembled the Health Manager binary using ILSpy, It’s just regular .NET code. After a bit of digging, I could confirm my new findings. While the first measurement byte (called the header) is recorded, it is never used except for rejecting the transfer if it’s equal to 0xA9. Bummer..

Well.. You can’t win them all..

Leave a Reply

Your email address will not be published. Required fields are marked *