Hacking wireless sockets like a NOOB

Olof Astrand
10 min readApr 11, 2021
Ultimate rafdo hacker
Universal Radio Hacker

Do you have some wireless devices and maybe an SDR like the RTL-SDR? Then you should download Universal Radio Hacker and look at the data. In this article I will go through that process with a wireless socket set, that I bought at the supermarket (Lidl).

I used version 2.9.1 of URH and a lime SDR mini and an RTL-SDR. I started out to do radio hacking like a Boss but ended up feeling like a NOOB. However, I was finally able to decode the signal with a lot of help from google.

The URH image was used with permission of Andreas and the following license. https://github.com/jopohl/urh/blob/master/LICENSE

https://github.com/jopohl/urh, is the git repository for URH.

The steps we use in URH,

  1. Record signal
  2. Interpret
  3. Analyze

When doing interpretation you want to use recorded complex data, that is data in the IQ form. Here is some good info about complex signal data (IQ). https://www.ni.com/sv-se/innovations/videos/07/i-q-data--plain-and-simple.html

Before even start recording, you might want to look at the spectrum analysis while pressing the buttons of the remote.

Spectrum Analyzer

Notice the waterfall plot of the spectrum on the bottom. Here you can get some idea of how the signal is encoded. You can also look at the back of the box. For devices in the united states, you should also look for your device here. https://fccid.io/

Wireless plug

Recording the signal

Remote control

Recording is rather straightforward, and is found in the File menu.

A larger recording with all button presses can be made and then split up with right click on the menu “selection to signal”.

The first step when powering on the socket is to program the device so that it knows what button to react to. While the green led on the socket is flashing you must press A-on and then A-Off. If done correctly it should be possible to switch on and off this socket with the A and Master buttons.

Interpretation

The first thing to do in the interpretation step is to analyze the recording and split the signal into different parts. Select the signal you want to analyze and right click, “create signal from selection”. After that you select the identified modulation type. This signal looks like ASK, aka On/Off Keying, where the signal is on for 1 and off for a 0. After selecting ASK as modulation type, then press the Autodetect parameters button. This will in most cases be enough, but you can also edit the recording by i.e. muting noisy parts. Select some single 1:s later in the sequence and compare them to the detected Samples/Symbol . Hold shift to drag data. Replay can also be useful if your device supports transmission.

Sometimes the spectrogram view also can bee helpful. Switch to view signal as HEX to get a more compact form of the data. Play around with the settings and try to make sense of the data.

URH interprets the following for with automatic detection,

A_On

9369b69b4db69b4da44111b688db6d11a22236d110446da236db4468888db444111b688db6d11a22236d110446da236db4468888db447f [Pause: 14086 samples]
936d26db6934926da4fe [Pause: 14096 samples]
936d26db6934926da4fe [Pause: 14086 samples]
936d26db6934926da4fe [Pause: 14096 samples]

The pattern 9369a6924d34db69a6fe seems to repeat, but something is not right.

A_Off

82236da22236db44468da22088db68888db6d111a368882236da22236db44468da22088db68888db6d111a3688fe [Pause: 14140 samples]
936da4936db4934da4fe [Pause: 14135 samples]
936da4936db4934da4fe [Pause: 14133 samples]
936da4936db4934da4fe [Pause: 14145 samples]
936d26db6934926da4fe

Ok, maybe we have made some kind of mistake here. It does not feel right so, we try the with the RTL-SDR device. Try autodetect parameters. In these recordings the RTL-SDR has a lower bandwidth (1MS/s). So pauses are about half in sample length.

A_On with the (RTL-SDR)

934b6c4a69a6da69b6920936db4926936d34da4824db6d249a4db4d36920936db4926936d34da4824db6d249a4db4d3693f [Pause: 7055 samples]
934b6c4249a4db4d3693f [Pause: 7059 samples]
934b6c4249a4db4d3693f [Pause: 7056 samples]
934b6c4249a4db4d3693f [Pause: 7060 samples]
934b6c4249a4db4d369

Oh No. Not exactly the same, but similar. 500 Samples per symbol equals a pause of 15.2 symbols (7060 sampels) and 15 symbols on the LimeSDR.

If we assume there should be no pause just a continuous stream of data. By summing up 84+15 symbols we can adjust the samples per symbol until a much simpler protocol appears. Remember that 0x8 and 0xe are encoded as a single 1 and the rest is 0.

46 ms between the repeating packets

This exercise was however not the correct way to get to the correct solution.

Another transmitter for wireless lightbulbs

I had bought a similar kit with lightbulbs instead of sockets. Why not also give it a try. This remote has the exact same buttons but a smaller size. It also has some text written on the back as seen to the left.

After plugging in the sockets, or lightbulb you must first press the on button and then the off button to initialize them correctly. I was able to program the socket so that both remotes button A on and off works just fine.

When testing the new remote, it seems like is slightly out of tune. 433.972. It also sends a signal continuously for 1.58S seconds after press. This can be seen with the spectrum analyzer. It seems likely that the bulbs do not like a fast on/off switching scenario. Interestingly enough both signals control the the switch, but master OFF on the new remote does not work. Anyway I now have 3 button to turn on the first switch.

New lightbulb remote, slightly off 433.972 MHz, alternated by pushing the switch remote

The new remote gives different results.

New lightbulb remote

When repeating the previously steps we get the following.

A_On with lightbulb remote

Note that autodetect now found 200 samples per Symbol.

c [Pause: 4901 samples]
ffc1ff83 [Pause: 2620 samples]
ffc1ff83ff06 [Pause: 2577 samples]
ffc18 [Pause: 2567 samples]
e [Pause: 2595 samples]
ffc1ff83ff07fe0ffc1ff83 [Pause: 2573 samples]
ffc1ff83ff06 [Pause: 2586 samples]
c [Pause: 2587 samples]
c [Pause: 2627 samples]

c [Pause: 4865 samples]
ffc1ff83 [Pause: 2609 samples]
ffc1ff83ff06 [Pause: 2593 samples]
ffc18 [Pause: 2613 samples]
c [Pause: 2599 samples]
ffc1ff83ff07fe0ffc1ff83 [Pause: 2585 samples]
ffc1ff83ff06 [Pause: 2596 samples]
c [Pause: 2609 samples]

However we see a similar pattern here,

84 [Pause: 21842 samples]

842 [Pause: 2851 samples]
84 [Pause: 2892 samples]
84 [Pause: 2858 samples]

Analysis stage

As the signal is not so well behaved, the analysis stage did not make much sense. There exist some documentation on the home of URH https://github.com/jopohl/urh and some videos made by the creator. https://www.youtube.com/channel/UCqIWuCQfX00XHFiwTENI79A

But instead we chose the quick fix, and use google.

The easy solution

Using google is not as educational as do it yourself, but can save you some time. The following links seemed relevant. https://github.com/sui77/rc-switch/pull/11

https://github.com/pilight/pilight/blob/master/libs/pilight/protocols/433.92/quigg_gt1000.c

It seems like the remote has 4 codes that the device cycles through and that it repeats four times, then it changes the timing and repeats four times again.

First, there is a Sync bit and then a pause, after that follows the data.

We start by doing analysis of a single section. It seems like a one is encoded by High pulse for 2ms and then low for 1ms and a 0 is encoded as a high pulse for 1 ms and then low for 2 ms. This encoding probably has a fancier name so please tell me if you know it.

The sync pulse is high for 1500 micros then low for 3500 microseconds.

After that you see 24 pulses. Here is the Arduino code that can generate the pulses for the older version of the remote.

Original defines,
#define SHORT_DELAY 380
#define NORMAL_DELAY 500
#define SIGNAL_DELAY 1500
#define SYNC_DELAY 2650
#define EXTRASHORT_DELAY 3000
#define EXTRA_DELAY 10000
This remote however is probably a newer version with different timings, by coincidence half of the previous values.
#define EXTRASHORT_DELAY 1500
#define EXTRA_DELAY 5000
Repeat four times,
sendSync();
for (unsigned char k=0; k<24; k++) {
//as 24 long and short signals, this loop sends each one and if it is long, it takes it away from total delay so that there is a short between it and the next signal and vice versa
sendValue(bitRead(signal, 23-k),SHORT_DELAY);
}
Then with new timing, repeat 4 times
longSync();
for (unsigned char k=0; k<24; k++) {
sendValue(bitRead(signal, 23-k),NORMAL_DELAY);
}
|-|0 — — — — — -4|5 — — — — -20|21 — — — 24|
|S| group-id[4] | random[16] |unit-id[4] |
|-| — — — — — — -| — — — — — — | — — — — — |
void sendSync(){
digitalWrite(RF_DATA_PIN, HIGH); delayMicroseconds(SHORT_DELAY);
digitalWrite(RF_DATA_PIN, LOW); delayMicroseconds(SYNC_DELAY — SHORT_DELAY);
}
void sendValue(boolean value, unsigned int base_delay){
unsigned long d = value? SIGNAL_DELAY — base_delay : base_delay;
digitalWrite(RF_DATA_PIN, HIGH); delayMicroseconds(d);
digitalWrite(RF_DATA_PIN, LOW);
delayMicroseconds(SIGNAL_DELAY — d);
}
void longSync(){
digitalWrite(RF_DATA_PIN, HIGH);
delayMicroseconds(EXTRASHORT_DELAY);
digitalWrite(RF_DATA_PIN, LOW); delayMicroseconds(EXTRA_DELAY — EXTRASHORT_DELAY);
}

If we use only the part after the sync bit we can use a symbol length that is 1/3 of the “real” symbol. If this is correct you will se decoding errors as 0%

This is a 0
This is a 1

Elite decoder

If we want to be able to compare our results with the earlier results found on the internet, we need to write our own decoder. 110 -> 1 & 100 -> 0

This program can be compiled and assigned in Edit -> Decoding. Just remember to add an e for encoding and d for decoding.

#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
int i;
if (argc > 2)
{
if (argv[1][0] == 'd')
{
char *str = argv[2];
for (i = 0; i < strlen(argv[2]); i++) {
if (strlen(str) >= 3) {
if (str[0] == '1' && str[1] == '1' && str[2] == '0') putchar('1');
if (str[0] == '1' && str[1] == '0' && str[2] == '0') putchar('0'); str++; str++; str++;
} else if (strlen(str) == 2) {
if (str[0] == '1' && str[1] == '1' ) putchar('1');
if (str[0] == '1' && str[1] == '0' ) putchar('0');
str++; str++;
}
i +=3;
}
}
else
{
for (i = 0; i < strlen(argv[2]); i++)
{
if (argv[2][i] == '0')
{
putchar('1'); putchar('0'); putchar('0');
} else {
putchar('1'); putchar('1'); putchar('0');
}
}
}
}
printf("\n");
fflush(stdout);
return 0;
}

However the last 6 bits was lost, probably to an error in the program and instead I found the substitute filter. It worked better. The trick was dragging substitution to Your decoding then use, Save As.

Substitute

Now if we perform a new analysis things adds up much better.

2*A_ON, A_OFF,B_ON,B_OFF

Here is the protocol. Group id is the remote control id

|-|0-----------4|5---------20|21------24|   
|S| group-id[4] | random[16] |unit-id[4]|
|-|-------------|------------|----------|

A_on codes:

With our analysis we found: 001110011111001000011100, which is

 0x39f21c

On the internet we can find the codes used in another version of the remote.
101100010110110110101100 ,101110101110010001101100
101111000001000101011100, 101101000101010100011100

0xB16DAC, 0xBAE46C,0xBC115C,0xB4551C

A_on codes from another forum with probably another remote:

0xF8C5AC, 0xF6AA6C,0xF9DD1C,0xFD995C

Note that we can conclude that the Unit-id for the A button is 0xc

Lightbulb remote

Now we revisit the recording of the Lightbulb remote from Luxorparts. This signal was much weaker and contained 32 pulses.

32 pulse-trains

Three types of encodings was used and they are repeated 8 times each. I am not sure about how the sync works though.

Decoding this is saved as an exercise for the reader. Somewhere here we can probably find the answer https://github.com/pilight/pilight/tree/master/libs/pilight/protocols/433.92

Final conclusions,

The journey from NOOB to boss was not so hard and a lot of fun. However without splitting the different parts of the recording with “new signal from selection” URH could not do a good job. This as the timing of the encoding changed, halfway through. I should have spent more time looking at the pulse trains but without help from the Internet, this would have taken a very long lime. However, we can conclude that URH is quite capable and very useful if you want to deep dive into the 0:s and 1:s. flying through the air. Thank you Johannes and Andreas for this cool software.

Next steps

Armed with the knowledge, I will make a new recording and press the A on button 5 times, where we expect to see the same code repeated again. We will also create a transmitter device that can control the switches. This will however be done in another article which I will link to when it it done.

--

--