Skip to content

Instantly share code, notes, and snippets.

@pudquick
Last active June 20, 2020 15:47
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save pudquick/2800b39b68f5acb135b4 to your computer and use it in GitHub Desktop.
Save pudquick/2800b39b68f5acb135b4 to your computer and use it in GitHub Desktop.
Decompressing and re-assembling LVZN compressed animations and logos from boot.efi
# This file parses this file:
# https://github.com/Piker-Alpha/macosxbootloader/blob/El-Capitan/src/boot/NetBootImages.h
# and this one:
# https://github.com/Piker-Alpha/macosxbootloader/blob/El-Capitan/src/boot/AppleLogoData.h
from ctypes import CDLL, create_string_buffer, c_size_t, c_void_p
import re
CPK = CDLL('/System/Library/PrivateFrameworks/PackageKit.framework/Versions/Current/PackageKit')
lzvn_decode = CPK.lzvn_decode
lzvn_decode.restype = c_size_t
lzvn_decode.argtypes = [c_void_p, c_size_t, c_void_p, c_size_t]
def lzvn_unpack(buf):
el = len(buf)
dl = 0x80000
encoded_buf = create_string_buffer(buf, el)
decoded_buf = create_string_buffer(dl)
s = lzvn_decode(decoded_buf, dl, encoded_buf, el)
return decoded_buf.raw[:s]
def clean_data(raw_data):
return re.sub('[^A-F0-9]', '', re.sub('0x', '', raw_data)).decode('hex')
def parse_h(h_file):
with open(h_file) as f:
header = f.read()
# Look for declarations of the form: STATIC UINT8 DataNameHere[ SizeNumberHere ] = { HexDataHere ... };
byte_dump = re.compile(r'STATIC UINT8 ([^ ]+?)\[ [0-9]+ \][^{]+?\{([^;}]+?)\};', re.MULTILINE)
# Build up a dictionary where key name is from .h (example: NetBootBlackPacked), value is raw bytes
members = dict()
for data_name, raw_data in byte_dump.findall(header):
# Find all matches, store the raw bytes
members[data_name] = clean_data(raw_data)
return members
class Icon(object):
pass
def parse_members(members):
icons = dict()
for icon_name in [x.split('Packed',1)[0] for x in members.keys() if x.endswith('Packed')]:
i = Icon()
i.name = icon_name
i.data = [ord(x) for x in lzvn_unpack(members[icon_name + 'Packed'])]
i.clut = map(''.join, zip(*[iter(members[icon_name + 'Clut'])]*3))
icons[icon_name] = i
return icons
def dump_animated_icon(icon_obj, file_prefix):
# Build a new RAW using the .data + .clut
RAW = ''.join(icon_obj.clut[x] for x in icon_obj.data)
# If the icon's name ends in '2X', it's 64x64 pixels, otherwise 32x32 (and x3 for RGB)
icon_length = [3*32*32,3*64*64][icon_obj.name.endswith('2X')]
frames = map(''.join, zip(*[iter(RAW)]*icon_length))
# Save output to file_prefix%02.RAW
for i,data in enumerate(frames):
with open('%s%02d.RAW' % (file_prefix, i+1), 'wb') as f:
f.write(data)
def dump_single_icon(icon_obj, file_prefix):
# Build a new RAW using the .data + .clut
RAW = ''.join(icon_obj.clut[x] for x in icon_obj.data)
# If the icon's name ends in '2X', it's 64x64 pixels, otherwise 32x32 (and x3 for RGB)
with open('%s.RAW' % (file_prefix), 'wb') as f:
f.write(RAW)
def dump_NetBootImages_icons(file_path):
members = parse_h(file_path)
icons = parse_members(members)
for name, icon in icons.items():
dump_animated_icon(icon, name+'_')
# dump_NetBootImages_icons('NetBootImages.h')
def dump_AppleLogoData_icons(file_path):
members = parse_h(file_path)
icons = parse_members(members)
for name, icon in icons.items():
dump_single_icon(icon, name)
# dump_AppleLogoData_icons('AppleLogoData.h')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment