On how to reverse engineer device communication

Hi Folks,

Introduction

based on the question from @Christopher_Hemmings, I’d like to introduce you to the world of reverse engineering a device communication protocol. As many products we buy, there is mearly an APP or a vendor-specific way to access the device, rendering it next to useless to our smart homes.

In this topic, I’ll show you how I reverse engineered our Poolstar / PoolEx Heat Pump controller. Goal was to replace the LCD-controller with an WIFI MQTT bridge.

What I’ve reverse engineered so far, some examples

What you need

  • Time and interest
  • PC with SigRok installed
  • Multimeter (Volts, Continuity / Resistance)
  • Advisable: Osciloscope (Some el-cheapo DS150 might do)
  • Logic analyser (I can recommend this or its cheap clones)
  • Some wires :wink:
  • Manuals (in this case this one)
  • Screwdriver etc.
  • USB to RS485 transceiver

Step 1: Know your ground / Research

The first step is to read all consumer information materials carefully. Notice where which information is present. For example, the controller in this case is able to display the water temperatures entering and leaving the unit and the fan RPM. So there must be some communication telling the controller what to display. Also take note how many PCBs are present and how they are interconnected.
As you finished getting to know the unit inside out, we’ll start to go layer-by-layer upwards to our target.

Step 2: Starting with the physical layer

There’s something called the ISO OSI Model which is a good starting point for a structured analysis. We’ll therefor start with the physical layer / layer1.
You take a close look at the connection between the controller and the heat pump. You’ll notice there are four wires between the devices - red, black, yellow and green.
First guess would be: Red positive supply, black is ground and the others are for communication. You may verify or falsify the guessing with the Multimeter. As the wires are thin and easily accessible, common sense says: there has to be no mains voltage on it. So set the multimeter to voltage measurement in DC and something smaller than 50 V and start probing. You see between red and black 12V and fluctating voltages between black (GND) and yellow and black (GND) and green. These go from 0 to approx. 3,5V.
Next step to short cut is to disconnect and open up the controller and take a close look.


Notice the labels on the connector? 12V, G, B and A. Mh, so our voltage measurement is correct. Black is ground and A,B - what’s that. Take a look at the labels on the ICs. in the upper left corner is an max13085E IC which is an RS485 transceiver. RS485 has to has something of about 120Ohms between A and B. Measure this and you’ll see, R58 is the searched resistor. You may also probe the pins on the IC and the wires just to verify.

So in conslusio, we know we get 12V and ground along with an RS485 communication on the wire. Good start!

Step 3: Starting to sniff

Now that we know what we have sitting before us, we can grab our logic analyser and take some traces. Hook up GND, A and B and start a capturing session with sigrok. Once you got some stream, add an UART decoder and save the file. The baud rate is guessable or tried until no errors appear. I got one published here for you to play with. Beside the data, take a look at the timings between messages. Those are also important.

Set up a way to produce a long term log of the communication data as it is important to get a grip on which data changeds when. Let the unit sit a few hours and use it as a normal user while logging all.

Step 4: Making sense out of the data

As soon as you got some data, you may copy and paste it into an excel table and first step is to filter out same lines. Put each byte into a seperate column and add some color:

Take a look at changing data. Mark never chaning data. Most communication protocols add a CRC check to the end of each message, as is this time. You may guess if its a CRC by seeing it frequently and heavily change.

Now, go thru all operational modes and let them run a few minutes - cooling, heating, automatic, silent mode, boost mode. Mark the bytes that change. Those have to contain information on the operational mode.

Temperatures are identified by converting the hex values (2 bytes per temperature) to decimal and matching up with the controller value. For example, 01 A7 is 423 decimal (use windows calculator) while the controller shows 1,2°C. You need to collect enough data and start calculating. Result in this case is to convert to decimal and substract 300 then divide by 10. So we even get more resolution: 01 A7 turns out to be 1,23°C.

Step 5: Resolving diffucult data

That has been easy. However - how do you resolv data you just can’t get a grip on. Simple: Emulate the heatpump and send the controller known values and check this for changes.

In this case, I got some problem with f.e. the fan RPM readout.

I’ve used a python script which sends the controller hooked up the the USB/RS485 dongle and a 12V power supply values which may be changed one by one using the cursor keys:

Step 6: Create a MQTT bridge

Now we know what those bytes mean, grab an ESP8266 and start up your prepared arduino environment. You may use my sktech as a starting point.

Basic workflow is:

  • Connect to WiFi and MQTT broker
  • Read bytes until a valid message appears (CRC, length)
  • Parse it
  • Send it to broker
  • If mqtt command received, send to heat pump

Result

TBD / Notes

  • The communication between heat pump and controller is kind of challange/response, e.g.: HP sends state until controller responds with “go on” reply. If no reply is received, the HP repeats to send its state. Controller behaves the same.
  • Baudrate is measureable: see SparkFun
  • Work in progress, I’m happy for feedback :smiley:
11 Likes

This is the easy case because of the serial port.
In more advanced cases an Android application is a good starting point. Dalvik code is pretty easy to decompile. It’s normally obfuscated by removing readable names, but there are still some anchor points left: enums, text messages, debug logging. Debug normally gives off 70% of things, including original function names, and i’ve never seen a released app where the debug code is removed. :grinning: Many vendors don’t even bother disabling it.
A C(++) code is the most difficult (and most exciting) thing to reverse. Yes, you need to understand the assembly code; and you need to understand how C code gets compiled to assembly. Then you can start unwinding the code in your mind. I used IDA Pro (free home version) for taking apart Danfoss’ communication library. Linux is a good hacker-friendly OS :smiley:, a binary will always some named references to symbols from other libraries it uses. Just google for them. Sometimes googling for strings may help. Once you’ve identified some part of the code, you know what it does, what arguments are, so you can unwind from that point up.
Another good technique, applicable to Linux .so’s is tapping and active experimentation. Once you have an externally visible symbol, you can hook up to it, call it and see what happens, and even override it with your own code (that was how i dumped decrypted DeviSmart conversation).

1 Like