From 6de50c422f3f2600662b78b3bd8e1831cb930ec4 Mon Sep 17 00:00:00 2001 From: platomav Date: Mon, 12 Sep 2022 23:09:12 +0300 Subject: [PATCH] Created common template for executing all utilities Unified extracted output directory naming logic Multiple code fixes, refactors and improvements --- .gitignore | 5 + AMI_PFAT_Extract.py | 49 +---- AMI_UCP_Extract.py | 52 +---- Apple_EFI_ID.py | 52 ++--- Apple_EFI_IM4P.py | 35 +--- Apple_EFI_PBZX.py | 37 +--- Apple_EFI_PKG.py | 52 ++--- Award_BIOS_Extract.py | 43 +--- Dell_PFS_Extract.py | 153 ++++++-------- Fujitsu_SFX_Extract.py | 39 +--- Fujitsu_UPC_Extract.py | 37 +--- Insyde_IFD_Extract.py | 43 +--- Panasonic_BIOS_Extract.py | 47 +---- Phoenix_TDK_Extract.py | 45 +--- Portwell_EFI_Extract.py | 41 +--- README.md | 419 -------------------------------------- Toshiba_COM_Extract.py | 54 ++--- VAIO_Package_Extract.py | 45 +--- common/comp_efi.py | 2 +- common/comp_szip.py | 4 +- common/externals.py | 15 +- common/path_ops.py | 57 +----- common/pe_ops.py | 4 +- common/system.py | 60 ------ common/templates.py | 152 ++++++++++++++ external/requirements.txt | 4 +- 26 files changed, 377 insertions(+), 1169 deletions(-) create mode 100644 .gitignore create mode 100644 common/templates.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..238b83e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# Skip all external files +external/* + +# Keep external > requirements file +!external/requirements.txt diff --git a/AMI_PFAT_Extract.py b/AMI_PFAT_Extract.py index bb9fdae..026b74a 100644 --- a/AMI_PFAT_Extract.py +++ b/AMI_PFAT_Extract.py @@ -7,7 +7,7 @@ AMI BIOS Guard Extractor Copyright (C) 2018-2022 Plato Mavropoulos """ -TITLE = 'AMI BIOS Guard Extractor v4.0_a11' +TITLE = 'AMI BIOS Guard Extractor v4.0_a12' import os import re @@ -19,10 +19,11 @@ sys.dont_write_bytecode = True from common.externals import get_bgs_tool from common.num_ops import get_ordinal -from common.path_ops import make_dirs, safe_name +from common.path_ops import make_dirs, safe_name, get_extract_path, extract_suffix from common.patterns import PAT_AMI_PFAT from common.struct_ops import char, get_struct, uint8_t, uint16_t, uint32_t -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes class AmiBiosGuardHeader(ctypes.LittleEndianStructure): @@ -147,7 +148,7 @@ def parse_bg_script(script_data, padding=0): is_opcode_div = len(script_data) % 8 == 0 if not is_opcode_div: - printer('Error: Script not divisible by OpCode length!', padding, False) + printer('Error: Script is not divisible by OpCode length!', padding, False) return 1 @@ -161,7 +162,7 @@ def parse_bg_script(script_data, padding=0): BigScript = get_bgs_tool() if not BigScript: - printer('Error: BIOS Guard Script Tool dependency missing!', padding, False) + printer('Note: BIOS Guard Script Tool optional dependency is missing!', padding, False) return 3 @@ -220,7 +221,7 @@ def parse_pfat_hdr(buffer, padding=0): return block_all, hdr_size, files_count -def parse_pfat_file(input_file, output_path, padding=0): +def parse_pfat_file(input_file, extract_path, padding=0): input_buffer = file_to_bytes(input_file) pfat_buffer = get_ami_pfat(input_buffer) @@ -228,9 +229,7 @@ def parse_pfat_file(input_file, output_path, padding=0): file_path = '' all_blocks_dict = {} - extract_name = os.path.basename(output_path) - - extract_path = os.path.join(f'{output_path}_extracted') + extract_name = os.path.basename(extract_path).rstrip(extract_suffix()) make_dirs(extract_path, delete=True) @@ -299,7 +298,7 @@ def parse_pfat_file(input_file, output_path, padding=0): out_oob.write(pfat_oob_data) if is_ami_pfat(pfat_oob_data): - parse_pfat_file(pfat_oob_data, pfat_oob_path, padding) + parse_pfat_file(pfat_oob_data, get_extract_path(pfat_oob_path), padding) in_all_data = b''.join([block[1] for block in sorted(all_blocks_dict.items())]) @@ -317,32 +316,4 @@ PFAT_BLK_HDR_LEN = ctypes.sizeof(IntelBiosGuardHeader) PFAT_BLK_S2K_LEN = ctypes.sizeof(IntelBiosGuardSignature2k) 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) - - with open(input_file, 'rb') as in_file: - input_buffer = in_file.read() - - if not is_ami_pfat(input_buffer): - printer('Error: This is not an AMI BIOS Guard (PFAT) image!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - parse_pfat_file(input_buffer, extract_path, padding) - - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + BIOSUtility(TITLE, is_ami_pfat, parse_pfat_file).run_utility() diff --git a/AMI_UCP_Extract.py b/AMI_UCP_Extract.py index 7aef35e..2f59e6f 100644 --- a/AMI_UCP_Extract.py +++ b/AMI_UCP_Extract.py @@ -7,7 +7,7 @@ AMI UCP Update Extractor Copyright (C) 2021-2022 Plato Mavropoulos """ -TITLE = 'AMI UCP Update Extractor v2.0_a19' +TITLE = 'AMI UCP Update Extractor v2.0_a20' import os import re @@ -21,10 +21,11 @@ sys.dont_write_bytecode = True from common.checksums import get_chk_16 from common.comp_efi import efi_decompress, is_efi_compressed -from common.path_ops import agnostic_path, make_dirs, safe_name, safe_path +from common.path_ops import agnostic_path, make_dirs, safe_name, safe_path, get_extract_path from common.patterns import PAT_AMI_UCP, PAT_INTEL_ENG from common.struct_ops import char, get_struct, uint8_t, uint16_t, uint32_t -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes, to_string from AMI_PFAT_Extract import is_ami_pfat, parse_pfat_file @@ -211,15 +212,13 @@ def get_uaf_mod(buffer, uaf_off=0x0): return uaf_all # Parse & Extract AMI UCP structures -def ucp_extract(in_file, out_path, padding=0, checksum=False): +def ucp_extract(in_file, extract_path, padding=0, checksum=False): input_buffer = file_to_bytes(in_file) nal_dict = {} # Initialize @NAL Dictionary per UCP printer('Utility Configuration Program', padding) - extract_path = os.path.join(f'{out_path}_extracted') - make_dirs(extract_path, delete=True) # Get best AMI UCP Pattern match based on @UAF|@HPU Size @@ -419,14 +418,14 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, checksum=False, nal_d if uaf_tag == '@INS' and is_insyde_ifd(uaf_fname): ins_dir = os.path.join(extract_path, safe_name(f'{uaf_tag}_nested-IFD')) # Generate extraction directory - if insyde_ifd_extract(uaf_fname, ins_dir, padding + 4) == 0: + if insyde_ifd_extract(uaf_fname, get_extract_path(ins_dir), padding + 4) == 0: os.remove(uaf_fname) # Delete raw nested Insyde IFD image after successful extraction # Detect & Unpack AMI BIOS Guard (PFAT) BIOS image if is_ami_pfat(uaf_data_raw): pfat_dir = os.path.join(extract_path, safe_name(uaf_name)) - parse_pfat_file(uaf_data_raw, pfat_dir, padding + 4) + parse_pfat_file(uaf_data_raw, get_extract_path(pfat_dir), padding + 4) os.remove(uaf_fname) # Delete raw PFAT BIOS image after successful extraction @@ -439,7 +438,7 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, checksum=False, nal_d if is_ami_ucp(uaf_data_raw): uaf_dir = os.path.join(extract_path, safe_name(f'{uaf_tag}_nested-UCP')) # Generate extraction directory - ucp_extract(uaf_data_raw, uaf_dir, padding + 4, checksum) # Call recursively + ucp_extract(uaf_data_raw, get_extract_path(uaf_dir), padding + 4, checksum) # Call recursively os.remove(uaf_fname) # Delete raw nested AMI UCP image after successful extraction @@ -511,35 +510,6 @@ UAF_TAG_DICT = { } if __name__ == '__main__': - # Set argparse Arguments - argparser = argparse_init() - argparser.add_argument('-c', '--checksum', help='verify AMI UCP Checksums (slow)', action='store_true') - arguments = argparser.parse_args() - - checksum = arguments.checksum # Set Checksum verification optional argument - - # 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) - - with open(input_file, 'rb') as in_file: - input_buffer = in_file.read() - - if not is_ami_ucp(input_buffer): - printer('Error: This is not an AMI UCP Update executable!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - ucp_extract(input_buffer, extract_path, padding, checksum) - - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + utility = BIOSUtility(TITLE, is_ami_ucp, ucp_extract) + utility.parse_argument('-c', '--checksum', help='verify AMI UCP Checksums (slow)', action='store_true') + utility.run_utility() diff --git a/Apple_EFI_ID.py b/Apple_EFI_ID.py index 1897560..1003b67 100644 --- a/Apple_EFI_ID.py +++ b/Apple_EFI_ID.py @@ -7,7 +7,7 @@ Apple EFI Image Identifier Copyright (C) 2018-2022 Plato Mavropoulos """ -TITLE = 'Apple EFI Image Identifier v2.0_a4' +TITLE = 'Apple EFI Image Identifier v2.0_a5' import os import sys @@ -23,7 +23,8 @@ from common.externals import get_uefifind_path, get_uefiextract_path from common.path_ops import del_dirs, path_parent, path_suffixes from common.patterns import PAT_APPLE_EFI from common.struct_ops import char, get_struct, uint8_t -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes class IntelBiosId(ctypes.LittleEndianStructure): @@ -92,11 +93,11 @@ def is_apple_efi(input_file): check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return True - except: + except Exception: return False # Parse & Identify (or Rename) Apple EFI image -def apple_efi_identify(input_file, output_path, padding=0, rename=False): +def apple_efi_identify(input_file, extract_path, padding=0, rename=False): if not os.path.isfile(input_file): printer('Error: Could not find input file path!', padding) @@ -116,22 +117,20 @@ def apple_efi_identify(input_file, output_path, padding=0, rename=False): bios_id_res = subprocess.check_output([get_uefifind_path(), input_file, 'body', 'list', PAT_UEFIFIND], text=True)[:36] - temp_dir = os.path.join(f'{output_path}_uefiextract') + del_dirs(extract_path) # UEFIExtract must create its output folder itself, make sure it is not present - del_dirs(temp_dir) # UEFIExtract must create its output folder itself, make sure it is not present - - _ = subprocess.run([get_uefiextract_path(), input_file, bios_id_res, '-o', temp_dir, '-m', 'body'], + _ = subprocess.run([get_uefiextract_path(), input_file, bios_id_res, '-o', extract_path, '-m', 'body'], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - with open(os.path.join(temp_dir, 'body.bin'), 'rb') as raw_body: + with open(os.path.join(extract_path, 'body.bin'), 'rb') as raw_body: body_buffer = raw_body.read() bios_id_match = PAT_APPLE_EFI.search(body_buffer) # Detect decompressed $IBIOSI$ pattern bios_id_hdr = get_struct(body_buffer, bios_id_match.start(), IntelBiosId) - del_dirs(temp_dir) # Successful UEFIExtract extraction, remove its output (temp) folder - except: + del_dirs(extract_path) # Successful UEFIExtract extraction, remove its output (temp) folder + except Exception: printer('Error: Failed to parse compressed $IBIOSI$ pattern!', padding) return 2 @@ -163,31 +162,6 @@ def apple_efi_identify(input_file, output_path, padding=0, rename=False): PAT_UEFIFIND = f'244942494F534924{"."*32}2E00{"."*12}2E00{"."*16}2E00{"."*12}2E00{"."*40}0000' if __name__ == '__main__': - # Set argparse Arguments - argparser = argparse_init() - argparser.add_argument('-r', '--rename', help='rename EFI image based on its tag', action='store_true') - arguments = argparser.parse_args() - - rename = arguments.rename # Set EFI image tag renaming optional argument - - # 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_efi(input_file): - printer('Error: This is not an Apple EFI image!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - if apple_efi_identify(input_file, extract_path, padding, rename) == 0: - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + utility = BIOSUtility(TITLE, is_apple_efi, apple_efi_identify) + utility.parse_argument('-r', '--rename', help='rename EFI image based on its tag', action='store_true') + utility.run_utility() diff --git a/Apple_EFI_IM4P.py b/Apple_EFI_IM4P.py index fe2bd3e..5dceefa 100644 --- a/Apple_EFI_IM4P.py +++ b/Apple_EFI_IM4P.py @@ -7,7 +7,7 @@ Apple EFI IM4P Splitter Copyright (C) 2018-2022 Plato Mavropoulos """ -TITLE = 'Apple EFI IM4P Splitter v3.0_a4' +TITLE = 'Apple EFI IM4P Splitter v3.0_a5' import os import sys @@ -17,7 +17,8 @@ sys.dont_write_bytecode = True from common.path_ops import make_dirs, path_stem from common.patterns import PAT_APPLE_IM4P, PAT_INTEL_IFD -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes # Check if input is Apple EFI IM4P image @@ -31,13 +32,11 @@ def is_apple_im4p(input_file): return bool(is_im4p and is_ifd) # Parse & Split Apple EFI IM4P image -def apple_im4p_split(input_file, output_path, padding=0): +def apple_im4p_split(input_file, extract_path, padding=0): exit_codes = [] input_buffer = file_to_bytes(input_file) - extract_path = os.path.join(f'{output_path}_extracted') - make_dirs(extract_path, delete=True) # Detect IM4P EFI pattern @@ -143,28 +142,4 @@ def apple_im4p_split(input_file, output_path, padding=0): IFD_COMP_LEN = {3: 0x400000, 4: 0x800000, 5: 0x1000000, 6: 0x2000000} 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_im4p(input_file): - printer('Error: This is not an Apple EFI IM4P image!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - if apple_im4p_split(input_file, extract_path, padding) == 0: - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + BIOSUtility(TITLE, is_apple_im4p, apple_im4p_split).run_utility() diff --git a/Apple_EFI_PBZX.py b/Apple_EFI_PBZX.py index 05e5eae..8e4f553 100644 --- a/Apple_EFI_PBZX.py +++ b/Apple_EFI_PBZX.py @@ -7,7 +7,7 @@ Apple EFI PBZX Extractor Copyright (C) 2021-2022 Plato Mavropoulos """ -TITLE = 'Apple EFI PBZX Extractor v1.0_a4' +TITLE = 'Apple EFI PBZX Extractor v1.0_a5' import os import sys @@ -21,7 +21,8 @@ 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.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes class PbzxChunk(ctypes.BigEndianStructure): @@ -47,11 +48,9 @@ def is_apple_pbzx(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): +def apple_pbzx_extract(input_file, extract_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 @@ -78,7 +77,7 @@ def apple_pbzx_extract(input_file, output_path, padding=0): cpio_bin += lzma.LZMADecompressor().decompress(comp_bin) printer('Successful LZMA decompression!', padding + 8) - except: + except Exception: # Otherwise, Chunk data is not compressed cpio_bin += comp_bin @@ -116,28 +115,4 @@ def apple_pbzx_extract(input_file, output_path, padding=0): 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) + BIOSUtility(TITLE, is_apple_pbzx, apple_pbzx_extract).run_utility() diff --git a/Apple_EFI_PKG.py b/Apple_EFI_PKG.py index 636f99e..a185547 100644 --- a/Apple_EFI_PKG.py +++ b/Apple_EFI_PKG.py @@ -7,7 +7,7 @@ Apple EFI Package Extractor Copyright (C) 2019-2022 Plato Mavropoulos """ -TITLE = 'Apple EFI Package Extractor v2.0_a4' +TITLE = 'Apple EFI Package Extractor v2.0_a5' import os import sys @@ -16,9 +16,10 @@ import sys 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.path_ops import copy_file, del_dirs, get_path_files, make_dirs, path_name, path_parent, get_extract_path from common.patterns import PAT_APPLE_PKG -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes from Apple_EFI_ID import apple_efi_identify, is_apple_efi @@ -35,11 +36,11 @@ def is_apple_pkg(input_file): def efi_split_rename(in_file, out_path, padding=0): exit_codes = [] - working_dir = f'{in_file}_extracted' + working_dir = get_extract_path(in_file) 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) + im4p_exit = apple_im4p_split(in_file, working_dir, padding + 4) exit_codes.append(im4p_exit) else: make_dirs(working_dir, delete=True) @@ -59,13 +60,11 @@ def efi_split_rename(in_file, out_path, padding=0): return sum(exit_codes) # Parse & Extract Apple EFI PKG packages -def apple_pkg_extract(input_file, output_path, padding=0): +def apple_pkg_extract(input_file, extract_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') @@ -82,12 +81,13 @@ def apple_pkg_extract(input_file, output_path, padding=0): 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: + pbzx_path = get_extract_path(xar_file) + if apple_pbzx_extract(xar_file, pbzx_path, padding + 8) == 0: printer(f'Succesfull PBZX extraction via {pbzx_module}!', padding + 4) - for pbzx_file in get_path_files(f'{xar_file}_extracted'): + for pbzx_file in get_path_files(pbzx_path): 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' + zip_path = get_extract_path(pbzx_file) 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': @@ -114,11 +114,11 @@ def apple_pkg_extract(input_file, output_path, padding=0): if path_name(xar_file) == 'Scripts': if is_szip_supported(xar_file, padding + 4, args=['-tGZIP'], check=True): - gzip_path = f'{xar_file}_extracted' + gzip_path = get_extract_path(xar_file) 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' + cpio_path = get_extract_path(gzip_file) 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': @@ -145,28 +145,4 @@ def apple_pkg_extract(input_file, output_path, padding=0): 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) + BIOSUtility(TITLE, is_apple_pkg, apple_pkg_extract).run_utility() diff --git a/Award_BIOS_Extract.py b/Award_BIOS_Extract.py index f06963f..12d1e96 100644 --- a/Award_BIOS_Extract.py +++ b/Award_BIOS_Extract.py @@ -7,7 +7,7 @@ Award BIOS Module Extractor Copyright (C) 2018-2022 Plato Mavropoulos """ -TITLE = 'Award BIOS Module Extractor v2.0_a4' +TITLE = 'Award BIOS Module Extractor v2.0_a5' import os import sys @@ -16,9 +16,10 @@ import sys sys.dont_write_bytecode = True from common.comp_szip import szip_decompress -from common.path_ops import make_dirs, safe_name +from common.path_ops import make_dirs, safe_name, get_extract_path from common.patterns import PAT_AWARD_LZH -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes # Check if input is Award BIOS image @@ -28,11 +29,9 @@ def is_award_bios(in_file): return bool(PAT_AWARD_LZH.search(in_buffer)) # Parse & Extract Award BIOS image -def award_bios_extract(input_file, output_path, padding=0): +def award_bios_extract(input_file, extract_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) for lzh_match in PAT_AWARD_LZH.finditer(input_buffer): @@ -69,35 +68,7 @@ def award_bios_extract(input_file, output_path, padding=0): # Extract any nested LZH archives if is_award_bios(mod_path): # Recursively extract nested Award BIOS modules - award_bios_extract(mod_path, mod_path, padding + 8) + award_bios_extract(mod_path, get_extract_path(mod_path), padding + 8) 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) - - with open(input_file, 'rb') as in_file: - input_buffer = in_file.read() - - if not is_award_bios(input_buffer): - printer('Error: This is not an Award BIOS image!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - award_bios_extract(input_buffer, extract_path, padding) - - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + BIOSUtility(TITLE, is_award_bios, award_bios_extract).run_utility() diff --git a/Dell_PFS_Extract.py b/Dell_PFS_Extract.py index 59c91f2..c0d981c 100644 --- a/Dell_PFS_Extract.py +++ b/Dell_PFS_Extract.py @@ -7,7 +7,7 @@ Dell PFS/PKG Update Extractor Copyright (C) 2018-2022 Plato Mavropoulos """ -TITLE = 'Dell PFS/PKG Update Extractor v6.0_a12' +TITLE = 'Dell PFS/PKG Update Extractor v6.0_a13' import os import io @@ -25,7 +25,8 @@ from common.comp_szip import is_szip_supported, szip_decompress from common.path_ops import del_dirs, get_path_files, make_dirs, path_name, path_parent, path_stem, safe_name from common.patterns import PAT_DELL_FTR, PAT_DELL_HDR, PAT_DELL_PKG from common.struct_ops import char, get_struct, uint8_t, uint16_t, uint32_t, uint64_t -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes from AMI_PFAT_Extract import IntelBiosGuardHeader, IntelBiosGuardSignature2k, parse_bg_script @@ -225,6 +226,28 @@ def is_dell_pfs(in_file): return bool(is_pkg or is_hdr and is_ftr) +# Parse & Extract Dell PFS/PKG Update image +def pfs_pkg_parse(in_file, output_path, padding=0, structure=True, advanced=True): + in_buffer = file_to_bytes(in_file) + + make_dirs(output_path, delete=True) + + is_dell_pkg = is_pfs_pkg(in_buffer) + + if is_dell_pkg: + pfs_results = thinos_pkg_extract(in_buffer, output_path) + else: + pfs_results = {path_stem(in_file) if os.path.isfile(in_file) else 'Image': in_buffer} + + # Parse each Dell PFS image contained in the input file + for pfs_index,(pfs_name,pfs_buffer) in enumerate(pfs_results.items(), start=1): + # At ThinOS PKG packages, multiple PFS images may be included in separate model-named folders + pfs_path = os.path.join(output_path, f'{pfs_index} {pfs_name}') if is_dell_pkg else output_path + # Parse each PFS ZLIB section + for zlib_offset in get_section_offsets(pfs_buffer): + # Call the PFS ZLIB section parser function + pfs_section_parse(pfs_buffer, zlib_offset, pfs_path, pfs_name, pfs_index, 1, False, padding, structure, advanced) + # Extract Dell ThinOS PKG 7zXZ def thinos_pkg_extract(in_file, output_path): in_buffer = file_to_bytes(in_file) @@ -296,7 +319,7 @@ def get_section_offsets(buffer): return pfs_zlib_list # Dell PFS ZLIB Section Parser -def pfs_section_parse(zlib_data, zlib_start, output_path, pfs_name, pfs_index, pfs_count, is_rec, padding, structure=True, advanced=True): +def pfs_section_parse(zlib_data, zlib_start, output_path, pfs_name, pfs_index, pfs_count, is_rec, padding=0, structure=True, advanced=True): is_zlib_error = False # Initialize PFS ZLIB-related error state section_type = zlib_data[zlib_start - 0x1] # Byte before PFS ZLIB Section pattern is Section Type (e.g. AA, BB) @@ -365,34 +388,34 @@ def pfs_section_parse(zlib_data, zlib_start, output_path, pfs_name, pfs_index, p if is_zlib_error: raise Exception('ZLIB_ERROR') # ZLIB errors are critical section_data = zlib.decompress(compressed_data) # ZLIB decompression - except: + except Exception: section_data = zlib_data # Fallback to raw ZLIB data upon critical error # Call the PFS Extract function on the decompressed PFS ZLIB Section pfs_extract(section_data, pfs_index, pfs_name, pfs_count, section_path, padding, structure, advanced) # Parse & Extract Dell PFS Volume -def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, structure=True, advanced=True): +def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, padding=0, structure=True, advanced=True): # Show PFS Volume indicator if structure: - printer('PFS Volume:', pfs_padd) + printer('PFS Volume:', padding) # Get PFS Header Structure values pfs_hdr = get_struct(buffer, 0, DellPfsHeader) # Validate that a PFS Header was parsed if pfs_hdr.Tag != b'PFS.HDR.': - printer('Error: PFS Header could not be found!', pfs_padd + 4) + printer('Error: PFS Header could not be found!', padding + 4) return # Critical error, abort # Show PFS Header Structure info if structure: - printer('PFS Header:\n', pfs_padd + 4) - pfs_hdr.struct_print(pfs_padd + 8) + printer('PFS Header:\n', padding + 4) + pfs_hdr.struct_print(padding + 8) # Validate that a known PFS Header Version was encountered - chk_hdr_ver(pfs_hdr.HeaderVersion, 'PFS', pfs_padd + 8) + chk_hdr_ver(pfs_hdr.HeaderVersion, 'PFS', padding + 8) # Get PFS Payload Data pfs_payload = buffer[PFS_HEAD_LEN:PFS_HEAD_LEN + pfs_hdr.PayloadSize] @@ -407,7 +430,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, s while len(pfs_payload[entry_start:entry_start + pfs_entry_size]) == pfs_entry_size: # Analyze PFS Entry Structure and get relevant info _,entry_version,entry_guid,entry_data,entry_data_sig,entry_met,entry_met_sig,next_entry = \ - parse_pfs_entry(pfs_payload, entry_start, pfs_entry_size, pfs_entry_struct, 'PFS Entry', pfs_padd, structure) + parse_pfs_entry(pfs_payload, entry_start, pfs_entry_size, pfs_entry_struct, 'PFS Entry', padding, structure) entry_type = 'OTHER' # Adjusted later if PFS Entry is Zlib, PFAT, PFS Info, Model Info @@ -444,12 +467,12 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, s # Show PFS Information Header Structure info if structure: - printer('PFS Information Header:\n', pfs_padd + 4) - entry_info_hdr.struct_print(pfs_padd + 8) + printer('PFS Information Header:\n', padding + 4) + entry_info_hdr.struct_print(padding + 8) # Validate that a known PFS Information Header Version was encountered if entry_info_hdr.HeaderVersion != 1: - printer(f'Error: Unknown PFS Information Header Version {entry_info_hdr.HeaderVersion}!', pfs_padd + 8) + printer(f'Error: Unknown PFS Information Header Version {entry_info_hdr.HeaderVersion}!', padding + 8) break # Skip PFS Information Entries/Descriptors in case of unknown PFS Information Header Version # Get PFS Information Header GUID in Big Endian format to match each Info to the equivalent stored PFS Entry details @@ -468,8 +491,8 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, s # Show PFS FileName Structure info if structure: - printer('PFS FileName Entry:\n', pfs_padd + 8) - entry_info_mod.struct_print(pfs_padd + 12, entry_name) + printer('PFS FileName Entry:\n', padding + 8) + entry_info_mod.struct_print(padding + 12, entry_name) # Get PFS FileName Version string via "Version" and "VersionType" fields # PFS FileName Version string must be preferred over PFS Entry's Version @@ -496,8 +519,8 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, s # Show Nested PFS Metadata Structure info if structure: - printer('PFS Metadata Information:\n', pfs_padd + 4) - entry_info.struct_print(pfs_padd + 8) + printer('PFS Metadata Information:\n', padding + 4) + entry_info.struct_print(padding + 8) # As Nested PFS Entry Name, we'll use the actual PFS File Name # Replace common Windows reserved/illegal filename characters @@ -520,12 +543,12 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, s # Show PFS Information Header Structure info if structure: - printer('PFS Information Header:\n', pfs_padd + 4) - entry_info_hdr.struct_print(pfs_padd + 8) + printer('PFS Information Header:\n', padding + 4) + entry_info_hdr.struct_print(padding + 8) # Validate that a known PFS Information Header Version was encountered if entry_info_hdr.HeaderVersion != 1: - printer(f'Error: Unknown PFS Information Header Version {entry_info_hdr.HeaderVersion}!', pfs_padd + 8) + printer(f'Error: Unknown PFS Information Header Version {entry_info_hdr.HeaderVersion}!', padding + 8) break # Skip PFS Signature Entries/Descriptors in case of unknown Header Version # PFS Signature Entries/Descriptors have DellPfsInfo + DellPfsEntryR* + Sign Size [0x2] + Sign Data [Sig Size] @@ -536,8 +559,8 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, s # Show PFS Information Header Structure info if structure: - printer('PFS Information Entry:\n', pfs_padd + 8) - entry_hdr.struct_print(pfs_padd + 12) + printer('PFS Information Entry:\n', padding + 8) + entry_hdr.struct_print(padding + 12) # Show PFS Signature Size & Data (after DellPfsEntryR*) sign_info_start = sign_start + PFS_INFO_LEN + pfs_entry_size @@ -546,9 +569,9 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, s sign_data_txt = f'{int.from_bytes(sign_data_raw, "little"):0{sign_size * 2}X}' if structure: - printer('Signature Information:\n', pfs_padd + 8) - printer(f'Signature Size: 0x{sign_size:X}', pfs_padd + 12, False) - printer(f'Signature Data: {sign_data_txt[:32]} [...]', pfs_padd + 12, False) + printer('Signature Information:\n', padding + 8) + printer(f'Signature Size: 0x{sign_size:X}', padding + 12, False) + printer(f'Signature Data: {sign_data_txt[:32]} [...]', padding + 12, False) # The next PFS Signature Entry/Descriptor starts after the previous Signature Data sign_start += (PFS_INFO_LEN + pfs_entry_size + 0x2 + sign_size) @@ -578,7 +601,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, s if pfat_entry_hdr.Tag == b'PFS.HDR.' and is_pfat: entry_type = 'PFAT' # Re-set PFS Entry Type from OTHER to PFAT, to use such info afterwards - entry_data = parse_pfat_pfs(pfat_entry_hdr, entry_data, pfs_padd, structure) # Parse sub-PFS PFAT Volume + entry_data = parse_pfat_pfs(pfat_entry_hdr, entry_data, padding, structure) # Parse sub-PFS PFAT Volume # Parse PFS Entry which contains zlib-compressed sub-PFS Volume elif pfs_zlib_offsets: @@ -599,7 +622,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, s sub_pfs_path = os.path.join(output_path, f'{pfs_count} {safe_name(sub_pfs_name)}') # Recursively call the PFS ZLIB Section Parser function for the sub-PFS Volume (pfs_index = pfs_count) - pfs_section_parse(entry_data, offset, sub_pfs_path, sub_pfs_name, pfs_count, pfs_count, True, pfs_padd + 4, structure, advanced) + pfs_section_parse(entry_data, offset, sub_pfs_path, sub_pfs_name, pfs_count, pfs_count, True, padding + 4, structure, advanced) entries_all[index][4] = entry_data # Adjust PFS Entry Data after parsing PFAT (same ZLIB raw data, not stored afterwards) entries_all[index][3] = entry_type # Adjust PFS Entry Type from OTHER to PFAT or ZLIB (ZLIB is ignored at file extraction) @@ -668,16 +691,16 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, s # Write/Extract PFS Entry files for file in write_files: full_name = f'{pfs_index} {pfs_name} -- {file_index} {file_name} v{file_version}' # Full PFS Entry Name - pfs_file_write(file[0], file[1], file_type, full_name, output_path, pfs_padd, structure, advanced) + pfs_file_write(file[0], file[1], file_type, full_name, output_path, padding, structure, advanced) # Get PFS Footer Data after PFS Header Payload pfs_footer = buffer[PFS_HEAD_LEN + pfs_hdr.PayloadSize:PFS_HEAD_LEN + pfs_hdr.PayloadSize + PFS_FOOT_LEN] # Analyze PFS Footer Structure - chk_pfs_ftr(pfs_footer, pfs_payload, pfs_hdr.PayloadSize, 'PFS', pfs_padd, structure) + chk_pfs_ftr(pfs_footer, pfs_payload, pfs_hdr.PayloadSize, 'PFS', padding, structure) # Analyze Dell PFS Entry Structure -def parse_pfs_entry(entry_buffer, entry_start, entry_size, entry_struct, text, padding, structure=True): +def parse_pfs_entry(entry_buffer, entry_start, entry_size, entry_struct, text, padding=0, structure=True): # Get PFS Entry Structure values pfs_entry = get_struct(entry_buffer, entry_start, entry_struct) @@ -723,7 +746,7 @@ def parse_pfs_entry(entry_buffer, entry_start, entry_size, entry_struct, text, p return pfs_entry, entry_version, entry_guid, entry_data, entry_data_sig, entry_met, entry_met_sig, entry_met_sig_end # Parse Dell PFS Volume with PFAT Payload -def parse_pfat_pfs(entry_hdr, entry_data, padding, structure=True): +def parse_pfat_pfs(entry_hdr, entry_data, padding=0, structure=True): # Show PFS Volume indicator if structure: printer('PFS Volume:', padding + 4) @@ -886,7 +909,7 @@ def get_entry_ver(version_fields, version_types): return version # Check if Dell PFS Header Version is known -def chk_hdr_ver(version, text, padding): +def chk_hdr_ver(version, text, padding=0): if version in (1,2): return @@ -895,7 +918,7 @@ def chk_hdr_ver(version, text, padding): return # Analyze Dell PFS Footer Structure -def chk_pfs_ftr(footer_buffer, data_buffer, data_size, text, padding, structure=True): +def chk_pfs_ftr(footer_buffer, data_buffer, data_size, text, padding=0, structure=True): # Get PFS Footer Structure values pfs_ftr = get_struct(footer_buffer, 0, DellPfsFooter) @@ -920,7 +943,7 @@ def chk_pfs_ftr(footer_buffer, data_buffer, data_size, text, padding, structure= printer(f'Error: Invalid {text} Footer Payload Checksum!', padding + 4) # Write/Extract Dell PFS Entry Files (Data, Metadata, Signature) -def pfs_file_write(bin_buff, bin_name, bin_type, full_name, out_path, padding, structure=True, advanced=True): +def pfs_file_write(bin_buff, bin_name, bin_type, full_name, out_path, padding=0, structure=True, advanced=True): # Store Data/Metadata Signature (advanced users only) if bin_name.startswith('sign'): final_name = f'{safe_name(full_name)}.{bin_name.split("_")[1]}.sig' @@ -944,7 +967,7 @@ def pfs_file_write(bin_buff, bin_name, bin_type, full_name, out_path, padding, s pfs_out.write(final_data) # Write final Data/Metadata Payload # Check if Dell PFS Entry file/data is Text/XML and Convert -def bin_is_text(buffer, file_type, is_metadata, pfs_padd, structure=True, advanced=True): +def bin_is_text(buffer, file_type, is_metadata, padding=0, structure=True, advanced=True): is_text = False write_mode = 'wb' extension = '.bin' @@ -975,8 +998,8 @@ def bin_is_text(buffer, file_type, is_metadata, pfs_padd, structure=True, advanc # Show Model/PCR XML Information, if applicable if structure and is_text and not is_metadata: # Metadata is shown at initial DellPfsMetadata analysis - printer(f'PFS { {".txt": "Model", ".xml": "PCR XML"}[extension] } Information:\n', pfs_padd + 8) - _ = [printer(line.strip('\r'), pfs_padd + 12, False) for line in buffer.split('\n') if line] + printer(f'PFS { {".txt": "Model", ".xml": "PCR XML"}[extension] } Information:\n', padding + 8) + _ = [printer(line.strip('\r'), padding + 12, False) for line in buffer.split('\n') if line] # Only for non-advanced users due to signature (.sig) invalidation if advanced: @@ -994,52 +1017,8 @@ PFS_PFAT_LEN = ctypes.sizeof(DellPfsPfatMetadata) PFAT_HDR_LEN = ctypes.sizeof(IntelBiosGuardHeader) PFAT_SIG_LEN = ctypes.sizeof(IntelBiosGuardSignature2k) -if __name__ == '__main__': - # Set argparse arguments - argparser = argparse_init() - argparser.add_argument('-a', '--advanced', help='extract signatures and metadata', action='store_true') - argparser.add_argument('-s', '--structure', help='show PFS structure information', action='store_true') - arguments = argparser.parse_args() - - advanced = arguments.advanced # Set Advanced user mode optional argument - structure = arguments.structure # Set Structure output mode optional argument - - # 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) - - with open(input_file, 'rb') as in_file: - input_buffer = in_file.read() - - if not is_dell_pfs(input_buffer): - printer('Error: This is not a Dell PFS/PKG Update image!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, f'{input_name}_extracted') - - is_dell_pkg = is_pfs_pkg(input_buffer) - - if is_dell_pkg: - pfs_results = thinos_pkg_extract(input_buffer, extract_path) - else: - pfs_results = {path_stem(input_file): input_buffer} - - # Parse each Dell PFS image contained in the input file - for pfs_index,(pfs_name,pfs_buffer) in enumerate(pfs_results.items(), start=1): - # At ThinOS PKG packages, multiple PFS images may be included in separate model-named folders - pfs_path = os.path.join(extract_path, f'{pfs_index} {pfs_name}') if is_dell_pkg else extract_path - # Parse each PFS ZLIB section - for zlib_offset in get_section_offsets(pfs_buffer): - # Call the PFS ZLIB section parser function - pfs_section_parse(pfs_buffer, zlib_offset, pfs_path, pfs_name, pfs_index, 1, False, padding, structure, advanced) - - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) +if __name__ == '__main__': + utility = BIOSUtility(TITLE, is_dell_pfs, pfs_pkg_parse) + utility.parse_argument('-a', '--advanced', help='extract signatures and metadata', action='store_true') + utility.parse_argument('-s', '--structure', help='show PFS structure information', action='store_true') + utility.run_utility() diff --git a/Fujitsu_SFX_Extract.py b/Fujitsu_SFX_Extract.py index f27b984..52ba7c9 100644 --- a/Fujitsu_SFX_Extract.py +++ b/Fujitsu_SFX_Extract.py @@ -7,7 +7,7 @@ Fujitsu SFX BIOS Extractor Copyright (C) 2019-2022 Plato Mavropoulos """ -TITLE = 'Fujitsu SFX BIOS Extractor v3.0_a2' +TITLE = 'Fujitsu SFX BIOS Extractor v3.0_a3' import os import sys @@ -18,7 +18,8 @@ sys.dont_write_bytecode = True from common.comp_szip import is_szip_supported, szip_decompress from common.path_ops import make_dirs from common.patterns import PAT_FUJITSU_SFX -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes # Check if input is Fujitsu SFX image @@ -71,11 +72,9 @@ def fujitsu_cabinet(in_file, extract_path, padding=0): return 0 # Parse & Extract Fujitsu SFX image -def fujitsu_sfx_extract(in_file, output_path, padding=0): +def fujitsu_sfx_extract(in_file, extract_path, padding=0): buffer = file_to_bytes(in_file) - extract_path = os.path.join(f'{output_path}_extracted') - make_dirs(extract_path, delete=True) if fujitsu_cabinet(buffer, extract_path, padding) == 0: @@ -87,32 +86,4 @@ def fujitsu_sfx_extract(in_file, output_path, padding=0): 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) - - with open(input_file, 'rb') as in_file: - input_buffer = in_file.read() - - # Check if Fujitsu SFX pattern was found on image - if not is_fujitsu_sfx(input_buffer): - printer('Error: This is not a Fujitsu SFX image!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - if fujitsu_sfx_extract(input_buffer, extract_path, padding) == 0: - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + BIOSUtility(TITLE, is_fujitsu_sfx, fujitsu_sfx_extract).run_utility() diff --git a/Fujitsu_UPC_Extract.py b/Fujitsu_UPC_Extract.py index 24a7ebd..01d6ac7 100644 --- a/Fujitsu_UPC_Extract.py +++ b/Fujitsu_UPC_Extract.py @@ -7,7 +7,7 @@ Fujitsu UPC BIOS Extractor Copyright (C) 2021-2022 Plato Mavropoulos """ -TITLE = 'Fujitsu UPC BIOS Extractor v2.0_a4' +TITLE = 'Fujitsu UPC BIOS Extractor v2.0_a5' import os import sys @@ -17,7 +17,7 @@ sys.dont_write_bytecode = True from common.comp_efi import efi_decompress, is_efi_compressed from common.path_ops import make_dirs, path_suffixes -from common.system import argparse_init, printer, script_init +from common.templates import BIOSUtility from common.text_ops import file_to_bytes # Check if input is Fujitsu UPC image @@ -31,9 +31,7 @@ def is_fujitsu_upc(in_file): return is_ext and is_efi # Parse & Extract Fujitsu UPC image -def fujitsu_upc_extract(input_file, output_path, padding=0): - extract_path = os.path.join(f'{output_path}_extracted') - +def fujitsu_upc_extract(input_file, extract_path, padding=0): make_dirs(extract_path, delete=True) image_base = os.path.basename(input_file) @@ -43,31 +41,4 @@ def fujitsu_upc_extract(input_file, output_path, padding=0): return efi_decompress(input_file, image_path, padding) 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) - - with open(input_file, 'rb') as in_file: - input_buffer = in_file.read() - - if not is_fujitsu_upc(input_buffer): - printer('Error: This is not a Fujitsu UPC BIOS image!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - if fujitsu_upc_extract(input_file, extract_path, padding) == 0: - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + BIOSUtility(TITLE, is_fujitsu_upc, fujitsu_upc_extract).run_utility() diff --git a/Insyde_IFD_Extract.py b/Insyde_IFD_Extract.py index c68d4d4..65593f4 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_a10' +TITLE = 'Insyde iFlash/iFdPacker Extractor v2.0_a11' import os import sys @@ -17,10 +17,11 @@ import ctypes sys.dont_write_bytecode = True from common.comp_szip import is_szip_supported, szip_decompress -from common.path_ops import get_path_files, make_dirs, safe_name +from common.path_ops import get_path_files, make_dirs, safe_name, get_extract_path from common.patterns import PAT_INSYDE_IFL, PAT_INSYDE_SFX from common.struct_ops import char, get_struct, uint32_t -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes class IflashHeader(ctypes.LittleEndianStructure): @@ -57,11 +58,9 @@ def is_insyde_ifd(input_file): return is_ifl or is_sfx # Parse & Extract Insyde iFlash/iFdPacker Update images -def insyde_ifd_extract(input_file, output_path, padding=0): +def insyde_ifd_extract(input_file, extract_path, padding=0): input_buffer = file_to_bytes(input_file) - extract_path = os.path.join(f'{output_path}_extracted') - iflash_code = insyde_iflash_extract(input_buffer, extract_path, padding) ifdpack_path = os.path.join(extract_path, 'Insyde iFdPacker SFX') @@ -190,7 +189,7 @@ def insyde_packer_extract(input_buffer, extract_path, padding=0): if is_insyde_ifd(sfx_file): printer(f'{os.path.basename(sfx_file)}', padding + 12) - ifd_code = insyde_ifd_extract(sfx_file, sfx_file, padding + 16) + ifd_code = insyde_ifd_extract(sfx_file, get_extract_path(sfx_file), padding + 16) exit_codes.append(ifd_code) @@ -215,32 +214,4 @@ INS_IFL_IMG = { INS_IFL_LEN = ctypes.sizeof(IflashHeader) 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) - - with open(input_file, 'rb') as in_file: - input_buffer = in_file.read() - - if not is_insyde_ifd(input_buffer): - printer('Error: This is not an Insyde iFlash/iFdPacker Update image!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - insyde_ifd_extract(input_buffer, extract_path, padding) - - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + BIOSUtility(TITLE, is_insyde_ifd, insyde_ifd_extract).run_utility() diff --git a/Panasonic_BIOS_Extract.py b/Panasonic_BIOS_Extract.py index 900f1a6..096bec3 100644 --- a/Panasonic_BIOS_Extract.py +++ b/Panasonic_BIOS_Extract.py @@ -7,7 +7,7 @@ Panasonic BIOS Package Extractor Copyright (C) 2018-2022 Plato Mavropoulos """ -TITLE = 'Panasonic BIOS Package Extractor v2.0_a9' +TITLE = 'Panasonic BIOS Package Extractor v2.0_a10' import os import io @@ -22,7 +22,8 @@ from common.comp_szip import is_szip_supported, szip_decompress from common.path_ops import get_path_files, make_dirs, path_stem, safe_name from common.pe_ops import get_pe_file, get_pe_info, is_pe_file, show_pe_info from common.patterns import PAT_MICROSOFT_CAB -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes from AMI_PFAT_Extract import is_ami_pfat, parse_pfat_file @@ -111,7 +112,7 @@ def panasonic_res_extract(pe_name, pe_file, extract_path, padding=0): res_raw = lznt1.decompress(res_bin[0x8:]) printer('Succesfull LZNT1 decompression via lznt1!', padding + 8) - except: + except Exception: res_raw = res_bin printer('Succesfull PE Resource extraction!', padding + 8) @@ -161,10 +162,8 @@ def panasonic_img_extract(pe_name, pe_path, pe_file, extract_path, padding=0): return bool(img_bin) # Parse & Extract Panasonic BIOS Package PE -def panasonic_pkg_extract(input_path, input_buffer, output_path, padding=0): - is_upd_res,is_upd_img = [False] * 2 - - extract_path = os.path.join(f'{output_path}_extracted') +def panasonic_pkg_extract(input_file, extract_path, padding=0): + input_buffer = file_to_bytes(input_file) make_dirs(extract_path, delete=True) @@ -178,7 +177,7 @@ def panasonic_pkg_extract(input_path, input_buffer, output_path, padding=0): if not pkg_pe_info: return 3 - pkg_pe_name = path_stem(input_path) + pkg_pe_name = path_stem(input_file) printer(f'Panasonic BIOS Package > PE ({pkg_pe_name})\n', padding) @@ -195,6 +194,8 @@ def panasonic_pkg_extract(input_path, input_buffer, output_path, padding=0): show_pe_info(upd_pe_info, padding + 16) + is_upd_res, is_upd_img = False, False + is_upd_res = panasonic_res_extract(upd_pe_name, upd_pe_file, extract_path, padding + 16) if not is_upd_res: @@ -205,32 +206,4 @@ def panasonic_pkg_extract(input_path, input_buffer, output_path, padding=0): return 0 if is_upd_res or is_upd_img else 1 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) - - with open(input_file, 'rb') as in_file: - input_buffer = in_file.read() - - # Check if Panasonic BIOS Package pattern was found on executable - if not is_panasonic_pkg(input_buffer): - printer('Error: This is not a Panasonic BIOS Package executable!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - if panasonic_pkg_extract(input_file, input_buffer, extract_path, padding) == 0: - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + BIOSUtility(TITLE, is_panasonic_pkg, panasonic_pkg_extract).run_utility() diff --git a/Phoenix_TDK_Extract.py b/Phoenix_TDK_Extract.py index 5d7456a..3328ad4 100644 --- a/Phoenix_TDK_Extract.py +++ b/Phoenix_TDK_Extract.py @@ -7,7 +7,7 @@ Phoenix TDK Packer Extractor Copyright (C) 2021-2022 Plato Mavropoulos """ -TITLE = 'Phoenix TDK Packer Extractor v2.0_a9' +TITLE = 'Phoenix TDK Packer Extractor v2.0_a10' import os import sys @@ -21,7 +21,8 @@ from common.path_ops import make_dirs, safe_name from common.pe_ops import get_pe_file, get_pe_info from common.patterns import PAT_MICROSOFT_MZ, PAT_MICROSOFT_PE, PAT_PHOENIX_TDK from common.struct_ops import char, get_struct, uint32_t -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes class PhoenixTdkHeader(ctypes.LittleEndianStructure): @@ -110,7 +111,7 @@ def get_tdk_base(in_buffer, pack_off): # Parse detected MZ > PE > Info > Product Name pe_name = pe_info.get(b'ProductName',b'') - except: + except Exception: # Any error means no MZ > PE > Info > Product Name pe_name = b'' @@ -152,12 +153,10 @@ def is_phoenix_tdk(in_file): return bool(get_phoenix_tdk(buffer)[1] is not None) # Parse & Extract Phoenix Tools Development Kit (TDK) Packer -def phoenix_tdk_extract(input_file, output_path, padding=0): - input_buffer = file_to_bytes(input_file) - +def phoenix_tdk_extract(input_file, extract_path, padding=0): exit_code = 0 - extract_path = os.path.join(f'{output_path}_extracted') + input_buffer = file_to_bytes(input_file) make_dirs(extract_path, delete=True) @@ -214,7 +213,7 @@ def phoenix_tdk_extract(input_file, output_path, padding=0): if tdk_mod.get_compression() == 'LZMA': try: mod_data = lzma.LZMADecompressor().decompress(mod_data) - except: + except Exception: printer('Error: Phoenix TDK Entry > LZMA decompression failed!\n', padding + 12, pause=True) exit_code = 5 @@ -241,32 +240,4 @@ TDK_MOD_LEN = ctypes.sizeof(PhoenixTdkEntry) TDK_DUMMY_LEN = 0x200 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) - - with open(input_file, 'rb') as in_file: - input_buffer = in_file.read() - - # Check if Phoenix TDK Packer pattern was found on executable - if not is_phoenix_tdk(input_buffer): - printer('Error: This is not a Phoenix TDK Packer executable!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - if phoenix_tdk_extract(input_buffer, extract_path, padding) == 0: - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + BIOSUtility(TITLE, is_phoenix_tdk, phoenix_tdk_extract).run_utility() diff --git a/Portwell_EFI_Extract.py b/Portwell_EFI_Extract.py index 316181e..bb40705 100644 --- a/Portwell_EFI_Extract.py +++ b/Portwell_EFI_Extract.py @@ -7,7 +7,7 @@ Portwell EFI Update Extractor Copyright (C) 2021-2022 Plato Mavropoulos """ -TITLE = 'Portwell EFI Update Extractor v2.0_a11' +TITLE = 'Portwell EFI Update Extractor v2.0_a12' import os import sys @@ -19,7 +19,8 @@ from common.comp_efi import efi_decompress, is_efi_compressed from common.path_ops import make_dirs, safe_name from common.pe_ops import get_pe_file from common.patterns import PAT_MICROSOFT_MZ, PAT_PORTWELL_EFI -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes FILE_NAMES = { @@ -36,7 +37,7 @@ def is_portwell_efi(in_file): try: pe_buffer = get_portwell_pe(in_buffer)[1] - except: + except Exception: pe_buffer = b'' is_mz = PAT_MICROSOFT_MZ.search(in_buffer[:0x2]) # EFI images start with PE Header MZ @@ -54,10 +55,10 @@ def get_portwell_pe(in_buffer): return pe_file, pe_data # Parse & Extract Portwell UEFI Unpacker -def portwell_efi_extract(input_buffer, output_path, padding=0): +def portwell_efi_extract(input_file, extract_path, padding=0): efi_files = [] # Initialize EFI Payload file chunks - extract_path = os.path.join(f'{output_path}_extracted') + input_buffer = file_to_bytes(input_file) make_dirs(extract_path, delete=True) @@ -132,32 +133,4 @@ def parse_efi_files(extract_path, efi_files, padding): os.remove(comp_fname) # Successful decompression, delete compressed file 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) - - with open(input_file, 'rb') as in_file: - input_buffer = in_file.read() - - if not is_portwell_efi(input_buffer): - printer('Error: This is not a Portwell EFI Update Package!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - portwell_efi_extract(input_buffer, extract_path, padding) - - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + BIOSUtility(TITLE, is_portwell_efi, portwell_efi_extract).run_utility() diff --git a/README.md b/README.md index 0df5ebb..6b5d67b 100644 --- a/README.md +++ b/README.md @@ -50,32 +50,6 @@ Optionally, to decompile the AMI PFAT \> Intel BIOS Guard Scripts, you must have * [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py) -#### **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: - -> BIOS Guard Script Tool (optional) - -4. Build/Freeze/Compile: - -> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/AMI_PFAT_Extract.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** ![]() @@ -114,34 +88,6 @@ Optionally, to decompile the AMI UCP \> AMI PFAT \> Intel BIOS Guard Scripts (wh * [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py) -#### **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: - -> TianoCompress\ -> 7-Zip Console\ -> BIOS Guard Script Tool (optional) - -4. Build/Freeze/Compile: - -> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/AMI_UCP_Extract.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** ![]() @@ -172,28 +118,6 @@ Should work at all Windows, Linux or macOS operating systems which have Python 3 To run the utility, you do not need any prerequisites. -#### **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. Build/Freeze/Compile: - -> pyinstaller --noupx --onefile \\/Apple_EFI_IM4P.py - -At dist folder you should find the final utility executable - -#### **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** ![]() @@ -228,33 +152,6 @@ To run the utility, you must have the following 3rd party tools at the "external * [UEFIFind](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIFind.exe for Windows or UEFIFind for Linux](https://github.com/LongSoft/UEFITool/releases)) * [UEFIExtract](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIExtract.exe for Windows or UEFIExtract for Linux](https://github.com/LongSoft/UEFITool/releases)) -#### **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: - -> UEFIFind\ -> UEFIExtract - -4. Build/Freeze/Compile: - -> 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** ![]() @@ -287,32 +184,6 @@ To run the utility, you must have the following 3rd party tools at the "external * [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** ![]() @@ -345,32 +216,6 @@ To run the utility, you must have the following 3rd party tools at the "external * [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 - -#### **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** ![]() @@ -403,32 +248,6 @@ To run the utility, you must have the following 3rd party tool at the "external" * [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 prerequisite at the "external" project directory: - -> 7-Zip Console - -4. Build/Freeze/Compile: - -> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/Award_BIOS_Extract.py - -At dist folder you should find the final utility executable - -#### **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** ![]() @@ -463,32 +282,6 @@ Optionally, to decompile the Intel BIOS Guard (PFAT) Scripts, you must have the * [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py) -#### **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: - -> BIOS Guard Script Tool (optional) - -4. Build/Freeze/Compile: - -> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/Dell_PFS_Extract.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** ![]() @@ -521,32 +314,6 @@ To run the utility, you must have the following 3rd party tool at the "external" * [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 prerequisite at the "external" project directory: - -> 7-Zip Console - -4. Build/Freeze/Compile: - -> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/Fujitsu_SFX_Extract.py - -At dist folder you should find the final utility executable - -#### **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** ![]() @@ -579,32 +346,6 @@ To run the utility, you must have the following 3rd party tool at the "external" * [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress 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 prerequisite at the "external" project directory: - -> TianoCompress - -4. Build/Freeze/Compile: - -> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/Fujitsu_UPC_Extract.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** ![]() @@ -635,28 +376,6 @@ Should work at all Windows, Linux or macOS operating systems which have Python 3 To run the utility, you do not need any prerequisites. -#### **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. Build/Freeze/Compile: - -> pyinstaller --noupx --onefile \\/Insyde_IFD_Extract.py - -At dist folder you should find the final utility executable - -#### **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** ![]() @@ -694,36 +413,6 @@ Moreover, you must have the following 3rd party tool at the "external" project d * [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. Use pip to install pefile and lznt1: - -> pip3 install pefile lznt1 - -4. Place prerequisite at the "external" project directory: - -> 7-Zip Console - -5. Build/Freeze/Compile: - -> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/Panasonic_BIOS_Extract.py - -At dist folder you should find the final utility executable - -#### **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** ![]() @@ -756,32 +445,6 @@ To run the utility, you must have the following 3rd party Python module installe * [pefile](https://pypi.org/project/pefile/) -#### **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. Use pip to install pefile: - -> pip3 install pefile - -4. Build/Freeze/Compile: - -> pyinstaller --noupx --onefile \\/Phoenix_TDK_Extract.py - -At dist folder you should find the final utility executable - -#### **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** ![]() @@ -820,36 +483,6 @@ Moreover, you must have the following 3rd party tool at the "external" project d * [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress 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. Use pip to install pefile: - -> pip3 install pefile - -4. Place prerequisite at the "external" project directory: - -> TianoCompress - -5. Build/Freeze/Compile: - -> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/Portwell_EFI_Extract.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** ![]() @@ -882,32 +515,6 @@ To run the utility, you must have the following 3rd party tool at the "external" * [ToshibaComExtractor](https://github.com/LongSoft/ToshibaComExtractor) (i.e. [comextract.exe for Windows or comextract for Linux](https://github.com/LongSoft/ToshibaComExtractor/releases)) -#### **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 prerequisite at the "external" project directory: - -> ToshibaComExtractor - -4. Build/Freeze/Compile: - -> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/Toshiba_COM_Extract.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** ![]() @@ -940,32 +547,6 @@ To run the utility, you must have the following 3rd party tool at the "external" * [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 prerequisite at the "external" project directory: - -> 7-Zip Console - -4. Build/Freeze/Compile: - -> pyinstaller --add-data="external/*;external/" --noupx --onefile \\/VAIO_Package_Extract.py - -At dist folder you should find the final utility executable - -#### **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** ![]() \ No newline at end of file diff --git a/Toshiba_COM_Extract.py b/Toshiba_COM_Extract.py index 4a6e1c2..da6ee43 100644 --- a/Toshiba_COM_Extract.py +++ b/Toshiba_COM_Extract.py @@ -7,7 +7,7 @@ Toshiba BIOS COM Extractor Copyright (C) 2018-2022 Plato Mavropoulos """ -TITLE = 'Toshiba BIOS COM Extractor v2.0_a3' +TITLE = 'Toshiba BIOS COM Extractor v2.0_a4' import os import sys @@ -16,9 +16,11 @@ import subprocess # Stop __pycache__ generation sys.dont_write_bytecode = True -from common.path_ops import make_dirs, path_stem, path_suffixes, project_root, safe_path +from common.externals import get_comextract_path +from common.path_ops import make_dirs, path_stem, path_suffixes from common.patterns import PAT_TOSHIBA_COM -from common.system import argparse_init, get_os_ver, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes # Check if input is Toshiba BIOS COM image @@ -31,15 +33,12 @@ def is_toshiba_com(in_file): return is_ext and is_com -# Get ToshibaComExtractor path -def get_comextract_path(): - exec_name = 'comextract.exe' if get_os_ver()[1] else 'comextract' - - return safe_path(project_root(), ['external',exec_name]) - # Parse & Extract Toshiba BIOS COM image -def toshiba_com_extract(input_file, output_path, padding=0): - extract_path = os.path.join(f'{output_path}_extracted') +def toshiba_com_extract(input_file, extract_path, padding=0): + if not os.path.isfile(input_file): + printer('Error: Could not find input file path!', padding) + + return 1 make_dirs(extract_path, delete=True) @@ -51,41 +50,14 @@ def toshiba_com_extract(input_file, output_path, padding=0): if not os.path.isfile(output_file): raise Exception('EXTRACT_FILE_MISSING') - except: + except Exception: printer(f'Error: ToshibaComExtractor could not extract file {input_file}!', padding) - return 1 + return 2 printer(f'Succesfull {output_name} extraction via ToshibaComExtractor!', padding) 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) - - with open(input_file, 'rb') as in_file: - input_buffer = in_file.read() - - if not is_toshiba_com(input_file): - printer('Error: This is not a Toshiba BIOS COM image!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - if toshiba_com_extract(input_file, extract_path, padding) == 0: - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + BIOSUtility(TITLE, is_toshiba_com, toshiba_com_extract).run_utility() diff --git a/VAIO_Package_Extract.py b/VAIO_Package_Extract.py index c8cec9c..9bb49bf 100644 --- a/VAIO_Package_Extract.py +++ b/VAIO_Package_Extract.py @@ -7,7 +7,7 @@ VAIO Packaging Manager Extractor Copyright (C) 2019-2022 Plato Mavropoulos """ -TITLE = 'VAIO Packaging Manager Extractor v3.0_a7' +TITLE = 'VAIO Packaging Manager Extractor v3.0_a8' import os import sys @@ -18,7 +18,8 @@ sys.dont_write_bytecode = True from common.comp_szip import is_szip_supported, szip_decompress from common.path_ops import make_dirs from common.patterns import PAT_VAIO_CAB, PAT_VAIO_CFG, PAT_VAIO_CHK, PAT_VAIO_EXT -from common.system import argparse_init, printer, script_init +from common.system import printer +from common.templates import BIOSUtility from common.text_ops import file_to_bytes # Check if input is VAIO Packaging Manager @@ -125,14 +126,16 @@ def vaio_unlock(name, buffer, extract_path, padding=0): return 0 # Parse & Extract or Unlock VAIO Packaging Manager -def vaio_pkg_extract(name, buffer, output_path, padding=0): - extract_path = os.path.join(f'{output_path}_extracted') +def vaio_pkg_extract(input_file, extract_path, padding=0): + input_buffer = file_to_bytes(input_file) + + input_name = os.path.basename(input_file) make_dirs(extract_path, delete=True) - if vaio_cabinet(name, buffer, extract_path, padding) == 0: + if vaio_cabinet(input_name, input_buffer, extract_path, padding) == 0: printer('Successfully Extracted!', padding) - elif vaio_unlock(name, bytearray(buffer), extract_path, padding) == 0: + elif vaio_unlock(input_name, bytearray(input_buffer), extract_path, padding) == 0: printer('Successfully Unlocked!', padding) else: printer('Error: Failed to Extract or Unlock executable!', padding) @@ -141,32 +144,4 @@ def vaio_pkg_extract(name, buffer, output_path, padding=0): 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) - - with open(input_file, 'rb') as in_file: - input_buffer = in_file.read() - - # Check if VAIO Packaging Manager pattern was found on executable - if not is_vaio_pkg(input_buffer): - printer('Error: This is not a VAIO Packaging Manager executable!', padding) - - continue # Next input file - - extract_path = os.path.join(output_path, input_name) - - if vaio_pkg_extract(input_name, input_buffer, extract_path, padding) == 0: - exit_code -= 1 - - printer('Done!', pause=True) - - sys.exit(exit_code) + BIOSUtility(TITLE, is_vaio_pkg, vaio_pkg_extract).run_utility() diff --git a/common/comp_efi.py b/common/comp_efi.py index 3c14b71..2837898 100644 --- a/common/comp_efi.py +++ b/common/comp_efi.py @@ -45,7 +45,7 @@ def efi_decompress(in_path, out_path, padding=0, silent=False, comp_type='--uefi if os.path.getsize(out_path) != size_orig: raise Exception('EFI_DECOMPRESS_ERROR') - except: + except Exception: if not silent: printer(f'Error: TianoCompress could not extract file {in_path}!', padding) diff --git a/common/comp_szip.py b/common/comp_szip.py index 3db03a6..fb6041b 100644 --- a/common/comp_szip.py +++ b/common/comp_szip.py @@ -34,7 +34,7 @@ def is_szip_supported(in_path, padding=0, args=None, check=False, silent=False): if check: check_bad_exit_code(szip_t.returncode) - except: + except Exception: if not silent: printer(f'Error: 7-Zip could not check support for file {in_path}!', padding) @@ -60,7 +60,7 @@ def szip_decompress(in_path, out_path, in_name, padding=0, args=None, check=Fals if not os.path.isdir(out_path): raise Exception('EXTRACT_DIR_MISSING') - except: + except Exception: if not silent: printer(f'Error: 7-Zip could not extract {in_name} file {in_path}!', padding) diff --git a/common/externals.py b/common/externals.py index 5aa17ae..f81e3b9 100644 --- a/common/externals.py +++ b/common/externals.py @@ -12,8 +12,9 @@ from common.system import get_os_ver # https://github.com/platomav/BGScriptTool by Plato Mavropoulos def get_bgs_tool(): try: - from external.big_script_tool import BigScript - except: + # noinspection PyUnresolvedReferences + from external.big_script_tool import BigScript # pylint: disable=E0401,E0611 + except Exception: BigScript = None return BigScript @@ -22,10 +23,16 @@ def get_bgs_tool(): def get_uefifind_path(): exec_name = f'UEFIFind{".exe" if get_os_ver()[1] else ""}' - return safe_path(project_root(), ['external',exec_name]) + return safe_path(project_root(), ['external', exec_name]) # Get UEFIExtract path def get_uefiextract_path(): exec_name = f'UEFIExtract{".exe" if get_os_ver()[1] else ""}' - return safe_path(project_root(), ['external',exec_name]) + return safe_path(project_root(), ['external', exec_name]) + +# Get ToshibaComExtractor path +def get_comextract_path(): + exec_name = f'comextract{".exe" if get_os_ver()[1] else ""}' + + return safe_path(project_root(), ['external', exec_name]) diff --git a/common/path_ops.py b/common/path_ops.py index e2420e6..26eca72 100644 --- a/common/path_ops.py +++ b/common/path_ops.py @@ -130,58 +130,13 @@ def get_dequoted_path(in_path): return out_path -# Get absolute file path of argparse object -def get_argparse_path(argparse_path): - if not argparse_path: - # Use runtime directory if no user path is specified - absolute_path = runtime_root() - else: - # Check if user specified path is absolute - if is_path_absolute(argparse_path): - absolute_path = argparse_path - # Otherwise, make it runtime directory relative - else: - absolute_path = safe_path(runtime_root(), argparse_path) - - return absolute_path +# Set utility extraction stem +def extract_suffix(): + return '_extracted' -# Process input files (argparse object) -def process_input_files(argparse_args, sys_argv=None): - input_files = [] - - if sys_argv is None: - sys_argv = [] - - if len(sys_argv) >= 2: - # Drag & Drop or CLI - if argparse_args.input_dir: - input_path_user = argparse_args.input_dir - input_path_full = get_argparse_path(input_path_user) if input_path_user else '' - input_files = get_path_files(input_path_full) - else: - # Parse list of input files (i.e. argparse FileType objects) - for file_object in argparse_args.files: - # Store each argparse FileType object's name (i.e. path) - input_files.append(file_object.name) - # Close each argparse FileType object (i.e. allow input file changes) - file_object.close() - - # Set output fallback value for missing argparse Output and Input Path - output_fallback = path_parent(input_files[0]) if input_files else None - - # Set output path via argparse Output path or argparse Input path or first input file path - output_path = argparse_args.output_dir or argparse_args.input_dir or output_fallback - else: - # Script w/o parameters - input_path_user = get_dequoted_path(input('\nEnter input directory path: ')) - input_path_full = get_argparse_path(input_path_user) if input_path_user else '' - input_files = get_path_files(input_path_full) - - output_path = get_dequoted_path(input('\nEnter output directory path: ')) - - output_path_final = get_argparse_path(output_path) - - return input_files, output_path_final +# Get utility extraction path +def get_extract_path(in_path, suffix=extract_suffix()): + return f'{in_path}{suffix}' # Get project's root directory def project_root(): diff --git a/common/pe_ops.py b/common/pe_ops.py index 572ac0e..ba23828 100644 --- a/common/pe_ops.py +++ b/common/pe_ops.py @@ -21,7 +21,7 @@ def get_pe_file(in_file, fast=True): try: # Analyze detected MZ > PE image buffer pe_file = pefile.PE(data=in_buffer, fast_load=fast) - except: + except Exception: pe_file = None return pe_file @@ -34,7 +34,7 @@ def get_pe_info(pe_file): # Retrieve MZ > PE > FileInfo > StringTable information pe_info = pe_file.FileInfo[0][0].StringTable[0].entries - except: + except Exception: pe_info = {} return pe_info diff --git a/common/system.py b/common/system.py index fab02ef..32056e0 100644 --- a/common/system.py +++ b/common/system.py @@ -6,12 +6,8 @@ Copyright (C) 2022 Plato Mavropoulos """ import sys -import ctypes -import argparse -import traceback from common.text_ops import padder, to_string -from common.path_ops import process_input_files # Get Python Version (tuple) def get_py_ver(): @@ -59,62 +55,6 @@ def check_sys_os(): if os_win: sys.stdout.reconfigure(encoding='utf-8') -# Initialize common argparse arguments -def argparse_init(): - argparser = argparse.ArgumentParser() - - argparser.add_argument('files', type=argparse.FileType('r'), nargs='*') - argparser.add_argument('-e', '--auto-exit', help='skip press enter to exit prompts', action='store_true') - argparser.add_argument('-v', '--version', help='show utility name and version', action='store_true') - argparser.add_argument('-o', '--output-dir', help='extract in given output directory') - argparser.add_argument('-i', '--input-dir', help='extract from given input directory') - - return argparser - -# Initialize Script (must be after argparse) -def script_init(title, arguments, padding=0): - # Pretty Python exception handler - sys.excepthook = nice_exc_handler - - # Check Python Version - check_sys_py() - - # Check OS Platform - check_sys_os() - - # Show Script Title - printer(title, new_line=False) - - # Show Utility Version on demand - if arguments.version: - sys.exit(0) - - # Set console/terminal window title (Windows only) - if get_os_ver()[1]: - ctypes.windll.kernel32.SetConsoleTitleW(title) - - # Process input files and generate output path - input_files,output_path = process_input_files(arguments, sys.argv) - - # Count input files for exit code - input_count = len(input_files) - - return input_count, input_files, output_path, padding - -# https://stackoverflow.com/a/781074 by Torsten Marek -def nice_exc_handler(exc_type, exc_value, tb): - if exc_type is KeyboardInterrupt: - printer('') - else: - printer('Error: Script crashed, please report the following:\n') - - traceback.print_exception(exc_type, exc_value, tb) - - if not is_auto_exit(): - input('\nPress enter to exit') - - sys.exit(127) - # Show message(s) while controlling padding, newline, pausing & separator def printer(in_message='', padd_count=0, new_line=True, pause=False, sep_char=' '): message = to_string(in_message, sep_char) diff --git a/common/templates.py b/common/templates.py new file mode 100644 index 0000000..6eeeff3 --- /dev/null +++ b/common/templates.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +#coding=utf-8 + +""" +Copyright (C) 2022 Plato Mavropoulos +""" + +import os +import sys +import ctypes +import argparse +import traceback + +from common.path_ops import runtime_root, is_path_absolute, safe_path, get_dequoted_path, get_path_files, path_parent, get_extract_path +from common.system import check_sys_py, check_sys_os, get_os_ver, printer, is_auto_exit + +class BIOSUtility: + + def __init__(self, title, check, main, padding=0): + self._title = title + self._main = main + self._check = check + self._padding = padding + self._arguments_kw = {} + + # Initialize argparse argument parser + self._argparser = argparse.ArgumentParser() + + self._argparser.add_argument('files', type=argparse.FileType('r', encoding='utf-8'), nargs='*') + self._argparser.add_argument('-e', '--auto-exit', help='skip press enter to exit prompts', action='store_true') + self._argparser.add_argument('-v', '--version', help='show utility name and version', action='store_true') + self._argparser.add_argument('-o', '--output-dir', help='extract in given output directory') + self._argparser.add_argument('-i', '--input-dir', help='extract from given input directory') + + self._arguments,self._arguments_unk = self._argparser.parse_known_args() + + # Managed Python exception handler + sys.excepthook = self._exception_handler + + # Check Python Version + check_sys_py() + + # Check OS Platform + check_sys_os() + + # Show Script Title + printer(self._title, new_line=False) + + # Show Utility Version on demand + if self._arguments.version: + sys.exit(0) + + # Set console/terminal window title (Windows only) + if get_os_ver()[1]: + ctypes.windll.kernel32.SetConsoleTitleW(self._title) + + # Process input files and generate output path + self._process_input_files() + + # Count input files for exit code + self.exit_code = len(self._input_files) + + def parse_argument(self, *args, **kwargs): + _dest = self._argparser.add_argument(*args, **kwargs).dest + self._arguments = self._argparser.parse_known_args(self._arguments_unk)[0] + self._arguments_kw.update({_dest: self._arguments.__dict__[_dest]}) + + def run_utility(self): + for _input_file in self._input_files: + _input_name = os.path.basename(_input_file) + + printer(['***', _input_name], self._padding) + + if not self._check(_input_file): + printer('Error: This is not a supported input!', self._padding + 4) + + continue # Next input file + + _extract_path = os.path.join(self._output_path, get_extract_path(_input_name)) + + if self._main(_input_file, _extract_path, self._padding + 4, **self._arguments_kw) in [0, None]: + self.exit_code -= 1 + + #print(self.exit_code) + + printer('Done!', pause=True) + + sys.exit(self.exit_code) + + # Process input files + def _process_input_files(self): + self._input_files = [] + + if len(sys.argv) >= 2: + # Drag & Drop or CLI + if self._arguments.input_dir: + _input_path_user = self._arguments.input_dir + _input_path_full = self._get_input_path(_input_path_user) if _input_path_user else '' + self._input_files = get_path_files(_input_path_full) + else: + # Parse list of input files (i.e. argparse FileType objects) + for _file_object in self._arguments.files: + # Store each argparse FileType object's name (i.e. path) + self._input_files.append(_file_object.name) + # Close each argparse FileType object (i.e. allow input file changes) + _file_object.close() + + # Set output fallback value for missing argparse Output and Input Path + _output_fallback = path_parent(self._input_files[0]) if self._input_files else None + + # Set output path via argparse Output path or argparse Input path or first input file path + _output_path = self._arguments.output_dir or self._arguments.input_dir or _output_fallback + else: + # Script w/o parameters + _input_path_user = get_dequoted_path(input('\nEnter input directory path: ')) + _input_path_full = self._get_input_path(_input_path_user) if _input_path_user else '' + self._input_files = get_path_files(_input_path_full) + + _output_path = get_dequoted_path(input('\nEnter output directory path: ')) + + self._output_path = self._get_input_path(_output_path) + + # Get absolute input file path + @staticmethod + def _get_input_path(input_path): + if not input_path: + # Use runtime directory if no user path is specified + absolute_path = runtime_root() + else: + # Check if user specified path is absolute + if is_path_absolute(input_path): + absolute_path = input_path + # Otherwise, make it runtime directory relative + else: + absolute_path = safe_path(runtime_root(), input_path) + + return absolute_path + + # https://stackoverflow.com/a/781074 by Torsten Marek + @staticmethod + def _exception_handler(exc_type, exc_value, exc_traceback): + if exc_type is KeyboardInterrupt: + printer('') + else: + printer('Error: Utility crashed, please report the following:\n') + + traceback.print_exception(exc_type, exc_value, exc_traceback) + + if not is_auto_exit(): + input('\nPress enter to exit') + + sys.exit(127) diff --git a/external/requirements.txt b/external/requirements.txt index f6b760a..798c16c 100644 --- a/external/requirements.txt +++ b/external/requirements.txt @@ -1,2 +1,2 @@ -lznt1==0.2 -pefile==2022.5.30 +lznt1 >= 0.2 +pefile >= 2022.5.30