Our Blog

Decoding RF Protocols Within GRC

Reading time ~6 min

I’ve been fascinated by SDR and everything you can do with it for a long time, and from a pentesters perspective, I thought it would be awesome to be able to fuzz random devices. RF devices are everywhere, and people have used SDR to mess with lots of devices, such as portable traffic lights, weather stations, and older car key fobs.
The thing is, getting started is much harder than I thought it would be as most tutorials are ambiguous, or much more manual that I’d like. There are lots of tutorials that describe how to find and view an RF signal, but they tend to end up with you counting square waves in audacity, and writing custom scripts to decode the bits you manually wrote down.

When I first started looking into this, I went through a few of these projects which are all awesome, but typically don’t offer any insight into how they work, or how you could replicate the projects on your own.
There are some other great blogs that describe how to approach reversing a protocol, such as this one, however, the approach requires a lot of manual work, where I wanted to do as much as possible directly in GRC.
After some searching, I came across an excellent video series by Tim Kuester (@bjt2n3904) which starts off simply, and ends up describing how to find and decode individual transmissions in awesome detail. My biggest takeaway from the course was this GRC block that he wrote. It takes the output from a binary slicer block, lets you specify a preamble, sync word, and transmission length, and writes individual transmissions to a file for later analysis. He then describes a technique to figure out the protocol you’re looking at so you can view the values that were transmitted. I learned a lot from this course, and highly recommend it if you’re looking to learn about all things SDR.

The only problem I had with the final result was that it was still an offline process. To decode individual transmissions, you either needed to write them to a file and decode them later, or write a custom GRC block to decode them for you in real-time. I wanted something for rapid prototyping, so I could quickly build a complete receiver and decoder directly in GRC. After Tim’s work, the only thing missing was a place to describe a protocol, so I decided to build one.

Data sent over RF will typically have a preamble, a sync word to tell the receiver that data is about to be sent, and data encoded in some way. This could be text or hexadecimal characters, integers, or anything else, but it will be encoded in binary before transmission. One of the devices I used while learning was this current-cost power monitor which has a simple protocol with four null separated integers. rtl_433 has a decoder for it, which made it easy to test with.

Excluding the preamble, the manchester-decoded bits you’ll get from one of the transmissions will look like this: 1x0x00x0000000000011001100000001000110100000000111100100000000101010111

To get this yourself. run the example graph here, double-click the Pattern Dump block, and change ‘Print to stdout’ to Yes.

This particular transmission sent a device ID of 25, and three watt values, being 141, 242, and 343. Breaking this up a little shows that some of the bits can be ignored, and others are used as separators:

Bits Length Purpose Value
1x0x00x0000 11 Padding
000000011001 12 Device ID 25
1 1 Separator
000000010001101 15 Watt value 1 141
0 1 Separator
000000011110010 15 Watt value 2 242
0 1 Separator
000000101010111 15 Watt value 3 343

This might not be 100% accurate. I figured this out manually without looking at a spec sheet, so corrections are welcome! However, this is super straightforward, and transmissions from different devices will be similar, but with different values in different places. In order to describe a protocol in GRC, I wrote this GRC block that lets you convert groups of bits to integers or hex values, optionally label values, and ignore bits if they’re simply separators with no meaning. For example, to describe this protocol, you would set the Protocol field to

ignore.11 label.deviceid int.12 ignore.1 label.value1 int.15 ignore.1 label.value2 int.15 ignore.1 label.value3 int.15

Each element is separated by a space, and describes what do do with a chunk of bits in a sequence. For example, the first key, “ignore.11” will skip over the first 11 bits, the “label” key lets you optionally label other values you decode, and the “int.12” key will take the following 12 bits, convert them to a decimal value, and add them to the output.

You can see how this would be useful for rapid prototyping. You can build up the protocol as you go along, and it will only throw an error if you specify more bits in the protocol than there are in the transmission. To use it, put it after Tim’s Pattern Dump block, run your project, and get some neatly decoded values right in GRC, like so:

There are lots of things I could add to this. For example, it would be nice to separate values with tabs, so they can be spaced out better and easier to read. It would also be useful to add more formats. Currently, this only lets you convert a chunk of bits to decimal or hexadecimal, but it would be easy to add more formats as needed. I hope this proves useful to someone, and comments and suggestions are always welcome!