Skip to content

ELF Headers

The ELF header data structure is the same for both 32 and 64 bit architectures. For the 32 bit systems, Elf32 is used instead of "Elf64. One minor difference, some of the Elf64_ fields are actually a 32 bit value. There is much publicly available documentation on the ELF data structure, this is just an overview with notes about the Qualcomm implementation used for their binary blobs.

The ELF Header

The binary blobs used for firmware use an ELF header that defines the type of executable. For Android this is either a executable file or a shared library. The shared library blobs in the modem.img file appear to be Android only, and unused by Android. Linux on the same hardware works fine without them. The guess is these are to support the Qualcomm testing program. The values of a file with an ELF header can be displayed using the readelf program from the GNU Binutils.


|Type|Variable|Function| |----|--------|--------| | unsigned char | e_ident[EI_NIDENT]| ELF magic number | | Elf64_Half | e_type | This the program type| | Elf64_Half | e_machine | This is the architecture | | Elf64_Word | e_version | The version of this data structure | | Elf64_Addr | e_entry | Entry point virtual address | | Elf64_Off | e_phoff | Program header table file offset | | Elf64_Off | e_shoff | Section header table file offset | | Elf64_Word | e_flags | | | Elf64_Half | e_ehsize | The size of this data structure | | Elf64_Half | e_phentsize | The size of the program header data structure | | Elf64_Half | e_phnum | The number of program headers | | Elf64_Half | e_shentsize | The size of the section header data structure | | Elf64_Half | e_shnum | The number of sections headers | | Elf64_Half | e_shstrndx| The string table |

MBN/MDT Files

Android uses .mdt files, which consist of an ELF header and SSL certificates, but no other data. The data is in other files, all with a .b[0-9][] suffix. These other files are split from the ELF executable using the program headers.

Linux uses*.mbn files, which consist of an ELF header and SSL certificates, plus all the executable code and data.

The Program Header

The Program Headers data stricture are different between 32 and 64 bit architectures with p_flags being in a different location. This matters when you are parsing binary data. but otherwise the data structures are the same, with the same constants. The primary types we care about when reverse engineering PT_LOAD and PT_NULL.

PT_NULL doesn't get loaded at boot time, it's usually only the ELF header. On Linux, PT_NULL is also used as the container for the SSL certificates used to sign the blob. PT_LOAD is used for data that does get loaded into memory and is usually an executable.

The p_flags define how the data is used, it has three values, which can be combined. These are executable data or read/write access.

Type Variable Function
Elf32_Word p_type The type of program data
Elf32_Off p_offset The offset within the input file
Elf32_Addr p_vaddr The virtual address
Elf32_Addr p_paddr The pyhsical address
Elf32_Word p_filesz The size of the data in the input file
Elf32_Word p_memsz The size of the memory required
Elf32_Word p_flags The permission for this data
Elf32_Word p_align The alignment in memory, usually 4k


Type Variable Function
Elf64_Word p_type The type of program data
Elf64_Word p_flags The permission for this data
Elf64_Off p_offset Segment file offset
Elf64_Addr p_paddr Segment physical address
Elf64_Xword p_filesz Segment size in file
Elf64_Xword p_memsz Segment size in memory
Elf64_Xword p_align Segment alignment, file & memory

Embedded SSL Certificates

On Android, the SSL certificates are stored in a file that contains only them. For Linux, these are buried in one of the program headers. This can be identified as it'll have a PT_NULL p_type, and a zero p_filesz. The SSL certificates can be found by scanning for the ASN.1 prefix. There are always three DER certificates used to sign a blob. These can be extracted from the .mdt file using the mdttool.py utility in ths project.

Section Headers

Sections are stripped from all blobs on Android and Linux, so this data structure isn't currently being used. This is here since it's used in the ELF header.

Type Variable Function
Elf32_Word sh_name
Elf32_Word sh_type
Elf32_Word sh_flags
Elf32_Addr sh_addr
Elf32_Off sh_offset
Elf32_Word sh_size
Elf32_Word sh_link
Elf32_Word sh_info
Elf32_Word sh_addralign
Elf32_Word sh_entsize

Runtime Sections

These sections are used by the runtime linker to resolve all symbols.

  • .dynstr
    • An array of strings of function names
  • .dynsym
    • An array of ELFn_SYM data structures for external symbols
  • .dynamic
    • An array of ELFn_Dyn data structures of the libraries needed

Compile Time Sections

These sections are used by the linker when compiling to resolve all symbols.

  • .strtab
    • An array of NULL terminated strings
  • .symtab
    • An array of ELFn_SYM data structures
  • .shstrtab
    • An array of NULL terminated strings that refer to sections

Relocation Sections

These sections are for resolving external symbols when dynamically linking at runtime.

  • .rel.dyn
    • Relocation entries for .got
  • .rel.plt
    • Relocation entries for .got.plt
  • .got
    • Resolved addresses for global variables
  • .got.plt
    • Recolved address for external functions

Other Sections

There are many other sections, some are used to initialize functions, others for debugging. The ones we are interested in are:

  • .text
    • The executable code
  • .data
    • Initialized global or static variables
  • .bss
    • Uninitialized global or static variables

If the file has been stripped, it will have no sections. An unstripped file will have many sections. Some are needed for the runtime linker, some for debugging, and others for compilation. For this project, we only care about the sections used to resolve symbols.

Program Headers

  • PT_INTERP
    • Added to an executable to use the runtime linker.
  • DYNAMIC
    • A .dynamic section used for runtime linking.
  • GNU_RELRO
    • A read-only address reloction array.

Utility Program

This project has a python file for parsing and manipulating ELF files. Part of this duplicates the output of the readelf program in the binutils, but also extracts the data so it can be manipulated. While it does have a few command line options, those are only used for testing during development. The class should just be imported to be useful.

Options

usage: elf [-h] [-v] [-d] [-t] [-y] [-s SECTION]

options:
-h, --help     show this help message and exit
-v, --verbose  verbose output
-d, --dump     Dump All Headers
-s, --section  Dump the data in a section