Last active
June 20, 2020 15:47
-
-
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 contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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