diff --git a/AMI_PFAT_Extract.py b/AMI_PFAT_Extract.py index 9f15c18..4c12be3 100644 --- a/AMI_PFAT_Extract.py +++ b/AMI_PFAT_Extract.py @@ -10,6 +10,7 @@ Copyright (C) 2018-2024 Plato Mavropoulos import ctypes import os import re +import struct from common.externals import get_bgs_tool from common.num_ops import get_ordinal @@ -20,7 +21,7 @@ from common.system import printer from common.templates import BIOSUtility from common.text_ops import bytes_to_hex, file_to_bytes -TITLE = 'AMI BIOS Guard Extractor v5.0' +TITLE = 'AMI BIOS Guard Extractor v6.0' class AmiBiosGuardHeader(ctypes.LittleEndianStructure): @@ -79,6 +80,11 @@ class IntelBiosGuardHeader(ctypes.LittleEndianStructure): return f'{id_text} {id_guid}' + def get_hdr_marker(self) -> bytes: + """ Get Intel BIOS Guard Header Marker """ + + return struct.pack(' tuple: """ Get Intel BIOS Guard Header Attributes """ @@ -261,19 +267,30 @@ def parse_bg_script(script_data: bytes, padding: int = 0) -> int: return 0 -def parse_bg_sign(input_data: bytes, sign_offset: int, print_info: bool = False, padding: int = 0) -> int: +def parse_bg_sign(input_data: bytes, sign_offset: int, sign_length: int = 0, + print_info: bool = False, padding: int = 0) -> int: """ Process Intel BIOS Guard Signature """ bg_sig_hdr = get_struct(input_data, sign_offset, IntelBiosGuardSignatureHeader) if bg_sig_hdr.Unknown0 == 1: - # Unknown0 = 1, Unknown1 = 1 + bg_sig_rsa_struct = IntelBiosGuardSignatureRsa2k # Unknown0 = 1, Unknown1 = 1 + elif bg_sig_hdr.Unknown0 == 2: + bg_sig_rsa_struct = IntelBiosGuardSignatureRsa3k # Unknown0 = 2, Unknown1 = 3 + elif sign_length == PFAT_INT_SIG_HDR_LEN + PFAT_INT_SIG_R2K_LEN: bg_sig_rsa_struct = IntelBiosGuardSignatureRsa2k - else: - # Unknown0 = 2, Unknown1 = 3 + + printer('Warning: Detected Intel BIOS Guard Signature 2K length via pattern!\n', padding, False) + elif sign_length == PFAT_INT_SIG_HDR_LEN + PFAT_INT_SIG_R3K_LEN: bg_sig_rsa_struct = IntelBiosGuardSignatureRsa3k - bg_sig_rsa = get_struct(input_data, sign_offset + PFAT_BLK_SIG_LEN, bg_sig_rsa_struct) + printer('Warning: Detected Intel BIOS Guard Signature 3K length via pattern!\n', padding, False) + else: + bg_sig_rsa_struct = IntelBiosGuardSignatureRsa3k + + printer('Error: Could not detect Intel BIOS Guard Signature length, assuming 3K!\n', padding, False, pause=True) + + bg_sig_rsa = get_struct(input_data, sign_offset + PFAT_INT_SIG_HDR_LEN, bg_sig_rsa_struct) if print_info: bg_sig_hdr.struct_print(padding) @@ -281,7 +298,7 @@ def parse_bg_sign(input_data: bytes, sign_offset: int, print_info: bool = False, bg_sig_rsa.struct_print(padding) # Total size of Signature Header and RSA Structure - return PFAT_BLK_SIG_LEN + ctypes.sizeof(bg_sig_rsa_struct) + return PFAT_INT_SIG_HDR_LEN + ctypes.sizeof(bg_sig_rsa_struct) def parse_pfat_hdr(buffer: bytes | bytearray, padding: int = 0) -> tuple: @@ -347,6 +364,8 @@ def parse_pfat_file(input_object: str | bytes | bytearray, extract_path: str, pa all_blocks_dict: dict = {} + bg_sign_len: int = 0 + extract_name: str = path_name(extract_path).removesuffix(extract_suffix()) make_dirs(extract_path, delete=True) @@ -371,7 +390,7 @@ def parse_pfat_file(input_object: str | bytes | bytearray, extract_path: str, pa bg_hdr.struct_print(padding + 12) - bg_script_bgn: int = block_off + PFAT_BLK_HDR_LEN + bg_script_bgn: int = block_off + PFAT_INT_HDR_LEN bg_script_end: int = bg_script_bgn + bg_hdr.ScriptSize bg_data_bgn: int = bg_script_end @@ -379,15 +398,19 @@ def parse_pfat_file(input_object: str | bytes | bytearray, extract_path: str, pa bg_data_bin: bytes = pfat_buffer[bg_data_bgn:bg_data_end] - block_off: int = bg_data_end # Assume next block starts at data end + block_off = bg_data_end # Assume next block starts at data end is_sfam, _, _, _, _ = bg_hdr.get_flags() # SFAM, ProtectEC, GFXMitDis, FTU, Reserved if is_sfam: printer(f'Intel BIOS Guard {block_status} Signature:\n', padding + 8) + if bg_sign_len == 0: + bg_sign_len = pfat_buffer.find(bg_hdr.get_hdr_marker(), bg_data_end, + bg_data_end + PFAT_INT_SIG_MAX_LEN) - bg_data_end + # Adjust next block to start after current block Data + Signature - block_off += parse_bg_sign(pfat_buffer, bg_data_end, True, padding + 12) + block_off += parse_bg_sign(pfat_buffer, bg_data_end, bg_sign_len, True, padding + 12) printer(f'Intel BIOS Guard {block_status} Script:\n', padding + 8) @@ -427,8 +450,11 @@ def parse_pfat_file(input_object: str | bytes | bytearray, extract_path: str, pa PFAT_AMI_HDR_LEN: int = ctypes.sizeof(AmiBiosGuardHeader) -PFAT_BLK_HDR_LEN: int = ctypes.sizeof(IntelBiosGuardHeader) -PFAT_BLK_SIG_LEN: int = ctypes.sizeof(IntelBiosGuardSignatureHeader) +PFAT_INT_HDR_LEN: int = ctypes.sizeof(IntelBiosGuardHeader) +PFAT_INT_SIG_HDR_LEN: int = ctypes.sizeof(IntelBiosGuardSignatureHeader) +PFAT_INT_SIG_R2K_LEN: int = ctypes.sizeof(IntelBiosGuardSignatureRsa2k) +PFAT_INT_SIG_R3K_LEN: int = ctypes.sizeof(IntelBiosGuardSignatureRsa3k) +PFAT_INT_SIG_MAX_LEN: int = PFAT_INT_SIG_HDR_LEN + PFAT_INT_SIG_R3K_LEN if __name__ == '__main__': BIOSUtility(title=TITLE, check=is_ami_pfat, main=parse_pfat_file).run_utility() diff --git a/Dell_PFS_Extract.py b/Dell_PFS_Extract.py index fafdd8b..b1eb9af 100644 --- a/Dell_PFS_Extract.py +++ b/Dell_PFS_Extract.py @@ -24,9 +24,9 @@ from common.system import printer from common.templates import BIOSUtility from common.text_ops import file_to_bytes -from AMI_PFAT_Extract import IntelBiosGuardHeader, parse_bg_script, parse_bg_sign +from AMI_PFAT_Extract import IntelBiosGuardHeader, parse_bg_script, parse_bg_sign, PFAT_INT_SIG_MAX_LEN -TITLE = 'Dell PFS Update Extractor v7.0' +TITLE = 'Dell PFS Update Extractor v7.1' class DellPfsHeader(ctypes.LittleEndianStructure): @@ -934,10 +934,14 @@ def parse_pfat_pfs(entry_hdr, entry_data, padding=0, structure=True): if structure: printer(f'PFAT Block {pfat_entry_idx_ord} - Signature:\n', padding + 12) - # Get sub-PFS PFAT Signature Structure values - bg_sign_len = parse_bg_sign(pfat_payload, pfat_payload_end, structure, padding + 16) + # Get sub-PFS PFAT Signature length from Header pattern (not needed for Dell PFS) + _pfat_sign_len = pfat_payload.find(pfat_hdr.get_hdr_marker(), pfat_payload_end, + pfat_payload_end + PFAT_INT_SIG_MAX_LEN) - pfat_payload_end - if len(pfat_payload[pfat_payload_end:pfat_payload_end + bg_sign_len]) != bg_sign_len: + # Get sub-PFS PFAT Signature Structure values + pfat_sign_len = parse_bg_sign(pfat_payload, pfat_payload_end, _pfat_sign_len, structure, padding + 16) + + if len(pfat_payload[pfat_payload_end:pfat_payload_end + pfat_sign_len]) != pfat_sign_len: printer(f'Error: Detected sub-PFS PFAT Block {pfat_entry_idx_ord} Signature Size mismatch!', padding + 12) diff --git a/README.md b/README.md index c35eca2..512326e 100644 --- a/README.md +++ b/README.md @@ -318,7 +318,7 @@ To run the utility, you do not need any prerequisites. #### **Description** -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. The output comprises only final firmware components which are directly usable by end users. +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** diff --git a/requirements.txt b/requirements.txt index 3bfae9f..ccc77f9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -dissect.util == 3.15 -pefile == 2023.2.7 +dissect.util==3.16 +pefile==2023.2.7