Qemu vs sstrip

Qemu usually does a great job emulating embedded Linux applications, but as with anything you will occasionally run into bugs. While attempting to debug an embedded application in Qemu the other day, I ran into the following error:

eve@eve:~/firmware$ sudo chroot . ./qemu-mips bin/ls 
bin/ls: Invalid ELF image for this architecture

This error is usually indicative of using the wrong endian emulator, but I knew that the target binary was big endian MIPS. The file utility began to shed some light on the issue:

eve@eve:~/firmware$ file bin/busybox 
bin/busybox: ELF 32-bit MSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked (uses shared libs), corrupted section header size

Hmmm, a corrupted section header? Let’s take a closer look at the binary.

Readelf will give us some more detailed information:

ELF Header:
  Magic:   7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, big endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           MIPS R3000
  Version:                           0x1
  Entry point address:               0x4052a0
  Start of program headers:          52 (bytes into file)
  Start of section headers:          0 (bytes into file)
  Flags:                             0x1007, noreorder, pic, cpic, o32, mips1
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         6
  Size of section headers:           0 (bytes)
  Number of section headers:         0
  Section header string table index: 0

Sure enough, the section headers had been stripped out of the ELF binary. This is commonly done by tools such as sstrip in order to save precious storage space on embedded devices, and since section headers are not required in order to execute the program this shouldn’t prevent Qemu from loading the binary.

A quick grep of Qemu’s source quickly found the culprit in linux-user/elfload.c:

static bool elf_check_ehdr(struct elfhdr *ehdr)
{
    return (elf_check_arch(ehdr->e_machine)
            && ehdr->e_ehsize == sizeof(struct elfhdr)
            && ehdr->e_phentsize == sizeof(struct elf_phdr)
            && ehdr->e_shentsize == sizeof(struct elf_shdr)
            && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
}

Even though section headers aren’t required to load an ELF file, the elf_check_ehdr function expects the section header size to equal the size of the elf_shdr structure; simply commenting out this line and re-compiling did the trick:

eve@eve:~/firmware$ sudo chroot . ./qemu-mips bin/ls 
bin        lib        qemu-mips  tmp       var
dev        home       sbin       usr       

A patch has been submitted, but if you need this to work now it’s a quick and easy fix.

Tagged , . Bookmark the permalink.

5 Responses to Qemu vs sstrip

  1. Quentangle says:

    Hello, I was wondering if you could give me some advice as to how to extract the modified SquashFS used in some of the Belkin modem/router combos. These seem to be using the same format, but I have linked both for the sake of completeness.

    F7D4401au v1000:
    http://cache-www.belkin.com/support/dl/F7D4401-4_WW_1.00.46.bin
    F7D4402au v1000:
    http://cache-www.belkin.com/support/dl/F7D4402-4_WW_1.00.15.bin

    Binwalk is giving the result:
    Signatures: 75
    Target File: F7D4401-4_WW_1.00.46.bin
    MD5 Checksum: 17070390b5e660a27209441d64517c6b

    28 0x1C LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 4181876 bytes
    1609592 0x188F78 Squashfs filesystem, little endian, non-standard signature, version 3.0, size: 6415834 bytes, 842 inodes, blocksize: 65536 bytes, created: Thu Jan 13 14:09:28 2011
    7412216 0x7119F8 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 489219 bytes

    The Squashfs header that is being matched is ‘shsq’, which none of the unsquashfs tools in firmware-mod-kit understand. I have tried patching ‘shsq’ to the other standard Squashfs magic codes, but unsquashfs is still failing.

    I have sent a request to Belkin for the modified source code under GPL, but they have yet to respond. They do have a GPL compliant source code page, but none of the F7D models are on it right now.
    http://www.belkin.com/support/opensource/

    • Quentangle says:

      They finally got back to me with the response:
      “We are really sorry to inform you that we don’t have any new firmware or any open source development for the router available and as of now. if we do have any update we will update that on the http://belkin.com/support

      Don’t they have to release the GPL code when asked? I suppose this could have been a simple tech support guy that doesn’t know the licenses.

  2. binoopang says:

    I ran into this problem too.
    But now I solved it using your solution.
    Thank you 🙂

  3. Guest says:

    Strange what this bug not rectify still. Thansk author.

  4. Anon says:

    I ran into this same problem today, using qemu-mips version 2.0.0. So apparently the “bug” has not been through yet or has maybe been rejected in the process.

    Anyways, I used another way to circumvent the same issue: simply modify the executable itself to report a non zero section_header_size. (the number of section headers stays at 0, so there is no wrongdoing here).
    So practically, I used xxd then xxd -r to change the byte at offset 0x2f to read 40(0x28) instead of 0.

    Of course, with this method, one need to fix each and every executable (i am guessing all the dependent shared objects as well), which can be pretty unconvenient depending on your scenario.

Leave a Reply

Your email address will not be published. Required fields are marked *