# ELF (Executable and Linkable Format) Reference Reference for analyzing Linux/Unix ELF binaries during malware static analysis. ## Overall Structure ``` +---------------------------+ | ELF Header (64 bytes) | Magic: \x7fELF +---------------------------+ | Program Header Table | Segment descriptions (for execution) +---------------------------+ | Section Data | | .text (code) | | .rodata (read-only data) | | .data (initialized data) | | .bss (uninitialized) | | .dynamic (dynamic info) | | .dynsym (dynamic symbols)| | .strtab (string table) | | .symtab (symbol table) | | ... | +---------------------------+ | Section Header Table | Section descriptions (for linking) +---------------------------+ ``` ## ELF Header | Offset | Size | Field | Description | |--------|------|-------|-------------| | 0x00 | 4 | e_ident[EI_MAG] | Magic: `\x7fELF` | | 0x04 | 1 | e_ident[EI_CLASS] | 1=32-bit, 2=64-bit | | 0x05 | 1 | e_ident[EI_DATA] | 1=little-endian, 2=big-endian | | 0x06 | 1 | e_ident[EI_VERSION] | ELF version (1) | | 0x07 | 1 | e_ident[EI_OSABI] | OS/ABI identification | | 0x10 | 2 | e_type | Object file type | | 0x12 | 2 | e_machine | Architecture | | 0x18 | 4/8 | e_entry | Entry point virtual address | | 0x1C/0x20 | 4/8 | e_phoff | Program header table offset | | 0x20/0x28 | 4/8 | e_shoff | Section header table offset | | 0x2C/0x34 | 2 | e_phnum | Number of program headers | | 0x30/0x3A | 2 | e_shnum | Number of section headers | **File types (e_type):** | Value | Name | Description | |-------|------|-------------| | 0x01 | ET_REL | Relocatable file (.o) | | 0x02 | ET_EXEC | Executable (fixed address) | | 0x03 | ET_DYN | Shared object / PIE executable | | 0x04 | ET_CORE | Core dump | **Common architectures (e_machine):** | Value | Architecture | |-------|-------------| | 0x03 | EM_386 (x86) | | 0x3E | EM_X86_64 (AMD64) | | 0x28 | EM_ARM | | 0xB7 | EM_AARCH64 | | 0x08 | EM_MIPS | | 0xF3 | EM_RISCV | ## Program Headers (Segments) Describe memory layout for the loader. Each segment (56 bytes for 64-bit): | Field | Description | |-------|-------------| | p_type | Segment type | | p_flags | Permission flags (R/W/X) | | p_offset | File offset | | p_vaddr | Virtual address | | p_filesz | Size in file | | p_memsz | Size in memory | **Segment types:** | Type | Description | Malware Relevance | |------|-------------|-------------------| | PT_LOAD | Loadable segment | Contains code and data | | PT_DYNAMIC | Dynamic linking info | Library dependencies | | PT_INTERP | Interpreter path | Usually /lib64/ld-linux-x86-64.so.2 | | PT_NOTE | Auxiliary info | Build ID, ABI tag | | PT_GNU_STACK | Stack executability | NX bit control | | PT_GNU_RELRO | Read-only after reloc | Security hardening | **Suspicious indicators:** - `PT_GNU_STACK` with execute flag (executable stack) - Custom or missing `PT_INTERP` (non-standard loader) - Very few segments (stripped/packed) - `p_memsz` >> `p_filesz` on executable segment (unpacking space) ## Section Headers Each section header (64 bytes for 64-bit): | Field | Description | |-------|-------------| | sh_name | Section name (index into .shstrtab) | | sh_type | Section type | | sh_flags | Section attributes | | sh_addr | Virtual address | | sh_offset | File offset | | sh_size | Section size | **Common sections:** | Section | Purpose | Analysis Value | |---------|---------|---------------| | .text | Executable code | Primary analysis target | | .rodata | Read-only data (strings, constants) | String extraction | | .data | Initialized global data | Configuration data | | .bss | Uninitialized data | Runtime buffers | | .init / .fini | Init/cleanup code | Startup/shutdown hooks | | .init_array / .fini_array | Constructor/destructor arrays | Startup hooks | | .plt / .plt.got | Procedure Linkage Table | Imported function stubs | | .got / .got.plt | Global Offset Table | Function pointers | | .dynamic | Dynamic linking info | Libraries, symbols | | .dynsym | Dynamic symbol table | Imported/exported symbols | | .dynstr | Dynamic string table | Symbol names | | .symtab | Full symbol table | All symbols (if not stripped) | | .strtab | String table | Symbol name strings | | .comment | Compiler information | GCC/Clang version | | .note.* | Build notes | Build ID, ABI info | | .eh_frame | Exception handling | Stack unwinding | | .interp | Interpreter path | Dynamic linker | **Section flags:** | Flag | Value | Description | |------|-------|-------------| | SHF_WRITE | 0x1 | Writable | | SHF_ALLOC | 0x2 | Allocated in memory | | SHF_EXECINSTR | 0x4 | Executable | ## Symbol Tables ### Dynamic Symbol Table (.dynsym) Contains symbols needed for dynamic linking: - Imported functions (undefined symbols) - Exported functions (global defined symbols) ```bash readelf --dyn-syms binary ``` ### Full Symbol Table (.symtab) Contains all symbols including local ones. Stripped binaries lack this section. ```bash readelf -s binary ``` **Symbol types:** | Type | Description | |------|-------------| | STT_FUNC | Function | | STT_OBJECT | Data object | | STT_SECTION | Section | | STT_FILE | Source file name | **Symbol binding:** | Binding | Description | |---------|-------------| | STB_LOCAL | Local (file scope) | | STB_GLOBAL | Global (visible everywhere) | | STB_WEAK | Weak (can be overridden) | ## Dynamic Section Contains entries needed by the dynamic linker: | Tag | Description | Malware Relevance | |-----|-------------|-------------------| | DT_NEEDED | Required shared library | Dependencies | | DT_SONAME | Shared object name | DLL name | | DT_RPATH | Library search path | Hijack potential | | DT_RUNPATH | Library search path | Hijack potential | | DT_INIT | Init function address | Startup code | | DT_FINI | Cleanup function address | Cleanup code | | DT_INIT_ARRAY | Array of init functions | Multiple startup hooks | | DT_DEBUG | Debug info address | Anti-debug detection | | DT_TEXTREL | Text relocations | Self-modifying code | | DT_FLAGS | Flags | BIND_NOW, TEXTREL | **Suspicious dynamic indicators:** - Custom `DT_RPATH` or `DT_RUNPATH` (library hijacking) - `DT_TEXTREL` present (self-modifying code possible) - Missing `DT_NEEDED` entries on dynamically linked binary - Very few needed libraries on a complex binary ## Analysis with Command-Line Tools ```bash # Full header information readelf -a binary # File header only readelf -h binary # Program headers (segments) readelf -l binary # Section headers readelf -S binary # Symbol tables readelf -s binary # Full symbol table readelf --dyn-syms binary # Dynamic symbols only # Dynamic section readelf -d binary # String dump of a section readelf -p .rodata binary # Hex dump of a section readelf -x .data binary # Disassemble objdump -d binary # All sections objdump -d -j .text binary # Specific section # Shared library dependencies ldd binary # WARNING: may execute binary code readelf -d binary | grep NEEDED # Safe alternative # Check for RELRO, stack canary, NX, PIE checksec --file=binary ``` ## Security Features | Feature | How to Check | Implication When Missing | |---------|-------------|------------------------| | NX (No-Execute) | `readelf -l` - PT_GNU_STACK without E flag | Stack-based code execution possible | | PIE (Position Independent) | `readelf -h` - Type is DYN | ASLR bypass easier | | RELRO | `readelf -l` - PT_GNU_RELRO present | GOT overwrite possible | | Full RELRO | `readelf -d` - BIND_NOW flag | Lazy binding attacks possible | | Stack Canary | `readelf -s` - `__stack_chk_fail` symbol | Buffer overflow exploitation easier | | Fortify Source | `readelf -s` - `*_chk` functions | Format string attacks possible | Malware typically lacks most security features since it does not need to defend against exploitation. ## Suspicious ELF Indicators 1. **Statically linked** - No shared libraries needed (self-contained) 2. **Stripped** - No `.symtab` section (hiding function names) 3. **UPX packed** - `UPX!` marker, very few sections 4. **Custom sections** - Non-standard section names 5. **Executable stack** - PT_GNU_STACK with execute flag 6. **High entropy** - Sections with entropy > 7.0 7. **Missing .comment** - No compiler information 8. **Self-modifying** - DT_TEXTREL present 9. **Go binary** - Characteristic section layout and large static binary 10. **No standard C runtime** - Missing `__libc_start_main` call