TL;DR?

Click here to jump directly to the decoding website:

Preamble

So I have this Triax-Hirschmann S-930 DVB-S2 satellite television receiver. It has a feature that allows exporting the channel list to a USB-Drive which will generate a file called OHS1720IR_Channel.OCH on said drive.

Sadly I wasn’t able to find any documentation about this .OCH file format whatsoever.

What’s in it?

Opening the file in a normal hex editor doesn’t really tell us anything useful with a short look. However when we use the awesome tool binwalk to analyse the file, we get the following output:

$ binwalk OHS1720IR_Channel.OCH

DECIMAL       HEXADECIMAL     DESCRIPTION
---------------------------------------------------------------------
96            0x60            Zlib compressed data, compressed

This tells us that there is some Zlib compressed data starting at byte 96 (hex 0x60). We can use dd to remove the first 96 bytes from the file so it starts with our Zlib data:

$ dd if=OHS1720IR_Channel.OCH bs=96 skip=1 of=OHS1720IR_Channel.gz
6143+0 records in
6143+0 records out
589728 bytes (590 kB, 576 KiB) copied, 0.0423137 s, 13.9 MB/s

Thanks to the magic of the StackExchange we find out how to decompress this data:

Edit: A friend told me I could have just used binwalk -e instead…

$ printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" | cat - OHS1720IR_Channel.gz | gzip -dc >OHS1720IR_Channel.bin

gzip: stdin: invalid compressed data--crc error

gzip: stdin: invalid compressed data--length error

Because there is still some other data at the end of the file, this will spit out a warning, but it still gives us the output file we need as OHS1720IR_Channel.bin.

Let’s see what we’ve got using hexdump:

$ hd OHS1720IR_Channel.bin | head
00000000  53 69 72 69 75 73 32 2c  33 00 00 00 00 00 00 00  |Sirius2,3.......|
00000010  00 01 16 26 68 29 00 00  22 00 00 00 00 00 00 00  |...&h)..".......|
00000020  00 00 00 00 32 00 00 00  00 00 00 00 45 75 74 65  |....2.......Eute|
00000030  6c 73 61 74 20 57 33 41  00 00 00 00 00 01 16 26  |lsat W3A.......&|
00000040  68 29 23 00 39 00 00 00  00 00 00 00 00 00 00 00  |h)#.9...........|
00000050  46 00 00 00 00 00 00 00  45 75 74 65 6c 73 61 74  |F.......Eutelsat|
00000060  20 57 31 00 00 00 00 00  00 01 16 26 68 29 3a 00  | W1........&h):.|
00000070  4d 00 00 00 00 00 00 00  00 00 00 00 64 00 00 00  |M...........d...|
00000080  00 00 00 00 48 6f 74 62  69 72 64 32 2c 36 2c 37  |....Hotbird2,6,7|
00000090  41 2c 38 00 00 01 16 26  68 29 4e 00 bb 00 00 00  |A,8....&h)N.....|

That looks like a list of satellites. Bingo!

Using emacs in hex-editor mode (or any other hex editor) we can take a closer look at the file. And sure enough, by searching the text for our first channel’s name, we can see the start of our channel list at decimal 100400:

00018830: 4f52 4631 2048 4400 0000 0000 0000 0000  ORF1 HD.........
00018840: 0000 0000 0000 0000 3701 6b00 2f13 8127  ........7.k./..'
00018850: 8227 ff1f ff1f ff1f ff1f 8027 8007 8507  .'.........'....
00018860: 0000 0100 1f15 0001 0000 0000 0000 0000  ................
00018870: c100 0000 0100 ff3f 0000 0000 4f52 4632  .......?....ORF2
00018880: 5720 4844 0000 0000 0000 0000 0000 0000  W HD............
00018890: 0000 0000 3701 6c00 3013 692b 6a2b ff1f  ....7.l.0.i+j+..
000188a0: ff1f ff1f ff1f 682b 680b 6d0b 0000 0700  ......h+h.m.....
000188b0: 1f15 0001 0000 0000 0000 0000 c100 0000  ................
000188c0: 0200 ff3f 0000 0000 4154 5600 0000 0000  ...?....ATV....

What I figured out is that channels seem to start at decimal 100400 and are always 76 bytes apart from each other.

Sorting

Although on first sight the channels appear to be in the correct order, they are actually arranged in the order they were found ignoring any customisations.

To find out how the actual position is determined, we switch two channels and then compare these files. For this example I moved BCC World from position 46 to position 45 where CNBC Europe used to be.

Binwalk again saves the day with its awesome binary diff tool that we can get using the -W argument. By adding --red to the command, we can see only the lines where something was changed.

$ binwalk -W OHS1720IR_Channel.bin OHS1720IR_Channel_bbc.bin --red
Console Output:
OFFSET      OHS1720IR_Channel.bin                                                OHS1720IR_Channel_bbc.bin
--------------------------------------------------------------------------------
*
0x00004780  01 00 55 00 C5 0B 0F 00 B2 21 00 00 20 01 22 01 |..U......!....".| \ 01 00 55 00 C5 0B 0F 00 B2 21 03 00 20 01 22 01 |..U......!....".|
*
0x00004810  01 00 3B 00 E1 02 0E 00 B1 A1 05 00 23 01 25 01 |..;.........#.%.| / 01 00 3B 00 E1 02 0E 00 B1 21 00 00 23 01 25 01 |..;......!..#.%.|
*
0x00004CC0  85 00 BC 00 33 03 09 00 F5 A2 47 01 3C 01 3E 01 |....3.....G.<.>.| \ 85 00 BC 00 33 03 09 00 F5 62 40 01 3C 01 3E 01 |....3....b@.<.>.|
*
0x00019E40  29 01 EC 03 D6 32 FF 01 FF 1F FF 1F FF 1F FF 1F |)....2..........| / 29 01 EC 03 D6 32 AB 00 FF 1F FF 1F FF 1F FF 1F |)....2..........|
0x00019E50  FF 1F FE 01 FE 01 F9 01 00 00 9C 0A 00 12 00 01 |................| \ FF 1F AA 00 AA 00 F9 01 00 00 9C 0A 00 12 00 01 |................|
*
0x00027B90  00 00 00 00 00 00 00 00 34 03 00 00 00 20 00 00 |........4.......| / 00 00 00 00 00 00 00 00 34 03 00 00 00 00 00 00 |........4.......|
*
0x00028880  9D 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.#..............| \ 9D 23 FE 07 FF 1F FF 1F FF 1F FF 1F FF 1F 00 00 |.#..............|
0x00028890  00 00 00 00 00 00 80 03 00 02 00 01 00 00 00 00 |................| / FF 1F 00 00 00 00 80 03 00 12 00 01 00 00 00 00 |................|
*
0x000321F0  00 00 00 00 00 00 00 00 B9 04 3A 01 02 34 FF 1F |..........:..4..| \ 00 00 00 00 00 00 00 00 B9 04 3A 01 02 34 45 0C |..........:..4E.|
*
0x00032210  00 00 57 05 00 10 00 01 00 00 00 00 00 00 00 00 |..W.............| / 00 00 57 05 00 12 00 01 00 00 00 00 00 00 00 00 |..W.............|
*
0x00087DD0  39 00 3A 00 3B 00 3C 00 57 0B 56 0B 3F 00 40 00 |9.:.;.<.W.V.?.@.| \ 3A 00 39 00 3B 00 3C 00 57 0B 56 0B 3F 00 40 00 |:.9.;.<.W.V.?.@.|
*
Binwalk diff after moving a channel

Because we swapped two channels, what we’re looking for is two numbers that swapped. In the very last line, at 0x00087DD0 (decimal 556496‬) we can see two numbers that swapped places, spaced between other incrementing 16 bit, least significant byte first, numbers. That looks very much like a sorting grid to me. And indeed, after inspecting that space further, there appears to be a sorting grid, starting at decimal 556400 in which the index determines the channel number (as entered with the remote) and the value (two bytes) determines the position in the channel list (described above).

Radio and TV

Both the sorting table and the channel list are for both radio and TV channels even though the receiver doesn’t mix them together and instead has separate modes and channel numbers for those. While the sorting table did give us the correct order, because radio channels were mixed with the TV channels, the numbers didn’t line up correctly when we both count them from one starting point. Thus we need to find a way to determine whether a channel is a radio or a TV channel. I did this by copying the full, hex encoded, data from some of each type and checking them for similarities.

TV:
4d44 5220 5361 6368 7365 6e20 4844 0000 0000 0000 0000 0000 c304 c814 7028 d414 d514 d834 ff1f ff1f ff1f d334 d314 d614 0000 9b05 0016 0001 0000 0000 0000 0000 c104 0000 e02e 0000 0000 0000
8544 6973 6e65 7920 4368 616e 6e65 6c00 0000 0000 0000 0000 1d01 7300 0107 0008 0328 ff1f ff1f ff1f ff1f ff07 ff07 2400 0000 8b00 0014 0001 0000 0000 0000 0000 2100 0000 5f00 ff3f 0000 0000
8586 4e61 7487 696f 6e61 6c20 8647 656f 8767 7261 7000 0000 0801 6b00 0d00 ff1f ff1f ff1f ff1f ff1f ff1f ff2b ff0b 2000 0000 a800 1f11 0001 0000 0000 0000 0000 0100 0000 a800 e02e 0000 0000

RADIO:
4f45 3100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 2701 6104 4133 a501 ff1f ff1f ff1f ff1f ff1f 0000 a501 0000 0000 2000 0012 0001 0000 0000 0000 0000 0100 0000 2000 ff3f 0000 0000
464d 3400 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 2701 6e04 4e33 b201 0000 0000 0000 0000 0000 0000 b201 0000 0000 c800 0002 0001 0000 0000 0000 0000 0100 0000 c800 ff3f 0000 0000
8652 4f43 4b20 414e 5487 454e 4e45 0000 0000 0000 0000 0001 0d01 6500 a000 3001 0000 0000 0000 0000 0000 0000 3001 0000 0000 6402 0002 0001 0000 0000 0000 0000 0100 0000 6402 ff3f 0000 0000
                                                         ||
                                                   24th byte is here

We see that all radio channels have the 24th byte (index 23) set, while all TV channels don’t.

Online Decoder

Based on that knowledge, I was able to build a very crude web-based decoder that you can use here:

If you wish to use it on a separate tab, use this link: https://jsfiddle.net/Himbeer/94pL2sbj/embedded/result/

You may also see the website with (bad) code here: https://jsfiddle.net/Himbeer/94pL2sbj/

Epilogue

I sadly didn’t have time to reverse engineer the full protocol properly (nor do I need or want to, because I just wanted to know the number for each channel so I can print the list).


0 Comments

Leave a Reply