Carving up EFI fat binaries

Apple uses a custom fat binary format so their EFI applications can contain both 32-bit and 64-bit sections. IDA Pro isn’t too keen on this format, and (last time I looked) won’t disassemble them unless you specify the starting offset for the architecture section you want to disassemble.

The format is just a header that looks like this:

typedef struct {
    UINT32 magic;               // Apple EFI fat binary magic number (0x0ef1fab9)
    UINT32 num_archs;           // number of architectures
    EFIFatArchHeader archs[];   // architecture headers
} EFIFatHeader;

Followed by some architecture headers that look like this:

typedef struct {
    UINT32 cpu_type;    // probably 0x07 (CPU_TYPE_X86) or 0x01000007 (CPU_TYPE_X86_64)
    UINT32 cpu_subtype; // probably 3 (CPU_SUBTYPE_I386_ALL)
    UINT32 offset;      // offset to beginning of architecture section
    UINT32 size;        // size of arch section
    UINT32 align;       // alignment
} EFIFatArchHeader;

Followed by the data for the sections.

I wrote a quick bit of python early last year to parse the headers and split the fat binaries into their single architecture sections and thought someone might find it useful. It’s on my github. I’ve got a couple of other half finished EFI-related scripts that I’ll add to that repo soon, when they are a bit more useful.

Running efi_lipo.py:

$ ./efi_lipo.py SmcFlasher.efi 
processing 'SmcFlasher.efi'
this is an EFI fat binary with 2 architectures
architecture 0 (X86):
  offset: 0x30
  size:   0x8bd0
architecture 1 (X64):
  offset: 0x8c00
  size:   0x9e70
saving X86 section to 'SmcFlasher.efi.X86'
saving X64 section to 'SmcFlasher.efi.X64'

It might have been better to write an IDA Python script to do it instead, maybe I’ll do that at some stage, but this does the job for now.

The rEFIt site has some good info on the data structure layout, as does awkwardTV.