diff --git a/Apple_EFI_Identify.py b/Apple_EFI_ID.py similarity index 97% rename from Apple_EFI_Identify.py rename to Apple_EFI_ID.py index d203d5b..1897560 100644 --- a/Apple_EFI_Identify.py +++ b/Apple_EFI_ID.py @@ -2,12 +2,12 @@ #coding=utf-8 """ -Apple EFI Identify +Apple EFI ID Apple EFI Image Identifier Copyright (C) 2018-2022 Plato Mavropoulos """ -TITLE = 'Apple EFI Image Identifier v2.0_a3' +TITLE = 'Apple EFI Image Identifier v2.0_a4' import os import sys @@ -143,7 +143,7 @@ def apple_efi_identify(input_file, output_path, padding=0, rename=False): if rename: input_parent = path_parent(input_file) - input_suffix = path_suffixes(input_file)[0] + input_suffix = path_suffixes(input_file)[-1] input_adler32 = zlib.adler32(input_buffer) @@ -156,7 +156,7 @@ def apple_efi_identify(input_file, output_path, padding=0, rename=False): if not os.path.isfile(output_file): os.replace(input_file, output_file) # Rename input file based on its EFI tag - printer(f'Renamed input to {output_name}', padding) + printer(f'Renamed to {output_name}', padding) return 0 diff --git a/Apple_EFI_Split.py b/Apple_EFI_IM4P.py similarity index 91% rename from Apple_EFI_Split.py rename to Apple_EFI_IM4P.py index 930d54e..fe2bd3e 100644 --- a/Apple_EFI_Split.py +++ b/Apple_EFI_IM4P.py @@ -2,12 +2,12 @@ #coding=utf-8 """ -Apple EFI Split +Apple EFI IM4P Apple EFI IM4P Splitter Copyright (C) 2018-2022 Plato Mavropoulos """ -TITLE = 'Apple EFI IM4P Splitter v3.0_a2' +TITLE = 'Apple EFI IM4P Splitter v3.0_a4' import os import sys @@ -32,6 +32,8 @@ def is_apple_im4p(input_file): # Parse & Split Apple EFI IM4P image def apple_im4p_split(input_file, output_path, padding=0): + exit_codes = [] + input_buffer = file_to_bytes(input_file) extract_path = os.path.join(f'{output_path}_extracted') @@ -48,7 +50,7 @@ def apple_im4p_split(input_file, output_path, padding=0): mefi_data_bgn = im4p_match.start() + input_buffer[im4p_match.start() - 0x1] # IM4P mefi payload size - mefi_data_len = int.from_bytes(input_buffer[im4p_match.end() + 0x9:im4p_match.end() + 0xD], 'big') + mefi_data_len = int.from_bytes(input_buffer[im4p_match.end() + 0x5:im4p_match.end() + 0x9], 'big') # Check if mefi is followed by _MEFIBIN mefibin_exist = input_buffer[mefi_data_bgn:mefi_data_bgn + 0x8] == b'_MEFIBIN' @@ -119,6 +121,8 @@ def apple_im4p_split(input_file, output_path, padding=0): output_data = input_buffer[ifd_data_bgn:ifd_data_end] + output_size = len(output_data) + output_name = path_stem(input_file) if os.path.isfile(input_file) else 'Part' output_path = os.path.join(extract_path, f'{output_name}_[{ifd_data_txt}].fd') @@ -127,6 +131,13 @@ def apple_im4p_split(input_file, output_path, padding=0): output_image.write(output_data) printer(f'Split Apple EFI image at {ifd_data_txt}!', padding) + + if output_size != ifd_comp_all_size: + printer(f'Error: Bad image size 0x{output_size:07X}, expected 0x{ifd_comp_all_size:07X}!', padding + 4) + + exit_codes.append(1) + + return sum(exit_codes) # Intel Flash Descriptor Component Sizes (4MB, 8MB, 16MB and 32MB) IFD_COMP_LEN = {3: 0x400000, 4: 0x800000, 5: 0x1000000, 6: 0x2000000} @@ -151,9 +162,8 @@ if __name__ == '__main__': extract_path = os.path.join(output_path, input_name) - apple_im4p_split(input_file, extract_path, padding) - - exit_code -= 1 + if apple_im4p_split(input_file, extract_path, padding) == 0: + exit_code -= 1 printer('Done!', pause=True) diff --git a/Apple_EFI_PBZX.py b/Apple_EFI_PBZX.py new file mode 100644 index 0000000..05e5eae --- /dev/null +++ b/Apple_EFI_PBZX.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +#coding=utf-8 + +""" +Apple PBZX Extract +Apple EFI PBZX Extractor +Copyright (C) 2021-2022 Plato Mavropoulos +""" + +TITLE = 'Apple EFI PBZX Extractor v1.0_a4' + +import os +import sys +import lzma +import ctypes + +# Stop __pycache__ generation +sys.dont_write_bytecode = True + +from common.comp_szip import is_szip_supported, szip_decompress +from common.path_ops import make_dirs, path_stem +from common.patterns import PAT_APPLE_PBZX +from common.struct_ops import get_struct, uint32_t +from common.system import argparse_init, printer, script_init +from common.text_ops import file_to_bytes + +class PbzxChunk(ctypes.BigEndianStructure): + _pack_ = 1 + _fields_ = [ + ('Reserved0', uint32_t), # 0x00 + ('InitSize', uint32_t), # 0x04 + ('Reserved1', uint32_t), # 0x08 + ('CompSize', uint32_t), # 0x0C + # 0x10 + ] + + def struct_print(self, p): + printer(['Reserved 0 :', f'0x{self.Reserved0:X}'], p, False) + printer(['Initial Size :', f'0x{self.InitSize:X}'], p, False) + printer(['Reserved 1 :', f'0x{self.Reserved1:X}'], p, False) + printer(['Compressed Size:', f'0x{self.CompSize:X}'], p, False) + +# Check if input is Apple PBZX image +def is_apple_pbzx(input_file): + input_buffer = file_to_bytes(input_file) + + return bool(PAT_APPLE_PBZX.search(input_buffer[:0x4])) + +# Parse & Extract Apple PBZX image +def apple_pbzx_extract(input_file, output_path, padding=0): + input_buffer = file_to_bytes(input_file) + + extract_path = os.path.join(f'{output_path}_extracted') + + make_dirs(extract_path, delete=True) + + cpio_bin = b'' # Initialize PBZX > CPIO Buffer + cpio_len = 0x0 # Initialize PBZX > CPIO Length + + chunk_off = 0xC # First PBZX Chunk starts at 0xC + while chunk_off < len(input_buffer): + chunk_hdr = get_struct(input_buffer, chunk_off, PbzxChunk) + + printer(f'PBZX Chunk at 0x{chunk_off:08X}\n', padding) + + chunk_hdr.struct_print(padding + 4) + + # PBZX Chunk data starts after its Header + comp_bgn = chunk_off + PBZX_CHUNK_HDR_LEN + + # To avoid a potential infinite loop, double-check Compressed Size + comp_end = comp_bgn + max(chunk_hdr.CompSize, PBZX_CHUNK_HDR_LEN) + + comp_bin = input_buffer[comp_bgn:comp_end] + + try: + # Attempt XZ decompression, if applicable to Chunk data + cpio_bin += lzma.LZMADecompressor().decompress(comp_bin) + + printer('Successful LZMA decompression!', padding + 8) + except: + # Otherwise, Chunk data is not compressed + cpio_bin += comp_bin + + # Final CPIO size should match the sum of all Chunks > Initial Size + cpio_len += chunk_hdr.InitSize + + # Next Chunk starts at the end of current Chunk's data + chunk_off = comp_end + + # Check that CPIO size is valid based on all Chunks > Initial Size + if cpio_len != len(cpio_bin): + printer('Error: Unexpected CPIO archive size!', padding) + + return 1 + + cpio_name = path_stem(input_file) if os.path.isfile(input_file) else 'Payload' + + cpio_path = os.path.join(extract_path, f'{cpio_name}.cpio') + + with open(cpio_path, 'wb') as cpio_object: + cpio_object.write(cpio_bin) + + # Decompress PBZX > CPIO archive with 7-Zip + if is_szip_supported(cpio_path, padding, args=['-tCPIO'], check=True): + if szip_decompress(cpio_path, extract_path, 'CPIO', padding, args=['-tCPIO'], check=True) == 0: + os.remove(cpio_path) # Successful extraction, delete PBZX > CPIO archive + else: + return 3 + else: + return 2 + + return 0 + +# Get common ctypes Structure Sizes +PBZX_CHUNK_HDR_LEN = ctypes.sizeof(PbzxChunk) + +if __name__ == '__main__': + # Set argparse Arguments + argparser = argparse_init() + arguments = argparser.parse_args() + + # Initialize script (must be after argparse) + exit_code,input_files,output_path,padding = script_init(TITLE, arguments, 4) + + for input_file in input_files: + input_name = os.path.basename(input_file) + + printer(['***', input_name], padding - 4) + + if not is_apple_pbzx(input_file): + printer('Error: This is not an Apple PBZX image!', padding) + + continue # Next input file + + extract_path = os.path.join(output_path, input_name) + + if apple_pbzx_extract(input_file, extract_path, padding) == 0: + exit_code -= 1 + + printer('Done!', pause=True) + + sys.exit(exit_code) diff --git a/Apple_EFI_PKG.py b/Apple_EFI_PKG.py new file mode 100644 index 0000000..636f99e --- /dev/null +++ b/Apple_EFI_PKG.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 +#coding=utf-8 + +""" +Apple EFI PKG +Apple EFI Package Extractor +Copyright (C) 2019-2022 Plato Mavropoulos +""" + +TITLE = 'Apple EFI Package Extractor v2.0_a4' + +import os +import sys + +# Stop __pycache__ generation +sys.dont_write_bytecode = True + +from common.comp_szip import is_szip_supported, szip_decompress +from common.path_ops import copy_file, del_dirs, get_path_files, make_dirs, path_name, path_parent +from common.patterns import PAT_APPLE_PKG +from common.system import argparse_init, printer, script_init +from common.text_ops import file_to_bytes + +from Apple_EFI_ID import apple_efi_identify, is_apple_efi +from Apple_EFI_IM4P import apple_im4p_split, is_apple_im4p +from Apple_EFI_PBZX import apple_pbzx_extract, is_apple_pbzx + +# Check if input is Apple EFI PKG package +def is_apple_pkg(input_file): + input_buffer = file_to_bytes(input_file) + + return bool(PAT_APPLE_PKG.search(input_buffer[:0x4])) + +# Split Apple EFI image (if applicable) and Rename +def efi_split_rename(in_file, out_path, padding=0): + exit_codes = [] + + working_dir = f'{in_file}_extracted' + + if is_apple_im4p(in_file): + printer(f'Splitting IM4P via {is_apple_im4p.__module__}...', padding) + im4p_exit = apple_im4p_split(in_file, in_file, padding + 4) + exit_codes.append(im4p_exit) + else: + make_dirs(working_dir, delete=True) + copy_file(in_file, working_dir, True) + + for efi_file in get_path_files(working_dir): + if is_apple_efi(efi_file): + printer(f'Renaming EFI via {is_apple_efi.__module__}...', padding) + name_exit = apple_efi_identify(efi_file, efi_file, padding + 4, True) + exit_codes.append(name_exit) + + for named_file in get_path_files(working_dir): + copy_file(named_file, out_path, True) + + del_dirs(working_dir) + + return sum(exit_codes) + +# Parse & Extract Apple EFI PKG packages +def apple_pkg_extract(input_file, output_path, padding=0): + if not os.path.isfile(input_file): + printer('Error: Could not find input file path!', padding) + return 1 + + extract_path = os.path.join(f'{output_path}_extracted') + + make_dirs(extract_path, delete=True) + + xar_path = os.path.join(extract_path, 'xar') + + # Decompress PKG > XAR archive with 7-Zip + if is_szip_supported(input_file, padding, args=['-tXAR'], check=True): + if szip_decompress(input_file, xar_path, 'XAR', padding, args=['-tXAR'], check=True) != 0: + return 3 + else: + return 2 + + for xar_file in get_path_files(xar_path): + if path_name(xar_file) == 'Payload': + pbzx_module = is_apple_pbzx.__module__ + if is_apple_pbzx(xar_file): + printer(f'Extracting PBZX via {pbzx_module}...', padding + 4) + if apple_pbzx_extract(xar_file, xar_file, padding + 8) == 0: + printer(f'Succesfull PBZX extraction via {pbzx_module}!', padding + 4) + for pbzx_file in get_path_files(f'{xar_file}_extracted'): + if path_name(pbzx_file) == 'UpdateBundle.zip': + if is_szip_supported(pbzx_file, padding + 8, args=['-tZIP'], check=True): + zip_path = f'{pbzx_file}_extracted' + if szip_decompress(pbzx_file, zip_path, 'ZIP', padding + 8, args=['-tZIP'], check=True) == 0: + for zip_file in get_path_files(zip_path): + if path_name(path_parent(zip_file)) == 'MacEFI': + printer(path_name(zip_file), padding + 12) + if efi_split_rename(zip_file, extract_path, padding + 16) != 0: + printer(f'Error: Could not split and rename {path_name(zip_file)}!', padding) + return 10 + else: + return 9 + else: + return 8 + break # ZIP found, stop + else: + printer('Error: Could not find "UpdateBundle.zip" file!', padding) + return 7 + else: + printer(f'Error: Failed to extract PBZX file via {pbzx_module}!', padding) + return 6 + else: + printer(f'Error: Failed to detect file as PBZX via {pbzx_module}!', padding) + return 5 + + break # Payload found, stop searching + + if path_name(xar_file) == 'Scripts': + if is_szip_supported(xar_file, padding + 4, args=['-tGZIP'], check=True): + gzip_path = f'{xar_file}_extracted' + if szip_decompress(xar_file, gzip_path, 'GZIP', padding + 4, args=['-tGZIP'], check=True) == 0: + for gzip_file in get_path_files(gzip_path): + if is_szip_supported(gzip_file, padding + 8, args=['-tCPIO'], check=True): + cpio_path = f'{gzip_file}_extracted' + if szip_decompress(gzip_file, cpio_path, 'CPIO', padding + 8, args=['-tCPIO'], check=True) == 0: + for cpio_file in get_path_files(cpio_path): + if path_name(path_parent(cpio_file)) == 'EFIPayloads': + printer(path_name(cpio_file), padding + 12) + if efi_split_rename(cpio_file, extract_path, padding + 16) != 0: + printer(f'Error: Could not split and rename {path_name(cpio_file)}!', padding) + return 15 + else: + return 14 + else: + return 13 + else: + return 12 + else: + return 11 + + break # Scripts found, stop searching + else: + printer('Error: Could not find "Payload" or "Scripts" file!', padding) + return 4 + + del_dirs(xar_path) # Delete temporary/working XAR folder + + return 0 + +if __name__ == '__main__': + # Set argparse Arguments + argparser = argparse_init() + arguments = argparser.parse_args() + + # Initialize script (must be after argparse) + exit_code,input_files,output_path,padding = script_init(TITLE, arguments, 4) + + for input_file in input_files: + input_name = os.path.basename(input_file) + + printer(['***', input_name], padding - 4) + + if not is_apple_pkg(input_file): + printer('Error: This is not an Apple EFI PKG package!', padding) + + continue # Next input file + + extract_path = os.path.join(output_path, input_name) + + if apple_pkg_extract(input_file, extract_path, padding) == 0: + exit_code -= 1 + + printer('Done!', pause=True) + + sys.exit(exit_code) diff --git a/Insyde_IFD_Extract.py b/Insyde_IFD_Extract.py index ba9c28e..c68d4d4 100644 --- a/Insyde_IFD_Extract.py +++ b/Insyde_IFD_Extract.py @@ -7,7 +7,7 @@ Insyde iFlash/iFdPacker Extractor Copyright (C) 2022 Plato Mavropoulos """ -TITLE = 'Insyde iFlash/iFdPacker Extractor v2.0_a9' +TITLE = 'Insyde iFlash/iFdPacker Extractor v2.0_a10' import os import sys @@ -175,9 +175,9 @@ def insyde_packer_extract(input_buffer, extract_path, padding=0): with open(sfx_path, 'wb') as sfx_file: sfx_file.write(sfx_buffer) - if is_szip_supported(sfx_path, padding + 8, password=INS_SFX_PWD, check=True): + if is_szip_supported(sfx_path, padding + 8, args=[f'-p{INS_SFX_PWD}'], check=True): if szip_decompress(sfx_path, extract_path, 'Insyde iFdPacker > 7-Zip SFX', - padding + 8, password=INS_SFX_PWD, check=True) == 0: + padding + 8, args=[f'-p{INS_SFX_PWD}'], check=True) == 0: os.remove(sfx_path) else: return 125 diff --git a/README.md b/README.md index 897f3ad..0df5ebb 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ * [**AMI UCP Update Extractor**](#ami-ucp-update-extractor) * [**Apple EFI IM4P Splitter**](#apple-efi-im4p-splitter) * [**Apple EFI Image Identifier**](#apple-efi-image-identifier) +* [**Apple EFI Package Extractor**](#apple-efi-package-extractor) +* [**Apple EFI PBZX Extractor**](#apple-efi-pbzx-extractor) * [**Award BIOS Module Extractor**](#award-bios-module-extractor) * [**Dell PFS/PKG Update Extractor**](#dell-pfspkg-update-extractor) * [**Fujitsu SFX BIOS Extractor**](#fujitsu-sfx-bios-extractor) @@ -150,7 +152,7 @@ Some Anti-Virus software may claim that the built/frozen/compiled executable con #### **Description** -Parses Apple IM4P multi-EFI files and splits all detected EFI firmware into separate Intel SPI/BIOS images. +Parses Apple IM4P multi-EFI files and splits all detected EFI firmware into separate Intel SPI/BIOS images. The output comprises only final firmware components and utilities which are directly usable by end users. #### **Usage** @@ -184,7 +186,7 @@ PyInstaller can build/freeze/compile the utility at all three supported platform 3. Build/Freeze/Compile: -> pyinstaller --noupx --onefile \\/Apple_EFI_Split.py +> pyinstaller --noupx --onefile \\/Apple_EFI_IM4P.py At dist folder you should find the final utility executable @@ -245,7 +247,123 @@ PyInstaller can build/freeze/compile the utility at all three supported platform 4. Build/Freeze/Compile: -> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/Apple_EFI_Identify.py +> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/Apple_EFI_ID.py + +You should find the final utility executable at "dist" folder + +#### **Anti-Virus False Positives** + +Some Anti-Virus software may claim that the built/frozen/compiled executable contains viruses. Any such detections are false positives, usually of PyInstaller. You can switch to a better Anti-Virus software, report the false positive to their support, add the executable to the exclusions, build/freeze/compile yourself or use the Python script directly. + +#### **Pictures** + +![]() + +## **Apple EFI Package Extractor** + +![]() + +#### **Description** + +Parses Apple EFI PKG firmware packages (i.e. FirmwareUpdate.pkg, BridgeOSUpdateCustomer.pkg), extracts their EFI images, splits those in IM4P format and identifies/renames the final Intel SPI/BIOS images accordingly. The output comprises only final firmware components which are directly usable by end users. + +#### **Usage** + +You can either Drag & Drop or manually enter Apple EFI PKG package file(s). Optional arguments: + +* -h or --help : show help message and exit +* -v or --version : show utility name and version +* -i or --input-dir : extract from given input directory +* -o or --output-dir : extract in given output directory +* -e or --auto-exit : skip press enter to exit prompts + +#### **Compatibility** + +Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support. + +#### **Prerequisites** + +To run the utility, you must have the following 3rd party tools at the "external" project directory: + +* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zzs for Linux) + +#### **Build/Freeze/Compile with PyInstaller** + +PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. + +1. Make sure Python 3.10.0 or newer is installed: + +> python --version + +2. Use pip to install PyInstaller: + +> pip3 install pyinstaller + +3. Place prerequisites at the "external" project directory: + +> 7-Zip Console + +4. Build/Freeze/Compile: + +> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/Apple_EFI_PKG.py + +You should find the final utility executable at "dist" folder + +#### **Anti-Virus False Positives** + +Some Anti-Virus software may claim that the built/frozen/compiled executable contains viruses. Any such detections are false positives, usually of PyInstaller. You can switch to a better Anti-Virus software, report the false positive to their support, add the executable to the exclusions, build/freeze/compile yourself or use the Python script directly. + +#### **Pictures** + +![]() + +## **Apple EFI PBZX Extractor** + +![]() + +#### **Description** + +Parses Apple EFI PBZX images, re-assembles their CPIO payload and extracts its firmware components (e.g. IM4P, EFI, Utilities, Scripts etc). It supports CPIO re-assembly from both Raw and XZ compressed PBZX Chunks. The output comprises only final firmware components and utilities which are directly usable by end users. + +#### **Usage** + +You can either Drag & Drop or manually enter Apple EFI PBZX image file(s). Optional arguments: + +* -h or --help : show help message and exit +* -v or --version : show utility name and version +* -i or --input-dir : extract from given input directory +* -o or --output-dir : extract in given output directory +* -e or --auto-exit : skip press enter to exit prompts + +#### **Compatibility** + +Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support. + +#### **Prerequisites** + +To run the utility, you must have the following 3rd party tools at the "external" project directory: + +* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zzs for Linux) + +#### **Build/Freeze/Compile with PyInstaller** + +PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. + +1. Make sure Python 3.10.0 or newer is installed: + +> python --version + +2. Use pip to install PyInstaller: + +> pip3 install pyinstaller + +3. Place prerequisites at the "external" project directory: + +> 7-Zip Console + +4. Build/Freeze/Compile: + +> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/Apple_EFI_PBZX.py You should find the final utility executable at "dist" folder diff --git a/common/comp_szip.py b/common/comp_szip.py index 4a3d26b..3db03a6 100644 --- a/common/comp_szip.py +++ b/common/comp_szip.py @@ -23,9 +23,12 @@ def check_bad_exit_code(exit_code): raise Exception(f'BAD_EXIT_CODE_{exit_code}') # Check if file is 7-Zip supported -def is_szip_supported(in_path, padding=0, password='', check=False, silent=False): +def is_szip_supported(in_path, padding=0, args=None, check=False, silent=False): try: - szip_c = [get_szip_path(), 't', in_path, f'-p{password}', '-bso0', '-bse0', '-bsp0'] + if args is None: + args = [] + + szip_c = [get_szip_path(), 't', in_path, *args, '-bso0', '-bse0', '-bsp0'] szip_t = subprocess.run(szip_c, check=False) @@ -40,12 +43,15 @@ def is_szip_supported(in_path, padding=0, password='', check=False, silent=False return True # Archive decompression via 7-Zip -def szip_decompress(in_path, out_path, in_name, padding=0, password='', check=False, silent=False): +def szip_decompress(in_path, out_path, in_name, padding=0, args=None, check=False, silent=False): if not in_name: in_name = 'archive' try: - szip_c = [get_szip_path(), 'x', f'-p{password}', '-aou', '-bso0', '-bse0', '-bsp0', f'-o{out_path}', in_path] + if args is None: + args = [] + + szip_c = [get_szip_path(), 'x', *args, '-aou', '-bso0', '-bse0', '-bsp0', f'-o{out_path}', in_path] szip_x = subprocess.run(szip_c, check=False) diff --git a/common/path_ops.py b/common/path_ops.py index 8e093fe..e2420e6 100644 --- a/common/path_ops.py +++ b/common/path_ops.py @@ -71,6 +71,10 @@ def agnostic_path(in_path): def path_parent(in_path): return Path(in_path).parent.absolute() +# Get final path component, with suffix +def path_name(in_path): + return PurePath(in_path).name + # Get final path component, w/o suffix def path_stem(in_path): return PurePath(in_path).stem @@ -95,6 +99,13 @@ def del_dirs(in_path): if Path(in_path).is_dir(): shutil.rmtree(in_path, onerror=clear_readonly) +# Copy file to path with or w/o metadata +def copy_file(in_path, out_path, meta=False): + if meta: + shutil.copy2(in_path, out_path) + else: + shutil.copy(in_path, out_path) + # Clear read-only file attribute (on shutil.rmtree error) def clear_readonly(in_func, in_path, _): os.chmod(in_path, stat.S_IWRITE) diff --git a/common/patterns.py b/common/patterns.py index 27405e8..ecdde39 100644 --- a/common/patterns.py +++ b/common/patterns.py @@ -11,6 +11,8 @@ PAT_AMI_PFAT = re.compile(br'_AMIPFAT.AMI_BIOS_GUARD_FLASH_CONFIGURATIONS', re.D PAT_AMI_UCP = re.compile(br'@(UAF|HPU).{12}@', re.DOTALL) PAT_APPLE_EFI = re.compile(br'\$IBIOSI\$.{16}\x2E\x00.{6}\x2E\x00.{8}\x2E\x00.{6}\x2E\x00.{20}\x00{2}', re.DOTALL) PAT_APPLE_IM4P = re.compile(br'\x16\x04IM4P\x16\x04mefi') +PAT_APPLE_PBZX = re.compile(br'pbzx') +PAT_APPLE_PKG = re.compile(br'xar!') PAT_AWARD_LZH = re.compile(br'-lh[04567]-') PAT_DELL_FTR = re.compile(br'\xEE\xAA\xEE\x8F\x49\x1B\xE8\xAE\x14\x37\x90') PAT_DELL_HDR = re.compile(br'\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.\x78\x9C', re.DOTALL)