Skip to content

Instantly share code, notes, and snippets.

@Intyre
Last active February 14, 2024 21:34
Show Gist options
  • Save Intyre/d72fc40df079611ed78a4d8c18e45858 to your computer and use it in GitHub Desktop.
Save Intyre/d72fc40df079611ed78a4d8c18e45858 to your computer and use it in GitHub Desktop.
Wahoo Rival Firmware

Wahoo Rival Firmware

fw.rom

Structure of the header

Found some old linkit sdk with the FOTA_MAGIC_HEADER on github.com.

File header

Size Type Info
4 bytes uint32 FOTA_MAGIC_HEADER
4 bytes uint32 number of binaries
128 bytes Binary info

Binary info

Size Type Info
4 bytes uint32 binary offset
4 bytes uint32 binary start address
4 bytes uint32 binary length
4 bytes uint32 partition length
4 bytes uint32 signature offset
4 bytes uint32 signature length
4 bytes uint32 is lzma compressed
4 bytes uint32 reserved

Example

$ xxd -l 20 RNNR_HW01_0.0.18/update/mtk/fw.rom
00000000: 4d4d 4d00 0100 0000 9c00 0000 0000 0108  MMM.............
00000010: 1ac8 0700

$ xxd -l 20 RNNR_HW06_1.57.8/update/mtk/fw.rom
00000000: 4d4d 4d00 0100 0000 9c00 0000 0000 0108  MMM.............
00000010: 252f 1400
Name 0.0.18 1.57.8 Note
binary offset 0x0000_009c = 156 0x0000_009c = 156
binary start address 0x0801_0000 0x0801_0000 use this address in ghidra
binary length 0x0007_c81a = 509978 0x0014_2f25 = 1322789

extract

$ dd if=RNNR_HW01_0.0.18/update/mtk/fw.rom of=fw-0.0.18.bin.lzma bs=1 skip=156 count=509978
$ unlzma fw-0.0.18.bin.lzma

$ dd if=RNNR_HW06_1.57.8/update/mtk/fw.rom of=fw-1.57.8.bin.lzma bs=1 skip=156 count=1322789
$ unlzma fw-1.57.8.bin.lzma
$ strings fw-1.57.8.bin | grep Happy

Ghidra

Load the binary with Ghidra.

  • set the Language to ARM:LE:32:Cortex:default
    • click on the dots and search for cortex. Pick the one with little endian.
  • click on options and set the Base Address to the binary start address 0x08010000.
import lzma
import struct
import sys
if len(sys.argv) != 2:
print(f'Usage: mtk-fw-extract.py fw.rom')
sys.exit(1)
name = sys.argv[1]
print(f'# reading {name}')
f = open(name, 'rb')
(magic, bins) = struct.unpack('2I', f.read(8))
if (magic&0x00ffffff) != 0x004d4d4d:
print(f'invalid maigc: 0x{magic:08x}')
sys.exit(1)
print(f'# total bins: {bins}')
for i in range(bins):
data = struct.unpack('8I', f.read(32))
(offset, address, size) = data[:3]
print(f'- bin{i} = offset=0x{offset:x} size=0x{size:08x} address=0x{address:08x}')
outname = f'fw-{i}.bin'
print(f'# writing {outname}')
f.seek(offset)
fout = open(outname, 'wb')
fout.write(lzma.decompress(f.read(size)))
fout.close()
f.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment