SimplifyC++ Article
Understanding Executable File Headers Across Platforms (Windows, Linux, macOS) — With Hex Analysis
Understanding Executable File Headers Across Platforms (Windows, Linux, macOS) — With Hex Analysis
When a program is compiled into an executable, it carries a binary header at the beginning. This header is crucial — it tells the operating system how to load and run the program. These headers differ across platforms and architectures (32-bit vs 64-bit). This article presents a comprehensive overview of executable headers on Windows, Linux, and macOS, including real hexadecimal headers extracted from binaries.
Windows PE Format (Portable Executable)
Windows executables follow the PE format, built on top of an older DOS format for compatibility.
PE Header Structure
DOS Header (IMAGE_DOS_HEADER) Starts with
MZ(0x4D 0x5A) and contains a pointer to the PE header at offset 0x3C.PE Signature:
"PE\0\0"=0x50 0x45 0x00 0x00COFF File Header (IMAGE_FILE_HEADER) Contains machine type, section count, and flags.
Optional Header (IMAGE_OPTIONAL_HEADER) Contains entry point, memory layout, and more. It differs between 32-bit (PE32) and 64-bit (PE32+).
PE Header Structure (Simplified Overview):
+----------------------------+| DOS Header (IMAGE_DOS_HEADER) [64 bytes]| Magic = "MZ"| Offset to PE header at offset 0x3C (e_lfanew)+----------------------------+| DOS Stub Program [Variable size]+----------------------------+| PE Signature ("PE\0\0") [4 bytes]+----------------------------+| COFF File Header (IMAGE_FILE_HEADER)| Machine (x86=0x014C, x64=0x8664)| NumberOfSections| TimeDateStamp| PointerToSymbolTable| NumberOfSymbols| SizeOfOptionalHeader| Characteristics+----------------------------+| Optional Header (IMAGE_OPTIONAL_HEADER)| (Differs for 32-bit and 64-bit)| Magic = 0x10B for PE32, 0x20B for PE32+ (x64)| EntryPoint, ImageBase, SectionAlignment, etc.+----------------------------+| Section Headers (.text, .data, .rdata, etc.)+----------------------------+PE32 vs PE32+ Differences:
PE32 is used for 32-bit executables.
PE32+ is used for 64-bit executables.
In PE32+,
ImageBaseand other fields are 64-bit wide.
Use dumpbin /headers yourfile.exe or objdump -f yourfile.exe to inspect.
Hexadecimal PE Header (Simplified 32-bit Example)
4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00...80 00 00 00 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4CCD 21 50 45 00 00 4C 01 03 00 00 00 00 00 00 0000 00 00 00 E0 00 02 01 0B 01 08 00 00 10 00 0000 20 00 00 00 00 00 00 00 10 00 00 00 10 00 0000 30 00 00 00 40 00 00 ...4D 5A= "MZ"50 45 00 00= "PE\0\0"0B 01= PE32 (for PE32+ use0B 02)
Linux ELF Format (Executable and Linkable Format)
The ELF format is used on Linux and many Unix-like systems.
ELF Header Structure
Magic Bytes:
0x7F 45 4C 46="\x7FELF"Class:
0x01= 32-bit,0x02= 64-bitData Encoding:
0x01= Little Endian,0x02= Big EndianFile Type:
0x02= ExecutableMachine Type: e.g.,
0x03= x86,0x3E= x86_64
ELF Header Structure (for 32-bit and 64-bit):
+----------------------------+| ELF Header (EI_MAG = 0x7F 'E' 'L' 'F')| e_ident[16]| EI_CLASS (32/64-bit)| EI_DATA (Little/Big Endian)| EI_VERSION| e_type (Executable, Relocatable, etc.)| e_machine (e.g., x86=3, x86-64=62)| e_entry (Entry point)| e_phoff (Program header offset)| e_shoff (Section header offset)| e_flags| e_ehsize+----------------------------+| Program Headers| (Segment info: LOAD, DYNAMIC, etc.)+----------------------------+| Section Headers| (.text, .data, .bss, .symtab, etc.)+----------------------------+Use readelf -h yourfile or objdump -f yourfile to inspect.
Hexadecimal ELF Header (64-bit Example)
7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 0002 00 3E 00 01 00 00 00 78 56 34 12 00 00 00 0040 00 00 00 00 00 00 00 80 00 00 00 00 00 00 0000 00 00 00 40 00 38 00 09 00 40 00 1B 00 1A 007F 45 4C 46= ELF02= 64-bit3E 00= x86-64 architecture
For 32-bit ELF, use 01 in the class byte, and the rest of the layout is adjusted accordingly.
macOS Mach-O Format
Mach-O (Mach Object) is the native binary format for macOS and iOS.
Mach-O Header Structure (64-bit)
Magic:
0xCFFAEDFE= little-endian 64-bit Mach-OCPU Type: e.g.,
0x01000007= x86_64File Type:
0x02= ExecutableLoad Commands: Follow immediately after the header
macOS Executable Header – Mach-O Format
macOS (and iOS) uses the Mach-O (Mach Object) format, which can also be packaged in Fat/Universal binaries (for Intel and ARM).
Mach-O Header Structure:
+----------------------------+| Mach Header| magic (e.g., 0xFEEDFACE, 0xFEEDFACF for 64-bit)| cputype (e.g., x86, x86_64, arm64)| cpusubtype| filetype (e.g., MH_EXECUTE, MH_DYLIB)| ncmds (number of load commands)| sizeofcmds (size of all load commands)| flags| reserved (64-bit only)+----------------------------+| Load Commands| LC_SEGMENT / LC_SEGMENT_64| LC_SYMTAB| LC_MAIN (entry point)+----------------------------+| Sections (within segments)| __TEXT, __DATA, __LINKEDIT, etc.+----------------------------+Use otool -hv yourfile or mach-o-analyzer to view header info.
Hexadecimal Mach-O Header (64-bit Intel)
CF FA ED FE 07 00 00 01 03 00 00 00 02 00 00 000A 00 00 00 F0 00 00 00 85 00 00 00 00 00 00 00CF FA ED FE= Mach-O 64-bit (little endian)07 00 00 01= x86_6402 00 00 00= Executable
Mach-O Fat Binary Header
CA FE BA BE 00 00 00 02 00 00 00 07 00 00 00 0300 00 00 01 00 00 00 00 00 02 00 00 00 00 00 00Used when a binary includes multiple architectures (e.g., Intel + ARM).
Summary Table: Headers and Magic Bytes
| Platform | Format | Magic Bytes (Hex) | Description |
|---|---|---|---|
| Windows | PE | 4D 5A → 50 45 00 00 | DOS header, then PE signature |
| Linux | ELF | 7F 45 4C 46 | \x7FELF |
| macOS | Mach-O | CF FA ED FE | 64-bit Mach-O (little endian) |
| macOS | FAT | CA FE BA BE | Fat binary (multi-arch) |
Bonus: How to View These Headers
Linux/macOS:
xxd your_binary | headreadelf -h your_binaryotool -hv your_macho_file
Windows:
Use CFF Explorer, PE-bear, or
dumpbin /headers yourfile.exe
Final Thoughts
Understanding executable headers is essential for:
Writing loaders, debuggers, or virtual machines
Malware analysis and reverse engineering
Building cross-platform compilers and linkers
Developing custom packers or OS loaders
These headers reveal the true structure and intent of the binary before the code even runs.