BIOSUtilities v24.10.23

New "package" flow, arguments now provided during utility call (README)
New "main" flow, using old "run_utility" method of BIOSUtility (README)
Removed "run_utility" and "show_version" methods from base BIOSUtility
Removed argparse argument parsing logic from base BIOSUtility class
Removed notion of "pause" (i.e. user action) from BIOSUtility logic
Adjusted the README with usage info for "main" and "package" flows
This commit is contained in:
Plato Mavropoulos 2024-10-23 13:24:16 +03:00
parent 35455f735c
commit d8e23f9ef3
24 changed files with 561 additions and 652 deletions

View file

@ -1,3 +1,12 @@
24.10.23
New "package" flow, arguments now provided during utility call (README)
New "main" flow, using old "run_utility" method of BIOSUtility (README)
Removed "run_utility" and "show_version" methods from base BIOSUtility
Removed argparse argument parsing logic from base BIOSUtility class
Removed notion of "pause" (i.e. user action) from BIOSUtility logic
Adjusted the README with usage info for "main" and "package" flows
24.10.18
Removed all Python built-in library keyword arguments (#55)

143
README.md
View file

@ -8,10 +8,10 @@ Various BIOS/UEFI-related utilities which aid in modding and/or research
### Main
The "main" script provides a simple way to check and parse each of the user provided files against all utilities, in succession. It is ideal for quick drag & drop operations but lacks the finer control of the BIOSUtility method. If needed, a few options can be set, by using the command line:
The "main" script provides a simple way to check and parse each of the user provided files against all utilities, in succession. It is ideal for quick drag & drop operations but lacks the finer control of the "Package" method. If needed, a few options can be set, by using the command line:
``` bash
usage: [-h] [-e] [-o OUTPUT_DIR] paths [paths ...]
usage: main.py [-h] [-e] [-o OUTPUT_DIR] [paths ...]
positional arguments:
paths
@ -26,29 +26,9 @@ options:
python ./main.py "/path/to/input/file.bin" --output-dir "/path/to/file extractions"
```
### BIOSUtility
If no arguments/options are provided, the "main" script requests the input and output paths from the user. If no output path is provided, the utility will use the parent directory of the first input file or fallback to the runtime execution directory.
Each utility is derived from a base template: BIOSUtility. The base BIOSUtility offers the following options, applicable to all utilities:
``` bash
usage: [-h] [-e] [-o OUTPUT_DIR] [paths ...]
positional arguments:
paths
options:
-h, --help show help and exit
-e, --auto-exit skip user action prompts
-o OUTPUT_DIR, --output-dir OUTPUT_DIR output extraction directory
```
``` bash
python -m biosutilities.ami_pfat_extract -e "/path/to/input/file1.bin" "/path/to/input/file2.bin" "/path/to/input/folder/with/files/" -o "/path/to/output_directory"
```
If no arguments are provided, the BIOSUtility.run_utility() method gets executed, which will request the input and output paths from the user. If no output path is provided, the utility will use the parent directory of the first input file or fallback to the runtime execution directory.
``` bash
``` python
Enter input file or directory path: "C:\P5405CSA.303"
Enter output directory path: "C:\P5405CSA.303_output"
@ -56,7 +36,7 @@ Enter output directory path: "C:\P5405CSA.303_output"
### Package
All utilities form the "biosutilities" python package, which can be installed from PyPi:
Each utility is derived from a base "BIOSUtility" template and all utilities form the "biosutilities" python package, which can be installed from PyPi:
``` bash
python -m pip install --upgrade biosutilities[pefile,lznt1]
@ -67,72 +47,67 @@ Installing the python package is the recommended way to call one or more utiliti
``` python
from biosutilities.ami_pfat_extract import AmiPfatExtract
ami_pfat_extractor = AmiPfatExtract()
ami_pfat_extractor = AmiPfatExtract(input_object='/path/to/input/file.bin', extract_path='/path/to/output/folder/')
ami_pfat_extractor.check_format(input_object='/path/to/input/file.bin')
ami_pfat_extractor.parse_format(input_object='/path/to/input/file.bin', extract_path='/path/to/output/folder/')
is_supported = ami_pfat_extractor.check_format()
is_extracted = ami_pfat_extractor.parse_format()
```
``` python
from biosutilities.dell_pfs_extract import DellPfsExtract
dell_pfs_extractor = DellPfsExtract()
with open('/path/to/input/file.bin', 'rb') as pfs_file:
pfs_data = pfs_file.read()
with open(file='/path/to/input/file.bin', mode='rb') as pfs_file:
pfs_buffer = pfs_file.read()
dell_pfs_extractor = DellPfsExtract(input_object=pfs_data, extract_path='/path/to/output/directory/', padding=8)
dell_pfs_extractor.check_format(input_object=pfs_buffer)
dell_pfs_extractor.parse_format(input_object=pfs_buffer, extract_path='/path/to/output/directory/', padding=8)
is_supported = dell_pfs_extractor.check_format()
is_extracted = dell_pfs_extractor.parse_format()
```
#### Arguments
Each BIOSUtility expects the following required and optional arguments to check and/or parse a given file format:
##### input_object (required)
``` python
from biosutilities.phoenix_tdk_extract import PhoenixTdkExtract
phoenix_tdk_extractor = PhoenixTdkExtract(arguments=['-e', '/path/to/input/file.bin', '-o', '/path/to/output/folder/'])
phoenix_tdk_extractor.run_utility(padding=4)
input_object: str | bytes | bytearray = b''
```
##### extract_path (required)
``` python
from biosutilities.apple_efi_pbzx import AppleEfiPbzxExtract
apple_efi_pbzx_extractor = AppleEfiPbzxExtract()
apple_efi_pbzx_extractor.show_version(is_boxed=False, padding=12)
extract_path: str = ''
```
It also allows to use directly the four public methods which are inherited by every utility from the base BIOSUtility class.
#### run_utility
Run utility after checking for supported format
##### padding (optional)
``` python
run_utility(padding: int = 0) -> bool
padding: int = 0
```
#### check_format
If the required arguments are not provided, it is still possible to use the BIOSUtility-inherited instance to access
auxiliary public methods and class constants. However, checking and/or parsing of file formats will not yield results.
#### Methods
Once the BIOSUtility-inherited object is initialized with arguments, its two public methods can be called:
##### check_format
Check if input object is of specific supported format
``` python
check_format(input_object: str | bytes | bytearray) -> bool
is_supported: bool = check_format()
```
#### parse_format
##### parse_format
Process input object as a specific supported format
``` python
parse_format(input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool
```
#### show_version
Show title and version of utility
``` python
show_version(is_boxed: bool = True, padding: int = 0) -> None
is_extracted: bool = parse_format()
```
## Compatibility
@ -208,7 +183,7 @@ Parses AMI BIOS Guard (a.k.a. PFAT, Platform Firmware Armoring Technology) image
Note that the AMI PFAT structure may not have an explicit component order. AMI's BIOS Guard Firmware Update Tool (AFUBGT) updates components based on the user/OEM provided Parameters and Options or Index Information table, when applicable. Thus, merging all the components together does not usually yield a proper SPI/BIOS/UEFI image. The utility does generate such a merged file with the name "00 -- \<filename\>\_ALL.bin" but it is up to the end user to determine its usefulness. Additionally, any custom OEM data, after the AMI PFAT structure, is stored in the last file with the name "\<n+1\> -- \_OOB.bin" and it is once again up to the end user to determine its usefulness. In cases where the trailing custom OEM data includes a nested AMI PFAT structure, the utility will process and extract it automatically as well.
#### Usage
#### Arguments
No additional optional arguments are provided for this utility.
@ -224,11 +199,11 @@ Optionally, to decompile the AMI PFAT \> Intel BIOS Guard Scripts, you must have
Parses AMI UCP (Utility Configuration Program) Update executables, extracts their firmware components (e.g. SPI/BIOS/UEFI, EC, ME etc) and shows all relevant info. It supports all AMI UCP revisions and formats, including those with nested AMI PFAT, AMI UCP or Insyde iFlash/iFdPacker structures. The output comprises only final firmware components and utilities which are directly usable by end users.
#### Usage
#### Arguments
Additional optional arguments are provided for this utility:
* -c or --checksum : verify AMI UCP Checksums (slow)
* checksum -> bool : verify AMI UCP Checksums (slow)
#### Prerequisites
@ -249,7 +224,7 @@ Note: On Linux and macOS, you'll need to compile TianoCompress from sources as n
Parses Apple IM4P multi-EFI files and splits all detected EFI firmware into separate Intel SPI/BIOS images. The output comprises only final firmware components and utilities which are directly usable by end users.
#### Usage
#### Arguments
No additional optional arguments are provided for this utility.
@ -263,17 +238,17 @@ To run the utility, you do not need any prerequisites.
Parses Apple EFI images and identifies them based on Intel's official "IBIOSI" tag, which contains info such as Model, Version, Build, Date and Time. Additionally, the utility can provide both "IBIOSI" and "Apple ROM Version" structure info, when available, as well as a suggested EFI image filename, while also making sure to differentiate any EFI images with the same "IBIOSI" tag (e.g. Production, Pre-Production) by appending a checksum of their data.
#### Usage
#### Arguments
Additional optional arguments are provided for this utility:
* -q or --silent : suppress structure display
* silent -> bool : suppress structure display
The utility exposes certain public class attributes, once parse_format() method has been successfully executed:
* _efi_file_name_ -> str : Suggested image filename, based on Intel "IBIOSI" information
* _intel_bios_info_ -> dict[str, str] : Information contained at Intel "IBIOSI" structure
* _apple_rom_version_ -> defaultdict[str, set] : Information contained at "Apple ROM Version" structure
* efi_file_name -> str : Suggested image filename, based on Intel "IBIOSI" information
* intel_bios_info -> dict[str, str] : Information contained at Intel "IBIOSI" structure
* apple_rom_version -> defaultdict[str, set] : Information contained at "Apple ROM Version" structure
#### Prerequisites
@ -288,7 +263,7 @@ To run the utility, you must have the following 3rd party tools at PATH or "exte
Parses Apple EFI PKG firmware packages (e.g. FirmwareUpdate.pkg, BridgeOSUpdateCustomer.pkg, InstallAssistant.pkg, iMacEFIUpdate.pkg, iMacFirmwareUpdate.tar), extracts their EFI images, splits those in IM4P format and identifies/renames the final Intel SPI/BIOS images accordingly. The output comprises only final firmware components which are directly usable by end users.
#### Usage
#### Arguments
No additional optional arguments are provided for this utility.
@ -304,7 +279,7 @@ To run the utility, you must have the following 3rd party tools at PATH or "exte
Parses Apple EFI PBZX images, re-assembles their CPIO payload and extracts its firmware components (e.g. IM4P, EFI, Utilities, Scripts etc). It supports CPIO re-assembly from both Raw and XZ compressed PBZX Chunks. The output comprises only final firmware components and utilities which are directly usable by end users.
#### Usage
#### Arguments
No additional optional arguments are provided for this utility.
@ -320,7 +295,7 @@ To run the utility, you must have the following 3rd party tools at PATH or "exte
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
#### Arguments
No additional optional arguments are provided for this utility.
@ -336,12 +311,12 @@ To run the utility, you must have the following 3rd party tool at PATH or "exter
Parses Dell PFS Update images and extracts their Firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and Utilities (e.g. Flasher etc) component sections. It supports all Dell PFS revisions and formats, including those which are originally LZMA compressed in ThinOS packages (PKG), ZLIB compressed or Intel BIOS Guard (PFAT) protected. The output comprises only final firmware components which are directly usable by end users.
#### Usage
#### Arguments
Additional optional arguments are provided for this utility:
* -a or --advanced : extract signatures and metadata
* -s or --structure : show PFS structure information
* advanced -> bool : extract signatures and metadata
* structure -> bool : show PFS structure information
#### Prerequisites
@ -355,7 +330,7 @@ Optionally, to decompile the Intel BIOS Guard (PFAT) Scripts, you must have the
Parses Fujitsu SFX BIOS images and extracts their obfuscated Microsoft CAB archived firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and utilities (e.g. WinPhlash, PHLASH.INI etc) components. The output comprises only final firmware components which are directly usable by end users.
#### Usage
#### Arguments
No additional optional arguments are provided for this utility.
@ -371,7 +346,7 @@ To run the utility, you must have the following 3rd party tool at PATH or "exter
Parses Fujitsu UPC BIOS images and extracts their EFI compressed SPI/BIOS/UEFI firmware component. The output comprises only a final firmware component which is directly usable by end users.
#### Usage
#### Arguments
No additional optional arguments are provided for this utility.
@ -389,7 +364,7 @@ Note: On Linux and macOS, you'll need to compile TianoCompress from sources as n
Parses Insyde iFlash/iFdPacker Update images and extracts their firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and utilities (e.g. InsydeFlash, H2OFFT, FlsHook, iscflash, platform.ini etc) components. It supports all Insyde iFlash/iFdPacker revisions and formats, including those which are 7-Zip SFX 7z compressed in raw, obfuscated or password-protected form. The output comprises only final firmware components which are directly usable by end users.
#### Usage
#### Arguments
No additional optional arguments are provided for this utility.
@ -403,7 +378,7 @@ To run the utility, you do not need any prerequisites.
Parses Panasonic BIOS Package executables and extracts their firmware (e.g. SPI, BIOS/UEFI, EC etc) and utilities (e.g. winprom, configuration etc) components. It supports all Panasonic BIOS Package revisions and formats, including those which contain LZNT1 compressed files and/or AMI PFAT payloads. The output comprises only final firmware components which are directly usable by end users.
#### Usage
#### Arguments
No additional optional arguments are provided for this utility.
@ -424,7 +399,7 @@ Moreover, you must have the following 3rd party tool at PATH or "external":
Parses Phoenix Tools Development Kit (TDK) Packer executables and extracts their firmware (e.g. SPI, BIOS/UEFI, EC etc) and utilities (e.g. WinFlash etc) components. It supports all Phoenix TDK Packer revisions and formats, including those which contain LZMA compressed files. The output comprises only final firmware components which are directly usable by end users.
#### Usage
#### Arguments
No additional optional arguments are provided for this utility.
@ -440,7 +415,7 @@ To run the utility, you must have the following 3rd party Python module installe
Parses Portwell UEFI Unpacker EFI executables (usually named "Update.efi") and extracts their firmware (e.g. SPI, BIOS/UEFI, EC etc) and utilities (e.g. Flasher etc) components. It supports all known Portwell UEFI Unpacker revisions (v1.1, v1.2, v2.0) and formats (used, empty, null), including those which contain EFI compressed files. The output comprises only final firmware components and utilities which are directly usable by end users.
#### Usage
#### Arguments
No additional optional arguments are provided for this utility.
@ -462,7 +437,7 @@ Note: On Linux and macOS, you'll need to compile TianoCompress from sources as n
Parses Toshiba BIOS COM images and extracts their raw or compressed SPI/BIOS/UEFI firmware component. This utility is effectively a python wrapper around [ToshibaComExtractor by LongSoft](https://github.com/LongSoft/ToshibaComExtractor). The output comprises only a final firmware component which is directly usable by end users.
#### Usage
#### Arguments
No additional optional arguments are provided for this utility.
@ -480,7 +455,7 @@ Note: On Linux, you'll need to compile comextract from sources as no pre-built b
Parses VAIO Packaging Manager executables and extracts their firmware (e.g. SPI, BIOS/UEFI, EC, ME etc), utilities (e.g. WBFLASH etc) and driver (audio, video etc) components. If direct extraction fails, it attempts to unlock the executable in order to run at all non-VAIO systems and allow the user to choose the extraction location. It supports all VAIO Packaging Manager revisions and formats, including those which contain obfuscated Microsoft CAB archives or obfuscated unlock values. The output comprises only final firmware components which are directly usable by end users.
#### Usage
#### Arguments
No additional optional arguments are provided for this utility.

View file

@ -5,4 +5,4 @@
Copyright (C) 2018-2024 Plato Mavropoulos
"""
__version__ = '24.10.18'
__version__ = '24.10.23'

View file

@ -213,17 +213,17 @@ class AmiPfatExtract(BIOSUtility):
PFAT_INT_SIG_R3K_LEN: Final[int] = ctypes.sizeof(IntelBiosGuardSignatureRsa3k)
PFAT_INT_SIG_MAX_LEN: Final[int] = PFAT_INT_SIG_HDR_LEN + PFAT_INT_SIG_R3K_LEN
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is AMI BIOS Guard """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
return bool(self._get_ami_pfat(input_object=input_buffer))
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Process and store AMI BIOS Guard output file """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
pfat_buffer: bytes = self._get_ami_pfat(input_object=input_buffer)
@ -233,19 +233,19 @@ class AmiPfatExtract(BIOSUtility):
bg_sign_len: int = 0
extract_name: str = path_name(in_path=extract_path).removesuffix(extract_suffix())
extract_name: str = path_name(in_path=self.extract_path).removesuffix(extract_suffix())
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
block_all, block_off, file_count = self._parse_pfat_hdr(buffer=pfat_buffer, padding=padding)
block_all, block_off, file_count = self._parse_pfat_hdr(buffer=pfat_buffer, padding=self.padding)
for block in block_all:
file_desc, file_name, _, _, _, file_index, block_index, block_count = block
if block_index == 0:
printer(message=file_desc, padding=padding + 4)
printer(message=file_desc, padding=self.padding + 4)
file_path = os.path.join(extract_path, self._get_file_name(index=file_index + 1, name=file_name))
file_path = os.path.join(self.extract_path, self._get_file_name(index=file_index + 1, name=file_name))
all_blocks_dict[file_index] = b''
@ -253,9 +253,9 @@ class AmiPfatExtract(BIOSUtility):
bg_hdr: Any = ctypes_struct(buffer=pfat_buffer, start_offset=block_off, class_object=IntelBiosGuardHeader)
printer(message=f'Intel BIOS Guard {block_status} Header:\n', padding=padding + 8)
printer(message=f'Intel BIOS Guard {block_status} Header:\n', padding=self.padding + 8)
bg_hdr.struct_print(padding=padding + 12)
bg_hdr.struct_print(padding=self.padding + 12)
bg_script_bgn: int = block_off + self.PFAT_INT_HDR_LEN
bg_script_end: int = bg_script_bgn + bg_hdr.ScriptSize
@ -270,7 +270,7 @@ class AmiPfatExtract(BIOSUtility):
is_sfam, _, _, _, _ = bg_hdr.get_flags() # SFAM, ProtectEC, GFXMitDis, FTU, Reserved
if is_sfam:
printer(message=f'Intel BIOS Guard {block_status} Signature:\n', padding=padding + 8)
printer(message=f'Intel BIOS Guard {block_status} Signature:\n', padding=self.padding + 8)
# Manual BIOS Guard Signature length detection from Header pattern (e.g. Panasonic)
if bg_sign_len == 0:
@ -280,11 +280,11 @@ class AmiPfatExtract(BIOSUtility):
# Adjust next block to start after current block Data + Signature
block_off += self.parse_bg_sign(input_data=pfat_buffer, sign_offset=bg_data_end,
sign_length=bg_sign_len, print_info=True, padding=padding + 12)
sign_length=bg_sign_len, print_info=True, padding=self.padding + 12)
printer(message=f'Intel BIOS Guard {block_status} Script:\n', padding=padding + 8)
printer(message=f'Intel BIOS Guard {block_status} Script:\n', padding=self.padding + 8)
_ = self.parse_bg_script(script_data=pfat_buffer[bg_script_bgn:bg_script_end], padding=padding + 12)
_ = self.parse_bg_script(script_data=pfat_buffer[bg_script_bgn:bg_script_end], padding=self.padding + 12)
with open(file_path, 'ab') as out_dat:
out_dat.write(bg_data_bin)
@ -292,27 +292,33 @@ class AmiPfatExtract(BIOSUtility):
all_blocks_dict[file_index] += bg_data_bin
if block_index + 1 == block_count:
if self.check_format(input_object=all_blocks_dict[file_index]):
self.parse_format(input_object=all_blocks_dict[file_index],
extract_path=extract_folder(file_path), padding=padding + 8)
ami_pfat_extract: AmiPfatExtract = AmiPfatExtract(
input_object=all_blocks_dict[file_index], extract_path=extract_folder(file_path),
padding=self.padding + 8)
if ami_pfat_extract.check_format():
ami_pfat_extract.parse_format()
pfat_oob_data: bytes = pfat_buffer[block_off:] # Store out-of-bounds data after the end of PFAT files
pfat_oob_name: str = self._get_file_name(index=file_count + 1, name=f'{extract_name}_OOB.bin')
pfat_oob_path: str = os.path.join(extract_path, pfat_oob_name)
pfat_oob_path: str = os.path.join(self.extract_path, pfat_oob_name)
with open(pfat_oob_path, 'wb') as out_oob:
out_oob.write(pfat_oob_data)
if self.check_format(input_object=pfat_oob_data):
self.parse_format(input_object=pfat_oob_data, extract_path=extract_folder(pfat_oob_path), padding=padding)
ami_pfat_extract = AmiPfatExtract(
input_object=pfat_oob_data, extract_path=extract_folder(pfat_oob_path), padding=self.padding)
if ami_pfat_extract.check_format():
ami_pfat_extract.parse_format()
in_all_data: bytes = b''.join([block[1] for block in sorted(all_blocks_dict.items())])
in_all_name: str = self._get_file_name(index=0, name=f'{extract_name}_ALL.bin')
in_all_path: str = os.path.join(extract_path, in_all_name)
in_all_path: str = os.path.join(self.extract_path, in_all_name)
with open(in_all_path, 'wb') as out_all:
out_all.write(in_all_data + pfat_oob_data)
@ -471,7 +477,3 @@ class AmiPfatExtract(BIOSUtility):
printer(message=block[0], padding=padding + 8, new_line=False)
return block_all, hdr_size, files_count
if __name__ == '__main__':
AmiPfatExtract().run_utility()

View file

@ -183,10 +183,6 @@ class AmiUcpExtract(BIOSUtility):
TITLE: str = 'AMI UCP Update Extractor'
ARGUMENTS: list[tuple[list[str], dict[str, str]]] = [
(['-c', '--checksum'], {'help': 'verify AMI UCP Checksums (slow)', 'action': 'store_true'})
]
# Get common ctypes Structure Sizes
UAF_HDR_LEN: Final[int] = ctypes.sizeof(UafHeader)
UAF_MOD_LEN: Final[int] = ctypes.sizeof(UafModule)
@ -254,23 +250,29 @@ class AmiUcpExtract(BIOSUtility):
'@W64': ['amifldrv64.sys', 'amifldrv64.sys', '']
}
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def __init__(self, input_object: str | bytes | bytearray = b'', extract_path: str = '', padding: int = 0,
checksum: bool = False) -> None:
super().__init__(input_object=input_object, extract_path=extract_path, padding=padding)
self.checksum: bool = checksum
def check_format(self) -> bool:
""" Check if input is AMI UCP image """
buffer: bytes = file_to_bytes(in_object=input_object)
buffer: bytes = file_to_bytes(in_object=self.input_object)
return bool(self._get_ami_ucp(input_object=buffer)[0])
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract AMI UCP structures """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
nal_dict: dict[str, tuple[str, str]] = {} # Initialize @NAL Dictionary per UCP
printer(message='Utility Configuration Program', padding=padding)
printer(message='Utility Configuration Program', padding=self.padding)
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
# Get best AMI UCP Pattern match based on @UAF|@HPU Size
ucp_buffer, ucp_tag = self._get_ami_ucp(input_object=input_buffer)
@ -278,9 +280,9 @@ class AmiUcpExtract(BIOSUtility):
# Parse @UAF|@HPU Header Structure
uaf_hdr: Any = ctypes_struct(buffer=ucp_buffer, start_offset=0, class_object=UafHeader)
printer(message=f'Utility Auxiliary File > {ucp_tag}:\n', padding=padding + 4)
printer(message=f'Utility Auxiliary File > {ucp_tag}:\n', padding=self.padding + 4)
uaf_hdr.struct_print(padding=padding + 8)
uaf_hdr.struct_print(padding=self.padding + 8)
fake = struct.pack('<II', len(ucp_buffer), len(ucp_buffer)) # Generate UafModule Structure
@ -292,16 +294,16 @@ class AmiUcpExtract(BIOSUtility):
uaf_desc = self.UAF_TAG_DICT[ucp_tag][1] # Get @UAF|@HPU Module Description
# Print @UAF|@HPU Module EFI Info
uaf_mod.struct_print(filename=uaf_name, description=uaf_desc, padding=padding + 8)
uaf_mod.struct_print(filename=uaf_name, description=uaf_desc, padding=self.padding + 8)
if self.arguments.checksum:
self._chk16_validate(data=ucp_buffer, tag=ucp_tag, padding=padding + 8)
if self.checksum:
self._chk16_validate(data=ucp_buffer, tag=ucp_tag, padding=self.padding + 8)
uaf_all = self._get_uaf_mod(buffer=ucp_buffer, uaf_off=self.UAF_HDR_LEN)
for mod_info in uaf_all:
nal_dict = self._uaf_extract(buffer=ucp_buffer, extract_path=extract_path, mod_info=mod_info,
nal_dict=nal_dict, padding=padding + 8)
nal_dict = self._uaf_extract(buffer=ucp_buffer, extract_path=self.extract_path, mod_info=mod_info,
nal_dict=nal_dict, padding=self.padding + 8)
return True
@ -421,7 +423,7 @@ class AmiUcpExtract(BIOSUtility):
not uaf_tag.startswith(('@ROM', '@R0', '@S0', '@DR', '@DS')):
printer(message=f'Note: Detected new AMI UCP Module {uaf_tag} ({nal_dict[uaf_tag][1]}) in @NAL!',
padding=padding + 4, pause=not self.arguments.auto_exit)
padding=padding + 4)
# Generate @UAF|@HPU Module File name, depending on whether decompression will be required
uaf_sname: str = safe_name(in_name=uaf_name + ('.temp' if is_comp else uaf_fext))
@ -435,7 +437,7 @@ class AmiUcpExtract(BIOSUtility):
else:
uaf_fname = safe_path(base_path=extract_path, user_paths=uaf_sname)
if self.arguments.checksum:
if self.checksum:
self._chk16_validate(data=uaf_data_all, tag=uaf_tag, padding=padding + 4)
# Parse Utility Identification Information @UAF|@HPU Module (@UII)
@ -453,7 +455,7 @@ class AmiUcpExtract(BIOSUtility):
info_hdr.struct_print(description=info_desc, padding=padding + 8) # Print @UII Module Info
if self.arguments.checksum:
if self.checksum:
self._chk16_validate(data=uaf_data_raw, tag='@UII > Info', padding=padding + 8)
# Store/Save @UII Module Info in file
@ -562,25 +564,25 @@ class AmiUcpExtract(BIOSUtility):
# Assign a file path & name to each Tag
nal_dict[info_tag] = (info_path, info_name)
insyde_ifd_extract: InsydeIfdExtract = InsydeIfdExtract()
# Parse Insyde BIOS @UAF|@HPU Module (@INS)
if uaf_tag == '@INS' and insyde_ifd_extract.check_format(input_object=uaf_fname):
# Generate extraction directory
if uaf_tag == '@INS':
ins_dir: str = os.path.join(extract_path, safe_name(in_name=f'{uaf_tag}_nested-IFD'))
if insyde_ifd_extract.parse_format(input_object=uaf_fname, extract_path=extract_folder(ins_dir),
padding=padding + 4):
insyde_ifd_extract: InsydeIfdExtract = InsydeIfdExtract(
input_object=uaf_fname, extract_path=extract_folder(ins_dir), padding=padding + 4)
if insyde_ifd_extract.check_format():
if insyde_ifd_extract.parse_format():
os.remove(uaf_fname) # Delete raw nested Insyde IFD image after successful extraction
ami_pfat_extract: AmiPfatExtract = AmiPfatExtract()
# Detect & Unpack AMI BIOS Guard (PFAT) BIOS image
if ami_pfat_extract.check_format(input_object=uaf_data_raw):
pfat_dir: str = os.path.join(extract_path, safe_name(in_name=uaf_name))
ami_pfat_extract.parse_format(input_object=uaf_data_raw, extract_path=extract_folder(pfat_dir),
padding=padding + 4)
ami_pfat_extract: AmiPfatExtract = AmiPfatExtract(
input_object=uaf_data_raw, extract_path=extract_folder(pfat_dir), padding=padding + 4)
# Detect & Unpack AMI BIOS Guard (PFAT) BIOS image
if ami_pfat_extract.check_format():
ami_pfat_extract.parse_format()
os.remove(uaf_fname) # Delete raw PFAT BIOS image after successful extraction
@ -590,18 +592,15 @@ class AmiUcpExtract(BIOSUtility):
printer(message='Use "ME Analyzer" from https://github.com/platomav/MEAnalyzer',
padding=padding + 8, new_line=False)
# Parse Nested AMI UCP image
if self.check_format(input_object=uaf_data_raw):
# Generate extraction directory
uaf_dir: str = os.path.join(extract_path, safe_name(in_name=f'{uaf_tag}_nested-UCP'))
uaf_dir: str = extract_folder(os.path.join(extract_path, safe_name(in_name=f'{uaf_tag}_nested-UCP')))
self.parse_format(input_object=uaf_data_raw, extract_path=extract_folder(uaf_dir),
padding=padding + 4) # Call recursively
ami_ucp_extract: AmiUcpExtract = AmiUcpExtract(
input_object=uaf_data_raw, extract_path=uaf_dir, padding=padding + 4, checksum=self.checksum)
# Parse Nested AMI UCP image
if ami_ucp_extract.check_format():
ami_ucp_extract.parse_format()
os.remove(uaf_fname) # Delete raw nested AMI UCP image after successful extraction
return nal_dict
if __name__ == '__main__':
AmiUcpExtract().run_utility()

View file

@ -116,31 +116,31 @@ class AppleEfiIdentify(BIOSUtility):
TITLE: str = 'Apple EFI Image Identifier'
ARGUMENTS: list[tuple[list[str], dict[str, str]]] = [
(['-q', '--silent'], {'help': 'suppress structure display', 'action': 'store_true'})
]
PAT_UEFIFIND: Final[str] = f'244942494F534924{"." * 32}2E00{"." * 12}2E00{"." * 16}2E00{"." * 12}2E00{"." * 40}00'
def __init__(self, arguments: list[str] | None = None) -> None:
super().__init__(arguments=arguments)
def __init__(self, input_object: str | bytes | bytearray = b'', extract_path: str = '', padding: int = 0,
silent: bool = False) -> None:
super().__init__(input_object=input_object, extract_path=extract_path, padding=padding)
self.silent: bool = silent
self.efi_file_name: str = ''
self.intel_bios_info: dict[str, str] = {}
self.apple_rom_version: defaultdict[str, set] = defaultdict(set)
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is Apple EFI image """
if isinstance(input_object, str) and is_file(in_path=input_object) and is_access(in_path=input_object):
if path_suffixes(in_path=input_object)[-1].lower() not in ('.fd', '.scap', '.im4p'):
if isinstance(self.input_object, str) and is_file(in_path=self.input_object) and is_access(
in_path=self.input_object):
if path_suffixes(in_path=self.input_object)[-1].lower() not in ('.fd', '.scap', '.im4p'):
return False
input_path: str = input_object
input_path: str = self.input_object
input_buffer: bytes = file_to_bytes(in_object=input_path)
elif isinstance(input_object, (bytes, bytearray)):
elif isinstance(self.input_object, (bytes, bytearray)):
input_path = os.path.join(runtime_root(), 'APPLE_EFI_ID_INPUT_BUFFER_CHECK.tmp')
input_buffer = input_object
input_buffer = self.input_object
with open(input_path, 'wb') as check_out:
check_out.write(input_buffer)
@ -160,16 +160,16 @@ class AppleEfiIdentify(BIOSUtility):
return False
finally:
if input_path != input_object:
if input_path != self.input_object:
delete_file(in_path=input_path)
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Identify (or Rename) Apple EFI image """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
if isinstance(input_object, str) and is_file(in_path=input_object):
input_path: str = input_object
if isinstance(self.input_object, str) and is_file(in_path=self.input_object):
input_path: str = self.input_object
else:
input_path = os.path.join(runtime_root(), 'APPLE_EFI_ID_INPUT_BUFFER_PARSE.bin')
@ -190,12 +190,12 @@ class AppleEfiIdentify(BIOSUtility):
self.PAT_UEFIFIND], text=True)[:36]
# UEFIExtract must create its output folder itself
delete_dirs(in_path=extract_path)
delete_dirs(in_path=self.extract_path)
_ = subprocess.run([uefiextract_path(), input_path, bios_id_res, '-o', extract_path, '-m', 'body'],
_ = subprocess.run([uefiextract_path(), input_path, bios_id_res, '-o', self.extract_path, '-m', 'body'],
check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
with open(os.path.join(extract_path, 'body.bin'), 'rb') as raw_body:
with open(os.path.join(self.extract_path, 'body.bin'), 'rb') as raw_body:
body_buffer: bytes = raw_body.read()
# Detect decompressed $IBIOSI$ pattern
@ -207,25 +207,25 @@ class AppleEfiIdentify(BIOSUtility):
bios_id_hdr = ctypes_struct(buffer=body_buffer, start_offset=bios_id_match.start(),
class_object=IntelBiosId)
delete_dirs(in_path=extract_path) # Successful UEFIExtract extraction, remove its output folder
delete_dirs(in_path=self.extract_path) # Successful UEFIExtract extraction, remove its output folder
except Exception as error: # pylint: disable=broad-except
printer(message=f'Error: Failed to parse compressed $IBIOSI$ pattern: {error}!', padding=padding)
printer(message=f'Error: Failed to parse compressed $IBIOSI$ pattern: {error}!', padding=self.padding)
return False
if not self.arguments.silent:
printer(message=f'Detected Intel BIOS Info at {bios_id_res}\n', padding=padding)
if not self.silent:
printer(message=f'Detected Intel BIOS Info at {bios_id_res}\n', padding=self.padding)
bios_id_hdr.struct_print(padding=padding + 4)
bios_id_hdr.struct_print(padding=self.padding + 4)
self.intel_bios_info = bios_id_hdr.get_bios_id()
self.efi_file_name = (f'{self.intel_bios_info["efi_name_id"]}_{zlib.adler32(input_buffer):08X}'
f'{path_suffixes(in_path=input_path)[-1]}')
_ = self._apple_rom_version(input_buffer=input_buffer, padding=padding)
_ = self._apple_rom_version(input_buffer=input_buffer, padding=self.padding)
if input_path != input_object:
if input_path != self.input_object:
delete_file(in_path=input_path)
return True
@ -255,7 +255,7 @@ class AppleEfiIdentify(BIOSUtility):
self.apple_rom_version[rom_version_parts[0].strip()].add(rom_version_parts[1].strip())
if not self.arguments.silent:
if not self.silent:
printer(message=f'Detected Apple ROM Version at 0x{rom_version_match_off:X}', padding=padding)
printer(message=rom_version_text, strip=True, padding=padding + 4)
@ -263,7 +263,3 @@ class AppleEfiIdentify(BIOSUtility):
return True
return False
if __name__ == '__main__':
AppleEfiIdentify().run_utility()

View file

@ -27,27 +27,27 @@ class AppleEfiIm4pSplit(BIOSUtility):
# Intel Flash Descriptor Component Sizes (2MB, 4MB, 8MB, 16MB and 32MB)
IFD_COMP_LEN: Final[dict[int, int]] = {2: 0x200000, 3: 0x400000, 4: 0x800000, 5: 0x1000000, 6: 0x2000000}
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is Apple EFI IM4P image """
if isinstance(input_object, str) and not input_object.lower().endswith('.im4p'):
if isinstance(self.input_object, str) and not self.input_object.lower().endswith('.im4p'):
return False
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
if PAT_APPLE_IM4P.search(input_buffer) and PAT_INTEL_FD.search(input_buffer):
return True
return False
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Split Apple EFI IM4P image """
parse_success: bool = True
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
# Detect IM4P EFI pattern
im4p_match: Match[bytes] | None = PAT_APPLE_IM4P.search(input_buffer)
@ -138,23 +138,19 @@ class AppleEfiIm4pSplit(BIOSUtility):
output_size: int = len(output_data)
output_name: str = path_stem(in_path=input_object) if isinstance(input_object, str) else 'Part'
output_name: str = path_stem(in_path=self.input_object) if isinstance(self.input_object, str) else 'Part'
output_path: str = os.path.join(extract_path, f'{output_name}_[{ifd_data_txt}].fd')
output_path: str = os.path.join(self.extract_path, f'{output_name}_[{ifd_data_txt}].fd')
with open(output_path, 'wb') as output_image:
output_image.write(output_data)
printer(message=f'Split Apple EFI image at {ifd_data_txt}!', padding=padding)
printer(message=f'Split Apple EFI image at {ifd_data_txt}!', padding=self.padding)
if output_size != ifd_comp_all_size:
printer(message=f'Error: Bad image size 0x{output_size:07X}, expected 0x{ifd_comp_all_size:07X}!',
padding=padding + 4)
padding=self.padding + 4)
parse_success = False
return parse_success
if __name__ == '__main__':
AppleEfiIm4pSplit().run_utility()

View file

@ -51,19 +51,19 @@ class AppleEfiPbzxExtract(BIOSUtility):
PBZX_CHUNK_HDR_LEN: Final[int] = ctypes.sizeof(PbzxChunk)
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is Apple PBZX image """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
return bool(PAT_APPLE_PBZX.search(input_buffer, 0, 4))
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract Apple PBZX image """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
cpio_bin: bytes = b'' # Initialize PBZX > CPIO Buffer
@ -74,9 +74,9 @@ class AppleEfiPbzxExtract(BIOSUtility):
while chunk_off < len(input_buffer):
chunk_hdr: Any = ctypes_struct(buffer=input_buffer, start_offset=chunk_off, class_object=PbzxChunk)
printer(message=f'PBZX Chunk at 0x{chunk_off:08X}\n', padding=padding)
printer(message=f'PBZX Chunk at 0x{chunk_off:08X}\n', padding=self.padding)
chunk_hdr.struct_print(padding=padding + 4)
chunk_hdr.struct_print(padding=self.padding + 4)
# PBZX Chunk data starts after its Header
comp_bgn: int = chunk_off + self.PBZX_CHUNK_HDR_LEN
@ -90,7 +90,7 @@ class AppleEfiPbzxExtract(BIOSUtility):
# Attempt XZ decompression, if applicable to Chunk data
cpio_bin += lzma.LZMADecompressor().decompress(comp_bin)
printer(message='Successful LZMA decompression!', padding=padding + 8)
printer(message='Successful LZMA decompression!', padding=self.padding + 8)
except Exception as error: # pylint: disable=broad-except
logging.debug('Error: Failed to LZMA decompress PBZX Chunk 0x%X: %s', chunk_off, error)
@ -105,21 +105,21 @@ class AppleEfiPbzxExtract(BIOSUtility):
# Check that CPIO size is valid based on all Chunks > Initial Size
if cpio_len != len(cpio_bin):
printer(message='Error: Unexpected CPIO archive size!', padding=padding)
printer(message='Error: Unexpected CPIO archive size!', padding=self.padding)
return False
cpio_name: str = path_stem(in_path=input_object) if isinstance(input_object, str) else 'Payload'
cpio_name: str = path_stem(in_path=self.input_object) if isinstance(self.input_object, str) else 'Payload'
cpio_path: str = os.path.join(extract_path, f'{cpio_name}.cpio')
cpio_path: str = os.path.join(self.extract_path, f'{cpio_name}.cpio')
with open(cpio_path, 'wb') as cpio_object:
cpio_object.write(cpio_bin)
# Decompress PBZX > CPIO archive with 7-Zip
if is_szip_supported(in_path=cpio_path, padding=padding, args=['-tCPIO'], silent=False):
if szip_decompress(in_path=cpio_path, out_path=extract_path, in_name='CPIO',
padding=padding, args=['-tCPIO']):
if is_szip_supported(in_path=cpio_path, padding=self.padding, args=['-tCPIO'], silent=False):
if szip_decompress(in_path=cpio_path, out_path=self.extract_path, in_name='CPIO',
padding=self.padding, args=['-tCPIO']):
os.remove(cpio_path) # Successful extraction, delete PBZX > CPIO archive
else:
return False
@ -127,7 +127,3 @@ class AppleEfiPbzxExtract(BIOSUtility):
return False
return True
if __name__ == '__main__':
AppleEfiPbzxExtract().run_utility()

View file

@ -26,15 +26,15 @@ class AppleEfiPkgExtract(BIOSUtility):
TITLE: str = 'Apple EFI Package Extractor'
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is Apple EFI PKG package """
is_apple_efi_pkg: bool = False
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
if isinstance(input_object, str) and is_file(in_path=input_object):
input_path: str = input_object
if isinstance(self.input_object, str) and is_file(in_path=self.input_object):
input_path: str = self.input_object
else:
input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_CHECK.bin')
@ -47,45 +47,45 @@ class AppleEfiPkgExtract(BIOSUtility):
break
if input_path != input_object:
if input_path != self.input_object:
os.remove(input_path)
return is_apple_efi_pkg
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract Apple EFI PKG packages """
if isinstance(input_object, str) and is_file(in_path=input_object):
input_path: str = input_object
if isinstance(self.input_object, str) and is_file(in_path=self.input_object):
input_path: str = self.input_object
else:
input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_PARSE.bin')
with open(input_path, 'wb') as input_path_object:
input_path_object.write(file_to_bytes(in_object=input_object))
input_path_object.write(file_to_bytes(in_object=self.input_object))
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
working_dir: str = os.path.join(extract_path, 'temp')
working_dir: str = os.path.join(self.extract_path, 'temp')
make_dirs(in_path=working_dir)
for pkg_type in ('XAR', 'TAR', 'DMG'):
if is_szip_supported(in_path=input_path, padding=padding, args=[f'-t{pkg_type}']):
if szip_decompress(in_path=input_path, out_path=working_dir, in_name=pkg_type, padding=padding,
if is_szip_supported(in_path=input_path, padding=self.padding, args=[f'-t{pkg_type}']):
if szip_decompress(in_path=input_path, out_path=working_dir, in_name=pkg_type, padding=self.padding,
args=None if pkg_type == 'DMG' else [f'-t{pkg_type}']):
break
else:
return False
if input_path != input_object:
if input_path != self.input_object:
os.remove(input_path)
for work_file in path_files(in_path=working_dir):
if is_file(in_path=work_file) and is_access(in_path=work_file):
self._pbzx_zip(input_path=work_file, extract_path=extract_path, padding=padding + 4)
self._gzip_cpio(input_path=work_file, extract_path=extract_path, padding=padding + 4)
self._dmg_zip(input_path=work_file, extract_path=extract_path, padding=padding + 4)
self._xar_gzip(input_path=work_file, extract_path=extract_path, padding=padding + 4)
self._pbzx_zip(input_path=work_file, extract_path=self.extract_path, padding=self.padding + 4)
self._gzip_cpio(input_path=work_file, extract_path=self.extract_path, padding=self.padding + 4)
self._dmg_zip(input_path=work_file, extract_path=self.extract_path, padding=self.padding + 4)
self._xar_gzip(input_path=work_file, extract_path=self.extract_path, padding=self.padding + 4)
delete_dirs(in_path=working_dir)
@ -126,15 +126,16 @@ class AppleEfiPkgExtract(BIOSUtility):
def _pbzx_zip(self, input_path: str, extract_path: str, padding: int = 0) -> None:
""" PBZX > ZIP """
pbzx_module: AppleEfiPbzxExtract = AppleEfiPbzxExtract()
if pbzx_module.check_format(input_object=input_path):
printer(message=f'Extracting PBZX via {pbzx_module.title}', padding=padding)
pbzx_path: str = extract_folder(in_path=input_path, suffix='_pbzx_zip')
if pbzx_module.parse_format(input_object=input_path, extract_path=pbzx_path, padding=padding + 4):
printer(message=f'Successful PBZX extraction via {pbzx_module.title}!', padding=padding)
pbzx_module: AppleEfiPbzxExtract = AppleEfiPbzxExtract(
input_object=input_path, extract_path=pbzx_path, padding=padding + 4)
if pbzx_module.check_format():
printer(message=f'Extracting PBZX via {pbzx_module.TITLE}', padding=padding)
if pbzx_module.parse_format():
printer(message=f'Successful PBZX extraction via {pbzx_module.TITLE}!', padding=padding)
for pbzx_file in path_files(in_path=pbzx_path):
if is_file(in_path=pbzx_file) and is_access(in_path=pbzx_file):
@ -174,7 +175,7 @@ class AppleEfiPkgExtract(BIOSUtility):
if path_suffixes(in_path=input_path)[-1].lower() not in ('.fd', '.scap', '.im4p'):
return None
if not AppleEfiIdentify().check_format(input_object=input_path):
if not AppleEfiIdentify(input_object=input_path).check_format():
return None
input_name: str = path_name(in_path=input_path)
@ -183,12 +184,13 @@ class AppleEfiPkgExtract(BIOSUtility):
working_dir: str = extract_folder(in_path=input_path)
im4p_module: AppleEfiIm4pSplit = AppleEfiIm4pSplit()
im4p_module: AppleEfiIm4pSplit = AppleEfiIm4pSplit(
input_object=input_path, extract_path=working_dir, padding=padding + 8)
if im4p_module.check_format(input_object=input_path):
printer(message=f'Splitting IM4P via {im4p_module.title}', padding=padding + 4)
if im4p_module.check_format():
printer(message=f'Splitting IM4P via {im4p_module.TITLE}', padding=padding + 4)
im4p_module.parse_format(input_object=input_path, extract_path=working_dir, padding=padding + 8)
im4p_module.parse_format()
else:
make_dirs(in_path=working_dir, delete=True)
@ -196,13 +198,13 @@ class AppleEfiPkgExtract(BIOSUtility):
for efi_source in path_files(in_path=working_dir):
if is_file(in_path=efi_source) and is_access(in_path=efi_source):
efi_id_module: AppleEfiIdentify = AppleEfiIdentify()
efi_id_module: AppleEfiIdentify = AppleEfiIdentify(
input_object=efi_source, extract_path=extract_folder(in_path=efi_source), padding=padding + 8)
if efi_id_module.check_format(input_object=efi_source):
printer(message=f'Identifying EFI via {efi_id_module.title}', padding=padding + 4)
if efi_id_module.check_format():
printer(message=f'Identifying EFI via {efi_id_module.TITLE}', padding=padding + 4)
if efi_id_module.parse_format(input_object=efi_source, extract_path=extract_folder(
in_path=efi_source), padding=padding + 8):
if efi_id_module.parse_format():
efi_dest: str = os.path.join(path_parent(in_path=efi_source), efi_id_module.efi_file_name)
os.replace(efi_source, efi_dest)
@ -214,7 +216,3 @@ class AppleEfiPkgExtract(BIOSUtility):
delete_dirs(in_path=working_dir)
return None
if __name__ == '__main__':
AppleEfiPkgExtract().run_utility()

View file

@ -22,19 +22,19 @@ class AwardBiosExtract(BIOSUtility):
TITLE: str = 'Award BIOS Module Extractor'
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is Award BIOS image """
in_buffer: bytes = file_to_bytes(in_object=input_object)
in_buffer: bytes = file_to_bytes(in_object=self.input_object)
return bool(PAT_AWARD_LZH.search(in_buffer))
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract Award BIOS image """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
for lzh_match in PAT_AWARD_LZH.finditer(input_buffer):
lzh_type: str = lzh_match.group(0).decode('utf-8')
@ -52,7 +52,7 @@ class AwardBiosExtract(BIOSUtility):
if len(mod_bin) != 0x2 + hdr_len + mod_len:
printer(message=f'Error: Skipped incomplete LZH stream at 0x{mod_bgn:X}!',
padding=padding, new_line=True)
padding=self.padding, new_line=True)
continue
@ -61,9 +61,9 @@ class AwardBiosExtract(BIOSUtility):
else:
tag_txt = f'{mod_bgn:X}_{mod_end:X}'
printer(message=f'{lzh_text} > {tag_txt} [0x{mod_bgn:06X}-0x{mod_end:06X}]', padding=padding)
printer(message=f'{lzh_text} > {tag_txt} [0x{mod_bgn:06X}-0x{mod_end:06X}]', padding=self.padding)
mod_path: str = os.path.join(extract_path, tag_txt)
mod_path: str = os.path.join(self.extract_path, tag_txt)
lzh_path: str = f'{mod_path}.lzh'
@ -71,8 +71,8 @@ class AwardBiosExtract(BIOSUtility):
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(in_path=lzh_path, out_path=extract_path, in_name=lzh_text,
padding=padding + 4)
szip_decompress(in_path=lzh_path, out_path=self.extract_path, in_name=lzh_text,
padding=self.padding + 4)
# Manually check if 7-Zip extracted LZH due to its CRC check issue
if is_file(in_path=mod_path):
@ -80,14 +80,11 @@ class AwardBiosExtract(BIOSUtility):
os.remove(lzh_path) # Successful extraction, delete LZH archive
award_bios_extract: AwardBiosExtract = AwardBiosExtract(
input_object=mod_path, extract_path=extract_folder(mod_path), padding=self.padding + 8)
# Extract any nested LZH archives
if self.check_format(input_object=mod_path):
# Recursively extract nested Award BIOS modules
self.parse_format(input_object=mod_path, extract_path=extract_folder(mod_path),
padding=padding + 8)
if award_bios_extract.check_format():
award_bios_extract.parse_format()
return True
if __name__ == '__main__':
AwardBiosExtract().run_utility()

View file

@ -30,7 +30,7 @@ def python_version() -> tuple:
def printer(message: str | list | tuple | None = None, padding: int = 0, new_line: bool = True,
pause: bool = False, sep_char: str = ' ', strip: bool = False) -> None:
sep_char: str = ' ', strip: bool = False) -> None:
""" Show message(s), controlling padding, newline, stripping, pausing & separating """
message_string: str = to_string(in_object='' if message is None else message, sep_char=sep_char)
@ -44,7 +44,4 @@ def printer(message: str | list | tuple | None = None, padding: int = 0, new_lin
message_output += f'{line_new}{" " * padding}{line_text}'
if pause:
input(message_output)
else:
print(message_output)

View file

@ -5,161 +5,23 @@
Copyright (C) 2022-2024 Plato Mavropoulos
"""
import os
import sys
from argparse import ArgumentParser, Namespace
from typing import Final
from biosutilities import __version__
from biosutilities.common.paths import (delete_dirs, extract_folder, is_access, is_dir, is_file, is_empty_dir,
path_files, path_name, path_parent, real_path, runtime_root)
from biosutilities.common.system import system_platform, python_version, printer
from biosutilities.common.texts import remove_quotes, to_boxed, to_ordinal
class BIOSUtility:
""" Base utility class for BIOSUtilities """
TITLE: str = 'BIOS Utility'
ARGUMENTS: list[tuple[list[str], dict[str, str]]] = []
def __init__(self, input_object: str | bytes | bytearray = b'', extract_path: str = '', padding: int = 0) -> None:
self.input_object: str | bytes | bytearray = input_object
self.extract_path: str = extract_path
self.padding: int = padding
MAX_FAT32_ITEMS: Final[int] = 65535
MIN_PYTHON_VER: Final[tuple[int, int]] = (3, 10)
def __init__(self, arguments: list[str] | None = None) -> None:
self.title: str = f'{self.TITLE.strip()} v{__version__}'
argparser: ArgumentParser = ArgumentParser(allow_abbrev=False)
argparser.add_argument('paths', nargs='*')
argparser.add_argument('-e', '--auto-exit', help='skip user action prompts', action='store_true')
argparser.add_argument('-o', '--output-dir', help='output extraction directory')
for argument in self.ARGUMENTS:
argparser.add_argument(*argument[0], **argument[1]) # type: ignore
sys_argv: list[str] = arguments if isinstance(arguments, list) and arguments else sys.argv[1:]
self.arguments: Namespace = argparser.parse_known_args(sys_argv)[0]
self._input_files: list[str] = []
self._output_path: str = ''
def run_utility(self, padding: int = 0) -> bool:
""" Run utility after checking for supported format """
self._check_sys_py()
self._check_sys_os()
self.show_version(padding=padding)
self._setup_input_files(padding=padding)
self._setup_output_dir(padding=padding)
exit_code: int = len(self._input_files)
for input_file in self._input_files:
input_name: str = path_name(in_path=input_file, limit=True)
printer(message=input_name, padding=padding + 4)
if not self.check_format(input_object=input_file):
printer(message='Error: This is not a supported format!', padding=padding + 8)
continue
extract_path: str = os.path.join(self._output_path, extract_folder(in_path=input_name))
if is_dir(in_path=extract_path):
for suffix in range(2, self.MAX_FAT32_ITEMS):
renamed_path: str = f'{os.path.normpath(extract_path)}_{to_ordinal(in_number=suffix)}'
if not is_dir(in_path=renamed_path):
extract_path = renamed_path
break
if self.parse_format(input_object=input_file, extract_path=extract_path, padding=padding + 8):
exit_code -= 1
if is_empty_dir(in_path=extract_path):
delete_dirs(in_path=extract_path)
printer(message='Done!\n' if not self.arguments.auto_exit else None, pause=not self.arguments.auto_exit)
return exit_code == 0
def show_version(self, is_boxed: bool = True, padding: int = 0) -> None:
""" Show title and version of utility """
printer(message=to_boxed(in_text=self.title) if is_boxed else self.title, new_line=False, padding=padding)
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
""" Process input object as a specific supported format """
raise NotImplementedError(f'Method "parse_format" not implemented at {__name__}')
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input object is of specific supported format """
raise NotImplementedError(f'Method "check_format" not implemented at {__name__}')
def _setup_input_files(self, padding: int = 0) -> None:
self._input_files = []
def parse_format(self) -> bool:
""" Process input object as a specific supported format """
input_paths: list[str] = self.arguments.paths
if not input_paths:
input_paths = [remove_quotes(in_text=input(f'\n{" " * padding}Enter input file or directory path: '))]
for input_path in [input_path for input_path in input_paths if input_path]:
input_path_real: str = real_path(in_path=input_path)
if is_dir(in_path=input_path_real):
for input_file in path_files(in_path=input_path_real):
if is_file(in_path=input_file) and is_access(in_path=input_file):
self._input_files.append(input_file)
elif is_file(in_path=input_path_real) and is_access(in_path=input_path_real):
self._input_files.append(input_path_real)
def _setup_output_dir(self, padding: int = 0) -> None:
self._output_path = ''
output_path: str = self.arguments.output_dir
if not output_path:
output_path = remove_quotes(in_text=input(f'\n{" " * padding}Enter output directory path: '))
if not output_path and self._input_files:
output_path = str(path_parent(in_path=self._input_files[0]))
if output_path and is_dir(in_path=output_path) and is_access(in_path=output_path):
self._output_path = output_path
else:
self._output_path = runtime_root()
def _check_sys_py(self) -> None:
""" Check Python Version """
sys_py: tuple = python_version()
if sys_py < self.MIN_PYTHON_VER:
min_py_str: str = '.'.join(map(str, self.MIN_PYTHON_VER))
sys_py_str: str = '.'.join(map(str, sys_py[:2]))
raise RuntimeError(f'Python >= {min_py_str} required, not {sys_py_str}')
@staticmethod
def _check_sys_os() -> None:
""" Check OS Platform """
os_tag, is_win, is_lnx = system_platform()
if not (is_win or is_lnx):
raise OSError(f'Unsupported operating system: {os_tag}')
raise NotImplementedError(f'Method "parse_format" not implemented at {__name__}')

View file

@ -37,13 +37,11 @@ def to_ordinal(in_number: int) -> str:
def file_to_bytes(in_object: str | bytes | bytearray) -> bytes:
""" Get bytes from given buffer or file path """
if not isinstance(in_object, (bytes, bytearray)):
with open(to_string(in_object=in_object), 'rb') as object_data:
object_bytes: bytes = object_data.read()
else:
object_bytes = in_object
if isinstance(in_object, str):
with open(in_object, 'rb') as object_fp:
return object_fp.read()
return object_bytes
return bytes(in_object)
def bytes_to_hex(in_buffer: bytes, order: str, data_len: int, slice_len: int | None = None) -> str:

View file

@ -226,11 +226,6 @@ class DellPfsExtract(BIOSUtility):
TITLE: str = 'Dell PFS Update Extractor'
ARGUMENTS: list[tuple[list[str], dict[str, str]]] = [
(['-a', '--advanced'], {'help': 'extract signatures and metadata', 'action': 'store_true'}),
(['-s', '--structure'], {'help': 'show PFS structure information', 'action': 'store_true'})
]
PFS_HEAD_LEN: Final[int] = ctypes.sizeof(DellPfsHeader)
PFS_FOOT_LEN: Final[int] = ctypes.sizeof(DellPfsFooter)
PFS_INFO_LEN: Final[int] = ctypes.sizeof(DellPfsInfo)
@ -239,10 +234,17 @@ class DellPfsExtract(BIOSUtility):
PFS_PFAT_LEN: Final[int] = ctypes.sizeof(DellPfsPfatMetadata)
PFAT_HDR_LEN: Final[int] = ctypes.sizeof(IntelBiosGuardHeader)
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def __init__(self, input_object: str | bytes | bytearray = b'', extract_path: str = '', padding: int = 0,
advanced: bool = False, structure: bool = False) -> None:
super().__init__(input_object=input_object, extract_path=extract_path, padding=padding)
self.advanced: bool = advanced
self.structure: bool = structure
def check_format(self) -> bool:
""" Check if input is Dell PFS/PKG image """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
if self._is_pfs_pkg(input_object=input_buffer):
return True
@ -252,33 +254,34 @@ class DellPfsExtract(BIOSUtility):
return False
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract Dell PFS Update image """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
is_dell_pkg: bool = self._is_pfs_pkg(input_object=input_buffer)
if is_dell_pkg:
pfs_results: dict[str, bytes] = self._thinos_pkg_extract(
input_object=input_buffer, extract_path=extract_path)
input_object=input_buffer, extract_path=self.extract_path)
else:
pfs_results = {path_stem(in_path=input_object) if isinstance(input_object, str) and is_file(
in_path=input_object) else 'Image': input_buffer}
pfs_results = {path_stem(in_path=self.input_object) if isinstance(self.input_object, str) and is_file(
in_path=self.input_object) else 'Image': 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: str = os.path.join(extract_path, f'{pfs_index} {pfs_name}') if is_dell_pkg else extract_path
pfs_path: str = os.path.join(
self.extract_path, f'{pfs_index} {pfs_name}') if is_dell_pkg else self.extract_path
# Parse each PFS ZLIB section
for zlib_offset in self._get_section_offsets(buffer=pfs_buffer):
# Call the PFS ZLIB section parser function
self._pfs_section_parse(zlib_data=pfs_buffer, zlib_start=zlib_offset, extract_path=pfs_path,
pfs_name=pfs_name, pfs_index=pfs_index, pfs_count=1, is_rec=False,
padding=padding)
padding=self.padding)
return True
@ -496,7 +499,7 @@ class DellPfsExtract(BIOSUtility):
""" Parse & Extract Dell PFS Volume """
# Show PFS Volume indicator
if self.arguments.structure:
if self.structure:
printer(message='PFS Volume:', padding=padding)
# Get PFS Header Structure values
@ -509,7 +512,7 @@ class DellPfsExtract(BIOSUtility):
return # Critical error, abort
# Show PFS Header Structure info
if self.arguments.structure:
if self.structure:
printer(message='PFS Header:\n', padding=padding + 4)
pfs_hdr.struct_print(padding=padding + 8)
@ -576,7 +579,7 @@ class DellPfsExtract(BIOSUtility):
class_object=DellPfsInfo)
# Show PFS Information Header Structure info
if self.arguments.structure:
if self.structure:
printer(message='PFS Filename Information Header:\n', padding=padding + 4)
filename_info_hdr.struct_print(padding=padding + 8)
@ -610,7 +613,7 @@ class DellPfsExtract(BIOSUtility):
entry_name: str = safe_name(in_name=name_data.decode('utf-16').strip())
# Show PFS FileName Structure info
if self.arguments.structure:
if self.structure:
printer(message='PFS FileName Entry:\n', padding=padding + 8)
entry_info_mod.struct_print(name=entry_name, padding=padding + 12)
@ -639,7 +642,7 @@ class DellPfsExtract(BIOSUtility):
entry_info: Any = ctypes_struct(buffer=entry_metadata, start_offset=0, class_object=DellPfsMetadata)
# Show Nested PFS Metadata Structure info
if self.arguments.structure:
if self.structure:
printer(message='PFS Metadata Information:\n', padding=padding + 4)
entry_info.struct_print(padding=padding + 8)
@ -667,7 +670,7 @@ class DellPfsExtract(BIOSUtility):
class_object=DellPfsInfo)
# Show PFS Information Header Structure info
if self.arguments.structure:
if self.structure:
printer(message='PFS Signature Information Header:\n', padding=padding + 4)
signature_info_hdr.struct_print(padding=padding + 8)
@ -688,7 +691,7 @@ class DellPfsExtract(BIOSUtility):
class_object=pfs_entry_struct)
# Show PFS Information Header Structure info
if self.arguments.structure:
if self.structure:
printer(message='PFS Information Entry:\n', padding=padding + 8)
entry_hdr.struct_print(padding=padding + 12)
@ -703,7 +706,7 @@ class DellPfsExtract(BIOSUtility):
sign_data_txt: str = f'{int.from_bytes(sign_data_raw, byteorder="little"):0{sign_size * 2}X}'
if self.arguments.structure:
if self.structure:
printer(message='Signature Information:\n', padding=padding + 8)
printer(message=f'Signature Size: 0x{sign_size:X}', padding=padding + 12, new_line=False)
@ -757,11 +760,11 @@ class DellPfsExtract(BIOSUtility):
class_object=DellPfsHeader)
# Show PFS Volume indicator
if self.arguments.structure:
if self.structure:
printer(message='PFS Volume:', padding=padding + 4)
# Show sub-PFS Header Structure Info
if self.arguments.structure:
if self.structure:
printer(message='PFS Header:\n', padding=padding + 8)
pfat_pfs_header.struct_print(padding=padding + 12)
@ -824,12 +827,12 @@ class DellPfsExtract(BIOSUtility):
elif file_type == 'NAME_INFO':
file_name = 'Filename Information'
if not self.arguments.advanced:
if not self.advanced:
continue # Don't store Filename Information in non-advanced user mode
elif file_type == 'SIG_INFO':
file_name = 'Signature Information'
if not self.arguments.advanced:
if not self.advanced:
continue # Don't store Signature Information in non-advanced user mode
else:
file_name = ''
@ -863,13 +866,13 @@ class DellPfsExtract(BIOSUtility):
if file_data and not is_zlib:
write_files.append([file_data, 'data']) # PFS Entry Data Payload
if file_data_sig and self.arguments.advanced:
if file_data_sig and self.advanced:
write_files.append([file_data_sig, 'sign_data']) # PFS Entry Data Signature
if file_meta and (is_zlib or self.arguments.advanced):
if file_meta and (is_zlib or self.advanced):
write_files.append([file_meta, 'meta']) # PFS Entry Metadata Payload
if file_meta_sig and self.arguments.advanced:
if file_meta_sig and self.advanced:
write_files.append([file_meta_sig, 'sign_meta']) # PFS Entry Metadata Signature
# Write/Extract PFS Entry files
@ -896,7 +899,7 @@ class DellPfsExtract(BIOSUtility):
pfs_entry: Any = ctypes_struct(buffer=entry_buffer, start_offset=entry_start, class_object=entry_struct)
# Show PFS Entry Structure info
if self.arguments.structure:
if self.structure:
printer(message='PFS Entry:\n', padding=padding + 4)
pfs_entry.struct_print(padding=padding + 8)
@ -981,7 +984,7 @@ class DellPfsExtract(BIOSUtility):
pfat_entry_idx_ord: str = to_ordinal(in_number=pfat_entry_index)
# Show sub-PFS PFAT Header Structure info
if self.arguments.structure:
if self.structure:
printer(message=f'PFAT Block {pfat_entry_idx_ord} - Header:\n', padding=padding + 12)
pfat_hdr.struct_print(padding=padding + 16)
@ -1012,7 +1015,7 @@ class DellPfsExtract(BIOSUtility):
# Parse sub-PFS PFAT Signature, if applicable (only when PFAT Header > SFAM flag is set)
if is_sfam:
if self.arguments.structure:
if self.structure:
printer(message=f'PFAT Block {pfat_entry_idx_ord} - Signature:\n', padding=padding + 12)
# Get sub-PFS PFAT Signature Size from Header pattern (not necessary for Dell PFS)
@ -1027,7 +1030,7 @@ class DellPfsExtract(BIOSUtility):
# Get sub-PFS PFAT Signature Structure values
pfat_sign_len: int = ami_pfat_extract.parse_bg_sign(
input_data=pfat_payload, sign_offset=pfat_payload_end, sign_length=_pfat_sign_len,
print_info=self.arguments.structure, padding=padding + 16)
print_info=self.structure, padding=padding + 16)
if not len(pfat_payload[pfat_payload_end:pfat_payload_end + pfat_sign_len]
) == pfat_sign_len == _pfat_sign_len:
@ -1035,7 +1038,7 @@ class DellPfsExtract(BIOSUtility):
f'Size mismatch!', padding=padding + 12)
# Show PFAT Script via BIOS Guard Script Tool
if self.arguments.structure:
if self.structure:
printer(message=f'PFAT Block {pfat_entry_idx_ord} - Script:\n', padding=padding + 12)
_ = ami_pfat_extract.parse_bg_script(script_data=pfat_script_data, padding=padding + 16)
@ -1066,7 +1069,7 @@ class DellPfsExtract(BIOSUtility):
pfat_entry_adr = pfat_met.Address
# Show sub-PFS PFAT Metadata Structure info
if self.arguments.structure:
if self.structure:
printer(message=f'PFAT Block {pfat_entry_idx_ord} - Metadata:\n', padding=padding + 12)
pfat_met.struct_print(padding=padding + 16)
@ -1134,7 +1137,7 @@ class DellPfsExtract(BIOSUtility):
block_data_gap: int = block_start - block_start_exp
if block_data_gap > 0:
if self.arguments.structure:
if self.structure:
printer(message=f'Warning: Filled sub-PFS PFAT {block_index} data gap 0x{block_data_gap:X} '
f'[0x{block_start_exp:X}-0x{block_start:X}]!', padding=padding + 8)
@ -1206,7 +1209,7 @@ class DellPfsExtract(BIOSUtility):
# Validate that a PFS Footer was parsed
if pfs_ftr.Tag == b'PFS.FTR.':
# Show PFS Footer Structure info
if self.arguments.structure:
if self.structure:
printer(message='PFS Footer:\n', padding=padding + 4)
pfs_ftr.struct_print(padding=padding + 8)
@ -1240,7 +1243,7 @@ class DellPfsExtract(BIOSUtility):
return # Skip further processing for Signatures
# Store Data/Metadata Payload (simpler Data/Metadata Extension for non-advanced users)
bin_ext: str = f'.{bin_name}.bin' if self.arguments.advanced else '.bin'
bin_ext: str = f'.{bin_name}.bin' if self.advanced else '.bin'
# Some Data may be Text or XML files with useful information for non-advanced users
final_data, file_ext = self._bin_is_text(buffer=bin_buff, file_type=bin_type,
@ -1265,7 +1268,7 @@ class DellPfsExtract(BIOSUtility):
extension: str = '.bin'
if self.arguments.advanced:
if self.advanced:
return buffer, extension
buffer_text: str = ''
@ -1293,7 +1296,7 @@ class DellPfsExtract(BIOSUtility):
# Show Model/PCR XML Information, if applicable
# Metadata is shown at initial DellPfsMetadata analysis
if self.arguments.structure and buffer_text and not is_metadata:
if self.structure and buffer_text and not is_metadata:
metadata_info_type: str = {".txt": "Model", ".xml": "PCR XML"}[extension]
printer(message=f'PFS {metadata_info_type} Information:\n', padding=padding + 8)
@ -1302,7 +1305,3 @@ class DellPfsExtract(BIOSUtility):
printer(message=line.strip('\r'), padding=padding + 12, new_line=False)
return buffer_text or buffer, extension
if __name__ == '__main__':
DellPfsExtract().run_utility()

View file

@ -23,17 +23,17 @@ class FujitsuSfxExtract(BIOSUtility):
TITLE: str = 'Fujitsu SFX BIOS Extractor'
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is Fujitsu SFX image """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
return bool(PAT_FUJITSU_SFX.search(input_buffer))
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract Fujitsu SFX image """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
# Microsoft CAB Header XOR 0xFF
match_cab: re.Match[bytes] | None = PAT_FUJITSU_SFX.search(input_buffer)
@ -41,7 +41,7 @@ class FujitsuSfxExtract(BIOSUtility):
if not match_cab:
return False
printer(message='Detected obfuscated CAB archive!', padding=padding)
printer(message='Detected obfuscated CAB archive!', padding=self.padding)
# Microsoft CAB Header XOR 0xFF starts after "FjSfxBinay" signature
cab_start: int = match_cab.start() + 0xA
@ -55,7 +55,7 @@ class FujitsuSfxExtract(BIOSUtility):
# Perform XOR 0xFF and get actual CAB size
cab_size ^= xor_size
printer(message='Removing obfuscation...', padding=padding + 4)
printer(message='Removing obfuscation...', padding=self.padding + 4)
# Get BE XOR-ed CAB data
cab_data: int = int.from_bytes(input_buffer[cab_start:cab_start + cab_size], byteorder='big')
@ -66,19 +66,19 @@ class FujitsuSfxExtract(BIOSUtility):
# Perform XOR 0xFF and get actual CAB data
raw_data: bytes = (cab_data ^ xor_data).to_bytes(cab_size, 'big')
printer(message='Extracting archive...', padding=padding + 4)
printer(message='Extracting archive...', padding=self.padding + 4)
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
cab_path: str = os.path.join(extract_path, 'FjSfxBinay.cab')
cab_path: str = os.path.join(self.extract_path, 'FjSfxBinay.cab')
# Create temporary CAB archive
with open(cab_path, 'wb') as cab_file_object:
cab_file_object.write(raw_data)
if is_szip_supported(in_path=cab_path, padding=padding + 8, silent=False):
if szip_decompress(in_path=cab_path, out_path=extract_path, in_name='FjSfxBinay CAB',
padding=padding + 8, check=True):
if is_szip_supported(in_path=cab_path, padding=self.padding + 8, silent=False):
if szip_decompress(in_path=cab_path, out_path=self.extract_path, in_name='FjSfxBinay CAB',
padding=self.padding + 8, check=True):
os.remove(cab_path)
else:
return False
@ -86,7 +86,3 @@ class FujitsuSfxExtract(BIOSUtility):
return False
return True
if __name__ == '__main__':
FujitsuSfxExtract().run_utility()

View file

@ -20,49 +20,45 @@ class FujitsuUpcExtract(BIOSUtility):
TITLE: str = 'Fujitsu UPC BIOS Extractor'
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is Fujitsu UPC image """
is_upc: bool = False
if isinstance(input_object, str) and is_file(in_path=input_object):
is_upc = path_suffixes(input_object)[-1].upper() == '.UPC'
elif isinstance(input_object, (bytes, bytearray)):
if isinstance(self.input_object, str) and is_file(in_path=self.input_object):
is_upc = path_suffixes(self.input_object)[-1].upper() == '.UPC'
elif isinstance(self.input_object, (bytes, bytearray)):
is_upc = True
if is_upc:
is_upc = is_efi_compressed(data=file_to_bytes(in_object=input_object))
is_upc = is_efi_compressed(data=file_to_bytes(in_object=self.input_object))
return is_upc
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract Fujitsu UPC image """
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
if isinstance(input_object, str) and is_file(in_path=input_object):
input_name: str = path_name(in_path=input_object)
if isinstance(self.input_object, str) and is_file(in_path=self.input_object):
input_name: str = path_name(in_path=self.input_object)
input_path: str = input_object
input_path: str = self.input_object
if input_name.upper().endswith('.UPC'):
input_name = input_name[:-4]
else:
input_name = 'Fujitsu_UPC_Image'
input_path = os.path.join(extract_path, f'{input_name}.UPC')
input_path = os.path.join(self.extract_path, f'{input_name}.UPC')
with open(input_path, 'wb') as input_path_object:
input_path_object.write(file_to_bytes(in_object=input_object))
input_path_object.write(file_to_bytes(in_object=self.input_object))
output_path: str = os.path.join(extract_path, f'{input_name}.bin')
output_path: str = os.path.join(self.extract_path, f'{input_name}.bin')
efi_status: bool = efi_decompress(in_path=input_path, out_path=output_path, padding=padding)
efi_status: bool = efi_decompress(in_path=input_path, out_path=output_path, padding=self.padding)
if input_path != input_object:
if input_path != self.input_object:
os.remove(input_path)
return efi_status
if __name__ == '__main__':
FujitsuUpcExtract().run_utility()

View file

@ -80,10 +80,10 @@ class InsydeIfdExtract(BIOSUtility):
# Get common ctypes Structure Sizes
INS_IFL_LEN: Final[int] = ctypes.sizeof(IflashHeader)
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is Insyde iFlash/iFdPacker Update image """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
if bool(self._insyde_iflash_detect(input_buffer=input_buffer)):
return True
@ -93,18 +93,18 @@ class InsydeIfdExtract(BIOSUtility):
return False
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract Insyde iFlash/iFdPacker Update images """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
iflash_code: int = self._insyde_iflash_extract(input_buffer=input_buffer, extract_path=extract_path,
padding=padding)
iflash_code: int = self._insyde_iflash_extract(input_buffer=input_buffer, extract_path=self.extract_path,
padding=self.padding)
ifdpack_path: str = os.path.join(extract_path, 'Insyde iFdPacker SFX')
ifdpack_path: str = os.path.join(self.extract_path, 'Insyde iFdPacker SFX')
ifdpack_code: int = self._insyde_packer_extract(input_buffer=input_buffer, extract_path=ifdpack_path,
padding=padding)
padding=self.padding)
return (iflash_code and ifdpack_code) == 0
@ -168,8 +168,7 @@ class InsydeIfdExtract(BIOSUtility):
ifl_hdr.struct_print(padding=padding + 8)
if img_val == [img_tag, img_ext]:
printer(message=f'Note: Detected new Insyde iFlash tag {img_tag}!',
padding=padding + 12, pause=not self.arguments.auto_exit)
printer(message=f'Note: Detected new Insyde iFlash tag {img_tag}!', padding=padding + 12)
out_name: str = f'{img_name}.{img_ext}'
@ -231,16 +230,14 @@ class InsydeIfdExtract(BIOSUtility):
for sfx_file in path_files(in_path=extract_path):
if is_file(in_path=sfx_file) and is_access(in_path=sfx_file):
if self.check_format(input_object=sfx_file):
insyde_ifd_extract: InsydeIfdExtract = InsydeIfdExtract(
input_object=sfx_file, extract_path=extract_folder(sfx_file), padding=padding + 16)
if insyde_ifd_extract.check_format():
printer(message=path_name(in_path=sfx_file), padding=padding + 12)
ifd_status: int = self.parse_format(input_object=sfx_file, extract_path=extract_folder(sfx_file),
padding=padding + 16)
ifd_status: int = insyde_ifd_extract.parse_format()
exit_codes.append(0 if ifd_status else 1)
return sum(exit_codes)
if __name__ == '__main__':
InsydeIfdExtract().run_utility()

View file

@ -39,10 +39,10 @@ class PanasonicBiosExtract(BIOSUtility):
PAN_PE_DESC_UPD: Final[str] = 'BIOS UPDATE'
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is Panasonic BIOS Package PE """
pe_file: pefile.PE | None = ms_pe(in_file=input_object, silent=True)
pe_file: pefile.PE | None = ms_pe(in_file=self.input_object, silent=True)
if not pe_file:
return False
@ -53,26 +53,26 @@ class PanasonicBiosExtract(BIOSUtility):
return True
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract Panasonic BIOS Package PE """
upd_pe_file: pefile.PE = ms_pe(in_file=input_object, padding=padding) # type: ignore
upd_pe_file: pefile.PE = ms_pe(in_file=self.input_object, padding=self.padding) # type: ignore
upd_pe_name: str = self._panasonic_pkg_name(input_object=input_object)
upd_pe_name: str = self._panasonic_pkg_name(input_object=self.input_object)
printer(message=f'Panasonic BIOS Package > PE ({upd_pe_name})\n'.replace(' ()', ''), padding=padding)
printer(message=f'Panasonic BIOS Package > PE ({upd_pe_name})\n'.replace(' ()', ''), padding=self.padding)
ms_pe_info_show(pe_file=upd_pe_file, padding=padding + 4)
ms_pe_info_show(pe_file=upd_pe_file, padding=self.padding + 4)
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
upd_pe_path: str = self._panasonic_cab_extract(input_object=input_object,
extract_path=extract_path, padding=padding + 8)
upd_pe_path: str = self._panasonic_cab_extract(input_object=self.input_object,
extract_path=self.extract_path, padding=self.padding + 8)
upd_padding: int = padding
upd_padding: int = self.padding
if upd_pe_path:
upd_padding = padding + 16
upd_padding = self.padding + 16
upd_pe_name = self._panasonic_pkg_name(input_object=upd_pe_path)
@ -84,11 +84,11 @@ class PanasonicBiosExtract(BIOSUtility):
os.remove(upd_pe_path)
is_upd_extracted: bool = self._panasonic_res_extract(pe_file=upd_pe_file, extract_path=extract_path,
is_upd_extracted: bool = self._panasonic_res_extract(pe_file=upd_pe_file, extract_path=self.extract_path,
pe_name=upd_pe_name, padding=upd_padding + 8)
if not is_upd_extracted:
is_upd_extracted = self._panasonic_img_extract(pe_file=upd_pe_file, extract_path=extract_path,
is_upd_extracted = self._panasonic_img_extract(pe_file=upd_pe_file, extract_path=self.extract_path,
pe_name=upd_pe_name, padding=upd_padding + 8)
return is_upd_extracted
@ -184,14 +184,14 @@ class PanasonicBiosExtract(BIOSUtility):
printer(message='Successful PE Resource extraction!', padding=padding + 4)
ami_pfat_extract: AmiPfatExtract = AmiPfatExtract()
# Detect & Unpack AMI BIOS Guard (PFAT) BIOS image
if ami_pfat_extract.check_format(input_object=res_raw):
pfat_dir: str = os.path.join(extract_path, res_tag)
ami_pfat_extract.parse_format(input_object=res_raw, extract_path=pfat_dir,
padding=padding + 8)
ami_pfat_extract: AmiPfatExtract = AmiPfatExtract(
input_object=res_raw, extract_path=pfat_dir, padding=padding + 8)
# Detect & Unpack AMI BIOS Guard (PFAT) BIOS image
if ami_pfat_extract.check_format():
ami_pfat_extract.parse_format()
else:
if is_ms_pe(in_file=res_raw):
res_ext: str = 'exe'
@ -242,7 +242,3 @@ class PanasonicBiosExtract(BIOSUtility):
printer(message='Successful PE Data extraction!', padding=padding + 4)
return bool(img_bin)
if __name__ == '__main__':
PanasonicBiosExtract().run_utility()

View file

@ -103,23 +103,23 @@ class PhoenixTdkExtract(BIOSUtility):
TDK_DUMMY_LEN: Final[int] = 0x200
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input contains valid Phoenix TDK image """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
return bool(self._get_phoenix_tdk(in_buffer=input_buffer)[1] is not None)
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract Phoenix Tools Development Kit (TDK) Packer """
exit_code: int = 0
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
printer(message='Phoenix Tools Development Kit Packer', padding=padding)
printer(message='Phoenix Tools Development Kit Packer', padding=self.padding)
base_off, pack_off = self._get_phoenix_tdk(in_buffer=input_buffer)
@ -127,13 +127,13 @@ class PhoenixTdkExtract(BIOSUtility):
tdk_hdr: Any = ctypes_struct(buffer=input_buffer, start_offset=pack_off, class_object=PhoenixTdkHeader)
# Print TDK Header structure info
printer(message='Phoenix TDK Header:\n', padding=padding + 4)
printer(message='Phoenix TDK Header:\n', padding=self.padding + 4)
tdk_hdr.struct_print(padding=padding + 8)
tdk_hdr.struct_print(padding=self.padding + 8)
# Check if reported TDK Header Size matches manual TDK Entry Count calculation
if tdk_hdr.Size != self.TDK_HDR_LEN + self.TDK_DUMMY_LEN + tdk_hdr.Count * self.TDK_MOD_LEN:
printer(message='Error: Phoenix TDK Header Size & Entry Count mismatch!\n', padding=padding + 8)
printer(message='Error: Phoenix TDK Header Size & Entry Count mismatch!\n', padding=self.padding + 8)
exit_code = 1
@ -147,16 +147,16 @@ class PhoenixTdkExtract(BIOSUtility):
class_object=PhoenixTdkEntry, param_list=[base_off])
# Print TDK Entry structure info
printer(message=f'Phoenix TDK Entry ({entry_index + 1}/{tdk_hdr.Count}):\n', padding=padding + 8)
printer(message=f'Phoenix TDK Entry ({entry_index + 1}/{tdk_hdr.Count}):\n', padding=self.padding + 8)
tdk_mod.struct_print(padding=padding + 12)
tdk_mod.struct_print(padding=self.padding + 12)
# Get TDK Entry raw data Offset (TDK Base + Entry Offset)
mod_off: int = tdk_mod.get_offset()
# Check if TDK Entry raw data Offset is valid
if mod_off >= len(input_buffer):
printer(message='Error: Phoenix TDK Entry > Offset is out of bounds!\n', padding=padding + 12)
printer(message='Error: Phoenix TDK Entry > Offset is out of bounds!\n', padding=self.padding + 12)
exit_code = 2
@ -165,13 +165,13 @@ class PhoenixTdkExtract(BIOSUtility):
# Check if TDK Entry raw data is complete
if len(mod_data) != tdk_mod.Size:
printer(message='Error: Phoenix TDK Entry > Data is truncated!\n', padding=padding + 12)
printer(message='Error: Phoenix TDK Entry > Data is truncated!\n', padding=self.padding + 12)
exit_code = 3
# Check if TDK Entry Reserved is present
if tdk_mod.Reserved:
printer(message='Error: Phoenix TDK Entry > Reserved is not empty!\n', padding=padding + 12)
printer(message='Error: Phoenix TDK Entry > Reserved is not empty!\n', padding=self.padding + 12)
exit_code = 4
@ -181,7 +181,7 @@ class PhoenixTdkExtract(BIOSUtility):
mod_data = lzma.LZMADecompressor().decompress(data=mod_data)
except Exception as error: # pylint: disable=broad-except
printer(message=f'Error: Phoenix TDK Entry > LZMA decompression failed: {error}!\n',
padding=padding + 12)
padding=self.padding + 12)
exit_code = 5
@ -189,7 +189,7 @@ class PhoenixTdkExtract(BIOSUtility):
mod_name: str = tdk_mod.get_name() or f'Unknown_{entry_index + 1:02d}.bin'
# Generate TDK Entry file data output path
mod_file: str = os.path.join(extract_path, safe_name(mod_name))
mod_file: str = os.path.join(self.extract_path, safe_name(mod_name))
# Account for potential duplicate file names
if is_file(in_path=mod_file):
@ -280,7 +280,3 @@ class PhoenixTdkExtract(BIOSUtility):
tdk_base_off: int | None = self._get_tdk_base(in_buffer, tdk_pack_off)
return tdk_base_off, tdk_pack_off
if __name__ == '__main__':
PhoenixTdkExtract().run_utility()

View file

@ -37,10 +37,10 @@ class PortwellEfiExtract(BIOSUtility):
4: 'SaveDmiData.efi'
}
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is Portwell EFI executable """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
try:
pe_buffer: bytes = self._get_portwell_pe(in_buffer=input_buffer)[1]
@ -57,21 +57,21 @@ class PortwellEfiExtract(BIOSUtility):
return False
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract Portwell UEFI Unpacker """
# Initialize EFI Payload file chunks
efi_files: list[bytes] = []
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
pe_file, pe_data = self._get_portwell_pe(in_buffer=input_buffer)
efi_title: str = self._get_unpacker_tag(input_buffer=input_buffer, pe_file=pe_file)
printer(message=efi_title, padding=padding)
printer(message=efi_title, padding=self.padding)
# Split EFI Payload into <UU> file chunks
efi_list: list[Match[bytes]] = list(PAT_PORTWELL_EFI.finditer(pe_data))
@ -82,7 +82,7 @@ class PortwellEfiExtract(BIOSUtility):
efi_files.append(pe_data[efi_bgn:efi_end])
self._parse_efi_files(extract_path=extract_path, efi_files=efi_files, padding=padding)
self._parse_efi_files(extract_path=self.extract_path, efi_files=efi_files, padding=self.padding)
return True
@ -145,8 +145,7 @@ class PortwellEfiExtract(BIOSUtility):
printer(message=f'[{file_index}] {file_name}', padding=padding + 4)
if file_name.startswith('Unknown_'):
printer(message=f'Note: Detected new Portwell EFI file ID {file_index}!',
padding=padding + 8, pause=not self.arguments.auto_exit)
printer(message=f'Note: Detected new Portwell EFI file ID {file_index}!', padding=padding + 8)
# Store EFI file output path
file_path: str = os.path.join(extract_path, safe_name(in_name=file_name))
@ -166,7 +165,3 @@ class PortwellEfiExtract(BIOSUtility):
# Successful decompression, delete compressed file
if efi_decompress(in_path=comp_fname, out_path=file_path, padding=padding + 8):
os.remove(comp_fname)
if __name__ == '__main__':
PortwellEfiExtract().run_utility()

View file

@ -23,29 +23,29 @@ class ToshibaComExtract(BIOSUtility):
TITLE: str = 'Toshiba BIOS COM Extractor'
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is Toshiba BIOS COM image """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
return bool(PAT_TOSHIBA_COM.search(input_buffer, 0, 0x100))
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract Toshiba BIOS COM image """
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
if isinstance(input_object, str) and is_file(in_path=input_object):
input_path: str = input_object
if isinstance(self.input_object, str) and is_file(in_path=self.input_object):
input_path: str = self.input_object
else:
input_path = os.path.join(extract_path, 'toshiba_bios.com')
input_path = os.path.join(self.extract_path, 'toshiba_bios.com')
with open(input_path, 'wb') as input_buffer:
input_buffer.write(file_to_bytes(in_object=input_object))
input_buffer.write(file_to_bytes(in_object=self.input_object))
output_name: str = f'{safe_name(in_name=path_stem(in_path=input_path))}_extracted.bin'
output_path: str = os.path.join(extract_path, output_name)
output_path: str = os.path.join(self.extract_path, output_name)
try:
subprocess.run([comextract_path(), input_path, output_path], check=True, stdout=subprocess.DEVNULL)
@ -53,17 +53,14 @@ class ToshibaComExtract(BIOSUtility):
if not is_file(in_path=output_path):
raise FileNotFoundError('EXTRACTED_FILE_MISSING')
except Exception as error: # pylint: disable=broad-except
printer(message=f'Error: ToshibaComExtractor could not extract {input_path}: {error}!', padding=padding)
printer(message=f'Error: ToshibaComExtractor could not extract {input_path}: {error}!',
padding=self.padding)
return False
if input_path != input_object:
if input_path != self.input_object:
os.remove(input_path)
printer(message='Successful extraction via ToshibaComExtractor!', padding=padding)
printer(message='Successful extraction via ToshibaComExtractor!', padding=self.padding)
return True
if __name__ == '__main__':
ToshibaComExtract().run_utility()

View file

@ -24,28 +24,30 @@ class VaioPackageExtract(BIOSUtility):
TITLE: str = 'VAIO Packaging Manager Extractor'
def check_format(self, input_object: str | bytes | bytearray) -> bool:
def check_format(self) -> bool:
""" Check if input is VAIO Packaging Manager """
input_buffer: bytes = file_to_bytes(in_object=input_object)
input_buffer: bytes = file_to_bytes(in_object=self.input_object)
return bool(PAT_VAIO_CFG.search(input_buffer))
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
def parse_format(self) -> bool:
""" Parse & Extract or Unlock VAIO Packaging Manager """
input_buffer: bytes = file_to_bytes(input_object)
input_buffer: bytes = file_to_bytes(self.input_object)
input_name: str = os.path.basename(input_object) if isinstance(input_buffer, str) else 'VAIO_Package'
input_name: str = os.path.basename(self.input_object) if isinstance(input_buffer, str) else 'VAIO_Package'
make_dirs(in_path=extract_path, delete=True)
make_dirs(in_path=self.extract_path, delete=True)
if self._vaio_cabinet(name=input_name, buffer=input_buffer, extract_path=extract_path, padding=padding) == 0:
printer(message='Successfully Extracted!', padding=padding)
elif self._vaio_unlock(name=input_name, buffer=input_buffer, extract_path=extract_path, padding=padding) == 0:
printer(message='Successfully Unlocked!', padding=padding)
if self._vaio_cabinet(name=input_name, buffer=input_buffer, extract_path=self.extract_path,
padding=self.padding) == 0:
printer(message='Successfully Extracted!', padding=self.padding)
elif self._vaio_unlock(name=input_name, buffer=input_buffer, extract_path=self.extract_path,
padding=self.padding) == 0:
printer(message='Successfully Unlocked!', padding=self.padding)
else:
printer(message='Error: Failed to Extract or Unlock executable!', padding=padding)
printer(message='Error: Failed to Extract or Unlock executable!', padding=self.padding)
return False
@ -174,7 +176,3 @@ class VaioPackageExtract(BIOSUtility):
unl_file.write(input_buffer)
return 0
if __name__ == '__main__':
VaioPackageExtract().run_utility()

164
main.py
View file

@ -5,8 +5,12 @@
Copyright (C) 2018-2024 Plato Mavropoulos
"""
import os
from argparse import ArgumentParser, Namespace
from pathlib import Path
from typing import Any, Final
from biosutilities import __version__
from biosutilities.ami_pfat_extract import AmiPfatExtract
from biosutilities.ami_ucp_extract import AmiUcpExtract
@ -25,39 +29,149 @@ from biosutilities.portwell_efi_extract import PortwellEfiExtract
from biosutilities.toshiba_com_extract import ToshibaComExtract
from biosutilities.vaio_package_extract import VaioPackageExtract
from biosutilities.common.paths import (delete_dirs, extract_folder, is_access, is_dir, is_empty_dir, is_file,
path_files, path_name, path_parent, real_path, runtime_root)
from biosutilities.common.system import python_version, printer, system_platform
from biosutilities.common.texts import remove_quotes, to_boxed, to_ordinal
if __name__ == '__main__':
class BIOSUtilities:
""" Main BIOSUtilities class """
MAX_FAT32_ITEMS: Final[int] = 65535
MIN_PYTHON_VER: Final[tuple[int, int]] = (3, 10)
def __init__(self) -> None:
main_argparser: ArgumentParser = ArgumentParser(allow_abbrev=False)
main_argparser.add_argument('paths', nargs='+')
main_argparser.add_argument('paths', nargs='*')
main_argparser.add_argument('-e', '--auto-exit', help='do not pause on exit', action='store_true')
main_argparser.add_argument('-o', '--output-dir', help='extraction directory')
main_arguments: Namespace = main_argparser.parse_args()
self.main_arguments: Namespace = main_argparser.parse_args()
if main_arguments.output_dir:
output_folder: Path = Path(main_arguments.output_dir)
self._input_files: list[str] = []
self._output_path: str = ''
def _setup_input_files(self, padding: int = 0) -> None:
self._input_files = []
input_paths: list[str] = self.main_arguments.paths
if not input_paths:
input_paths = [remove_quotes(in_text=input(f'\n{" " * padding}Enter input file or directory path: '))]
for input_path in [input_path for input_path in input_paths if input_path]:
input_path_real: str = real_path(in_path=input_path)
if is_dir(in_path=input_path_real):
for input_file in path_files(in_path=input_path_real):
if is_file(in_path=input_file) and is_access(in_path=input_file):
self._input_files.append(input_file)
elif is_file(in_path=input_path_real) and is_access(in_path=input_path_real):
self._input_files.append(input_path_real)
def _setup_output_dir(self, padding: int = 0) -> None:
self._output_path = ''
output_path: str = self.main_arguments.output_dir
if not output_path:
output_path = remove_quotes(in_text=input(f'\n{" " * padding}Enter output directory path: '))
if not output_path and self._input_files:
output_path = str(path_parent(in_path=self._input_files[0]))
if output_path and is_dir(in_path=output_path) and is_access(in_path=output_path):
self._output_path = output_path
else:
output_folder = Path(main_arguments.paths[0]).parent
self._output_path = runtime_root()
util_arguments: list[str] = [*main_arguments.paths, '-e', '-o', str(output_folder.absolute())]
def _check_sys_py(self) -> None:
""" Check Python Version """
AmiUcpExtract(arguments=util_arguments).run_utility()
AmiPfatExtract(arguments=util_arguments).run_utility()
InsydeIfdExtract(arguments=util_arguments).run_utility()
DellPfsExtract(arguments=util_arguments).run_utility()
PhoenixTdkExtract(arguments=util_arguments).run_utility()
PanasonicBiosExtract(arguments=util_arguments).run_utility()
VaioPackageExtract(arguments=util_arguments).run_utility()
PortwellEfiExtract(arguments=util_arguments).run_utility()
ToshibaComExtract(arguments=util_arguments).run_utility()
FujitsuSfxExtract(arguments=util_arguments).run_utility()
FujitsuUpcExtract(arguments=util_arguments).run_utility()
AwardBiosExtract(arguments=util_arguments).run_utility()
AppleEfiPkgExtract(arguments=util_arguments).run_utility()
AppleEfiPbzxExtract(arguments=util_arguments).run_utility()
AppleEfiIm4pSplit(arguments=util_arguments).run_utility()
AppleEfiIdentify(arguments=util_arguments).run_utility()
sys_py: tuple = python_version()
if not main_arguments.auto_exit:
if sys_py < self.MIN_PYTHON_VER:
min_py_str: str = '.'.join(map(str, self.MIN_PYTHON_VER))
sys_py_str: str = '.'.join(map(str, sys_py[:2]))
raise RuntimeError(f'Python >= {min_py_str} required, not {sys_py_str}')
@staticmethod
def _check_sys_os() -> None:
""" Check OS Platform """
os_tag, is_win, is_lnx = system_platform()
if not (is_win or is_lnx):
raise OSError(f'Unsupported operating system: {os_tag}')
def run_main(self, padding: int = 0) -> bool:
""" Run main """
self._check_sys_py()
self._check_sys_os()
self._setup_input_files(padding=padding)
self._setup_output_dir(padding=padding)
exit_code: int = len(self._input_files)
utilities_classes: list[Any] = [
AmiUcpExtract, AmiPfatExtract, InsydeIfdExtract, DellPfsExtract, PhoenixTdkExtract, PanasonicBiosExtract,
VaioPackageExtract, PortwellEfiExtract, ToshibaComExtract, FujitsuSfxExtract, FujitsuUpcExtract,
AwardBiosExtract, AppleEfiPkgExtract, AppleEfiPbzxExtract, AppleEfiIm4pSplit, AppleEfiIdentify
]
for input_file in self._input_files:
input_name: str = path_name(in_path=input_file, limit=True)
printer(message=f'{input_name}\n', padding=padding)
for utility_class in utilities_classes:
extract_path: str = os.path.join(self._output_path, extract_folder(in_path=input_name))
if is_dir(in_path=extract_path):
for suffix in range(2, self.MAX_FAT32_ITEMS):
renamed_path: str = f'{os.path.normpath(extract_path)}_{to_ordinal(in_number=suffix)}'
if not is_dir(in_path=renamed_path):
extract_path = renamed_path
break
utility: Any = utility_class(input_object=input_file, extract_path=extract_path, padding=padding + 8)
if not utility.check_format():
continue
printer(message=to_boxed(in_text=f'{utility.TITLE} v{__version__}'),
new_line=False, padding=padding + 4)
is_parsed_format: bool = utility.parse_format()
is_empty_output: bool = is_empty_dir(in_path=extract_path)
if is_empty_output:
delete_dirs(in_path=extract_path)
if is_parsed_format and not is_empty_output:
exit_code -= 1
break
printer(message=None, new_line=False)
if not self.main_arguments.auto_exit:
input('Press any key to exit...')
return exit_code == 0
if __name__ == '__main__':
BIOSUtilities().run_main()

View file

@ -1,2 +1,2 @@
mypy==1.12.0
mypy==1.13.0
pylint==3.3.1