BIOSUtilities/Apple EFI IM4P Splitter/Apple_EFI_Split.py
Plato Mavropoulos 2bcd917314 Apple EFI IM4P Splitter v1.2
Fixed IM4P payload start offset
2018-11-01 15:24:13 +02:00

76 lines
No EOL
2.5 KiB
Python

#!/usr/bin/env python3
"""
Apple EFI Split
Apple EFI IM4P Splitter
Copyright (C) 2018 Plato Mavropoulos
"""
print('Apple EFI IM4P Splitter v1.2')
import os
import re
import sys
im4p = re.compile(br'\x16\x04\x49\x4D\x34\x50\x16\x04') # Apple IM4P
ifd = re.compile(br'\x5A\xA5\xF0\x0F.{172}\xFF{16}', re.DOTALL) # Intel Flash Descriptor
if len(sys.argv) >= 2 :
# Drag & Drop or CLI
apple_im4p = sys.argv[1:]
else :
# Folder path
apple_im4p = []
in_path = input('\nEnter the full folder path: ')
print('\nWorking...')
for root, dirs, files in os.walk(in_path):
for name in files :
apple_im4p.append(os.path.join(root, name))
for input_file in apple_im4p :
file_path = os.path.abspath(input_file)
file_name = os.path.basename(input_file)
file_dir = os.path.dirname(file_path)
file_ext = os.path.splitext(file_path)[1]
print('\nFile: %s%s' % (file_name, file_ext))
# Must be IM4P file because its size is 0x0 dependent
if file_ext not in ('.im4p','.IM4P') :
print('\n Error: Could not find IM4P file extension at %s!' % file_name)
continue
with open(input_file, 'rb') as in_file : buffer = in_file.read()
is_im4p = im4p.search(buffer) # Detect IM4P pattern
if not is_im4p :
print('\n Error: Could not find IM4P pattern at %s!' % file_name)
continue
im4p_size = int.from_bytes(buffer[2:is_im4p.start()], 'big') # Variable, from 0x2 - IM4P
im4p_type = buffer[is_im4p.end():is_im4p.end() + 0x4].decode('utf-8') # mefi
if im4p_type != 'mefi' :
print('\n Error: Could not find "mefi" IM4P Type at %s!' % file_name)
continue
payload_start = is_im4p.start() + buffer[is_im4p.start() - 0x1]
payload_size = int.from_bytes(buffer[is_im4p.end() + 0x9:is_im4p.end() + 0xD], 'big')
ifd_count = list(ifd.finditer(buffer)) # Count the Intel FD(s) to determine each SPI size and offset
# After IM4P mefi (0x15), multi SPI payloads have _MEFIBIN (0x100, difficult to reverse without varying samples)
spi_start = payload_start + 0x100 if buffer[payload_start:payload_start + 0x8] == b'_MEFIBIN' else payload_start
spi_size = int(len(buffer[spi_start:]) / len(ifd_count)) # Each SPI should be of the same size (1st PRD, 2nd PRE)
# Parse all Intel FD and extract each SPI image
for fd in range(len(ifd_count)) :
file_path_new = os.path.join(file_dir, '%s_%d.fd' % (file_name[:-5], fd + 1))
with open(file_path_new, 'wb') as spi_image : spi_image.write(buffer[spi_start:spi_start + spi_size])
spi_start += spi_size
input('\nDone!')