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

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.

Section Header

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