0

I'm reversing firmware and I get some problem with it. I used binwalk to reversing the firmware, but binwalk produced different result than to my friend. My friend found some zlib data (see 1), but I could not find these zlib data items (see 2).

I don't understand what is wrong, however I use binwak -e in the same way. I'm so confuse.

My question is: how can I find the zlib data?

Thanks.

2
  • [link] (imgur.com/T8yWsgJ) <= My friend's reversing picture
    – Zarados
    Commented Feb 2, 2016 at 8:36
  • [link] (imgur.com/AHFSgsW) <= My reversing picture, and I use binwalk -e command is not different to this picture. I'm so confuse.
    – Zarados
    Commented Feb 2, 2016 at 8:37

1 Answer 1

5

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:

enter image description here

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.

enter image description here

The next part starts with the following bytes:

enter image description here

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))
8
  • Hey, Your response is awesome. I have the other question. How do you judgment fragment that is executable code or file system? In addition, what is the address 0x2865c util 0x286d6 doing? PS:I'm a beginner and I'm not nature speak. I try to express my question hardly. Thanks!!
    – Zarados
    Commented Feb 3, 2016 at 18:37
  • I edited my answer with some more details about the second part. The address between 0x2865c and 0x286d6 is a 2 byte long fragment, which possibly only a separator.
    – ebux
    Commented Feb 4, 2016 at 10:53
  • Hey, ebux! What tool is use to reversing this firmware? I mean what is the tool let you dismantling three parts? I use binwalk -e just dismantling two html files. I think it's useful. Thanks, and Happy New Year.
    – Zarados
    Commented Feb 10, 2016 at 17:41
  • I updated the answer with the script I created to parse the parts.
    – ebux
    Commented Feb 11, 2016 at 7:08
  • Hi, ebux! I find some overflow error in line 18. I use os.path.getsize() function and I get the file size is 376264. The offset is 2164228230 byte is larger than the file size. How can I fix the trouble? In fact I am not understand all of the code.
    – Zarados
    Commented Feb 24, 2016 at 8:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.