BIOSUtilities v24.11.10

Re-written public attributes of Apple EFI ID
Improved memory consumption for all utilities
Adjusted README with consolidated requirements
This commit is contained in:
Plato Mavropoulos 2024-11-11 01:18:34 +02:00
parent 29dabc7401
commit 35564f31b7
19 changed files with 252 additions and 198 deletions

View file

@ -1,3 +1,9 @@
24.11.10
Re-written public attributes of Apple EFI ID
Improved memory consumption for all utilities
Adjusted README with consolidated requirements
24.10.30 24.10.30
Improved UAF module detection at AMI UCP Extract Improved UAF module detection at AMI UCP Extract

164
README.md
View file

@ -2,7 +2,7 @@
## About ## About
Various BIOS/UEFI-related utilities which aid in modding and/or research Various BIOS/UEFI-related utilities which aid in research and/or modding
## Usage ## Usage
@ -10,7 +10,7 @@ Various BIOS/UEFI-related utilities which aid in modding and/or research
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: 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 ``` text
usage: main.py [-h] [-e] [-o OUTPUT_DIR] [paths ...] usage: main.py [-h] [-e] [-o OUTPUT_DIR] [paths ...]
positional arguments: positional arguments:
@ -22,13 +22,13 @@ options:
-o OUTPUT_DIR, --output-dir OUTPUT_DIR extraction directory -o OUTPUT_DIR, --output-dir OUTPUT_DIR extraction directory
``` ```
``` bash ``` text
python ./main.py "/path/to/input/file.bin" --output-dir "/path/to/file extractions" python ./main.py "/path/to/input/file.bin" --output-dir "/path/to/file extractions"
``` ```
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. 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.
``` python ``` text
Enter input file or directory path: "C:\P5405CSA.303" Enter input file or directory path: "C:\P5405CSA.303"
Enter output directory path: "C:\P5405CSA.303_output" Enter output directory path: "C:\P5405CSA.303_output"
@ -78,7 +78,7 @@ input_object: str | bytes | bytearray = b''
##### extract_path (required) ##### extract_path (required)
``` python ``` python
extract_path: str = '' extract_path: str = runtime_root()
``` ```
##### padding (optional) ##### padding (optional)
@ -87,8 +87,7 @@ extract_path: str = ''
padding: int = 0 padding: int = 0
``` ```
If the required arguments are not provided, it is still possible to use the BIOSUtility-inherited instance to access If the required arguments are not provided, placeholder values are set so that it is 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.
auxiliary public methods and class constants. However, checking and/or parsing of file formats will not yield results.
#### Methods #### Methods
@ -120,18 +119,38 @@ There are two main types of requirements, depending on the utility.
### Python Packages ### Python Packages
* [pefile](https://pypi.org/project/pefile/2023.2.7/)
* [dissect.util](https://pypi.org/project/dissect.util/3.18/)
Python packages can be installed via Pypi (e.g. pip) Python packages can be installed via Pypi (e.g. pip)
``` bash ``` bash
python -m pip install --upgrade -r requirements.txt python -m pip install --upgrade -r requirements.txt
``` ```
or
``` bash ``` bash
python -m pip install pefile==2023.2.7 dissect.util==3.18 python -m pip install pefile==2023.2.7 dissect.util==3.18
``` ```
### External Executables / Scripts ### External Executables / Scripts
To run the utilities, you must have the following 3rd party tools at PATH or "external":
* [7-Zip](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux)
* [UEFIFind](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIFind.exe for Windows or UEFIFind for Linux/macOS](https://github.com/LongSoft/UEFITool/releases))
* [UEFIExtract](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIExtract.exe for Windows or UEFIExtract for Linux/macOS](https://github.com/LongSoft/UEFITool/releases))
* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux/macOS)
* [ToshibaComExtractor](https://github.com/LongSoft/ToshibaComExtractor) (i.e. [comextract.exe for Windows or comextract for Linux/macOS](https://github.com/LongSoft/ToshibaComExtractor/releases))
Note: On Linux, you need to compile "comextract" from sources as no pre-built binary exists.
Note: On Linux and macOS, you need to compile "TianoCompress" from sources as no pre-built binary exists.
Optionally, to decompile the Intel BIOS Guard Scripts (when applicable), you must have the following 3rd party python script at PATH or "external":
* [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py)
External executables and/or scripts (e.g. TianoCompress.exe, big_script_tool.py, 7z.exe) need to be found via the "PATH" environment variable, which is configured differently depending on the operating system. External executables and/or scripts (e.g. TianoCompress.exe, big_script_tool.py, 7z.exe) need to be found via the "PATH" environment variable, which is configured differently depending on the operating system.
Alternatively, if neither modifying PATH environment variable nor copying the executables in standard OS PATH directories is an option, you can create a folder "external" at the root of the "biosutilities" project. Alternatively, if neither modifying PATH environment variable nor copying the executables in standard OS PATH directories is an option, you can create a folder "external" at the root of the "biosutilities" project.
@ -143,14 +162,14 @@ Alternatively, if neither modifying PATH environment variable nor copying the ex
or or
``` bash ``` bash
sudo install "/path/to/downloaded/external/executable/to/install" /usr/local/bin sudo install "/path/to/downloaded/executable" /usr/local/bin
``` ```
#### Windows #### Windows
[Windows Path](https://www.computerhope.com/issues/ch000549.htm) [Windows Path](https://www.computerhope.com/issues/ch000549.htm)
Note: In the "Environment Variables" window, you can modify the "Path" variable under "User variables" instead of "System variables", as many guides suggest. Note: In the "Environment Variables" window, you can modify the "Path" variable under "User variables" instead of "System variables", contrary to what many guides suggest.
#### MacOS #### MacOS
@ -187,11 +206,9 @@ Note that the AMI PFAT structure may not have an explicit component order. AMI's
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
Optionally, to decompile the AMI PFAT \> Intel BIOS Guard Scripts, you must have the following 3rd party python script at PATH or "external": * BIOS Guard Script Tool (optional)
* [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py)
### AMI UCP Update Extractor ### AMI UCP Update Extractor
@ -205,18 +222,11 @@ Additional optional arguments are provided for this utility:
* checksum -> bool : verify AMI UCP Checksums (slow) * checksum -> bool : verify AMI UCP Checksums (slow)
#### Prerequisites #### Requirements
To run the utility, you must have the following 3rd party tools at PATH or "external": * 7-Zip (required)
* TianoCompress (required)
* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux/macOS) * BIOS Guard Script Tool (optional)
* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux)
Optionally, to decompile the AMI UCP \> AMI PFAT \> Intel BIOS Guard Scripts (when applicable), you must have the following 3rd party python script at PATH or "external":
* [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py)
Note: On Linux and macOS, you'll need to compile TianoCompress from sources as no pre-built binary exists.
### Apple EFI IM4P Splitter ### Apple EFI IM4P Splitter
@ -228,9 +238,9 @@ Parses Apple IM4P multi-EFI files and splits all detected EFI firmware into sepa
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
To run the utility, you do not need any prerequisites. No additional requirements are needed for this utility.
### Apple EFI Image Identifier ### Apple EFI Image Identifier
@ -248,14 +258,12 @@ The utility exposes certain public class attributes, once parse_format() method
* efi_file_name -> str : Suggested image filename, based on Intel "IBIOSI" information * efi_file_name -> str : Suggested image filename, based on Intel "IBIOSI" information
* intel_bios_info -> dict[str, str] : Information contained at Intel "IBIOSI" structure * 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 * apple_rom_version -> dict[str, str] : Information contained at "Apple ROM Version" structure
#### Prerequisites #### Requirements
To run the utility, you must have the following 3rd party tools at PATH or "external": * UEFIFind (required)
* UEFIExtract (required)
* [UEFIFind](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIFind.exe for Windows or UEFIFind for Linux/macOS](https://github.com/LongSoft/UEFITool/releases))
* [UEFIExtract](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIExtract.exe for Windows or UEFIExtract for Linux/macOS](https://github.com/LongSoft/UEFITool/releases))
### Apple EFI Package Extractor ### Apple EFI Package Extractor
@ -267,13 +275,11 @@ Parses Apple EFI PKG firmware packages (e.g. FirmwareUpdate.pkg, BridgeOSUpdateC
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
To run the utility, you must have the following 3rd party tools at PATH or "external": * 7-Zip (required)
* UEFIFind (required)
* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux) * UEFIExtract (required)
* [UEFIFind](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIFind.exe for Windows or UEFIFind for Linux/macOS](https://github.com/LongSoft/UEFITool/releases))
* [UEFIExtract](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIExtract.exe for Windows or UEFIExtract for Linux/macOS](https://github.com/LongSoft/UEFITool/releases))
### Apple EFI PBZX Extractor ### Apple EFI PBZX Extractor
@ -285,11 +291,9 @@ Parses Apple EFI PBZX images, re-assembles their CPIO payload and extracts its f
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
To run the utility, you must have the following 3rd party tools at PATH or "external": * 7-Zip (required)
* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux)
### Award BIOS Module Extractor ### Award BIOS Module Extractor
@ -301,11 +305,9 @@ Parses Award BIOS images and extracts their modules (e.g. RAID, MEMINIT, \_EN_CO
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
To run the utility, you must have the following 3rd party tool at PATH or "external": * 7-Zip (required)
* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux)
### Dell PFS Update Extractor ### Dell PFS Update Extractor
@ -320,11 +322,9 @@ Additional optional arguments are provided for this utility:
* advanced -> bool : extract signatures and metadata * advanced -> bool : extract signatures and metadata
* structure -> bool : show PFS structure information * structure -> bool : show PFS structure information
#### Prerequisites #### Requirements
Optionally, to decompile the Intel BIOS Guard (PFAT) Scripts, you must have the following 3rd party utility at PATH or "external": * BIOS Guard Script Tool (optional)
* [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py)
### Fujitsu SFX BIOS Extractor ### Fujitsu SFX BIOS Extractor
@ -336,11 +336,9 @@ Parses Fujitsu SFX BIOS images and extracts their obfuscated Microsoft CAB archi
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
To run the utility, you must have the following 3rd party tool at PATH or "external": * 7-Zip (required)
* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux)
### Fujitsu UPC BIOS Extractor ### Fujitsu UPC BIOS Extractor
@ -352,13 +350,9 @@ Parses Fujitsu UPC BIOS images and extracts their EFI compressed SPI/BIOS/UEFI f
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
To run the utility, you must have the following 3rd party tool at PATH or "external": * TianoCompress (required)
* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux/macOS)
Note: On Linux and macOS, you'll need to compile TianoCompress from sources as no pre-built binary exists.
### Insyde iFlash/iFdPacker Extractor ### Insyde iFlash/iFdPacker Extractor
@ -370,9 +364,9 @@ Parses Insyde iFlash/iFdPacker Update images and extracts their firmware (e.g. S
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
To run the utility, you do not need any prerequisites. No additional requirements are needed for this utility.
### Panasonic BIOS Package Extractor ### Panasonic BIOS Package Extractor
@ -384,16 +378,11 @@ Parses Panasonic BIOS Package executables and extracts their firmware (e.g. SPI,
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
To run the utility, you must have the following 3rd party Python modules installed: * 7-Zip (required)
* pefile (required)
* [pefile](https://pypi.org/project/pefile/2023.2.7/) * dissect.util (required)
* [dissect.util](https://pypi.org/project/dissect.util/3.18/)
Moreover, you must have the following 3rd party tool at PATH or "external":
* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux)
### Phoenix TDK Packer Extractor ### Phoenix TDK Packer Extractor
@ -405,11 +394,9 @@ Parses Phoenix Tools Development Kit (TDK) Packer executables and extracts their
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
To run the utility, you must have the following 3rd party Python module installed: * pefile (required)
* [pefile](https://pypi.org/project/pefile/2023.2.7/)
### Portwell EFI Update Extractor ### Portwell EFI Update Extractor
@ -421,17 +408,10 @@ Parses Portwell UEFI Unpacker EFI executables (usually named "Update.efi") and e
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
To run the utility, you must have the following 3rd party Python module installed: * pefile (required)
* TianoCompress (required)
* [pefile](https://pypi.org/project/pefile/2023.2.7/)
Moreover, you must have the following 3rd party tool at PATH or "external":
* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux/macOS)
Note: On Linux and macOS, you'll need to compile TianoCompress from sources as no pre-built binary exists.
### Toshiba BIOS COM Extractor ### Toshiba BIOS COM Extractor
@ -443,13 +423,9 @@ Parses Toshiba BIOS COM images and extracts their raw or compressed SPI/BIOS/UEF
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
To run the utility, you must have the following 3rd party tool at PATH or "external": * ToshibaComExtractor (required)
* [ToshibaComExtractor](https://github.com/LongSoft/ToshibaComExtractor) (i.e. [comextract.exe for Windows or comextract for Linux/macOS](https://github.com/LongSoft/ToshibaComExtractor/releases))
Note: On Linux, you'll need to compile comextract from sources as no pre-built binary exists.
### VAIO Packaging Manager Extractor ### VAIO Packaging Manager Extractor
@ -461,8 +437,6 @@ Parses VAIO Packaging Manager executables and extracts their firmware (e.g. SPI,
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### Prerequisites #### Requirements
To run the utility, you must have the following 3rd party tool at PATH or "external": * 7-Zip (required)
* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux)

View file

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

View file

@ -13,18 +13,20 @@ import struct
import subprocess import subprocess
import zlib import zlib
from collections import defaultdict from datetime import datetime
from re import Match from re import Match
from typing import Any, Final from typing import Any, Final
from biosutilities.common.externals import uefiextract_path, uefifind_path from biosutilities.common.externals import uefiextract_path, uefifind_path
from biosutilities.common.paths import delete_dirs, delete_file, is_file, make_dirs, path_suffixes, runtime_root from biosutilities.common.paths import (delete_dirs, delete_file, is_file_read, make_dirs, path_size,
path_suffixes, runtime_root)
from biosutilities.common.patterns import PAT_INTEL_IBIOSI, PAT_APPLE_ROM_VER from biosutilities.common.patterns import PAT_INTEL_IBIOSI, PAT_APPLE_ROM_VER
from biosutilities.common.structs import CHAR, ctypes_struct, UINT8 from biosutilities.common.structs import CHAR, ctypes_struct, UINT8
from biosutilities.common.system import printer from biosutilities.common.system import printer
from biosutilities.common.templates import BIOSUtility from biosutilities.common.templates import BIOSUtility
EFI_EXTENSIONS: Final[list[str]] = ['.fd', '.scap', '.im4p'] EFI_EXTENSIONS: Final[list[str]] = ['.fd', '.scap', '.im4p']
EFI_MAX_SIZE: Final[int] = 0x3000000
class IntelBiosId(ctypes.LittleEndianStructure): class IntelBiosId(ctypes.LittleEndianStructure):
@ -62,35 +64,27 @@ class IntelBiosId(ctypes.LittleEndianStructure):
def get_bios_id(self) -> dict[str, str]: def get_bios_id(self) -> dict[str, str]:
""" Get Apple/Intel EFI BIOS ID """ """ Get Apple/Intel EFI BIOS ID """
intel_sig: str = self.Signature.decode('utf-8')
board_id: str = self._decode(field=self.BoardID) board_id: str = self._decode(field=self.BoardID)
board_ext: str = self._decode(field=self.BoardExt) board_ext: str = self._decode(field=self.BoardExt)
version_major: str = self._decode(field=self.VersionMajor) version_major: str = self._decode(field=self.VersionMajor)
build_type: str = self._decode(field=self.BuildType) build_type: str = self._decode(field=self.BuildType)
version_minor: str = self._decode(field=self.VersionMinor) version_minor: str = self._decode(field=self.VersionMinor)
build_year: str = self._decode(field=self.Year) build_year: int = int(f'20{self._decode(field=self.Year)}')
build_month: str = self._decode(field=self.Month) build_month: int = int(self._decode(field=self.Month))
build_day: str = self._decode(field=self.Day) build_day: int = int(self._decode(field=self.Day))
build_hour: str = self._decode(field=self.Hour) build_hour: int = int(self._decode(field=self.Hour))
build_minute: str = self._decode(field=self.Minute) build_minute: int = int(self._decode(field=self.Minute))
efi_name_id: str = (f'{board_id}_{board_ext}_{version_major}_{build_type}{version_minor}' efi_version: str = f'{version_major}_{build_type}{version_minor}'
f'_20{build_year}-{build_month}-{build_day}_{build_hour}-{build_minute}') efi_date: datetime = datetime(build_year, build_month, build_day, build_hour, build_minute)
efi_name: str = f'{board_id}_{board_ext}_{efi_version}_{efi_date.strftime("%Y-%m-%d_%H-%M")}'
return { return {
'intel_sig': intel_sig,
'board_id': board_id, 'board_id': board_id,
'board_ext': board_ext, 'apple_id': board_ext,
'version_major': version_major, 'version': efi_version,
'version_minor': version_minor, 'date': efi_date.isoformat(),
'build_type': build_type, 'name': efi_name
'build_year': build_year,
'build_month': build_month,
'build_day': build_day,
'build_hour': build_hour,
'build_minute': build_minute,
'efi_name_id': efi_name_id
} }
def struct_print(self, padding: int = 0) -> None: def struct_print(self, padding: int = 0) -> None:
@ -98,17 +92,10 @@ class IntelBiosId(ctypes.LittleEndianStructure):
ibiosi: dict[str, str] = self.get_bios_id() ibiosi: dict[str, str] = self.get_bios_id()
ibiosi_date: str = f'20{ibiosi["build_year"]}-{ibiosi["build_month"]}-{ibiosi["build_day"]}' printer(message=['Board ID: ', ibiosi['board_id']], padding=padding, new_line=False)
ibiosi_time: str = f'{ibiosi["build_hour"]}:{ibiosi["build_minute"]}' printer(message=['Apple ID: ', ibiosi['apple_id']], padding=padding, new_line=False)
printer(message=['Version: ', ibiosi['version']], padding=padding, new_line=False)
printer(message=['Intel Signature:', ibiosi['intel_sig']], padding=padding, new_line=False) printer(message=['Datetime: ', ibiosi['date']], padding=padding, new_line=False)
printer(message=['Board Identity: ', ibiosi['board_id']], padding=padding, new_line=False)
printer(message=['Apple Identity: ', ibiosi['board_ext']], padding=padding, new_line=False)
printer(message=['Major Version: ', ibiosi['version_major']], padding=padding, new_line=False)
printer(message=['Minor Version: ', ibiosi['version_minor']], padding=padding, new_line=False)
printer(message=['Build Type: ', ibiosi['build_type']], padding=padding, new_line=False)
printer(message=['Build Date: ', ibiosi_date], padding=padding, new_line=False)
printer(message=['Build Time: ', ibiosi_time], padding=padding, new_line=False)
class AppleEfiIdentify(BIOSUtility): class AppleEfiIdentify(BIOSUtility):
@ -125,26 +112,51 @@ class AppleEfiIdentify(BIOSUtility):
self.silent: bool = silent self.silent: bool = silent
self.efi_file_name: str = '' self.efi_file_name: str = ''
self.intel_bios_info: dict[str, str] = {}
self.apple_rom_version: defaultdict[str, set] = defaultdict(set) self.intel_bios_info: dict[str, str] = {
'board_id': '',
'apple_id': '',
'version': '',
'date': '',
'name': ''
}
self.apple_rom_version: dict[str, str] = {
'bios_id': '',
'board_id': '',
'build_type': '',
'buildcave_id': '',
'built_by': '',
'compiler': '',
'date': '',
'efi_version': '',
'model': '',
'rom_version': '',
'revision': '',
'uuid': ''
}
def check_format(self) -> bool: def check_format(self) -> bool:
""" Check if input is Apple EFI image """ """ Check if input is Apple EFI image """
if isinstance(self.input_object, str) and is_file(in_path=self.input_object): if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object):
if path_suffixes(in_path=self.input_object)[-1].lower() not in EFI_EXTENSIONS: if path_suffixes(in_path=self.input_object)[-1].lower() not in EFI_EXTENSIONS:
return False return False
if path_size(in_path=self.input_object) > EFI_MAX_SIZE:
return False
input_path: str = self.input_object input_path: str = self.input_object
else: else:
if len(self.input_buffer) > EFI_MAX_SIZE:
return False
input_path = os.path.join(runtime_root(), 'APPLE_EFI_ID_INPUT_BUFFER_CHECK.tmp') input_path = os.path.join(runtime_root(), 'APPLE_EFI_ID_INPUT_BUFFER_CHECK.tmp')
with open(input_path, 'wb') as check_out: with open(input_path, 'wb') as check_out:
check_out.write(self.input_buffer) check_out.write(self.input_buffer)
input_buffer: bytes = self.input_buffer if PAT_INTEL_IBIOSI.search(self.input_buffer):
if PAT_INTEL_IBIOSI.search(input_buffer):
return True return True
uefifind_cmd: list[str] = [uefifind_path(), input_path, 'body', 'list', self.PAT_UEFIFIND] uefifind_cmd: list[str] = [uefifind_path(), input_path, 'body', 'list', self.PAT_UEFIFIND]
@ -163,7 +175,7 @@ class AppleEfiIdentify(BIOSUtility):
def parse_format(self) -> bool: def parse_format(self) -> bool:
""" Parse & Identify (or Rename) Apple EFI image """ """ Parse & Identify (or Rename) Apple EFI image """
if isinstance(self.input_object, str) and is_file(in_path=self.input_object): if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object):
input_path: str = self.input_object input_path: str = self.input_object
else: else:
input_path = os.path.join(runtime_root(), 'APPLE_EFI_ID_INPUT_BUFFER_PARSE.tmp') input_path = os.path.join(runtime_root(), 'APPLE_EFI_ID_INPUT_BUFFER_PARSE.tmp')
@ -213,9 +225,9 @@ class AppleEfiIdentify(BIOSUtility):
bios_id_hdr.struct_print(padding=self.padding + 4) bios_id_hdr.struct_print(padding=self.padding + 4)
self.intel_bios_info = bios_id_hdr.get_bios_id() self.intel_bios_info |= bios_id_hdr.get_bios_id()
self.efi_file_name = (f'{self.intel_bios_info["efi_name_id"]}_{zlib.adler32(self.input_buffer):08X}' self.efi_file_name = (f'{self.intel_bios_info["name"]}_{zlib.adler32(self.input_buffer):08X}'
f'{path_suffixes(in_path=input_path)[-1]}') f'{path_suffixes(in_path=input_path)[-1]}')
_ = self._apple_rom_version(input_buffer=self.input_buffer, padding=self.padding) _ = self._apple_rom_version(input_buffer=self.input_buffer, padding=self.padding)
@ -245,16 +257,28 @@ class AppleEfiIdentify(BIOSUtility):
rom_version_text: str = rom_version_data.decode('utf-8').strip('\n') rom_version_text: str = rom_version_data.decode('utf-8').strip('\n')
for rom_version_line in [line.strip() for line in rom_version_text.split('\n')]:
rom_version_parts: list[str] = rom_version_line.split(sep=':', maxsplit=1)
self.apple_rom_version[rom_version_parts[0].strip()].add(rom_version_parts[1].strip())
if not self.silent: if not self.silent:
printer(message=f'Detected Apple ROM Version at 0x{rom_version_match_off:X}', padding=padding) 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) printer(message=rom_version_text, strip=True, padding=padding + 4)
for rom_version_line in [line.strip() for line in rom_version_text.split('\n')]:
rom_version_parts: list[str] = rom_version_line.split(sep=':', maxsplit=1)
rom_version_key: str = rom_version_parts[0].strip().lower().replace(' ', '_')
rom_version_val: str = rom_version_parts[1].strip()
if rom_version_key == 'uuid':
if self.apple_rom_version[rom_version_key] == '':
self.apple_rom_version[rom_version_key] = rom_version_val
else:
self.apple_rom_version[rom_version_key] += f', {rom_version_val}'
elif rom_version_key == 'date':
self.apple_rom_version[rom_version_key] = datetime.strptime(rom_version_val.replace(
' PDT', '').replace(' PST', ''), '%a %b %d %H:%M:%S %Y').isoformat()
else:
self.apple_rom_version[rom_version_key] = rom_version_val
return True return True
return False return False

View file

@ -12,11 +12,13 @@ import os
from re import Match from re import Match
from typing import Final from typing import Final
from biosutilities.common.paths import make_dirs, path_stem from biosutilities.common.paths import is_file_read, make_dirs, path_size, path_stem
from biosutilities.common.patterns import PAT_APPLE_IM4P, PAT_INTEL_FD from biosutilities.common.patterns import PAT_APPLE_IM4P, PAT_INTEL_FD
from biosutilities.common.system import printer from biosutilities.common.system import printer
from biosutilities.common.templates import BIOSUtility from biosutilities.common.templates import BIOSUtility
from biosutilities.apple_efi_id import EFI_MAX_SIZE
class AppleEfiIm4pSplit(BIOSUtility): class AppleEfiIm4pSplit(BIOSUtility):
""" Apple EFI IM4P Splitter """ """ Apple EFI IM4P Splitter """
@ -29,8 +31,12 @@ class AppleEfiIm4pSplit(BIOSUtility):
def check_format(self) -> bool: def check_format(self) -> bool:
""" Check if input is Apple EFI IM4P image """ """ Check if input is Apple EFI IM4P image """
if isinstance(self.input_object, str) and not self.input_object.lower().endswith('.im4p'): if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object):
return False if not self.input_object.lower().endswith('.im4p'):
return False
if path_size(in_path=self.input_object) > EFI_MAX_SIZE:
return False
if PAT_APPLE_IM4P.search(self.input_buffer) and PAT_INTEL_FD.search(self.input_buffer): if PAT_APPLE_IM4P.search(self.input_buffer) and PAT_INTEL_FD.search(self.input_buffer):
return True return True

View file

@ -15,7 +15,7 @@ import os
from typing import Any, Final from typing import Any, Final
from biosutilities.common.compression import is_szip_supported, szip_decompress from biosutilities.common.compression import is_szip_supported, szip_decompress
from biosutilities.common.paths import delete_file, make_dirs, path_stem from biosutilities.common.paths import delete_file, is_file_read, make_dirs, path_stem
from biosutilities.common.patterns import PAT_APPLE_PBZX from biosutilities.common.patterns import PAT_APPLE_PBZX
from biosutilities.common.structs import ctypes_struct, UINT32 from biosutilities.common.structs import ctypes_struct, UINT32
from biosutilities.common.system import printer from biosutilities.common.system import printer
@ -53,7 +53,13 @@ class AppleEfiPbzxExtract(BIOSUtility):
def check_format(self) -> bool: def check_format(self) -> bool:
""" Check if input is Apple PBZX image """ """ Check if input is Apple PBZX image """
return bool(PAT_APPLE_PBZX.search(self.input_buffer, 0, 4)) if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object):
with open(self.input_object, 'rb') as input_object:
check_buffer: bytes = input_object.read(4)
else:
check_buffer = self.input_buffer[:4]
return bool(PAT_APPLE_PBZX.search(check_buffer, 0, 4))
def parse_format(self) -> bool: def parse_format(self) -> bool:
""" Parse & Extract Apple PBZX image """ """ Parse & Extract Apple PBZX image """

View file

@ -10,8 +10,9 @@ Copyright (C) 2019-2024 Plato Mavropoulos
import os import os
from biosutilities.common.compression import is_szip_supported, szip_decompress from biosutilities.common.compression import is_szip_supported, szip_decompress
from biosutilities.common.paths import (copy_file, delete_dirs, delete_file, extract_folder, is_access, is_dir, from biosutilities.common.paths import (copy_file, delete_dirs, delete_file, extract_folder, is_dir,
is_file, make_dirs, path_files, path_name, path_suffixes, runtime_root) is_file_read, make_dirs, path_files, path_name, path_stem,
path_suffixes, runtime_root)
from biosutilities.common.system import printer from biosutilities.common.system import printer
from biosutilities.common.templates import BIOSUtility from biosutilities.common.templates import BIOSUtility
@ -30,7 +31,7 @@ class AppleEfiPkgExtract(BIOSUtility):
is_apple_efi_pkg: bool = False is_apple_efi_pkg: bool = False
if isinstance(self.input_object, str) and is_file(in_path=self.input_object): if isinstance(self.input_object, str) and self._is_file_processable(input_path=self.input_object):
input_path: str = self.input_object input_path: str = self.input_object
else: else:
input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_CHECK.bin') input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_CHECK.bin')
@ -52,7 +53,7 @@ class AppleEfiPkgExtract(BIOSUtility):
def parse_format(self) -> bool: def parse_format(self) -> bool:
""" Parse & Extract Apple EFI PKG packages """ """ Parse & Extract Apple EFI PKG packages """
if isinstance(self.input_object, str) and is_file(in_path=self.input_object): if isinstance(self.input_object, str) and self._is_file_processable(input_path=self.input_object):
input_path: str = self.input_object input_path: str = self.input_object
else: else:
input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_PARSE.bin') input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_PARSE.bin')
@ -76,7 +77,7 @@ class AppleEfiPkgExtract(BIOSUtility):
delete_file(in_path=input_path) delete_file(in_path=input_path)
for work_file in path_files(in_path=working_dir): for work_file in path_files(in_path=working_dir):
if is_file(in_path=work_file) and is_access(in_path=work_file): if self._is_file_processable(input_path=work_file):
self._pbzx_zip(input_path=work_file, padding=self.padding + 4) self._pbzx_zip(input_path=work_file, padding=self.padding + 4)
self._gzip_cpio(input_path=work_file, padding=self.padding + 4) self._gzip_cpio(input_path=work_file, padding=self.padding + 4)
self._dmg_zip(input_path=work_file, padding=self.padding + 4) self._dmg_zip(input_path=work_file, padding=self.padding + 4)
@ -86,6 +87,10 @@ class AppleEfiPkgExtract(BIOSUtility):
return True return True
@staticmethod
def _is_file_processable(input_path: str) -> bool:
return is_file_read(in_path=input_path) and path_stem(in_path=input_path) != '.aea'
def _xar_gzip(self, input_path: str, padding: int = 0) -> None: def _xar_gzip(self, input_path: str, padding: int = 0) -> None:
""" XAR/TAR > GZIP """ """ XAR/TAR > GZIP """
@ -96,7 +101,7 @@ class AppleEfiPkgExtract(BIOSUtility):
if szip_decompress(in_path=input_path, out_path=pkg_path, in_name=pkg_type, if szip_decompress(in_path=input_path, out_path=pkg_path, in_name=pkg_type,
padding=padding, args=[f'-t{pkg_type}']): padding=padding, args=[f'-t{pkg_type}']):
for pkg_file in path_files(in_path=pkg_path): for pkg_file in path_files(in_path=pkg_path):
if is_file(in_path=pkg_file) and is_access(in_path=pkg_file): if self._is_file_processable(input_path=pkg_file):
self._gzip_cpio(input_path=pkg_file, padding=padding + 4) self._gzip_cpio(input_path=pkg_file, padding=padding + 4)
break break
@ -109,14 +114,15 @@ class AppleEfiPkgExtract(BIOSUtility):
if szip_decompress(in_path=input_path, out_path=dmg_path, in_name='DMG', padding=padding, args=None): if szip_decompress(in_path=input_path, out_path=dmg_path, in_name='DMG', padding=padding, args=None):
for dmg_file in path_files(in_path=dmg_path): for dmg_file in path_files(in_path=dmg_path):
if is_file(in_path=dmg_file) and is_access(in_path=dmg_file): if self._is_file_processable(input_path=dmg_file):
if is_szip_supported(in_path=dmg_file, args=['-tZIP']): if is_szip_supported(in_path=dmg_file, args=['-tZIP']):
zip_path: str = extract_folder(in_path=dmg_file) zip_path: str = extract_folder(in_path=dmg_file)
if szip_decompress(in_path=dmg_file, out_path=zip_path, in_name='ZIP', if szip_decompress(in_path=dmg_file, out_path=zip_path, in_name='ZIP',
padding=padding + 4, args=['-tZIP']): padding=padding + 4, args=['-tZIP']):
for zip_file in path_files(in_path=zip_path): for zip_file in path_files(in_path=zip_path):
self._im4p_id(input_path=zip_file, padding=padding + 8) if self._is_file_processable(input_path=zip_file):
self._im4p_id(input_path=zip_file, padding=padding + 8)
def _pbzx_zip(self, input_path: str, padding: int = 0) -> None: def _pbzx_zip(self, input_path: str, padding: int = 0) -> None:
""" PBZX > ZIP """ """ PBZX > ZIP """
@ -133,14 +139,15 @@ class AppleEfiPkgExtract(BIOSUtility):
printer(message=f'Successful PBZX extraction via {pbzx_module.TITLE}!', padding=padding) printer(message=f'Successful PBZX extraction via {pbzx_module.TITLE}!', padding=padding)
for pbzx_file in path_files(in_path=pbzx_path): for pbzx_file in path_files(in_path=pbzx_path):
if is_file(in_path=pbzx_file) and is_access(in_path=pbzx_file): if self._is_file_processable(input_path=pbzx_file):
if is_szip_supported(in_path=pbzx_file, args=['-tZIP']): if is_szip_supported(in_path=pbzx_file, args=['-tZIP']):
zip_path: str = extract_folder(in_path=pbzx_file) zip_path: str = extract_folder(in_path=pbzx_file)
if szip_decompress(in_path=pbzx_file, out_path=zip_path, in_name='ZIP', if szip_decompress(in_path=pbzx_file, out_path=zip_path, in_name='ZIP',
padding=padding + 4, args=['-tZIP']): padding=padding + 4, args=['-tZIP']):
for zip_file in path_files(in_path=zip_path): for zip_file in path_files(in_path=zip_path):
self._im4p_id(input_path=zip_file, padding=padding + 8) if self._is_file_processable(input_path=zip_file):
self._im4p_id(input_path=zip_file, padding=padding + 8)
def _gzip_cpio(self, input_path: str, padding: int = 0) -> None: def _gzip_cpio(self, input_path: str, padding: int = 0) -> None:
""" GZIP > CPIO """ """ GZIP > CPIO """
@ -151,14 +158,15 @@ class AppleEfiPkgExtract(BIOSUtility):
if szip_decompress(in_path=input_path, out_path=gzip_path, in_name='GZIP', if szip_decompress(in_path=input_path, out_path=gzip_path, in_name='GZIP',
padding=padding, args=['-tGZIP']): padding=padding, args=['-tGZIP']):
for gzip_file in path_files(in_path=gzip_path): for gzip_file in path_files(in_path=gzip_path):
if is_file(in_path=gzip_file) and is_access(in_path=gzip_file): if self._is_file_processable(input_path=gzip_file):
if is_szip_supported(in_path=gzip_file, args=['-tCPIO']): if is_szip_supported(in_path=gzip_file, args=['-tCPIO']):
cpio_path: str = extract_folder(in_path=gzip_file) cpio_path: str = extract_folder(in_path=gzip_file)
if szip_decompress(in_path=gzip_file, out_path=cpio_path, in_name='CPIO', if szip_decompress(in_path=gzip_file, out_path=cpio_path, in_name='CPIO',
padding=padding + 4, args=['-tCPIO']): padding=padding + 4, args=['-tCPIO']):
for cpio_file in path_files(in_path=cpio_path): for cpio_file in path_files(in_path=cpio_path):
self._im4p_id(input_path=cpio_file, padding=padding + 8) if self._is_file_processable(input_path=cpio_file):
self._im4p_id(input_path=cpio_file, padding=padding + 8)
def _im4p_id(self, input_path: str, padding: int = 0) -> None: def _im4p_id(self, input_path: str, padding: int = 0) -> None:
""" Split IM4P (if applicable), identify and copy EFI """ """ Split IM4P (if applicable), identify and copy EFI """
@ -166,7 +174,7 @@ class AppleEfiPkgExtract(BIOSUtility):
if path_suffixes(in_path=input_path)[-1].lower() not in EFI_EXTENSIONS: if path_suffixes(in_path=input_path)[-1].lower() not in EFI_EXTENSIONS:
return None return None
if not (is_file(in_path=input_path) and is_access(in_path=input_path)): if not self._is_file_processable(input_path=input_path):
return None return None
working_dir: str = extract_folder(in_path=input_path) working_dir: str = extract_folder(in_path=input_path)
@ -185,7 +193,7 @@ class AppleEfiPkgExtract(BIOSUtility):
im4p_module.parse_format() im4p_module.parse_format()
for efi_path in path_files(in_path=working_dir) if is_dir(in_path=working_dir) else [input_path]: for efi_path in path_files(in_path=working_dir) if is_dir(in_path=working_dir) else [input_path]:
if is_file(in_path=efi_path) and is_access(in_path=efi_path): if self._is_file_processable(input_path=efi_path):
efi_id_module: AppleEfiIdentify = AppleEfiIdentify( efi_id_module: AppleEfiIdentify = AppleEfiIdentify(
input_object=efi_path, extract_path=extract_folder(in_path=efi_path), padding=padding + 8) input_object=efi_path, extract_path=extract_folder(in_path=efi_path), padding=padding + 8)

View file

@ -10,7 +10,8 @@ Copyright (C) 2018-2024 Plato Mavropoulos
import os import os
from biosutilities.common.compression import szip_decompress from biosutilities.common.compression import szip_decompress
from biosutilities.common.paths import clear_readonly, delete_file, extract_folder, is_file, make_dirs, safe_name from biosutilities.common.paths import (clear_readonly, delete_file, extract_folder, is_file_read,
make_dirs, safe_name)
from biosutilities.common.patterns import PAT_AWARD_LZH from biosutilities.common.patterns import PAT_AWARD_LZH
from biosutilities.common.system import printer from biosutilities.common.system import printer
from biosutilities.common.templates import BIOSUtility from biosutilities.common.templates import BIOSUtility
@ -70,7 +71,7 @@ class AwardBiosExtract(BIOSUtility):
padding=self.padding + 4) padding=self.padding + 4)
# Manually check if 7-Zip extracted LZH due to its CRC check issue # Manually check if 7-Zip extracted LZH due to its CRC check issue
if is_file(in_path=mod_path): if is_file_read(in_path=mod_path):
clear_readonly(in_path=lzh_path) clear_readonly(in_path=lzh_path)
delete_file(in_path=lzh_path) # Successful extraction, delete LZH archive delete_file(in_path=lzh_path) # Successful extraction, delete LZH archive

View file

@ -10,7 +10,7 @@ import subprocess
from typing import Final from typing import Final
from biosutilities.common.externals import szip_path, tiano_path from biosutilities.common.externals import szip_path, tiano_path
from biosutilities.common.paths import is_access, is_dir, is_file, is_empty_dir, path_size from biosutilities.common.paths import is_dir, is_file_read, is_empty_dir, path_size
from biosutilities.common.system import printer from biosutilities.common.system import printer
from biosutilities.common.texts import file_to_bytes from biosutilities.common.texts import file_to_bytes
@ -118,7 +118,7 @@ def efi_decompress(in_path: str, out_path: str, padding: int = 0, silent: bool =
tiano_x: subprocess.CompletedProcess[bytes] = subprocess.run(tiano_c, check=False, stdout=subprocess.DEVNULL) tiano_x: subprocess.CompletedProcess[bytes] = subprocess.run(tiano_c, check=False, stdout=subprocess.DEVNULL)
if tiano_x.returncode == 0 and is_file(in_path=out_path) and is_access(in_path=out_path): if tiano_x.returncode == 0 and is_file_read(in_path=out_path):
if efi_header_info(in_object=in_path)['size_decompressed'] == path_size(in_path=out_path): if efi_header_info(in_object=in_path)['size_decompressed'] == path_size(in_path=out_path):
if not silent: if not silent:
printer(message='Successful EFI decompression via TianoCompress!', padding=padding) printer(message='Successful EFI decompression via TianoCompress!', padding=padding)

View file

@ -16,7 +16,7 @@ from importlib.util import module_from_spec, spec_from_file_location
from types import ModuleType from types import ModuleType
from typing import Type from typing import Type
from biosutilities.common.paths import is_dir, is_file, project_root from biosutilities.common.paths import is_dir, is_file_read, project_root
from biosutilities.common.texts import to_string from biosutilities.common.texts import to_string
@ -30,10 +30,10 @@ def get_external_path(cmd: str | list | tuple) -> str:
for command in cmd if isinstance(cmd, (list, tuple)) else [to_string(in_object=cmd)]: for command in cmd if isinstance(cmd, (list, tuple)) else [to_string(in_object=cmd)]:
command_path: str | None = shutil.which(command, path=external_path) command_path: str | None = shutil.which(command, path=external_path)
if command_path and is_file(in_path=command_path): if command_path and is_file_read(in_path=command_path):
return command_path return command_path
raise OSError(f'{to_string(in_object=cmd, sep_char=", ")} could not be found!') raise OSError(f'{to_string(in_object=cmd, sep_char=", ")} requirement could not be found!')
def big_script_tool() -> Type | None: def big_script_tool() -> Type | None:

View file

@ -237,6 +237,18 @@ def is_access(in_path: str, access_mode: int = os.R_OK, follow_links: bool = Fal
return os.access(in_path, access_mode, follow_symlinks=follow_links) return os.access(in_path, access_mode, follow_symlinks=follow_links)
def is_file_read(in_path: str) -> bool:
""" Check if path is a readable file """
return isinstance(in_path, str) and is_file(in_path=in_path) and is_access(in_path=in_path)
def is_dir_read(in_path: str) -> bool:
""" Check if path is a readable directory """
return isinstance(in_path, str) and is_dir(in_path=in_path) and is_access(in_path=in_path)
def is_empty_dir(in_path: str, follow_links: bool = False) -> bool: def is_empty_dir(in_path: str, follow_links: bool = False) -> bool:
""" Check if directory is empty (file-wise) """ """ Check if directory is empty (file-wise) """

View file

@ -5,6 +5,7 @@
Copyright (C) 2022-2024 Plato Mavropoulos Copyright (C) 2022-2024 Plato Mavropoulos
""" """
from biosutilities.common.paths import runtime_root
from biosutilities.common.texts import file_to_bytes from biosutilities.common.texts import file_to_bytes
@ -13,12 +14,22 @@ class BIOSUtility:
TITLE: str = 'BIOS Utility' TITLE: str = 'BIOS Utility'
def __init__(self, input_object: str | bytes | bytearray = b'', extract_path: str = '', padding: int = 0) -> None: def __init__(self, input_object: str | bytes | bytearray = b'', extract_path: str = runtime_root(),
padding: int = 0) -> None:
self.input_object: str | bytes | bytearray = input_object self.input_object: str | bytes | bytearray = input_object
self.extract_path: str = extract_path self.extract_path: str = extract_path
self.padding: int = padding self.padding: int = padding
self.input_buffer: bytes = file_to_bytes(in_object=self.input_object) self.__input_buffer: bytes = b''
@property
def input_buffer(self) -> bytes:
""" Get input object buffer """
if not self.__input_buffer:
self.__input_buffer = file_to_bytes(in_object=self.input_object)
return self.__input_buffer
def check_format(self) -> bool: def check_format(self) -> bool:
""" Check if input object is of specific supported format """ """ Check if input object is of specific supported format """

View file

@ -19,7 +19,7 @@ from typing import Any, Final
from biosutilities.common.checksums import checksum_8_xor from biosutilities.common.checksums import checksum_8_xor
from biosutilities.common.compression import is_szip_supported, szip_decompress from biosutilities.common.compression import is_szip_supported, szip_decompress
from biosutilities.common.paths import (delete_dirs, delete_file, path_files, is_access, is_file, make_dirs, from biosutilities.common.paths import (delete_dirs, delete_file, path_files, is_file_read, make_dirs,
path_name, path_parent, path_stem, safe_name) path_name, path_parent, path_stem, safe_name)
from biosutilities.common.patterns import PAT_DELL_FTR, PAT_DELL_HDR, PAT_DELL_PKG from biosutilities.common.patterns import PAT_DELL_FTR, PAT_DELL_HDR, PAT_DELL_PKG
from biosutilities.common.structs import CHAR, ctypes_struct, UINT8, UINT16, UINT32, UINT64 from biosutilities.common.structs import CHAR, ctypes_struct, UINT8, UINT16, UINT32, UINT64
@ -263,7 +263,7 @@ class DellPfsExtract(BIOSUtility):
pfs_results: dict[str, bytes] = self._thinos_pkg_extract( pfs_results: dict[str, bytes] = self._thinos_pkg_extract(
input_object=self.input_buffer, extract_path=self.extract_path) input_object=self.input_buffer, extract_path=self.extract_path)
else: else:
pfs_results = {path_stem(in_path=self.input_object) if isinstance(self.input_object, str) and is_file( pfs_results = {path_stem(in_path=self.input_object) if isinstance(self.input_object, str) and is_file_read(
in_path=self.input_object) else 'Image': self.input_buffer} in_path=self.input_object) else 'Image': self.input_buffer}
# Parse each Dell PFS image contained in the input file # Parse each Dell PFS image contained in the input file
@ -362,7 +362,7 @@ class DellPfsExtract(BIOSUtility):
return pfs_results return pfs_results
for pkg_file in path_files(in_path=working_path): for pkg_file in path_files(in_path=working_path):
if is_file(in_path=pkg_file) and is_access(in_path=pkg_file): if is_file_read(in_path=pkg_file):
if self._is_pfs_hdr(input_object=pkg_file): if self._is_pfs_hdr(input_object=pkg_file):
pfs_name: str = path_name(in_path=str(path_parent(in_path=pkg_file))) pfs_name: str = path_name(in_path=str(path_parent(in_path=pkg_file)))

View file

@ -10,7 +10,7 @@ Copyright (C) 2021-2024 Plato Mavropoulos
import os import os
from biosutilities.common.compression import efi_decompress, is_efi_compressed from biosutilities.common.compression import efi_decompress, is_efi_compressed
from biosutilities.common.paths import delete_file, make_dirs, is_file, path_name, path_suffixes from biosutilities.common.paths import delete_file, make_dirs, is_file_read, path_name, path_suffixes
from biosutilities.common.templates import BIOSUtility from biosutilities.common.templates import BIOSUtility
@ -23,7 +23,7 @@ class FujitsuUpcExtract(BIOSUtility):
""" Check if input is Fujitsu UPC image """ """ Check if input is Fujitsu UPC image """
is_upc: bool = False is_upc: bool = False
if isinstance(self.input_object, str) and is_file(in_path=self.input_object): if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object):
is_upc = path_suffixes(self.input_object)[-1].upper() == '.UPC' is_upc = path_suffixes(self.input_object)[-1].upper() == '.UPC'
elif isinstance(self.input_object, (bytes, bytearray)): elif isinstance(self.input_object, (bytes, bytearray)):
is_upc = True is_upc = True
@ -38,7 +38,7 @@ class FujitsuUpcExtract(BIOSUtility):
make_dirs(in_path=self.extract_path) make_dirs(in_path=self.extract_path)
if isinstance(self.input_object, str) and is_file(in_path=self.input_object): if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object):
input_name: str = path_name(in_path=self.input_object) input_name: str = path_name(in_path=self.input_object)
input_path: str = self.input_object input_path: str = self.input_object

View file

@ -14,7 +14,7 @@ import re
from typing import Any, Final from typing import Any, Final
from biosutilities.common.compression import is_szip_supported, szip_decompress from biosutilities.common.compression import is_szip_supported, szip_decompress
from biosutilities.common.paths import (delete_file, extract_folder, is_access, is_file, path_files, from biosutilities.common.paths import (delete_file, extract_folder, is_file_read, path_files,
make_dirs, path_name, safe_name) make_dirs, path_name, safe_name)
from biosutilities.common.patterns import PAT_INSYDE_IFL, PAT_INSYDE_SFX from biosutilities.common.patterns import PAT_INSYDE_IFL, PAT_INSYDE_SFX
from biosutilities.common.structs import CHAR, ctypes_struct, UINT32 from biosutilities.common.structs import CHAR, ctypes_struct, UINT32
@ -224,7 +224,7 @@ class InsydeIfdExtract(BIOSUtility):
exit_codes: list[int] = [] exit_codes: list[int] = []
for sfx_file in path_files(in_path=extract_path): 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 is_file_read(in_path=sfx_file):
insyde_ifd_extract: InsydeIfdExtract = InsydeIfdExtract( insyde_ifd_extract: InsydeIfdExtract = InsydeIfdExtract(
input_object=sfx_file, extract_path=extract_folder(sfx_file), padding=padding + 16) input_object=sfx_file, extract_path=extract_folder(sfx_file), padding=padding + 16)

View file

@ -20,7 +20,7 @@ import pefile
from dissect.util.compression import lznt1 from dissect.util.compression import lznt1
from biosutilities.common.compression import is_szip_supported, szip_decompress from biosutilities.common.compression import is_szip_supported, szip_decompress
from biosutilities.common.paths import delete_file, is_access, is_file, path_files, make_dirs, path_stem, safe_name from biosutilities.common.paths import delete_file, is_file_read, path_files, make_dirs, path_stem, safe_name
from biosutilities.common.executables import ms_pe_desc, ms_pe, is_ms_pe, ms_pe_info_show from biosutilities.common.executables import ms_pe_desc, ms_pe, is_ms_pe, ms_pe_info_show
from biosutilities.common.patterns import PAT_MICROSOFT_CAB from biosutilities.common.patterns import PAT_MICROSOFT_CAB
from biosutilities.common.system import printer from biosutilities.common.system import printer
@ -97,7 +97,7 @@ class PanasonicBiosExtract(BIOSUtility):
def _panasonic_pkg_name(input_object: str | bytes | bytearray) -> str: def _panasonic_pkg_name(input_object: str | bytes | bytearray) -> str:
""" Get Panasonic BIOS Package file name, when applicable """ """ Get Panasonic BIOS Package file name, when applicable """
if isinstance(input_object, str) and is_file(in_path=input_object): if isinstance(input_object, str) and is_file_read(in_path=input_object):
return safe_name(in_name=path_stem(in_path=input_object)) return safe_name(in_name=path_stem(in_path=input_object))
return '' return ''
@ -129,7 +129,7 @@ class PanasonicBiosExtract(BIOSUtility):
delete_file(in_path=cab_path) # Successful extraction, delete CAB archive delete_file(in_path=cab_path) # Successful extraction, delete CAB archive
for extracted_file_path in path_files(in_path=extract_path): for extracted_file_path in path_files(in_path=extract_path):
if is_file(in_path=extracted_file_path) and is_access(in_path=extracted_file_path): if is_file_read(in_path=extracted_file_path):
extracted_pe_file: pefile.PE | None = ms_pe( extracted_pe_file: pefile.PE | None = ms_pe(
in_file=extracted_file_path, padding=padding, silent=True) in_file=extracted_file_path, padding=padding, silent=True)

View file

@ -17,7 +17,7 @@ from typing import Any, Final
from pefile import PE from pefile import PE
from biosutilities.common.paths import is_file, make_dirs, safe_name from biosutilities.common.paths import is_file_read, make_dirs, safe_name
from biosutilities.common.executables import ms_pe, ms_pe_info from biosutilities.common.executables import ms_pe, ms_pe_info
from biosutilities.common.patterns import PAT_MICROSOFT_MZ, PAT_MICROSOFT_PE, PAT_PHOENIX_TDK from biosutilities.common.patterns import PAT_MICROSOFT_MZ, PAT_MICROSOFT_PE, PAT_PHOENIX_TDK
from biosutilities.common.structs import CHAR, ctypes_struct, UINT32 from biosutilities.common.structs import CHAR, ctypes_struct, UINT32
@ -189,7 +189,7 @@ class PhoenixTdkExtract(BIOSUtility):
mod_file: str = os.path.join(self.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 # Account for potential duplicate file names
if is_file(in_path=mod_file): if is_file_read(in_path=mod_file):
mod_file += f'_{entry_index + 1:02d}' mod_file += f'_{entry_index + 1:02d}'
# Save TDK Entry data to output file # Save TDK Entry data to output file

View file

@ -11,7 +11,7 @@ import os
import subprocess import subprocess
from biosutilities.common.externals import comextract_path from biosutilities.common.externals import comextract_path
from biosutilities.common.paths import delete_file, is_file, make_dirs, path_stem from biosutilities.common.paths import delete_file, is_file_read, make_dirs, path_stem
from biosutilities.common.patterns import PAT_TOSHIBA_COM from biosutilities.common.patterns import PAT_TOSHIBA_COM
from biosutilities.common.system import printer from biosutilities.common.system import printer
from biosutilities.common.templates import BIOSUtility from biosutilities.common.templates import BIOSUtility
@ -25,14 +25,20 @@ class ToshibaComExtract(BIOSUtility):
def check_format(self) -> bool: def check_format(self) -> bool:
""" Check if input is Toshiba BIOS COM image """ """ Check if input is Toshiba BIOS COM image """
return bool(PAT_TOSHIBA_COM.search(self.input_buffer, 0, 0x100)) if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object):
with open(self.input_object, 'rb') as input_object:
check_buffer: bytes = input_object.read(0x100)
else:
check_buffer = self.input_buffer[:0x100]
return bool(PAT_TOSHIBA_COM.search(check_buffer, 0, 0x100))
def parse_format(self) -> bool: def parse_format(self) -> bool:
""" Parse & Extract Toshiba BIOS COM image """ """ Parse & Extract Toshiba BIOS COM image """
make_dirs(in_path=self.extract_path) make_dirs(in_path=self.extract_path)
if isinstance(self.input_object, str) and is_file(in_path=self.input_object): if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object):
input_path: str = self.input_object input_path: str = self.input_object
else: else:
input_path = os.path.join(self.extract_path, 'toshiba_bios.com') input_path = os.path.join(self.extract_path, 'toshiba_bios.com')
@ -48,7 +54,7 @@ class ToshibaComExtract(BIOSUtility):
if input_path != self.input_object: if input_path != self.input_object:
delete_file(in_path=input_path) delete_file(in_path=input_path)
if comextract_res.returncode == 0 and is_file(in_path=output_path): if comextract_res.returncode == 0 and is_file_read(in_path=output_path):
printer(message='Successful extraction via ToshibaComExtractor!', padding=self.padding) printer(message='Successful extraction via ToshibaComExtractor!', padding=self.padding)
return True return True

20
main.py
View file

@ -31,7 +31,7 @@ from biosutilities.portwell_efi_extract import PortwellEfiExtract
from biosutilities.toshiba_com_extract import ToshibaComExtract from biosutilities.toshiba_com_extract import ToshibaComExtract
from biosutilities.vaio_package_extract import VaioPackageExtract 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, from biosutilities.common.paths import (delete_dirs, extract_folder, is_dir_read, is_empty_dir, is_file_read,
path_files, path_name, path_parent, real_path, runtime_root) path_files, path_name, path_parent, real_path, runtime_root)
from biosutilities.common.system import python_version, printer, system_platform from biosutilities.common.system import python_version, printer, system_platform
from biosutilities.common.texts import remove_quotes, to_boxed, to_ordinal from biosutilities.common.texts import remove_quotes, to_boxed, to_ordinal
@ -68,11 +68,11 @@ class BIOSUtilities:
for input_path in [input_path for input_path in input_paths if input_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) input_path_real: str = real_path(in_path=input_path)
if is_dir(in_path=input_path_real): if is_dir_read(in_path=input_path_real):
for input_file in path_files(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): if is_file_read(in_path=input_file):
self._input_files.append(input_file) self._input_files.append(input_file)
elif is_file(in_path=input_path_real) and is_access(in_path=input_path_real): elif is_file_read(in_path=input_path_real):
self._input_files.append(input_path_real) self._input_files.append(input_path_real)
def _setup_output_dir(self, padding: int = 0) -> None: def _setup_output_dir(self, padding: int = 0) -> None:
@ -86,7 +86,7 @@ class BIOSUtilities:
if not output_path and self._input_files: if not output_path and self._input_files:
output_path = str(path_parent(in_path=self._input_files[0])) 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): if output_path and is_dir_read(in_path=output_path):
self._output_path = output_path self._output_path = output_path
else: else:
self._output_path = runtime_root() self._output_path = runtime_root()
@ -137,9 +137,9 @@ class BIOSUtilities:
exit_code: int = len(self._input_files) exit_code: int = len(self._input_files)
utilities_classes: list[Any] = [ utilities_classes: list[Any] = [
AmiUcpExtract, AmiPfatExtract, InsydeIfdExtract, DellPfsExtract, PhoenixTdkExtract, PanasonicBiosExtract, AppleEfiPkgExtract, AmiUcpExtract, AmiPfatExtract, InsydeIfdExtract, DellPfsExtract, PhoenixTdkExtract,
VaioPackageExtract, PortwellEfiExtract, ToshibaComExtract, FujitsuSfxExtract, FujitsuUpcExtract, PanasonicBiosExtract, VaioPackageExtract, PortwellEfiExtract, ToshibaComExtract, FujitsuSfxExtract,
AwardBiosExtract, AppleEfiPkgExtract, AppleEfiPbzxExtract, AppleEfiIm4pSplit, AppleEfiIdentify FujitsuUpcExtract, AwardBiosExtract, AppleEfiPbzxExtract, AppleEfiIm4pSplit, AppleEfiIdentify
] ]
for input_file in self._input_files: for input_file in self._input_files:
@ -150,11 +150,11 @@ class BIOSUtilities:
for utility_class in utilities_classes: for utility_class in utilities_classes:
extract_path: str = os.path.join(self._output_path, extract_folder(in_path=input_name)) extract_path: str = os.path.join(self._output_path, extract_folder(in_path=input_name))
if is_dir(in_path=extract_path): if is_dir_read(in_path=extract_path):
for suffix in range(2, self.MAX_FAT32_ITEMS): for suffix in range(2, self.MAX_FAT32_ITEMS):
renamed_path: str = f'{os.path.normpath(extract_path)}_{to_ordinal(in_number=suffix)}' renamed_path: str = f'{os.path.normpath(extract_path)}_{to_ordinal(in_number=suffix)}'
if not is_dir(in_path=renamed_path): if not is_dir_read(in_path=renamed_path):
extract_path = renamed_path extract_path = renamed_path
break break