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