mirror of
https://github.com/platomav/BIOSUtilities.git
synced 2025-05-13 14:44:46 -04:00
Dell PFS Update Extractor v6.0_a2
Added --version parameter Structure fixes and improvements
This commit is contained in:
parent
96e87455de
commit
d6e8d31391
7 changed files with 96 additions and 90 deletions
|
@ -7,7 +7,7 @@ AMI BIOS Guard Extractor
|
||||||
Copyright (C) 2018-2022 Plato Mavropoulos
|
Copyright (C) 2018-2022 Plato Mavropoulos
|
||||||
"""
|
"""
|
||||||
|
|
||||||
title = 'AMI BIOS Guard Extractor v4.0_a2'
|
title = 'AMI BIOS Guard Extractor v4.0_a3'
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
@ -20,10 +20,10 @@ sys.dont_write_bytecode = True
|
||||||
|
|
||||||
from common.externals import get_bgs_tool
|
from common.externals import get_bgs_tool
|
||||||
from common.num_ops import get_ordinal
|
from common.num_ops import get_ordinal
|
||||||
from common.path_ops import argparse_init, safe_name
|
from common.path_ops import safe_name
|
||||||
from common.patterns import PAT_AMI_PFAT
|
from common.patterns import PAT_AMI_PFAT
|
||||||
from common.struct_ops import get_struct, char, uint8_t, uint16_t, uint32_t
|
from common.struct_ops import get_struct, char, uint8_t, uint16_t, uint32_t
|
||||||
from common.system import script_init, script_title, printer
|
from common.system import script_init, script_title, argparse_init, printer
|
||||||
|
|
||||||
class AmiBiosGuardHeader(ctypes.LittleEndianStructure):
|
class AmiBiosGuardHeader(ctypes.LittleEndianStructure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
|
|
@ -7,7 +7,7 @@ AMI UCP BIOS Extractor
|
||||||
Copyright (C) 2021-2022 Plato Mavropoulos
|
Copyright (C) 2021-2022 Plato Mavropoulos
|
||||||
"""
|
"""
|
||||||
|
|
||||||
title = 'AMI UCP BIOS Extractor v2.0_a3'
|
title = 'AMI UCP BIOS Extractor v2.0_a4'
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
@ -23,10 +23,10 @@ sys.dont_write_bytecode = True
|
||||||
from common.a7z_comp import a7z_decompress, is_7z_supported
|
from common.a7z_comp import a7z_decompress, is_7z_supported
|
||||||
from common.checksums import get_chk_16
|
from common.checksums import get_chk_16
|
||||||
from common.efi_comp import efi_decompress, is_efi_compressed
|
from common.efi_comp import efi_decompress, is_efi_compressed
|
||||||
from common.path_ops import argparse_init, safe_name
|
from common.path_ops import safe_name
|
||||||
from common.patterns import PAT_AMI_UCP, PAT_INTEL_ENG
|
from common.patterns import PAT_AMI_UCP, PAT_INTEL_ENG
|
||||||
from common.struct_ops import get_struct, char, uint8_t, uint16_t, uint32_t
|
from common.struct_ops import get_struct, char, uint8_t, uint16_t, uint32_t
|
||||||
from common.system import script_init, script_title, printer
|
from common.system import script_init, script_title, argparse_init, printer
|
||||||
|
|
||||||
from AMI_PFAT_Extract import get_ami_pfat, parse_pfat_file
|
from AMI_PFAT_Extract import get_ami_pfat, parse_pfat_file
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ Dell PFS Update Extractor
|
||||||
Copyright (C) 2018-2022 Plato Mavropoulos
|
Copyright (C) 2018-2022 Plato Mavropoulos
|
||||||
"""
|
"""
|
||||||
|
|
||||||
title = 'Dell PFS Update Extractor v6.0_a1'
|
title = 'Dell PFS Update Extractor v6.0_a2'
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import io
|
import io
|
||||||
|
@ -22,10 +22,10 @@ import contextlib
|
||||||
sys.dont_write_bytecode = True
|
sys.dont_write_bytecode = True
|
||||||
|
|
||||||
from common.checksums import get_chk_8_xor
|
from common.checksums import get_chk_8_xor
|
||||||
from common.path_ops import argparse_init, safe_name
|
from common.path_ops import safe_name
|
||||||
from common.patterns import PAT_DELL_HDR, PAT_DELL_FTR, PAT_DELL_PKG
|
from common.patterns import PAT_DELL_HDR, PAT_DELL_FTR, PAT_DELL_PKG
|
||||||
from common.struct_ops import get_struct, char, uint8_t, uint16_t, uint32_t, uint64_t
|
from common.struct_ops import get_struct, char, uint8_t, uint16_t, uint32_t, uint64_t
|
||||||
from common.system import script_init, script_title, printer
|
from common.system import script_init, script_title, argparse_init, printer
|
||||||
|
|
||||||
from AMI_PFAT_Extract import IntelBiosGuardHeader, IntelBiosGuardSignature2k, parse_bg_script
|
from AMI_PFAT_Extract import IntelBiosGuardHeader, IntelBiosGuardSignature2k, parse_bg_script
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ class DellPfsEntryBase(ctypes.LittleEndianStructure):
|
||||||
def struct_print(self, p):
|
def struct_print(self, p):
|
||||||
GUID = '%0.*X' % (0x10 * 2, int.from_bytes(self.GUID, 'little'))
|
GUID = '%0.*X' % (0x10 * 2, int.from_bytes(self.GUID, 'little'))
|
||||||
Unknown = '%0.*X' % (len(self.Unknown) * 8, int.from_bytes(self.Unknown, 'little'))
|
Unknown = '%0.*X' % (len(self.Unknown) * 8, int.from_bytes(self.Unknown, 'little'))
|
||||||
Version = get_entry_ver(self.Version, self.VersionType, padding - 4)
|
Version = get_entry_ver(self.Version, self.VersionType)
|
||||||
|
|
||||||
printer(['Entry GUID :', GUID], p, False)
|
printer(['Entry GUID :', GUID], p, False)
|
||||||
printer(['Entry Version :', self.HeaderVersion], p, False)
|
printer(['Entry Version :', self.HeaderVersion], p, False)
|
||||||
|
@ -131,11 +131,12 @@ class DellPfsName(ctypes.LittleEndianStructure):
|
||||||
# 0x0E
|
# 0x0E
|
||||||
]
|
]
|
||||||
|
|
||||||
def struct_print(self, p):
|
def struct_print(self, p, name):
|
||||||
Version = get_entry_ver(self.Version, self.VersionType, padding - 4)
|
Version = get_entry_ver(self.Version, self.VersionType)
|
||||||
|
|
||||||
printer(['Payload Version:', Version], p, False)
|
printer(['Payload Version:', Version], p, False)
|
||||||
printer(['Character Count:', self.CharacterCount], p, False)
|
printer(['Character Count:', self.CharacterCount], p, False)
|
||||||
|
printer(['Payload Name :', name], p, False)
|
||||||
|
|
||||||
# Dell PFS Metadata Header Structure
|
# Dell PFS Metadata Header Structure
|
||||||
class DellPfsMetadata(ctypes.LittleEndianStructure):
|
class DellPfsMetadata(ctypes.LittleEndianStructure):
|
||||||
|
@ -189,7 +190,7 @@ class DellPfsPfatMetadata(ctypes.LittleEndianStructure):
|
||||||
# Each section starts with a 0x30 header, which begins with pattern 72135500.
|
# Each section starts with a 0x30 header, which begins with pattern 72135500.
|
||||||
# The section length is found at 0x10-0x14 and its (optional) MD5 hash at 0x20-0x30.
|
# The section length is found at 0x10-0x14 and its (optional) MD5 hash at 0x20-0x30.
|
||||||
# Section data can be raw or LZMA2 (7zXZ) compressed. The latter contains the PFS update image.
|
# Section data can be raw or LZMA2 (7zXZ) compressed. The latter contains the PFS update image.
|
||||||
def is_dell_pfs_pkg(in_buffer):
|
def is_pfs_pkg(in_buffer):
|
||||||
return PAT_DELL_PKG.search(in_buffer)
|
return PAT_DELL_PKG.search(in_buffer)
|
||||||
|
|
||||||
# The Dell PFS update images usually contain multiple sections.
|
# The Dell PFS update images usually contain multiple sections.
|
||||||
|
@ -197,17 +198,21 @@ def is_dell_pfs_pkg(in_buffer):
|
||||||
# where ******** is the zlib stream size, ++ is the section type and -- the header Checksum XOR 8.
|
# where ******** is the zlib stream size, ++ is the section type and -- the header Checksum XOR 8.
|
||||||
# The "Firmware" section has type AA and its files are stored in PFS format.
|
# The "Firmware" section has type AA and its files are stored in PFS format.
|
||||||
# The "Utility" section has type BB and its files are stored in PFS, BIN or 7z formats.
|
# The "Utility" section has type BB and its files are stored in PFS, BIN or 7z formats.
|
||||||
def is_dell_pfs_hdr(in_buffer):
|
def is_pfs_hdr(in_buffer):
|
||||||
return list(PAT_DELL_HDR.finditer(in_buffer))
|
return list(PAT_DELL_HDR.finditer(in_buffer))
|
||||||
|
|
||||||
# Each section is followed by the footer pattern ********EEAAEE8F491BE8AE143790--,
|
# Each section is followed by the footer pattern ********EEAAEE8F491BE8AE143790--,
|
||||||
# where ******** is the zlib stream size and ++ the footer Checksum XOR 8.
|
# where ******** is the zlib stream size and ++ the footer Checksum XOR 8.
|
||||||
def is_dell_pfs_ftr(in_buffer):
|
def is_pfs_ftr(in_buffer):
|
||||||
return PAT_DELL_FTR.search(in_buffer)
|
return PAT_DELL_FTR.search(in_buffer)
|
||||||
|
|
||||||
|
# Check if input buffer is Dell PFS/PKG image
|
||||||
|
def is_dell_pfs(in_buffer):
|
||||||
|
return is_pfs_hdr(in_buffer) or is_pfs_pkg(in_buffer)
|
||||||
|
|
||||||
# Get PFS ZLIB Section Offsets
|
# Get PFS ZLIB Section Offsets
|
||||||
def get_section_offsets(buffer):
|
def get_section_offsets(buffer):
|
||||||
pfs_zlib_init = is_dell_pfs_hdr(buffer)
|
pfs_zlib_init = is_pfs_hdr(buffer)
|
||||||
|
|
||||||
if not pfs_zlib_init: return [] # No PFS ZLIB detected
|
if not pfs_zlib_init: return [] # No PFS ZLIB detected
|
||||||
|
|
||||||
|
@ -228,7 +233,7 @@ def get_section_offsets(buffer):
|
||||||
return pfs_zlib_list
|
return pfs_zlib_list
|
||||||
|
|
||||||
# Dell PFS ZLIB Section Parser
|
# Dell PFS ZLIB Section Parser
|
||||||
def pfs_section_parse(zlib_data, zlib_start, output_path, pfs_name, pfs_index, pfs_count, is_rec, padding, is_verbose=True, is_advanced=True):
|
def pfs_section_parse(zlib_data, zlib_start, output_path, pfs_name, pfs_index, pfs_count, is_rec, padding, is_structure=True, is_advanced=True):
|
||||||
is_zlib_error = False # Initialize PFS ZLIB-related error state
|
is_zlib_error = False # Initialize PFS ZLIB-related error state
|
||||||
|
|
||||||
section_type = zlib_data[zlib_start - 0x1] # Byte before PFS ZLIB Section pattern is Section Type (e.g. AA, BB)
|
section_type = zlib_data[zlib_start - 0x1] # Byte before PFS ZLIB Section pattern is Section Type (e.g. AA, BB)
|
||||||
|
@ -278,7 +283,7 @@ def pfs_section_parse(zlib_data, zlib_start, output_path, pfs_name, pfs_index, p
|
||||||
footer_data = zlib_data[compressed_end:compressed_end + 0x10]
|
footer_data = zlib_data[compressed_end:compressed_end + 0x10]
|
||||||
|
|
||||||
# Search input section for PFS ZLIB section footer
|
# Search input section for PFS ZLIB section footer
|
||||||
pfs_zlib_footer_match = is_dell_pfs_ftr(footer_data)
|
pfs_zlib_footer_match = is_pfs_ftr(footer_data)
|
||||||
|
|
||||||
# Check if PFS ZLIB section footer was found in the section
|
# Check if PFS ZLIB section footer was found in the section
|
||||||
if not pfs_zlib_footer_match:
|
if not pfs_zlib_footer_match:
|
||||||
|
@ -306,12 +311,12 @@ def pfs_section_parse(zlib_data, zlib_start, output_path, pfs_name, pfs_index, p
|
||||||
section_data = zlib_data # Fallback to raw ZLIB data upon critical error
|
section_data = zlib_data # Fallback to raw ZLIB data upon critical error
|
||||||
|
|
||||||
# Call the PFS Extract function on the decompressed PFS ZLIB Section
|
# Call the PFS Extract function on the decompressed PFS ZLIB Section
|
||||||
pfs_extract(section_data, pfs_index, pfs_name, pfs_count, section_path, padding, is_verbose, is_advanced)
|
pfs_extract(section_data, pfs_index, pfs_name, pfs_count, section_path, padding, is_structure, is_advanced)
|
||||||
|
|
||||||
# Parse & Extract Dell PFS Volume
|
# Parse & Extract Dell PFS Volume
|
||||||
def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, is_verbose=True, is_advanced=True):
|
def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, is_structure=True, is_advanced=True):
|
||||||
# Show PFS Volume indicator
|
# Show PFS Volume indicator
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFS Volume:', pfs_padd)
|
printer('PFS Volume:', pfs_padd)
|
||||||
|
|
||||||
# Get PFS Header Structure values
|
# Get PFS Header Structure values
|
||||||
|
@ -324,7 +329,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
|
||||||
return # Critical error, abort
|
return # Critical error, abort
|
||||||
|
|
||||||
# Show PFS Header Structure info
|
# Show PFS Header Structure info
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFS Header:\n', pfs_padd + 4)
|
printer('PFS Header:\n', pfs_padd + 4)
|
||||||
pfs_hdr.struct_print(pfs_padd + 8)
|
pfs_hdr.struct_print(pfs_padd + 8)
|
||||||
|
|
||||||
|
@ -344,7 +349,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
|
||||||
while len(pfs_payload[entry_start:entry_start + pfs_entry_size]) == pfs_entry_size:
|
while len(pfs_payload[entry_start:entry_start + pfs_entry_size]) == pfs_entry_size:
|
||||||
# Analyze PFS Entry Structure and get relevant info
|
# Analyze PFS Entry Structure and get relevant info
|
||||||
_,entry_version,entry_guid,entry_data,entry_data_sig,entry_met,entry_met_sig,next_entry = \
|
_,entry_version,entry_guid,entry_data,entry_data_sig,entry_met,entry_met_sig,next_entry = \
|
||||||
parse_pfs_entry(pfs_payload, entry_start, pfs_entry_size, pfs_entry_struct, 'PFS Entry', pfs_padd, is_verbose)
|
parse_pfs_entry(pfs_payload, entry_start, pfs_entry_size, pfs_entry_struct, 'PFS Entry', pfs_padd, is_structure)
|
||||||
|
|
||||||
entry_type = 'OTHER' # Adjusted later if PFS Entry is Zlib, PFAT, PFS Info, Model Info
|
entry_type = 'OTHER' # Adjusted later if PFS Entry is Zlib, PFAT, PFS Info, Model Info
|
||||||
|
|
||||||
|
@ -380,7 +385,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
|
||||||
entry_info_hdr = get_struct(filename_info, info_start, DellPfsInfo)
|
entry_info_hdr = get_struct(filename_info, info_start, DellPfsInfo)
|
||||||
|
|
||||||
# Show PFS Information Header Structure info
|
# Show PFS Information Header Structure info
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFS Information Header:\n', pfs_padd + 4)
|
printer('PFS Information Header:\n', pfs_padd + 4)
|
||||||
entry_info_hdr.struct_print(pfs_padd + 8)
|
entry_info_hdr.struct_print(pfs_padd + 8)
|
||||||
|
|
||||||
|
@ -395,11 +400,6 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
|
||||||
# Get PFS FileName Structure values
|
# Get PFS FileName Structure values
|
||||||
entry_info_mod = get_struct(filename_info, info_start + PFS_INFO_LEN, DellPfsName)
|
entry_info_mod = get_struct(filename_info, info_start + PFS_INFO_LEN, DellPfsName)
|
||||||
|
|
||||||
# Show PFS FileName Structure info
|
|
||||||
if is_verbose:
|
|
||||||
printer('PFS FileName Entry:\n', pfs_padd + 8)
|
|
||||||
entry_info_mod.struct_print(pfs_padd + 12)
|
|
||||||
|
|
||||||
# The PFS FileName Structure is not complete by itself. The size of the last field (Entry Name) is determined from
|
# The PFS FileName Structure is not complete by itself. The size of the last field (Entry Name) is determined from
|
||||||
# CharacterCount multiplied by 2 due to usage of UTF-16 2-byte Characters. Any Entry Name leading and/or trailing
|
# CharacterCount multiplied by 2 due to usage of UTF-16 2-byte Characters. Any Entry Name leading and/or trailing
|
||||||
# space/null characters are stripped and common Windows reserved/illegal filename characters are replaced
|
# space/null characters are stripped and common Windows reserved/illegal filename characters are replaced
|
||||||
|
@ -408,13 +408,14 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
|
||||||
name_data = filename_info[name_start:name_start + name_size] # PFS Entry's FileName buffer
|
name_data = filename_info[name_start:name_start + name_size] # PFS Entry's FileName buffer
|
||||||
entry_name = safe_name(name_data.decode('utf-16').strip()) # PFS Entry's FileName value
|
entry_name = safe_name(name_data.decode('utf-16').strip()) # PFS Entry's FileName value
|
||||||
|
|
||||||
# Show PFS FileName Name info (padding matches the one from PFS FileName Structure info)
|
# Show PFS FileName Structure info
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('Payload Name : %s' % entry_name, pfs_padd + 12, False)
|
printer('PFS FileName Entry:\n', pfs_padd + 8)
|
||||||
|
entry_info_mod.struct_print(pfs_padd + 12, entry_name)
|
||||||
|
|
||||||
# Get PFS FileName Version string via "Version" and "VersionType" fields
|
# Get PFS FileName Version string via "Version" and "VersionType" fields
|
||||||
# PFS FileName Version string must be preferred over PFS Entry's Version
|
# PFS FileName Version string must be preferred over PFS Entry's Version
|
||||||
entry_version = get_entry_ver(entry_info_mod.Version, entry_info_mod.VersionType, pfs_padd + 12)
|
entry_version = get_entry_ver(entry_info_mod.Version, entry_info_mod.VersionType)
|
||||||
|
|
||||||
# Store all relevant PFS FileName details
|
# Store all relevant PFS FileName details
|
||||||
info_all.append([entry_guid, entry_name, entry_version])
|
info_all.append([entry_guid, entry_name, entry_version])
|
||||||
|
@ -436,7 +437,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
|
||||||
entry_info = get_struct(entry_metadata, 0, DellPfsMetadata)
|
entry_info = get_struct(entry_metadata, 0, DellPfsMetadata)
|
||||||
|
|
||||||
# Show Nested PFS Metadata Structure info
|
# Show Nested PFS Metadata Structure info
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFS Metadata Information:\n', pfs_padd + 4)
|
printer('PFS Metadata Information:\n', pfs_padd + 4)
|
||||||
entry_info.struct_print(pfs_padd + 8)
|
entry_info.struct_print(pfs_padd + 8)
|
||||||
|
|
||||||
|
@ -460,7 +461,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
|
||||||
entry_info_hdr = get_struct(signature_info, sign_start, DellPfsInfo)
|
entry_info_hdr = get_struct(signature_info, sign_start, DellPfsInfo)
|
||||||
|
|
||||||
# Show PFS Information Header Structure info
|
# Show PFS Information Header Structure info
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFS Information Header:\n', pfs_padd + 4)
|
printer('PFS Information Header:\n', pfs_padd + 4)
|
||||||
entry_info_hdr.struct_print(pfs_padd + 8)
|
entry_info_hdr.struct_print(pfs_padd + 8)
|
||||||
|
|
||||||
|
@ -476,7 +477,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
|
||||||
entry_hdr = get_struct(signature_info, sign_start + PFS_INFO_LEN, pfs_entry_struct)
|
entry_hdr = get_struct(signature_info, sign_start + PFS_INFO_LEN, pfs_entry_struct)
|
||||||
|
|
||||||
# Show PFS Information Header Structure info
|
# Show PFS Information Header Structure info
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFS Information Entry:\n', pfs_padd + 8)
|
printer('PFS Information Entry:\n', pfs_padd + 8)
|
||||||
entry_hdr.struct_print(pfs_padd + 12)
|
entry_hdr.struct_print(pfs_padd + 12)
|
||||||
|
|
||||||
|
@ -486,7 +487,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
|
||||||
sign_data_raw = signature_info[sign_info_start + 0x2:sign_info_start + 0x2 + sign_size]
|
sign_data_raw = signature_info[sign_info_start + 0x2:sign_info_start + 0x2 + sign_size]
|
||||||
sign_data_txt = '%0.*X' % (sign_size * 2, int.from_bytes(sign_data_raw, 'little'))
|
sign_data_txt = '%0.*X' % (sign_size * 2, int.from_bytes(sign_data_raw, 'little'))
|
||||||
|
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('Signature Information:\n', pfs_padd + 8)
|
printer('Signature Information:\n', pfs_padd + 8)
|
||||||
printer('Signature Size: 0x%X' % sign_size, pfs_padd + 12, False)
|
printer('Signature Size: 0x%X' % sign_size, pfs_padd + 12, False)
|
||||||
printer('Signature Data: %s [...]' % sign_data_txt[:32], pfs_padd + 12, False)
|
printer('Signature Data: %s [...]' % sign_data_txt[:32], pfs_padd + 12, False)
|
||||||
|
@ -518,7 +519,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
|
||||||
if pfat_entry_hdr.Tag == b'PFS.HDR.' and is_pfat:
|
if pfat_entry_hdr.Tag == b'PFS.HDR.' and is_pfat:
|
||||||
entry_type = 'PFAT' # Re-set PFS Entry Type from OTHER to PFAT, to use such info afterwards
|
entry_type = 'PFAT' # Re-set PFS Entry Type from OTHER to PFAT, to use such info afterwards
|
||||||
|
|
||||||
entry_data = parse_pfat_pfs(pfat_entry_hdr, entry_data, pfs_padd, is_verbose) # Parse sub-PFS PFAT Volume
|
entry_data = parse_pfat_pfs(pfat_entry_hdr, entry_data, pfs_padd, is_structure) # Parse sub-PFS PFAT Volume
|
||||||
|
|
||||||
# Parse PFS Entry which contains zlib-compressed sub-PFS Volume
|
# Parse PFS Entry which contains zlib-compressed sub-PFS Volume
|
||||||
elif pfs_zlib_offsets:
|
elif pfs_zlib_offsets:
|
||||||
|
@ -539,7 +540,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
|
||||||
sub_pfs_path = os.path.join(output_path, str(pfs_count) + sub_pfs_name)
|
sub_pfs_path = os.path.join(output_path, str(pfs_count) + sub_pfs_name)
|
||||||
|
|
||||||
# Recursively call the PFS ZLIB Section Parser function for the sub-PFS Volume (pfs_index = pfs_count)
|
# Recursively call the PFS ZLIB Section Parser function for the sub-PFS Volume (pfs_index = pfs_count)
|
||||||
pfs_section_parse(entry_data, offset, sub_pfs_path, sub_pfs_name, pfs_count, pfs_count, True, pfs_padd + 4, is_verbose, is_advanced)
|
pfs_section_parse(entry_data, offset, sub_pfs_path, sub_pfs_name, pfs_count, pfs_count, True, pfs_padd + 4, is_structure, is_advanced)
|
||||||
|
|
||||||
entries_all[index][4] = entry_data # Adjust PFS Entry Data after parsing PFAT (same ZLIB raw data, not stored afterwards)
|
entries_all[index][4] = entry_data # Adjust PFS Entry Data after parsing PFAT (same ZLIB raw data, not stored afterwards)
|
||||||
entries_all[index][3] = entry_type # Adjust PFS Entry Type from OTHER to PFAT or ZLIB (ZLIB is ignored at file extraction)
|
entries_all[index][3] = entry_type # Adjust PFS Entry Type from OTHER to PFAT or ZLIB (ZLIB is ignored at file extraction)
|
||||||
|
@ -598,21 +599,21 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
|
||||||
# Write/Extract PFS Entry files
|
# Write/Extract PFS Entry files
|
||||||
for file in write_files:
|
for file in write_files:
|
||||||
full_name = '%d%s -- %d %s v%s' % (pfs_index, pfs_name, file_index, file_name, file_version) # Full PFS Entry Name
|
full_name = '%d%s -- %d %s v%s' % (pfs_index, pfs_name, file_index, file_name, file_version) # Full PFS Entry Name
|
||||||
pfs_file_write(file[0], file[1], file_type, full_name, output_path, pfs_padd, is_verbose, is_advanced)
|
pfs_file_write(file[0], file[1], file_type, full_name, output_path, pfs_padd, is_structure, is_advanced)
|
||||||
|
|
||||||
# Get PFS Footer Data after PFS Header Payload
|
# Get PFS Footer Data after PFS Header Payload
|
||||||
pfs_footer = buffer[PFS_HEAD_LEN + pfs_hdr.PayloadSize:PFS_HEAD_LEN + pfs_hdr.PayloadSize + PFS_FOOT_LEN]
|
pfs_footer = buffer[PFS_HEAD_LEN + pfs_hdr.PayloadSize:PFS_HEAD_LEN + pfs_hdr.PayloadSize + PFS_FOOT_LEN]
|
||||||
|
|
||||||
# Analyze PFS Footer Structure
|
# Analyze PFS Footer Structure
|
||||||
chk_pfs_ftr(pfs_footer, pfs_payload, pfs_hdr.PayloadSize, 'PFS', pfs_padd, is_verbose)
|
chk_pfs_ftr(pfs_footer, pfs_payload, pfs_hdr.PayloadSize, 'PFS', pfs_padd, is_structure)
|
||||||
|
|
||||||
# Analyze Dell PFS Entry Structure
|
# Analyze Dell PFS Entry Structure
|
||||||
def parse_pfs_entry(entry_buffer, entry_start, entry_size, entry_struct, text, padding, is_verbose=True):
|
def parse_pfs_entry(entry_buffer, entry_start, entry_size, entry_struct, text, padding, is_structure=True):
|
||||||
# Get PFS Entry Structure values
|
# Get PFS Entry Structure values
|
||||||
pfs_entry = get_struct(entry_buffer, entry_start, entry_struct)
|
pfs_entry = get_struct(entry_buffer, entry_start, entry_struct)
|
||||||
|
|
||||||
# Show PFS Entry Structure info
|
# Show PFS Entry Structure info
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFS Entry:\n', padding + 4)
|
printer('PFS Entry:\n', padding + 4)
|
||||||
pfs_entry.struct_print(padding + 8)
|
pfs_entry.struct_print(padding + 8)
|
||||||
|
|
||||||
|
@ -624,7 +625,7 @@ def parse_pfs_entry(entry_buffer, entry_start, entry_size, entry_struct, text, p
|
||||||
printer('Error: Detected non-empty %s Reserved field!' % text, padding + 8)
|
printer('Error: Detected non-empty %s Reserved field!' % text, padding + 8)
|
||||||
|
|
||||||
# Get PFS Entry Version string via "Version" and "VersionType" fields
|
# Get PFS Entry Version string via "Version" and "VersionType" fields
|
||||||
entry_version = get_entry_ver(pfs_entry.Version, pfs_entry.VersionType, padding + 8)
|
entry_version = get_entry_ver(pfs_entry.Version, pfs_entry.VersionType)
|
||||||
|
|
||||||
# Get PFS Entry GUID in Big Endian format
|
# Get PFS Entry GUID in Big Endian format
|
||||||
entry_guid = '%0.*X' % (0x10 * 2, int.from_bytes(pfs_entry.GUID, 'little'))
|
entry_guid = '%0.*X' % (0x10 * 2, int.from_bytes(pfs_entry.GUID, 'little'))
|
||||||
|
@ -653,13 +654,13 @@ def parse_pfs_entry(entry_buffer, entry_start, entry_size, entry_struct, text, p
|
||||||
return pfs_entry, entry_version, entry_guid, entry_data, entry_data_sig, entry_met, entry_met_sig, entry_met_sig_end
|
return pfs_entry, entry_version, entry_guid, entry_data, entry_data_sig, entry_met, entry_met_sig, entry_met_sig_end
|
||||||
|
|
||||||
# Parse Dell PFS Volume with PFAT Payload
|
# Parse Dell PFS Volume with PFAT Payload
|
||||||
def parse_pfat_pfs(entry_hdr, entry_data, padding, is_verbose=True):
|
def parse_pfat_pfs(entry_hdr, entry_data, padding, is_structure=True):
|
||||||
# Show PFS Volume indicator
|
# Show PFS Volume indicator
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFS Volume:', padding + 4)
|
printer('PFS Volume:', padding + 4)
|
||||||
|
|
||||||
# Show sub-PFS Header Structure Info
|
# Show sub-PFS Header Structure Info
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFS Header:\n', padding + 8)
|
printer('PFS Header:\n', padding + 8)
|
||||||
entry_hdr.struct_print(padding + 12)
|
entry_hdr.struct_print(padding + 12)
|
||||||
|
|
||||||
|
@ -683,7 +684,7 @@ def parse_pfat_pfs(entry_hdr, entry_data, padding, is_verbose=True):
|
||||||
|
|
||||||
# Analyze sub-PFS PFAT Entry Structure and get relevant info
|
# Analyze sub-PFS PFAT Entry Structure and get relevant info
|
||||||
pfat_entry,_,_,pfat_entry_data,_,pfat_entry_met,_,pfat_next_entry = parse_pfs_entry(pfat_payload,
|
pfat_entry,_,_,pfat_entry_data,_,pfat_entry_met,_,pfat_next_entry = parse_pfs_entry(pfat_payload,
|
||||||
pfat_entry_start, pfat_entry_size, pfat_entry_struct, 'sub-PFS PFAT Entry', padding + 4, is_verbose)
|
pfat_entry_start, pfat_entry_size, pfat_entry_struct, 'sub-PFS PFAT Entry', padding + 4, is_structure)
|
||||||
|
|
||||||
# Each sub-PFS PFAT Entry includes an AMI BIOS Guard (a.k.a. PFAT) block at the beginning
|
# Each sub-PFS PFAT Entry includes an AMI BIOS Guard (a.k.a. PFAT) block at the beginning
|
||||||
# We need to parse the PFAT block and remove its contents from the final Payload/Raw Data
|
# We need to parse the PFAT block and remove its contents from the final Payload/Raw Data
|
||||||
|
@ -693,7 +694,7 @@ def parse_pfat_pfs(entry_hdr, entry_data, padding, is_verbose=True):
|
||||||
pfat_hdr = get_struct(pfat_payload, pfat_hdr_off, IntelBiosGuardHeader)
|
pfat_hdr = get_struct(pfat_payload, pfat_hdr_off, IntelBiosGuardHeader)
|
||||||
|
|
||||||
# Show sub-PFS PFAT Header Structure info
|
# Show sub-PFS PFAT Header Structure info
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFAT Block %d Header:\n' % pfat_entry_index, padding + 12)
|
printer('PFAT Block %d Header:\n' % pfat_entry_index, padding + 12)
|
||||||
pfat_hdr.struct_print(padding + 16)
|
pfat_hdr.struct_print(padding + 16)
|
||||||
|
|
||||||
|
@ -718,12 +719,12 @@ def parse_pfat_pfs(entry_hdr, entry_data, padding, is_verbose=True):
|
||||||
pfat_sig = get_struct(pfat_payload, pfat_payload_end, IntelBiosGuardSignature2k)
|
pfat_sig = get_struct(pfat_payload, pfat_payload_end, IntelBiosGuardSignature2k)
|
||||||
|
|
||||||
# Show sub-PFS PFAT Signature Structure info
|
# Show sub-PFS PFAT Signature Structure info
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFAT Block %d Signature:\n' % pfat_entry_index, padding + 12)
|
printer('PFAT Block %d Signature:\n' % pfat_entry_index, padding + 12)
|
||||||
pfat_sig.struct_print(padding + 16)
|
pfat_sig.struct_print(padding + 16)
|
||||||
|
|
||||||
# Show PFAT Script via BIOS Guard Script Tool
|
# Show PFAT Script via BIOS Guard Script Tool
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFAT Block %d Script:\n' % pfat_entry_index, padding + 12)
|
printer('PFAT Block %d Script:\n' % pfat_entry_index, padding + 12)
|
||||||
|
|
||||||
# https://github.com/allowitsme/big-tool by Dmitry Frolov
|
# https://github.com/allowitsme/big-tool by Dmitry Frolov
|
||||||
|
@ -740,7 +741,7 @@ def parse_pfat_pfs(entry_hdr, entry_data, padding, is_verbose=True):
|
||||||
pfat_met = get_struct(pfat_entry_met, 0, DellPfsPfatMetadata)
|
pfat_met = get_struct(pfat_entry_met, 0, DellPfsPfatMetadata)
|
||||||
|
|
||||||
# Show sub-PFS PFAT Metadata Structure info
|
# Show sub-PFS PFAT Metadata Structure info
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFAT Block %d Metadata:\n' % pfat_entry_index, padding + 12)
|
printer('PFAT Block %d Metadata:\n' % pfat_entry_index, padding + 12)
|
||||||
pfat_met.struct_print(padding + 16)
|
pfat_met.struct_print(padding + 16)
|
||||||
|
|
||||||
|
@ -779,7 +780,7 @@ def parse_pfat_pfs(entry_hdr, entry_data, padding, is_verbose=True):
|
||||||
printer('Error: Detected sub-PFS PFAT Entry Buffer & Last Offset Size mismatch!', padding + 8)
|
printer('Error: Detected sub-PFS PFAT Entry Buffer & Last Offset Size mismatch!', padding + 8)
|
||||||
|
|
||||||
# Analyze sub-PFS Footer Structure
|
# Analyze sub-PFS Footer Structure
|
||||||
chk_pfs_ftr(pfat_footer, pfat_payload, entry_hdr.PayloadSize, 'Sub-PFS', padding + 4, is_verbose)
|
chk_pfs_ftr(pfat_footer, pfat_payload, entry_hdr.PayloadSize, 'Sub-PFS', padding + 4, is_structure)
|
||||||
|
|
||||||
return entry_data
|
return entry_data
|
||||||
|
|
||||||
|
@ -793,20 +794,18 @@ def get_pfs_entry(buffer, offset):
|
||||||
return DellPfsEntryR2, ctypes.sizeof(DellPfsEntryR2)
|
return DellPfsEntryR2, ctypes.sizeof(DellPfsEntryR2)
|
||||||
|
|
||||||
# Determine Dell PFS Entry Version string
|
# Determine Dell PFS Entry Version string
|
||||||
def get_entry_ver(version_fields, version_types, msg_padd):
|
def get_entry_ver(version_fields, version_types):
|
||||||
version = '' # Initialize Version string
|
version = '' # Initialize Version string
|
||||||
|
|
||||||
# Each Version Type (1 byte) determines the type of each Version Value (2 bytes)
|
# Each Version Type (1 byte) determines the type of each Version Value (2 bytes)
|
||||||
# Version Type 'N' is Number, 'A' is Text and ' ' is Empty/Unused
|
# Version Type 'N' is Number, 'A' is Text and ' ' is Empty/Unused
|
||||||
for idx in range(len(version_fields)):
|
for index,field in enumerate(version_fields):
|
||||||
eol = '' if idx == len(version_fields) - 1 else '.'
|
eol = '' if index == len(version_fields) - 1 else '.'
|
||||||
|
|
||||||
if version_types[idx] == 65: version += '%X%s' % (version_fields[idx], eol) # 0x41 = ASCII
|
if version_types[index] == 65: version += '%X%s' % (field, eol) # 0x41 = ASCII
|
||||||
elif version_types[idx] == 78: version += '%d%s' % (version_fields[idx], eol) # 0x4E = Number
|
elif version_types[index] == 78: version += '%d%s' % (field, eol) # 0x4E = Number
|
||||||
elif version_types[idx] in (0, 32): version = version.strip('.') # 0x00 or 0x20 = Unused
|
elif version_types[index] in (0, 32): version = version.strip('.') # 0x00 or 0x20 = Unused
|
||||||
else:
|
else: version += '%X%s' % (field, eol) # Unknown
|
||||||
version += '%X%s' % (version_fields[idx], eol) # Unknown
|
|
||||||
printer('Error: Unknown PFS Entry Version Type 0x%0.2X!' % version_types[idx], msg_padd)
|
|
||||||
|
|
||||||
return version
|
return version
|
||||||
|
|
||||||
|
@ -817,14 +816,14 @@ def chk_hdr_ver(version, text, padding):
|
||||||
printer('Error: Unknown %s Header Version %d!' % (text, version), padding)
|
printer('Error: Unknown %s Header Version %d!' % (text, version), padding)
|
||||||
|
|
||||||
# Analyze Dell PFS Footer Structure
|
# Analyze Dell PFS Footer Structure
|
||||||
def chk_pfs_ftr(footer_buffer, data_buffer, data_size, text, padding, is_verbose=True):
|
def chk_pfs_ftr(footer_buffer, data_buffer, data_size, text, padding, is_structure=True):
|
||||||
# Get PFS Footer Structure values
|
# Get PFS Footer Structure values
|
||||||
pfs_ftr = get_struct(footer_buffer, 0, DellPfsFooter)
|
pfs_ftr = get_struct(footer_buffer, 0, DellPfsFooter)
|
||||||
|
|
||||||
# Validate that a PFS Footer was parsed
|
# Validate that a PFS Footer was parsed
|
||||||
if pfs_ftr.Tag == b'PFS.FTR.':
|
if pfs_ftr.Tag == b'PFS.FTR.':
|
||||||
# Show PFS Footer Structure info
|
# Show PFS Footer Structure info
|
||||||
if is_verbose:
|
if is_structure:
|
||||||
printer('PFS Footer:\n', padding + 4)
|
printer('PFS Footer:\n', padding + 4)
|
||||||
pfs_ftr.struct_print(padding + 8)
|
pfs_ftr.struct_print(padding + 8)
|
||||||
else:
|
else:
|
||||||
|
@ -842,7 +841,7 @@ def chk_pfs_ftr(footer_buffer, data_buffer, data_size, text, padding, is_verbose
|
||||||
printer('Error: Invalid %s Footer Payload Checksum!' % text, padding + 4)
|
printer('Error: Invalid %s Footer Payload Checksum!' % text, padding + 4)
|
||||||
|
|
||||||
# Write/Extract Dell PFS Entry Files (Data, Metadata, Signature)
|
# Write/Extract Dell PFS Entry Files (Data, Metadata, Signature)
|
||||||
def pfs_file_write(bin_buff, bin_name, bin_type, full_name, out_path, padding, is_verbose=True, is_advanced=True):
|
def pfs_file_write(bin_buff, bin_name, bin_type, full_name, out_path, padding, is_structure=True, is_advanced=True):
|
||||||
# Store Data/Metadata Signature (advanced users only)
|
# Store Data/Metadata Signature (advanced users only)
|
||||||
if bin_name.startswith('sign'):
|
if bin_name.startswith('sign'):
|
||||||
final_name = '%s.%s.sig' % (safe_name(full_name), bin_name.split('_')[1])
|
final_name = '%s.%s.sig' % (safe_name(full_name), bin_name.split('_')[1])
|
||||||
|
@ -856,7 +855,7 @@ def pfs_file_write(bin_buff, bin_name, bin_type, full_name, out_path, padding, i
|
||||||
bin_ext = '.%s.bin' % bin_name if is_advanced else '.bin' # Simpler Data/Metadata Extension for non-advanced users
|
bin_ext = '.%s.bin' % bin_name if is_advanced else '.bin' # Simpler Data/Metadata Extension for non-advanced users
|
||||||
|
|
||||||
# Some Data may be Text or XML files with useful information for non-advanced users
|
# Some Data may be Text or XML files with useful information for non-advanced users
|
||||||
is_text,final_data,file_ext,write_mode = bin_is_text(bin_buff, bin_type, bin_name == 'meta', padding, is_verbose, is_advanced)
|
is_text,final_data,file_ext,write_mode = bin_is_text(bin_buff, bin_type, bin_name == 'meta', padding, is_structure, is_advanced)
|
||||||
|
|
||||||
final_name = '%s%s' % (safe_name(full_name), bin_ext[:-4] + file_ext if is_text else bin_ext)
|
final_name = '%s%s' % (safe_name(full_name), bin_ext[:-4] + file_ext if is_text else bin_ext)
|
||||||
final_path = os.path.join(out_path, final_name)
|
final_path = os.path.join(out_path, final_name)
|
||||||
|
@ -864,7 +863,7 @@ def pfs_file_write(bin_buff, bin_name, bin_type, full_name, out_path, padding, i
|
||||||
with open(final_path, write_mode) as pfs_out: pfs_out.write(final_data) # Write final Data/Metadata Payload
|
with open(final_path, write_mode) as pfs_out: pfs_out.write(final_data) # Write final Data/Metadata Payload
|
||||||
|
|
||||||
# Check if Dell PFS Entry file/data is Text/XML and Convert
|
# Check if Dell PFS Entry file/data is Text/XML and Convert
|
||||||
def bin_is_text(buffer, file_type, is_metadata, pfs_padd, is_verbose=True, is_advanced=True):
|
def bin_is_text(buffer, file_type, is_metadata, pfs_padd, is_structure=True, is_advanced=True):
|
||||||
is_text = False
|
is_text = False
|
||||||
write_mode = 'wb'
|
write_mode = 'wb'
|
||||||
extension = '.bin'
|
extension = '.bin'
|
||||||
|
@ -894,7 +893,7 @@ def bin_is_text(buffer, file_type, is_metadata, pfs_padd, is_verbose=True, is_ad
|
||||||
buffer = text_buffer.getvalue()
|
buffer = text_buffer.getvalue()
|
||||||
|
|
||||||
# Show Model/PCR XML Information, if applicable
|
# Show Model/PCR XML Information, if applicable
|
||||||
if is_verbose and is_text and not is_metadata: # Metadata is shown at initial DellPfsMetadata analysis
|
if is_structure and is_text and not is_metadata: # Metadata is shown at initial DellPfsMetadata analysis
|
||||||
printer('PFS %s Information:\n' % {'.txt': 'Model', '.xml': 'PCR XML'}[extension], pfs_padd + 8)
|
printer('PFS %s Information:\n' % {'.txt': 'Model', '.xml': 'PCR XML'}[extension], pfs_padd + 8)
|
||||||
_ = [printer(line.strip('\r'), pfs_padd + 12, False) for line in buffer.split('\n') if line]
|
_ = [printer(line.strip('\r'), pfs_padd + 12, False) for line in buffer.split('\n') if line]
|
||||||
|
|
||||||
|
@ -920,11 +919,11 @@ if __name__ == '__main__':
|
||||||
# Set argparse arguments
|
# Set argparse arguments
|
||||||
argparser = argparse_init()
|
argparser = argparse_init()
|
||||||
argparser.add_argument('-a', '--advanced', help='extract signatures and metadata', action='store_true')
|
argparser.add_argument('-a', '--advanced', help='extract signatures and metadata', action='store_true')
|
||||||
argparser.add_argument('-v', '--verbose', help='show PFS structure information', action='store_true')
|
argparser.add_argument('-s', '--structure', help='show PFS structure information', action='store_true')
|
||||||
arguments = argparser.parse_args()
|
arguments = argparser.parse_args()
|
||||||
|
|
||||||
is_advanced = arguments.advanced # Set Advanced user mode optional argument
|
is_advanced = arguments.advanced # Set Advanced user mode optional argument
|
||||||
is_verbose = arguments.verbose # Set Verbose output mode optional argument
|
is_structure = arguments.structure # Set Structure output mode optional argument
|
||||||
|
|
||||||
# Initialize script (must be after argparse)
|
# Initialize script (must be after argparse)
|
||||||
input_files,output_path,padding = script_init(arguments, 4)
|
input_files,output_path,padding = script_init(arguments, 4)
|
||||||
|
@ -937,7 +936,7 @@ if __name__ == '__main__':
|
||||||
with open(input_file, 'rb') as in_file: input_buffer = in_file.read()
|
with open(input_file, 'rb') as in_file: input_buffer = in_file.read()
|
||||||
|
|
||||||
# Search input image for ThinOS PKG 7zXZ section header
|
# Search input image for ThinOS PKG 7zXZ section header
|
||||||
lzma_pkg_hdr_match = is_dell_pfs_pkg(input_buffer)
|
lzma_pkg_hdr_match = is_pfs_pkg(input_buffer)
|
||||||
|
|
||||||
# Decompress ThinOS PKG 7zXZ section first, if present
|
# Decompress ThinOS PKG 7zXZ section first, if present
|
||||||
if lzma_pkg_hdr_match:
|
if lzma_pkg_hdr_match:
|
||||||
|
@ -969,7 +968,7 @@ if __name__ == '__main__':
|
||||||
# Parse each PFS ZLIB Section
|
# Parse each PFS ZLIB Section
|
||||||
for offset in pfs_zlib_offsets:
|
for offset in pfs_zlib_offsets:
|
||||||
# Call the PFS ZLIB Section Parser function
|
# Call the PFS ZLIB Section Parser function
|
||||||
pfs_section_parse(input_buffer, offset, extract_path, extract_name, 1, 1, False, padding, is_verbose, is_advanced)
|
pfs_section_parse(input_buffer, offset, extract_path, extract_name, 1, 1, False, padding, is_structure, is_advanced)
|
||||||
|
|
||||||
printer('Extracted Dell PFS Update image!', padding)
|
printer('Extracted Dell PFS Update image!', padding)
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,12 @@ Parses Dell PFS Update images and extracts their Firmware (e.g. SPI, BIOS/UEFI,
|
||||||
You can either Drag & Drop or manually enter Dell PFS Update images(s). Optional arguments:
|
You can either Drag & Drop or manually enter Dell PFS Update images(s). Optional arguments:
|
||||||
|
|
||||||
* -h or --help : show help message and exit
|
* -h or --help : show help message and exit
|
||||||
|
* -v or --version : show utility name and version
|
||||||
* -i or --input-dir : extract from given input directory
|
* -i or --input-dir : extract from given input directory
|
||||||
* -o or --output-dir : extract in given output directory
|
* -o or --output-dir : extract in given output directory
|
||||||
* -e or --auto-exit : skip press enter to exit prompts
|
* -e or --auto-exit : skip press enter to exit prompts
|
||||||
* -a or --advanced : extract signatures and metadata
|
* -a or --advanced : extract signatures and metadata
|
||||||
* -v or --verbose : show PFS structure information
|
* -s or --structure : show PFS structure information
|
||||||
|
|
||||||
#### **Compatibility**
|
#### **Compatibility**
|
||||||
|
|
||||||
|
@ -81,6 +82,7 @@ Parses AMI UCP (Utility Configuration Program) BIOS executables, extracts their
|
||||||
You can either Drag & Drop or manually enter AMI UCP BIOS executable file(s). Optional arguments:
|
You can either Drag & Drop or manually enter AMI UCP BIOS executable file(s). Optional arguments:
|
||||||
|
|
||||||
* -h or --help : show help message and exit
|
* -h or --help : show help message and exit
|
||||||
|
* -v or --version : show utility name and version
|
||||||
* -i or --input-dir : extract from given input directory
|
* -i or --input-dir : extract from given input directory
|
||||||
* -o or --output-dir : extract in given output directory
|
* -o or --output-dir : extract in given output directory
|
||||||
* -e or --auto-exit : skip press enter to exit prompts
|
* -e or --auto-exit : skip press enter to exit prompts
|
||||||
|
@ -146,6 +148,7 @@ Note that the AMI PFAT structure may not have an explicit component order. AMI's
|
||||||
You can either Drag & Drop or manually enter AMI BIOS Guard (PFAT) image file(s). Optional arguments:
|
You can either Drag & Drop or manually enter AMI BIOS Guard (PFAT) image file(s). Optional arguments:
|
||||||
|
|
||||||
* -h or --help : show help message and exit
|
* -h or --help : show help message and exit
|
||||||
|
* -v or --version : show utility name and version
|
||||||
* -i or --input-dir : extract from given input directory
|
* -i or --input-dir : extract from given input directory
|
||||||
* -o or --output-dir : extract in given output directory
|
* -o or --output-dir : extract in given output directory
|
||||||
* -e or --auto-exit : skip press enter to exit prompts
|
* -e or --auto-exit : skip press enter to exit prompts
|
||||||
|
|
|
@ -5,7 +5,6 @@ import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import inspect
|
import inspect
|
||||||
import argparse
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Fix illegal/reserved Windows characters
|
# Fix illegal/reserved Windows characters
|
||||||
|
@ -43,17 +42,6 @@ def get_absolute_path(argparse_path):
|
||||||
|
|
||||||
return absolute_path
|
return absolute_path
|
||||||
|
|
||||||
# Initialize common argparse arguments
|
|
||||||
def argparse_init():
|
|
||||||
argparser = argparse.ArgumentParser()
|
|
||||||
|
|
||||||
argparser.add_argument('files', type=argparse.FileType('r'), nargs='*')
|
|
||||||
argparser.add_argument('-e', '--auto-exit', help='skip press enter to exit prompts', action='store_true')
|
|
||||||
argparser.add_argument('-o', '--output-dir', help='extract in given output directory')
|
|
||||||
argparser.add_argument('-i', '--input-dir', help='extract from given input directory')
|
|
||||||
|
|
||||||
return argparser
|
|
||||||
|
|
||||||
# Process input files (argparse object)
|
# Process input files (argparse object)
|
||||||
def process_input_files(argparse_args, sys_argv=None):
|
def process_input_files(argparse_args, sys_argv=None):
|
||||||
if sys_argv is None: sys_argv = []
|
if sys_argv is None: sys_argv = []
|
||||||
|
|
|
@ -5,7 +5,7 @@ import re
|
||||||
|
|
||||||
PAT_AMI_PFAT = re.compile(b'_AMIPFAT.AMI_BIOS_GUARD_FLASH_CONFIGURATIONS', re.DOTALL)
|
PAT_AMI_PFAT = re.compile(b'_AMIPFAT.AMI_BIOS_GUARD_FLASH_CONFIGURATIONS', re.DOTALL)
|
||||||
PAT_AMI_UCP = re.compile(br'@(UAF|HPU).{12}@', re.DOTALL)
|
PAT_AMI_UCP = re.compile(br'@(UAF|HPU).{12}@', re.DOTALL)
|
||||||
PAT_DELL_PKG = re.compile(br'\x72\x13\x55\x00.{45}\x37\x7A\x58\x5A', re.DOTALL)
|
PAT_DELL_PKG = re.compile(br'\x72\x13\x55\x00.{45}7zXZ', re.DOTALL)
|
||||||
PAT_DELL_HDR = re.compile(br'\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.\x78\x9C', re.DOTALL)
|
PAT_DELL_HDR = re.compile(br'\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.\x78\x9C', re.DOTALL)
|
||||||
PAT_DELL_FTR = re.compile(br'\xEE\xAA\xEE\x8F\x49\x1B\xE8\xAE\x14\x37\x90')
|
PAT_DELL_FTR = re.compile(br'\xEE\xAA\xEE\x8F\x49\x1B\xE8\xAE\x14\x37\x90')
|
||||||
PAT_INTEL_ENG = re.compile(br'\x04\x00{3}[\xA1\xE1]\x00{3}.{8}\x86\x80.{9}\x00\$((MN2)|(MAN))', re.DOTALL)
|
PAT_INTEL_ENG = re.compile(br'\x04\x00{3}[\xA1\xE1]\x00{3}.{8}\x86\x80.{9}\x00\$((MN2)|(MAN))', re.DOTALL)
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import ctypes
|
import ctypes
|
||||||
|
import argparse
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from common.text_ops import padder
|
from common.text_ops import padder
|
||||||
|
@ -53,6 +54,18 @@ def check_sys_os():
|
||||||
# Fix Windows Unicode console redirection
|
# Fix Windows Unicode console redirection
|
||||||
if os_win: sys.stdout.reconfigure(encoding='utf-8')
|
if os_win: sys.stdout.reconfigure(encoding='utf-8')
|
||||||
|
|
||||||
|
# Initialize common argparse arguments
|
||||||
|
def argparse_init():
|
||||||
|
argparser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
argparser.add_argument('files', type=argparse.FileType('r'), nargs='*')
|
||||||
|
argparser.add_argument('-e', '--auto-exit', help='skip press enter to exit prompts', action='store_true')
|
||||||
|
argparser.add_argument('-v', '--version', help='show utility name and version', action='store_true')
|
||||||
|
argparser.add_argument('-o', '--output-dir', help='extract in given output directory')
|
||||||
|
argparser.add_argument('-i', '--input-dir', help='extract from given input directory')
|
||||||
|
|
||||||
|
return argparser
|
||||||
|
|
||||||
# Show Script Title
|
# Show Script Title
|
||||||
def script_title(title):
|
def script_title(title):
|
||||||
printer(title)
|
printer(title)
|
||||||
|
@ -63,17 +76,20 @@ def script_title(title):
|
||||||
if os_win: ctypes.windll.kernel32.SetConsoleTitleW(title)
|
if os_win: ctypes.windll.kernel32.SetConsoleTitleW(title)
|
||||||
else: sys.stdout.write('\x1b]2;' + title + '\x07')
|
else: sys.stdout.write('\x1b]2;' + title + '\x07')
|
||||||
|
|
||||||
# Initialize Script
|
# Initialize Script (must be after argparse)
|
||||||
def script_init(arguments, padding=0):
|
def script_init(arguments, padding=0):
|
||||||
# Pretty Python exception handler (must be after argparse)
|
# Pretty Python exception handler
|
||||||
sys.excepthook = nice_exc_handler
|
sys.excepthook = nice_exc_handler
|
||||||
|
|
||||||
# Check Python Version (must be after argparse)
|
# Check Python Version
|
||||||
check_sys_py()
|
check_sys_py()
|
||||||
|
|
||||||
# Check OS Platform (must be after argparse)
|
# Check OS Platform
|
||||||
check_sys_os()
|
check_sys_os()
|
||||||
|
|
||||||
|
# Show Utility Version on demand
|
||||||
|
if arguments.version: sys.exit(0)
|
||||||
|
|
||||||
# Process input files and generate output path
|
# Process input files and generate output path
|
||||||
input_files,output_path = process_input_files(arguments, sys.argv)
|
input_files,output_path = process_input_files(arguments, sys.argv)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue