The differences between the binwalk results may be caused by the different version of the binwalk you use. So, check the version of your binwalk by simply running binwalk without any parameter.
Regarding to the firmware, you cannot unpack the content using binwalk. To see why, check the start of the firmware. You will find a 0x20
bytes header starting with the DLA50
string. This magic string and the header is repeated at offset 0x4020
, 0x8040
and so on. To see the structure of the header, check the following one from the middle of the firmware file:
I marked the magic string (DLA50) with yellow, the position of the fragment with green and the size of the fragment with blue.
The following script can follow the headers and extract the parts from the image:
import struct
import binascii
import sys
if (len(sys.argv) < 2):
print 'firm.py filename'
sys.exit(0)
id = 0
last = 0
idh = None
bf = open(sys.argv[1], 'rb')
while(True):
h = bf.read(0x20)
if (len(h) < 0x20 or h[0:5] != 'DLA50'):
break
dpos = struct.unpack('L', h[0x14:0x18])[0]
dsize = struct.unpack('L', h[0x18:0x1c])[0]
print '%s, pos: %x, size: %x'%(binascii.hexlify(h), dpos, dsize)
d = bf.read(dsize)
if (last != 0x4000):
if (idh != None):
idh.close()
idh = open('%d.bin'%(id), 'wb')
id += 1
idh.write(d)
last = dsize
idh.close()
The above script will extract the following parts:
0-0x2865b
: Executable code, may be compressed with LZMA, LZO or something similar
0x286d7-0x56f60
: File system, the individual files are also compressed
0x56f60-0x5bdc0
: Possibly a configuration area
The first part is starting with a 0x10
bytes header followed by a high entropy data. The header contains some flags or magic bytes and a data size, which I marked with blue in the next image. I can identify the size data item based on the size of the first part, which is 0x28555 = header size + 0x28545
.
The next part starts with the following bytes:
The area started at 0x60
seems to contain file names, such as 501h1_uk.js
and so on, along with other binary data. So, this area may contain file entries. If it is true, the previous data (0x00
-0x60
) is a directory entry or a header. In this header area, you can found some interesting value in little-endian byte order. The 0x0002e709
(marked with blue) is equal with the file size. The 0x00000060
(marked with yellow) may point to the start of the file entries. The 0x00000d48
(marked with red) after the file entry offset may be another offset inside the file. So, after checking that offset in the file, it see that it points right after the directory entries, so it may by the starting offset of the data area.
We have some guesses about the structure of the header, so let's check the file entries. If we suppose, that file names are started at the same position always inside a file entry, then we can calculate the size of one entry by subtracting the offset of two consecutive file names. Based on this calculation the file entry size will be 0x16
bytes.
Similarly to the previous steps, after a little more research, we can conclude that the file entry area starts with the count of the files and every file entry contains the file name, file flags, relative position of the file data and the file size.
Putting all together, the following script can extract the files from the second part of the firmware file:
import struct
import sys
if (len(sys.argv) < 2):
print 'parse_fs.py filename'
sys.exit(0)
fh = open(sys.argv[1],'rb')
h = fh.read(0x60)
fs_size = struct.unpack('L', h[0x08:0x0c])[0]
offset = struct.unpack('L', h[0x20:0x24])[0]
data_start = struct.unpack('L', h[0x24:0x28])[0]
print 'fs size: %x, dir offset: %x, data start: %x'%(fs_size, offset, data_start)
fh.seek(offset)
ds = data_start-offset
d = fh.read(ds)
count = struct.unpack('H', d[0:2])[0]
for i in xrange(count):
o = i*0x16+2
unk1 = struct.unpack('H', d[o+0x00:o+0x02])[0]
fname = d[o+0x02:o+0x0e]+'\x00'
fname = fname[0:fname.find('\x00')]
unk2 = struct.unpack('H', d[o+0x0e:o+0x10])[0]
pos = struct.unpack('L', d[o+0x10:o+0x14])[0]+data_start
size = struct.unpack('H', d[o+0x14:o+0x16])[0]
print ' %s, pos: %x, size: %x, unk1: %x, unk2: %x'%(fname, pos, size, unk1, unk2)
fh.seek(pos)
open('fs_%s'%(fname), 'wb').write(fh.read(size))