diff --git a/AMI_UCP_Extract.py b/AMI_UCP_Extract.py index 18b25db..44b1f98 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_a16' +TITLE = 'AMI UCP Update Extractor v2.0_a17' import os import re @@ -392,12 +392,12 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na nal_dict[info_tag] = (info_path,info_name) # Assign a file path & name to each Tag # Parse Insyde BIOS @UAF|@HPU Module (@INS) - if uaf_tag == '@INS' and is_szip_supported(uaf_fname, padding + 4): + if uaf_tag == '@INS' and is_szip_supported(uaf_fname, padding + 4, check=True): ins_dir = os.path.join(extract_path, safe_name(f'{uaf_tag}_nested-SFX')) # Generate extraction directory printer('Insyde BIOS 7z SFX Archive:', padding + 4) - if szip_decompress(uaf_fname, ins_dir, '7z SFX', padding + 8) == 0: + if szip_decompress(uaf_fname, ins_dir, '7z SFX', padding + 8, check=True) == 0: os.remove(uaf_fname) # Successful extraction, delete @INS Module file/archive # Detect & Unpack AMI BIOS Guard (PFAT) BIOS image diff --git a/Award_BIOS_Extract.py b/Award_BIOS_Extract.py new file mode 100644 index 0000000..14189ff --- /dev/null +++ b/Award_BIOS_Extract.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +#coding=utf-8 + +""" +Award BIOS Extract +Award BIOS Module Extractor +Copyright (C) 2018-2022 Plato Mavropoulos +""" + +TITLE = 'Award BIOS Module Extractor v2.0_a3' + +import os +import sys + +# Stop __pycache__ generation +sys.dont_write_bytecode = True + +from common.comp_szip import szip_decompress +from common.path_ops import make_dirs, safe_name +from common.patterns import PAT_AWARD_LZH +from common.system import script_init, argparse_init, printer +from common.text_ops import file_to_bytes + +# Check if input is Award BIOS image +def is_award_bios(in_file): + in_buffer = file_to_bytes(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): + 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): + lzh_type = lzh_match.group(0).decode('utf-8') + lzh_text = f'LZH-{lzh_type.strip("-").upper()}' + + lzh_bgn = lzh_match.start() + + mod_bgn = lzh_bgn - 0x2 + hdr_len = input_buffer[mod_bgn] + mod_len = int.from_bytes(input_buffer[mod_bgn + 0x7:mod_bgn + 0xB], 'little') + mod_end = lzh_bgn + hdr_len + mod_len + mod_bin = input_buffer[mod_bgn:mod_end] + + tag_bgn = mod_bgn + 0x16 + tag_end = tag_bgn + input_buffer[mod_bgn + 0x15] + tag_txt = input_buffer[tag_bgn:tag_end].decode('utf-8','ignore') + + printer(f'{lzh_text} > {tag_txt} [0x{mod_bgn:06X}-0x{mod_end:06X}]', padding) + + mod_path = os.path.join(extract_path, safe_name(tag_txt)) + lzh_path = f'{mod_path}.lzh' + + with open(lzh_path, 'wb') as lzh_file: + lzh_file.write(mod_bin) # Store LZH archive + + # 7-Zip returns critical exit code (i.e. 2) if LZH CRC is wrong, do not check result + szip_decompress(lzh_path, extract_path, lzh_text, padding + 4, check=False) + + # Manually check if 7-Zip extracted LZH due to its CRC check issue + if os.path.isfile(mod_path): + os.remove(lzh_path) # Successful extraction, delete LZH archive + + # 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) + +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) diff --git a/Panasonic_BIOS_Extract.py b/Panasonic_BIOS_Extract.py index 97290e9..3373f68 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_a7' +TITLE = 'Panasonic BIOS Package Extractor v2.0_a8' import os import io @@ -64,10 +64,10 @@ def panasonic_cab_extract(buffer, extract_path, padding=0): with open(cab_path, 'wb') as cab_file: cab_file.write(cab_bin) # Store CAB archive - if is_szip_supported(cab_path, padding): + if is_szip_supported(cab_path, padding, check=True): printer(f'Panasonic BIOS Package > PE > CAB {cab_tag}', padding) - if szip_decompress(cab_path, extract_path, 'CAB', padding + 4) == 0: + if szip_decompress(cab_path, extract_path, 'CAB', padding + 4, check=True) == 0: os.remove(cab_path) # Successful extraction, delete CAB archive else: return pe_path, pe_file, pe_info diff --git a/README.md b/README.md index 89bab1a..88851a7 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ * [**AMI BIOS Guard Extractor**](#ami-bios-guard-extractor) * [**AMI UCP Update Extractor**](#ami-ucp-update-extractor) +* [**Award BIOS Module Extractor**](#award-bios-module-extractor) * [**Dell PFS Update Extractor**](#dell-pfs-update-extractor) * [**Panasonic BIOS Package Extractor**](#panasonic-bios-package-extractor) * [**Phoenix TDK Packer Extractor**](#phoenix-tdk-packer-extractor) @@ -137,6 +138,64 @@ Some Anti-Virus software may claim that the built/frozen/compiled executable con ![]() +## **Award BIOS Module Extractor** + +![]() + +#### **Description** + +Parses Award BIOS images and extracts their modules (e.g. RAID, MEMINIT, \_EN_CODE, awardext etc). It supports all Award BIOS image revisions and formats, including those which contain LZH compressed files. The output comprises only final firmware components which are directly usable by end users. + +#### **Usage** + +You can either Drag & Drop or manually enter Award BIOS image file(s). Optional arguments: + +* -h or --help : show help message and exit +* -v or --version : show utility name and version +* -i or --input-dir : extract from given input directory +* -o or --output-dir : extract in given output directory +* -e or --auto-exit : skip press enter to exit prompts + +#### **Compatibility** + +Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support. + +#### **Prerequisites** + +To run the utility, you must have the following 3rd party tool at the "external" project directory: + +* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zzs for Linux) + +#### **Build/Freeze/Compile with PyInstaller** + +PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. + +1. Make sure Python 3.8.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** + +![]() + ## **Dell PFS Update Extractor** ![]() diff --git a/VAIO_Package_Extract.py b/VAIO_Package_Extract.py index 345d4b4..108f4e3 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_a5' +TITLE = 'VAIO Packaging Manager Extractor v3.0_a6' import os import sys @@ -53,8 +53,8 @@ def vaio_cabinet(name, buffer, extract_path, padding=0): with open(cab_path, 'wb') as cab_file: cab_file.write(cab_data) # Create temporary CAB archive - if is_szip_supported(cab_path, padding + 8): - if szip_decompress(cab_path, extract_path, 'CAB', padding + 8) == 0: + if is_szip_supported(cab_path, padding + 8, check=True): + if szip_decompress(cab_path, extract_path, 'CAB', padding + 8, check=True) == 0: os.remove(cab_path) # Successful extraction, delete temporary CAB archive else: return 3 diff --git a/common/comp_szip.py b/common/comp_szip.py index c49b8b7..e786622 100644 --- a/common/comp_szip.py +++ b/common/comp_szip.py @@ -18,10 +18,17 @@ def get_szip_path(): return safe_path(project_root(), ['external',exec_name]) +# Check 7-Zip bad exit codes (0 OK, 1 Warning) +def check_bad_exit_code(exit_code): + if exit_code not in (0,1): + raise Exception(f'BAD_EXIT_CODE_{exit_code}') + # Check if file is 7-Zip supported -def is_szip_supported(in_path, padding=0, silent=False): +def is_szip_supported(in_path, padding=0, check=False, silent=False): try: - subprocess.run([get_szip_path(), 't', in_path, '-bso0', '-bse0', '-bsp0'], check=True) + szip_t = subprocess.run([get_szip_path(), 't', in_path, '-bso0', '-bse0', '-bsp0'], check=False) + + if check: check_bad_exit_code(szip_t.returncode) except: if not silent: printer(f'Error: 7-Zip could not check support for file {in_path}!', padding) @@ -31,11 +38,13 @@ def is_szip_supported(in_path, padding=0, silent=False): return True # Archive decompression via 7-Zip -def szip_decompress(in_path, out_path, in_name, padding=0, silent=False): +def szip_decompress(in_path, out_path, in_name, padding=0, check=False, silent=False): if not in_name: in_name = 'archive' try: - subprocess.run([get_szip_path(), 'x', '-aou', '-bso0', '-bse0', '-bsp0', '-o' + out_path, in_path], check=True) + szip_x = subprocess.run([get_szip_path(), 'x', '-aou', '-bso0', '-bse0', '-bsp0', '-o' + out_path, in_path], check=False) + + if check: check_bad_exit_code(szip_x.returncode) if not os.path.isdir(out_path): raise Exception('EXTRACT_DIR_MISSING') except: diff --git a/common/patterns.py b/common/patterns.py index df5e5be..47846f2 100644 --- a/common/patterns.py +++ b/common/patterns.py @@ -9,6 +9,7 @@ import re PAT_AMI_PFAT = re.compile(br'_AMIPFAT.AMI_BIOS_GUARD_FLASH_CONFIGURATIONS', re.DOTALL) PAT_AMI_UCP = re.compile(br'@(UAF|HPU).{12}@', re.DOTALL) +PAT_AWARD_LZH = re.compile(br'-lh[04567]-') PAT_DELL_FTR = re.compile(br'\xEE\xAA\xEE\x8F\x49\x1B\xE8\xAE\x14\x37\x90') PAT_DELL_HDR = re.compile(br'\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.\x78\x9C', re.DOTALL) PAT_DELL_PKG = re.compile(br'\x72\x13\x55\x00.{45}7zXZ', re.DOTALL)