8

I'm working on unpacking Hauwei E586 MiFi firmware. I downloaded firmware update pack which is available as Windows EXE, then used Hauwei Modem Flasher to unpack real firmware from installer.

I've got 4 files:

01.bin: data
02.bin: ELF 32-bit LSB executable, ARM, version 1, statically linked, not stripped
03.bin: data
04.bin: ELF 32-bit LSB executable, ARM, version 1, statically linked, not stripped

As we can see 02 and 04 are executable files. 01 is probably some kind of bootloader (I assume it from string analysis). 03 is some kind of pseudo FS.

I started from analyzing 03 (I posted it here):

There is header part

02 00 EE EE  50 BA 6E 00  20 00 00 00  D0 A2 02 00
7B 02 00 00  00 00 00 00  00 00 00 00  00 00 00 00

7B 02 as 16 bits gives 635 which is number of files in binary (verified using strings). Then there are 635 parts describing each file (call it directory) and at the end there is content of files.

There is directory entry for first GIF file which I found. I choosed GIF because it's easy to identify (there is header GIF8X and footer 0x3B).

77 77 77 5C  75 6D 5C 70  75 62 6C 69  63 5F 73 79
73 2D 72 65  73 6F 75 72  63 65 73 5C  42 75 74 74
75 6E 5F 43  75 72 72 65  6E 74 2E 67  69 66 00 00
lot of zeros
18 22 11 00  10 02 00 00  00 00 00 00  00 00 FF EE

We can see its name: www\um\public_sys-resources\Buttun_Current.gif and in last line there is offset of file in binary and file size, but I'm not really sure how to interpret this values.

I found first GIF after directory and extracted it manually (from header to footer) which gives me file of size 528 bytes, so reading 10 02 as 16 bit unsigned gives me that number. I tried to treat 18 22 as 16 bit unsigned to get offset, but it was different from offset that I manually read from file. Bu there was constant difference between offset and real offset of file of 1286864. So I created script for unpacking this binary (I'm getting offset and adding to it 1286864).

Script worked only partially. It recreated directory structure, but was able only to extract files in one particular directory (directory with GIF which I was using as reference). After check on different part of file it seems that offset of offset in different subdirectories is another that in this GIF directory. So, my guess is that I'm interpreting offset wrong (but treating it as 32 bits gives nothing useful).

There is unpack script:

import sys, struct, os

def main(args):
    outdir = args[1]
    f = open(args[0], 'rb')
    f2 = open(args[0], 'rb')
    header = f.read(32)
    print(len(header[16:]))
    number_of_files = struct.unpack("h", header[16:18])[0]
    print(number_of_files)

    for i in range(number_of_files):
        body = f.read(272)
        file_, rest = body.split(b'\x00', 1)
        offset = struct.unpack("H", body[256:258])[0] + 1286864
        size = struct.unpack("H", body[260:262])[0]
        file_ = file_.decode(encoding='UTF-8').replace('\\', '/')
        dirname = os.path.join(outdir, os.path.dirname(file_))
        filename = os.path.basename(file_)
        print(filename, size, offset, dirname)
        try:
            os.makedirs(dirname)
        except OSError:
            pass

        outfile = open(os.path.join(dirname, filename), "wb")
        f2.seek(offset)
        outfile.write(f2.read(size))
        outfile.close()

if __name__=='__main__':
    sys.exit(main(sys.argv[1:]))

Usage: ./script.py 03.bin output_directory

So my question is: what I'm doing wrong? Maybe I should read some another data type as offset/size? Which one?

1
  • This file is partly similar to one which is described in article: devttys0.com/2011/06/mystery-file-system but files inside are not packed and I also cannot match offset and size in directory.
    – pbm
    Commented Sep 7, 2013 at 11:02

3 Answers 3

5

I managed to solve problem.

First file in directory is ZSP.bin. It doesn't matter if offset of this file is 16 or 32 bit because in both cases is 0. As I know where directory ends and first file after directory should be ZSP.bin.

Below there is last two lines of last directory entry and first line of which I suspected should be ZSP.bin.

00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00 
FC 94 6D 00  53 25 01 00  00 00 00 00  00 00 FF EE
11 00 10 00  30 00 00 00  10 00 00 00  00 00 00 00

Each directory entry ends with FF EE, so I checked offset of next byte and assumed that it will be begin of ZSP.bin. Offset of it was 0x2a2d0. Then I checked size of ZSP.bin.

I know that where it is, but I didn't know if it is 16 bits or 32 bits (B4 C3 or B4 C3 0C 00). When I added B4 C3 as 16 bits unsigned to my known offset 0x2a2d0 I landed at address 0x36684 which doesn't look like beginning of XML file (which is third in directory, but second one have 0 length). So I tried adding 0xcc3b4 (32 bits value) to my offset, which gives me 0xf6684 and at this address there was beginning of XML file... :)

So I modified my code:

offset = struct.unpack("I", body[256:260])[0] + 172752
size = struct.unpack("I", body[260:264])[0]

After manual check of some random not binary files all of them were ok (proper begins and ends of HTML and XML, GIFs identified as GIFs)...

BTW, idea of checking first file in directory not this GIFs was first thought that got to my mind after I woke up... :)

0
5

I couldn't get a comment to format right .. so forgive this being a new reply. Here is the header format:

offset:length   description
-------------   -----------
0x00 : 4        unknown, probably 2 16-byte words for a version or file ID
0x04 : 4        size of the data block containing file data
0x08 : 4        unknown
0x0C : 4        offset to the data block
0x10 : 4        number of file entries
0x14 : 12       unknown / padding

The file header can be read using this:

size_of_data, offset_to_data, number_of_files = struct.unpack("< 4x L 4x L L 12x", header)  

Each file entry looks like:

offset:length   description
-------------   -----------
0x000 : 256     file path
0x100 : 4       offset to file in data block
0x104 : 4       size of file data
0x108 : 8       unknown

Then for each file entry:

filepath, offset, size = struct.unpack("< 256s L L 8x", body)  

The final offset for a file is:

offset = offset + offset_to_data
1
  • Thanks for feedback. It should be reasonable to assume that there is offset of data block in header, I don't know why I haven't think of it. But when I found it I never looked at header again. About entries in directory: it is weird to me that at the end of every entry there is "end mark": FF EE, because all entries are have the same length. In fact you could calculate length of each directory entry from offset_to_data / number_of_files, so this separator is not needed... Thanks again. Your code will definitely help make my script more beautiful... :)
    – pbm
    Commented Sep 8, 2013 at 19:01
1

I know this is an old thread, but I just wanted to add that your Hauwei E586 is probably based on the HiSierrra Chipset and Firmware. (That is, Huawei firmwares starting with "21." when using the Huawei Modem Flasher. ) This is using an embedded linux server, unlike those MiFi's based on the Qualcomm chips with firmwares strting with "11.". Here is another interesting thread on reversing the firmware on one of these (E589).

My question is, did you also have to deal with a checksum for the entire binary? (Do you know how to calculate it, and where it's located?)

PS. This was meant as a comment, but I still don't have the required Rep. to do that.

1
  • 1
    My router wasn't Linux - it was VxWorks and I'm sure about it. I didn't changed anything in files so there was no need to recalculate checksum and I have no idea where it was located...
    – pbm
    Commented Mar 6, 2014 at 16:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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