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