├── .gitignore ├── README.md └── src └── efi_lipo.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | efitools 2 | ======== 3 | 4 | A few tools for doing stuff to EFI-related things. Well, eventually it will be a few. For now it's just one. 5 | 6 | 7 | efi_lipo.py 8 | ----------- 9 | 10 | A quick script for splitting up Apple EFI fat binaries into their individual per-architecture binary sections. 11 | 12 | ### Usage 13 | 14 | $ ./efi_lipo.py SmcFlasher.efi 15 | processing 'SmcFlasher.efi' 16 | this is an EFI fat binary with 2 architectures 17 | architecture 0 (X86): 18 | offset: 0x30 19 | size: 0x8bd0 20 | architecture 1 (X64): 21 | offset: 0x8c00 22 | size: 0x9e70 23 | saving X86 section to 'SmcFlasher.efi.X86' 24 | saving X64 section to 'SmcFlasher.efi.X64' -------------------------------------------------------------------------------- /src/efi_lipo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | efi_lipo.py - split Apple's EFI fat binaries into PE files that IDA Pro understands 4 | 5 | the EFI fat header looks something like this: 6 | 7 | 0000000 b9 fa f1 0e 02 00 00 00 07 00 00 01 03 00 00 00 8 | 0000010 30 00 00 00 40 ca 06 00 00 00 00 00 07 00 00 00 9 | 0000020 03 00 00 00 70 ca 06 00 40 50 06 00 00 00 00 00 10 | 11 | which breaks down to: 12 | 13 | typedef struct { 14 | UINT32 magic; // Apple EFI fat binary magic number (0x0ef1fab9) 15 | UINT32 num_archs; // number of architectures 16 | EFIFatArchHeader archs[]; // architecture headers 17 | } EFIFatHeader; 18 | 19 | the architecture header sections look something like: 20 | 21 | typedef struct { 22 | UINT32 cpu_type; // probably 0x07 (CPU_TYPE_X86) or 0x01000007 (CPU_TYPE_X86_64) 23 | UINT32 cpu_subtype; // probably 3 (CPU_SUBTYPE_I386_ALL) 24 | UINT32 offset; // offset to beginning of architecture section 25 | UINT32 size; // size of arch section 26 | UINT32 align; // alignment 27 | } EFIFatArchHeader; 28 | 29 | sections are PE/PE+ binaries and will start with 'MZ' (4d 5a) 30 | """ 31 | 32 | import argparse 33 | import struct 34 | import logging 35 | import logging.config 36 | import os.path 37 | 38 | EFI_FAT_MAGIC = 0x0ef1fab9 39 | 40 | # from mach/machine.h 41 | CPU_ARCH_ABI64 = 0x01000000 42 | CPU_TYPE_X86 = 7 43 | CPU_TYPE_X86_64 = (CPU_TYPE_X86 | CPU_ARCH_ABI64) 44 | 45 | 46 | # configure logging 47 | log = logging.getLogger() 48 | log.setLevel(logging.DEBUG) 49 | ch = logging.StreamHandler() 50 | log.addHandler(ch) 51 | 52 | 53 | def main(): 54 | # parse command line args 55 | parser = argparse.ArgumentParser(description="split up Apple EFI fat binaries") 56 | parser.add_argument('file', metavar='file', type=argparse.FileType('rb'), help="EFI fat binary to split.") 57 | args = parser.parse_args() 58 | f = args.file 59 | 60 | # read fat header 61 | log.info("processing '%s'" % f.name) 62 | (magic, num_archs) = struct.unpack("