Binary Image Analysis

I have gotten to the point with the MT76x0U driver where I need to load the firmware image onto the MCU. Unlike the older hardware on which the driver is based, the firmware image is much more complicated. The old images are 4KB and can be directly DMA'd across to the MCU, the newer image is around 80KB, contains 2 sections and the reference driver does a complicated dance to copy them across.

There is quite a lot of pointer magic in setting up the DMA buffers in the reference image, I need to understand the firmware layout to know what this is trying to accomplish.

First thing, binwalk is of no help:

$ binwalk mcu/bin/MT7610_formal_2.6.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
-------------------------------------------------------------------------------

The image size is:

$ ls -l 
-rw-r--r--  1 hacker hacker  80288 Dec 21 19:40 mcu/bin/MT7610_formal_2.6.bin

The reference code does some work to extract out build info from the 32 byte header, I put together this python script to do the same:

import sys
import struct

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("usage: {} firmware.bin".format(sys.argv[0]))
        exit()

    filename = sys.argv[1]
    data = None
    with open(filename, "rb") as f:
        data = f.read()

    print("Image size: {}".fomrat(len(data)))

#    ilm_len   4 bytes
#    dlm_len   4 bytes
#    fw_ver    2 bytes
#    build_ver 2 bytes
#
#    4 bytes of something?
#
#    build_time 16 byte str starting from byte 16 (base+16) """
    hdr = data[:32]

    ilm_len, dlm_len, fw_ver, build_ver, something, build_time = struct.unpack("<IIHH4s16s", hdr)

    print("ilm_len:    {}".format(ilm_len))
    print("dlm_len:    {}".format(dlm_len))
    print("fw_ver:     {}".format(fw_ver))
    print("build_ver:  {}".format(build_ver))
    print("something:  {}".format(something))
    print("build_time: {}".format(build_time))

    print("fw version: {}.{}.{}"
        .format(
            (fw_ver & 0xf000) >> 8,
            (fw_ver & 0x0f00) >> 8,
            fw_ver & 0x00ff))

I know from the reference driver that there are two images shipped in the firmware, called ILM and DLM (accoring to this Instruction and Data Local Memory).

$ python3.5 parsefirmware.py mcu/bin/MT7610_formal_2.6.bin 
Image size: 80288
ilm_len:    68780
dlm_len:    11476
fw_ver:     30272
build_ver:  256
something:  b'Bv\x11\x02'
build_time: b'201308221655____'
fw version: 112.6.64

The build time is happily just an ascii string, the first output in strings

$ strings ../../mcu/bin/MT7610_formal_2.6.bin| head -n 5 
201308221655____H
s@!
ELq@'P
ELq@
<@!H

and easy to spot in a hexdump

$ head -c 64 ../../mcu/bin/MT7610_formal_2.6.bin| hexdump -C
00000000  ac 0c 01 00 d4 2c 00 00  40 76 00 01 42 76 11 02  |.....,..@v..Bv..|
00000010  32 30 31 33 30 38 32 32  31 36 35 35 5f 5f 5f 5f  |201308221655____|
00000020  48 00 00 78 48 00 00 1e  48 00 00 1c 48 00 00 1a  |H..xH...H...H...|
00000030  48 00 00 18 48 00 00 16  48 00 00 14 48 00 00 12  |H...H...H...H...|

The ILM and DLM sizes are also very useful, with the header they add up to the firmware size!

Image size = hdr_size + ilm_len + dlm_len
80288 = 32 + 68780 + 11476

Currently I think the reference driver skips some further data in the ILM, I need to see if there is documentation for the format so I can make an informed guess.


Reading: Babylon's Ashes, Cryptonomicon

Aberdeen, Scotland: 6°C, Mostly cloudy throughout the day.