Boot.efi Information
Contents
Overview
In general, EFI executables adhere to the PE / COFF format, the documentation for which is readily available online: Portable Executable / Common Object File Format Documentation
At a glance, Apple's boot.efi does not adhere to this standard, but upon closer examination, it turns out to be two separate PE files concatenated together along with a Mach-O FAT Binary headerr.
FAT Mach-O header
<lang c> struct fat_header { uint32_t magic; /* FAT_MAGIC */ uint32_t nfat_arch; /* number of structs that follow */ };
struct fat_arch { cpu_type_t cputype; /* cpu specifier (int) */ cpu_subtype_t cpusubtype; /* machine specifier (int) */ uint32_t offset; /* file offset to this object file */ uint32_t size; /* size of this object file */ uint32_t align; /* alignment as a power of 2 */ }; </lang>
AppleTV boot.efi
00000000h: B9 FA F1 0E 02 00 00 00 07 00 00 00 03 00 00 00 30 00 00 00 D8 3F 02 00 00 00 00 00 07 00 00 01 ; ¹úñ.............0...Ø?.......... 00000020h: 03 00 00 00 08 40 02 00 28 4F 02 00 00 00 00 00 ; .....@..(O......
Offset | Data | Purpose |
---|---|---|
0x00 | B9 FA F1 0E | EFI Fat Binary Magic 0x0EF1FAB9 (little-endian) |
0x04 | 02 00 00 00 | Number of Architectures |
0x08 | 07 00 00 00 | First architecture record, 7 = CPU_TYPE_X86 |
0x0B | 03 00 00 00 | CPU subtype, 3 = CPU_SUBTYPE_I386_ALL |
0xF0 | 30 00 00 00 | Offset (in bytes) to beginning of first executable's header ( = 48 dec) |
0xF4 | D8 3F 02 00 | Length (in bytes) of first executable ( = 147416 dec) |
0xF8 | 00 00 00 00 | Alignment (i386 does not require alignment) |
0xFB | 07 00 00 01 | Second architecture record = CPU_TYPE_X86_64 |
0x20 | 03 00 00 00 | CPU_SUBTYPE_I386_ALL |
0x24 | 08 40 02 00 | Offset (in bytes) to beginning of second executable's header ( = 147464 dec) |
0x28 | 28 4f 02 00 | Length (in bytes) of first executable ( = 151336 dec) |
0x3B | 00 00 00 00 | Alignment |
OS X 10.4.8 boot.efi
00000000h: B9 FA F1 0E 02 00 00 00 07 00 00 00 03 00 00 00 30 00 00 00 21 0D 02 00 00 00 00 00 07 00 00 01 ; ¹úñ.............0...!........... 00000020h: 03 00 00 00 51 0D 02 00 17 13 02 00 00 00 00 00 ; ....Q...........
Offset | Data | Purpose |
---|---|---|
0x00 | B9 FA F1 0E | Magic number 0xEF1FAB9 looks like leetspeak |
0x04 | 02 00 00 00 | 2 architectures present (0x00000002, Little Endian) |
0x08 | 07 00 00 00 | 1st arch=i386 (0x0000007, Little Endian) |
0x0B | 03 00 00 00 | CPU_SUBTYPE_I386_ALL |
0xF0 | 30 00 00 00 | Offset (in bytes) to beginning of first executable's header ( = 48 dec) |
0xF4 | 21 0D 02 00 | Length (in bytes) of first executable ( = 134433 dec) |
0xF8 | 00 00 00 00 | Alignment |
0xFB | 07 00 00 01 | 2nd arch=x86_64 (0x01000007, little endian) |
0x20 | 03 00 00 00 | CPU_SUBTYPE_I386_ALL |
0x24 | 51 0D 02 00 | Offset (in bytes) to beginning of second executable's header ( = 134481 dec) |
0x28 | 17 13 02 00 | Length (in bytes) of first executable ( = 135959 dec) |
0x3B | 00 00 00 00 | Alignment |
Note that the "Unknown" fields are the same between both files - only the offset and length fields have changed.
PE Sections
If the AppleTV boot.efi is split according to the information in the proprietary header, the result is two valid and distinct PE files. Interestingly, the seldom-used checksum field in the "Optional Header" is filled in here (see Section 3.4.2 of the PE/COFF spec above). Combined with the fact that a single-byte change to a safe region of the file (ie, a string resource) is enough to keep the AppleTV from booting successfully, this suggests that the firmware is validating the checksum before beginning execution.
These checksums are not calculated in the usual manner. Microsoft keeps the actual algorithm used for calculating the checksum a secret, but they make a library for calculating the checksum of a PE image available, which produces the following results:
PE Section | File Checksum | Calculated MS Checksum |
---|---|---|
1 | 0xF59B0200 | 0x000262C5 |
2 | 0xCAAD0200 | 0x0002DD57 |
The checksum values from the OS X 10.4.8 PE sections are not included here, but are similarly incorrect.
None of the freely available EFI executables (elilo, refit, Intel reference shell implementation, etc) have a checksum value specified at all, although this knowledge is basically useless without knowing the method for calculating the proper checksum.
Experimentation
Experiment | Result |
---|---|
Modify the file by shifting both PE sections 4 bytes forward, update prop. header | Boots successfully |
Build a boot.efi with two copies of the first PE section, update prop. header | Fails to boot - question-mark icon |
Build a boot.efi with two copies of the second PE section, update prop. header | Fails to boot - question-mark icon |
Build a boot.efi with the first and second PE sections swapped, update prop. header | Fails to boot - question-mark icon |
Extract first PE section, rename to boot.efi | Fails to boot - question-mark icon |
Extract second PE section, rename to boot.efi | Fails to boot - question-mark icon |
The results of the first experiment are a pleasant surprise, since they indicate that the firmware doesn't validate the entire boot.efi file - only the PE sections contained within. This suggests that if the proper checksum algorithm is discovered, booting a custom EFI image should be within reach.
Update: The EFI System Partition has type 0xEF in the MBR Partition Table scheme, and a specific, well-known, GUID in the GUID Partition Table scheme. It contains boot loader programs, which are EFI executable programs that are loaded and run by the EFI boot manager. Not leetspeek! ;) Information quoted from: http://homepages.tesco.net/J.deBoynePollard/FGA/efi-boot-process.html[1]
Availability
update: the boot.efi file doesn't have to come from the 1.1 image link (which is broken)
the latest image is 2.1.0 http://mesu.apple.com/data/OS/061-5044.20080709.de43E/2Z694-5485-1.dmg and the boot.efi can be found in the same location (/usr/standalone/i386/boot.efi)
Apple's first software update contains a copy of the boot.efi file, for use in other projects. It can be downloaded from http://mesu.apple.com/data/OS/061-2988.20070620.bHy75/2Z694-5248-45.dmg and is located at usr/standalone/i386/boot.efi within the DMG.