Insyde iFlash/iFdPacker Extractor v2.0_a8

Improved PFAT, UCP, PFS, TDK format check methods

Cleanup/improvements to all utilities
This commit is contained in:
platomav 2022-07-06 17:54:17 +03:00
parent cd2704f743
commit 4749414f81
21 changed files with 603 additions and 435 deletions

View file

@ -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_a10' TITLE = 'AMI BIOS Guard Extractor v4.0_a11'
import os import os
import re import re
@ -19,10 +19,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 safe_name, make_dirs from common.path_ops import make_dirs, 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 char, get_struct, uint8_t, uint16_t, uint32_t
from common.system import script_init, argparse_init, printer from common.system import argparse_init, printer, script_init
from common.text_ops import file_to_bytes from common.text_ops import file_to_bytes
class AmiBiosGuardHeader(ctypes.LittleEndianStructure): class AmiBiosGuardHeader(ctypes.LittleEndianStructure):
@ -128,22 +128,22 @@ class IntelBiosGuardSignature2k(ctypes.LittleEndianStructure):
printer(['Exponent :', f'0x{self.Exponent:X}'], p, False) printer(['Exponent :', f'0x{self.Exponent:X}'], p, False)
printer(['Signature:', f'{Signature[:32]} [...]'], p, False) printer(['Signature:', f'{Signature[:32]} [...]'], p, False)
def is_ami_pfat(in_file): def is_ami_pfat(input_file):
input_buffer = file_to_bytes(in_file) input_buffer = file_to_bytes(input_file)
return bool(get_ami_pfat(input_buffer)[0]) return bool(get_ami_pfat(input_buffer))
def get_ami_pfat(input_file):
input_buffer = file_to_bytes(input_file)
def get_ami_pfat(input_buffer):
match = PAT_AMI_PFAT.search(input_buffer) match = PAT_AMI_PFAT.search(input_buffer)
buffer = input_buffer[match.start() - 0x8:] if match else b'' return input_buffer[match.start() - 0x8:] if match else b''
return match, buffer
def get_file_name(index, name): def get_file_name(index, name):
return safe_name(f'{index:02d} -- {name}') return safe_name(f'{index:02d} -- {name}')
def parse_bg_script(script_data, padding): def parse_bg_script(script_data, padding=0):
is_opcode_div = len(script_data) % 8 == 0 is_opcode_div = len(script_data) % 8 == 0
if not is_opcode_div: if not is_opcode_div:
@ -177,7 +177,7 @@ def parse_bg_script(script_data, padding):
return 0 return 0
def parse_pfat_hdr(buffer, padding): def parse_pfat_hdr(buffer, padding=0):
block_all = [] block_all = []
pfat_hdr = get_struct(buffer, 0x0, AmiBiosGuardHeader) pfat_hdr = get_struct(buffer, 0x0, AmiBiosGuardHeader)
@ -220,7 +220,11 @@ def parse_pfat_hdr(buffer, padding):
return block_all, hdr_size, files_count return block_all, hdr_size, files_count
def parse_pfat_file(buffer, output_path, padding): def parse_pfat_file(input_file, output_path, padding=0):
input_buffer = file_to_bytes(input_file)
pfat_buffer = get_ami_pfat(input_buffer)
file_path = '' file_path = ''
all_blocks_dict = {} all_blocks_dict = {}
@ -230,7 +234,7 @@ def parse_pfat_file(buffer, output_path, padding):
make_dirs(extract_path, delete=True) make_dirs(extract_path, delete=True)
block_all,block_off,file_count = parse_pfat_hdr(buffer, padding) block_all,block_off,file_count = parse_pfat_hdr(pfat_buffer, padding)
for block in block_all: for block in block_all:
file_desc,file_name,_,_,_,file_index,block_index,block_count = block file_desc,file_name,_,_,_,file_index,block_index,block_count = block
@ -244,7 +248,7 @@ def parse_pfat_file(buffer, output_path, padding):
block_status = f'{block_index + 1}/{block_count}' block_status = f'{block_index + 1}/{block_count}'
bg_hdr = get_struct(buffer, block_off, IntelBiosGuardHeader) bg_hdr = get_struct(pfat_buffer, block_off, IntelBiosGuardHeader)
printer(f'Intel BIOS Guard {block_status} Header:\n', padding + 8) printer(f'Intel BIOS Guard {block_status} Header:\n', padding + 8)
@ -252,11 +256,11 @@ def parse_pfat_file(buffer, output_path, padding):
bg_script_bgn = block_off + PFAT_BLK_HDR_LEN bg_script_bgn = block_off + PFAT_BLK_HDR_LEN
bg_script_end = bg_script_bgn + bg_hdr.ScriptSize bg_script_end = bg_script_bgn + bg_hdr.ScriptSize
bg_script_bin = buffer[bg_script_bgn:bg_script_end] bg_script_bin = pfat_buffer[bg_script_bgn:bg_script_end]
bg_data_bgn = bg_script_end bg_data_bgn = bg_script_end
bg_data_end = bg_data_bgn + bg_hdr.DataSize bg_data_end = bg_data_bgn + bg_hdr.DataSize
bg_data_bin = buffer[bg_data_bgn:bg_data_end] bg_data_bin = pfat_buffer[bg_data_bgn:bg_data_end]
block_off = bg_data_end # Assume next block starts at data end block_off = bg_data_end # Assume next block starts at data end
@ -265,7 +269,7 @@ def parse_pfat_file(buffer, output_path, padding):
if is_sfam: if is_sfam:
bg_sig_bgn = bg_data_end bg_sig_bgn = bg_data_end
bg_sig_end = bg_sig_bgn + PFAT_BLK_S2K_LEN bg_sig_end = bg_sig_bgn + PFAT_BLK_S2K_LEN
bg_sig_bin = buffer[bg_sig_bgn:bg_sig_end] bg_sig_bin = pfat_buffer[bg_sig_bgn:bg_sig_end]
if len(bg_sig_bin) == PFAT_BLK_S2K_LEN: if len(bg_sig_bin) == PFAT_BLK_S2K_LEN:
bg_sig = get_struct(bg_sig_bin, 0x0, IntelBiosGuardSignature2k) bg_sig = get_struct(bg_sig_bin, 0x0, IntelBiosGuardSignature2k)
@ -280,21 +284,22 @@ def parse_pfat_file(buffer, output_path, padding):
_ = parse_bg_script(bg_script_bin, padding + 12) _ = parse_bg_script(bg_script_bin, padding + 12)
with open(file_path, 'ab') as out_dat: out_dat.write(bg_data_bin) with open(file_path, 'ab') as out_dat:
out_dat.write(bg_data_bin)
all_blocks_dict[file_index] += bg_data_bin all_blocks_dict[file_index] += bg_data_bin
pfat_oob_data = buffer[block_off:] # Store out-of-bounds data after the end of PFAT files pfat_oob_data = pfat_buffer[block_off:] # Store out-of-bounds data after the end of PFAT files
pfat_oob_name = get_file_name(file_count + 1, f'{extract_name}_OOB.bin') pfat_oob_name = get_file_name(file_count + 1, f'{extract_name}_OOB.bin')
pfat_oob_path = os.path.join(extract_path, pfat_oob_name) pfat_oob_path = os.path.join(extract_path, pfat_oob_name)
with open(pfat_oob_path, 'wb') as out_oob: out_oob.write(pfat_oob_data) with open(pfat_oob_path, 'wb') as out_oob:
out_oob.write(pfat_oob_data)
oob_pfat_match,pfat_oob_buffer = get_ami_pfat(pfat_oob_data) if is_ami_pfat(pfat_oob_data):
parse_pfat_file(pfat_oob_data, pfat_oob_path, padding)
if oob_pfat_match: parse_pfat_file(pfat_oob_buffer, pfat_oob_path, padding)
in_all_data = b''.join([block[1] for block in sorted(all_blocks_dict.items())]) in_all_data = b''.join([block[1] for block in sorted(all_blocks_dict.items())])
@ -302,7 +307,10 @@ def parse_pfat_file(buffer, output_path, padding):
in_all_path = os.path.join(extract_path, in_all_name) in_all_path = os.path.join(extract_path, in_all_name)
with open(in_all_path, 'wb') as out_all: out_all.write(in_all_data + pfat_oob_data) with open(in_all_path, 'wb') as out_all:
out_all.write(in_all_data + pfat_oob_data)
return 0
PFAT_AMI_HDR_LEN = ctypes.sizeof(AmiBiosGuardHeader) PFAT_AMI_HDR_LEN = ctypes.sizeof(AmiBiosGuardHeader)
PFAT_BLK_HDR_LEN = ctypes.sizeof(IntelBiosGuardHeader) PFAT_BLK_HDR_LEN = ctypes.sizeof(IntelBiosGuardHeader)
@ -321,18 +329,17 @@ if __name__ == '__main__':
printer(['***', input_name], padding - 4) printer(['***', input_name], padding - 4)
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()
pfat_match,pfat_buffer = get_ami_pfat(input_buffer) if not is_ami_pfat(input_buffer):
if not pfat_match:
printer('Error: This is not an AMI BIOS Guard (PFAT) image!', padding) printer('Error: This is not an AMI BIOS Guard (PFAT) image!', padding)
continue # Next input file continue # Next input file
extract_path = os.path.join(output_path, input_name) extract_path = os.path.join(output_path, input_name)
parse_pfat_file(pfat_buffer, extract_path, padding) parse_pfat_file(input_buffer, extract_path, padding)
exit_code -= 1 exit_code -= 1

View file

@ -7,7 +7,7 @@ AMI UCP Update Extractor
Copyright (C) 2021-2022 Plato Mavropoulos Copyright (C) 2021-2022 Plato Mavropoulos
""" """
TITLE = 'AMI UCP Update Extractor v2.0_a17' TITLE = 'AMI UCP Update Extractor v2.0_a18'
import os import os
import re import re
@ -21,14 +21,14 @@ sys.dont_write_bytecode = True
from common.checksums import get_chk_16 from common.checksums import get_chk_16
from common.comp_efi import efi_decompress, is_efi_compressed from common.comp_efi import efi_decompress, is_efi_compressed
from common.comp_szip import is_szip_supported, szip_decompress from common.path_ops import agnostic_path, make_dirs, safe_name, safe_path
from common.path_ops import agnostic_path, safe_name, safe_path, make_dirs
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 char, get_struct, uint8_t, uint16_t, uint32_t
from common.system import script_init, argparse_init, printer from common.system import argparse_init, printer, script_init
from common.text_ops import file_to_bytes, to_string from common.text_ops import file_to_bytes, to_string
from AMI_PFAT_Extract import get_ami_pfat, parse_pfat_file from AMI_PFAT_Extract import is_ami_pfat, parse_pfat_file
from Insyde_IFD_Extract import insyde_ifd_extract, is_insyde_ifd
class UafHeader(ctypes.LittleEndianStructure): class UafHeader(ctypes.LittleEndianStructure):
_pack_ = 1 _pack_ = 1
@ -166,9 +166,10 @@ def is_ami_ucp(in_file):
return bool(get_ami_ucp(buffer)[0] is not None) return bool(get_ami_ucp(buffer)[0] is not None)
# Get all input file AMI UCP patterns # Get all input file AMI UCP patterns
def get_ami_ucp(buffer): def get_ami_ucp(in_file):
buffer = file_to_bytes(in_file)
uaf_len_max = 0x0 # Length of largest detected @UAF|@HPU uaf_len_max = 0x0 # Length of largest detected @UAF|@HPU
uaf_hdr_off = None # Offset of largest detected @UAF|@HPU
uaf_buf_bin = None # Buffer of largest detected @UAF|@HPU uaf_buf_bin = None # Buffer of largest detected @UAF|@HPU
uaf_buf_tag = '@UAF' # Tag of largest detected @UAF|@HPU uaf_buf_tag = '@UAF' # Tag of largest detected @UAF|@HPU
@ -181,7 +182,7 @@ def get_ami_ucp(buffer):
uaf_buf_bin = buffer[uaf_hdr_off:uaf_hdr_off + uaf_len_max] uaf_buf_bin = buffer[uaf_hdr_off:uaf_hdr_off + uaf_len_max]
uaf_buf_tag = uaf.group(0)[:4].decode('utf-8','ignore') uaf_buf_tag = uaf.group(0)[:4].decode('utf-8','ignore')
return uaf_hdr_off, uaf_buf_bin, uaf_buf_tag return uaf_buf_bin, uaf_buf_tag
# Get list of @UAF|@HPU Modules # Get list of @UAF|@HPU Modules
def get_uaf_mod(buffer, uaf_off=0x0): def get_uaf_mod(buffer, uaf_off=0x0):
@ -196,19 +197,23 @@ def get_uaf_mod(buffer, uaf_off=0x0):
uaf_off += uaf_hdr.ModuleSize # Adjust to next @UAF|@HPU Module offset uaf_off += uaf_hdr.ModuleSize # Adjust to next @UAF|@HPU Module offset
if uaf_off >= len(buffer): break # Stop parsing at EOF if uaf_off >= len(buffer):
break # Stop parsing at EOF
# Check if @UAF|@HPU Module @NAL exists and place it first # Check if @UAF|@HPU Module @NAL exists and place it first
# Parsing @NAL first allows naming all @UAF|@HPU Modules # Parsing @NAL first allows naming all @UAF|@HPU Modules
for mod_idx,mod_val in enumerate(uaf_all): for mod_idx,mod_val in enumerate(uaf_all):
if mod_val[0] == '@NAL': if mod_val[0] == '@NAL':
uaf_all.insert(1, uaf_all.pop(mod_idx)) # After UII for visual purposes uaf_all.insert(1, uaf_all.pop(mod_idx)) # After UII for visual purposes
break # @NAL found, skip the rest break # @NAL found, skip the rest
return uaf_all return uaf_all
# Parse & Extract AMI UCP structures # Parse & Extract AMI UCP structures
def ucp_extract(buffer, out_path, ucp_tag='@UAF', padding=0, is_checksum=False): def ucp_extract(in_file, out_path, padding=0, checksum=False):
input_buffer = file_to_bytes(in_file)
nal_dict = {} # Initialize @NAL Dictionary per UCP nal_dict = {} # Initialize @NAL Dictionary per UCP
printer('Utility Configuration Program', padding) printer('Utility Configuration Program', padding)
@ -217,13 +222,16 @@ def ucp_extract(buffer, out_path, ucp_tag='@UAF', padding=0, is_checksum=False):
make_dirs(extract_path, delete=True) make_dirs(extract_path, delete=True)
uaf_hdr = get_struct(buffer, 0, UafHeader) # Parse @UAF|@HPU Header Structure # Get best AMI UCP Pattern match based on @UAF|@HPU Size
ucp_buffer,ucp_tag = get_ami_ucp(input_buffer)
uaf_hdr = get_struct(ucp_buffer, 0, UafHeader) # Parse @UAF|@HPU Header Structure
printer(f'Utility Auxiliary File > {ucp_tag}:\n', padding + 4) printer(f'Utility Auxiliary File > {ucp_tag}:\n', padding + 4)
uaf_hdr.struct_print(padding + 8) uaf_hdr.struct_print(padding + 8)
fake = struct.pack('<II', len(buffer), len(buffer)) # Generate UafModule Structure fake = struct.pack('<II', len(ucp_buffer), len(ucp_buffer)) # Generate UafModule Structure
uaf_mod = get_struct(fake, 0x0, UafModule) # Parse @UAF|@HPU Module EFI Structure uaf_mod = get_struct(fake, 0x0, UafModule) # Parse @UAF|@HPU Module EFI Structure
@ -232,16 +240,18 @@ def ucp_extract(buffer, out_path, ucp_tag='@UAF', padding=0, is_checksum=False):
uaf_mod.struct_print(padding + 8, uaf_name, uaf_desc) # Print @UAF|@HPU Module EFI Info uaf_mod.struct_print(padding + 8, uaf_name, uaf_desc) # Print @UAF|@HPU Module EFI Info
if is_checksum: chk16_validate(buffer, ucp_tag, padding + 8) if checksum:
chk16_validate(ucp_buffer, ucp_tag, padding + 8)
uaf_all = get_uaf_mod(buffer, UAF_HDR_LEN) uaf_all = get_uaf_mod(ucp_buffer, UAF_HDR_LEN)
for mod_info in uaf_all: for mod_info in uaf_all:
nal_dict = uaf_extract(buffer, extract_path, mod_info, padding + 8, is_checksum, nal_dict) nal_dict = uaf_extract(ucp_buffer, extract_path, mod_info, padding + 8, checksum, nal_dict)
# Parse & Extract AMI UCP > @UAF|@HPU Module/Section # Parse & Extract AMI UCP > @UAF|@HPU Module/Section
def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, nal_dict=None): def uaf_extract(buffer, extract_path, mod_info, padding=0, checksum=False, nal_dict=None):
if nal_dict is None: nal_dict = {} if nal_dict is None:
nal_dict = {}
uaf_tag,uaf_off,uaf_hdr = mod_info uaf_tag,uaf_off,uaf_hdr = mod_info
@ -259,16 +269,26 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
is_comp = uaf_mod.CompressSize != uaf_mod.OriginalSize # Detect @UAF|@HPU Module EFI Compression is_comp = uaf_mod.CompressSize != uaf_mod.OriginalSize # Detect @UAF|@HPU Module EFI Compression
if uaf_tag in nal_dict: uaf_name = nal_dict[uaf_tag][1] # Always prefer @NAL naming first if uaf_tag in nal_dict:
elif uaf_tag in UAF_TAG_DICT: uaf_name = UAF_TAG_DICT[uaf_tag][0] # Otherwise use built-in naming uaf_name = nal_dict[uaf_tag][1] # Always prefer @NAL naming first
elif uaf_tag == '@ROM': uaf_name = 'BIOS.bin' # BIOS/PFAT Firmware (w/o Signature) elif uaf_tag in UAF_TAG_DICT:
elif uaf_tag.startswith('@R0'): uaf_name = f'BIOS_0{uaf_tag[3:]}.bin' # BIOS/PFAT Firmware uaf_name = UAF_TAG_DICT[uaf_tag][0] # Otherwise use built-in naming
elif uaf_tag.startswith('@S0'): uaf_name = f'BIOS_0{uaf_tag[3:]}.sig' # BIOS/PFAT Signature elif uaf_tag == '@ROM':
elif uaf_tag.startswith('@DR'): uaf_name = f'DROM_0{uaf_tag[3:]}.bin' # Thunderbolt Retimer Firmware uaf_name = 'BIOS.bin' # BIOS/PFAT Firmware (w/o Signature)
elif uaf_tag.startswith('@DS'): uaf_name = f'DROM_0{uaf_tag[3:]}.sig' # Thunderbolt Retimer Signature elif uaf_tag.startswith('@R0'):
elif uaf_tag.startswith('@EC'): uaf_name = f'EC_0{uaf_tag[3:]}.bin' # Embedded Controller Firmware uaf_name = f'BIOS_0{uaf_tag[3:]}.bin' # BIOS/PFAT Firmware
elif uaf_tag.startswith('@ME'): uaf_name = f'ME_0{uaf_tag[3:]}.bin' # Management Engine Firmware elif uaf_tag.startswith('@S0'):
else: uaf_name = uaf_tag # Could not name the @UAF|@HPU Module, use Tag instead uaf_name = f'BIOS_0{uaf_tag[3:]}.sig' # BIOS/PFAT Signature
elif uaf_tag.startswith('@DR'):
uaf_name = f'DROM_0{uaf_tag[3:]}.bin' # Thunderbolt Retimer Firmware
elif uaf_tag.startswith('@DS'):
uaf_name = f'DROM_0{uaf_tag[3:]}.sig' # Thunderbolt Retimer Signature
elif uaf_tag.startswith('@EC'):
uaf_name = f'EC_0{uaf_tag[3:]}.bin' # Embedded Controller Firmware
elif uaf_tag.startswith('@ME'):
uaf_name = f'ME_0{uaf_tag[3:]}.bin' # Management Engine Firmware
else:
uaf_name = uaf_tag # Could not name the @UAF|@HPU Module, use Tag instead
uaf_fext = '' if uaf_name != uaf_tag else '.bin' uaf_fext = '' if uaf_name != uaf_tag else '.bin'
@ -289,7 +309,8 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
else: else:
uaf_fname = safe_path(extract_path, uaf_sname) uaf_fname = safe_path(extract_path, uaf_sname)
if is_checksum: chk16_validate(uaf_data_all, uaf_tag, padding + 4) if checksum:
chk16_validate(uaf_data_all, uaf_tag, padding + 4)
# Parse Utility Identification Information @UAF|@HPU Module (@UII) # Parse Utility Identification Information @UAF|@HPU Module (@UII)
if uaf_tag == '@UII': if uaf_tag == '@UII':
@ -304,7 +325,8 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
info_hdr.struct_print(padding + 8, info_desc) # Print @UII Module Info info_hdr.struct_print(padding + 8, info_desc) # Print @UII Module Info
if is_checksum: chk16_validate(uaf_data_raw, '@UII > Info', padding + 8) if checksum:
chk16_validate(uaf_data_raw, '@UII > Info', padding + 8)
# Store/Save @UII Module Info in file # Store/Save @UII Module Info in file
with open(uaf_fname[:-4] + '.txt', 'a', encoding='utf-8') as uii_out: with open(uaf_fname[:-4] + '.txt', 'a', encoding='utf-8') as uii_out:
@ -324,14 +346,16 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
# Store/Save @UAF|@HPU Module file # Store/Save @UAF|@HPU Module file
if uaf_tag != '@UII': # Skip @UII binary, already parsed if uaf_tag != '@UII': # Skip @UII binary, already parsed
with open(uaf_fname, 'wb') as uaf_out: uaf_out.write(uaf_data_raw) with open(uaf_fname, 'wb') as uaf_out:
uaf_out.write(uaf_data_raw)
# @UAF|@HPU Module EFI/Tiano Decompression # @UAF|@HPU Module EFI/Tiano Decompression
if is_comp and is_efi_compressed(uaf_data_raw, False): if is_comp and is_efi_compressed(uaf_data_raw, False):
dec_fname = uaf_fname.replace('.temp', uaf_fext) # Decompressed @UAF|@HPU Module file path dec_fname = uaf_fname.replace('.temp', uaf_fext) # Decompressed @UAF|@HPU Module file path
if efi_decompress(uaf_fname, dec_fname, padding + 4) == 0: if efi_decompress(uaf_fname, dec_fname, padding + 4) == 0:
with open(dec_fname, 'rb') as dec: uaf_data_raw = dec.read() # Read back the @UAF|@HPU Module decompressed Raw data with open(dec_fname, 'rb') as dec:
uaf_data_raw = dec.read() # Read back the @UAF|@HPU Module decompressed Raw data
os.remove(uaf_fname) # Successful decompression, delete compressed @UAF|@HPU Module file os.remove(uaf_fname) # Successful decompression, delete compressed @UAF|@HPU Module file
@ -392,39 +416,32 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
nal_dict[info_tag] = (info_path,info_name) # Assign a file path & name to each Tag nal_dict[info_tag] = (info_path,info_name) # Assign a file path & name to each Tag
# Parse Insyde BIOS @UAF|@HPU Module (@INS) # Parse Insyde BIOS @UAF|@HPU Module (@INS)
if uaf_tag == '@INS' and is_szip_supported(uaf_fname, padding + 4, check=True): if uaf_tag == '@INS' and is_insyde_ifd(uaf_fname):
ins_dir = os.path.join(extract_path, safe_name(f'{uaf_tag}_nested-SFX')) # Generate extraction directory ins_dir = os.path.join(extract_path, safe_name(f'{uaf_tag}_nested-IFD')) # Generate extraction directory
printer('Insyde BIOS 7z SFX Archive:', padding + 4) if insyde_ifd_extract(uaf_fname, ins_dir, padding + 4) == 0:
os.remove(uaf_fname) # Delete raw nested Insyde IFD image after successful extraction
if szip_decompress(uaf_fname, ins_dir, '7z SFX', padding + 8, check=True) == 0:
os.remove(uaf_fname) # Successful extraction, delete @INS Module file/archive
# Detect & Unpack AMI BIOS Guard (PFAT) BIOS image # Detect & Unpack AMI BIOS Guard (PFAT) BIOS image
pfat_match,pfat_buffer = get_ami_pfat(uaf_data_raw) if is_ami_pfat(uaf_data_raw):
if pfat_match:
pfat_dir = os.path.join(extract_path, safe_name(uaf_name)) pfat_dir = os.path.join(extract_path, safe_name(uaf_name))
parse_pfat_file(pfat_buffer, pfat_dir, padding + 4) parse_pfat_file(uaf_data_raw, pfat_dir, padding + 4)
os.remove(uaf_fname) # Delete PFAT Module file after extraction os.remove(uaf_fname) # Delete raw PFAT BIOS image after successful extraction
# Detect Intel Engine firmware image and show ME Analyzer advice # Detect Intel Engine firmware image and show ME Analyzer advice
if uaf_tag.startswith('@ME') and PAT_INTEL_ENG.search(uaf_data_raw): if uaf_tag.startswith('@ME') and PAT_INTEL_ENG.search(uaf_data_raw):
printer('Intel Management Engine (ME) Firmware:\n', padding + 4) printer('Intel Management Engine (ME) Firmware:\n', padding + 4)
printer('Use "ME Analyzer" from https://github.com/platomav/MEAnalyzer', padding + 8, False) printer('Use "ME Analyzer" from https://github.com/platomav/MEAnalyzer', padding + 8, False)
# Get best Nested AMI UCP Pattern match based on @UAF|@HPU Size # Parse Nested AMI UCP image
nested_uaf_off,nested_uaf_bin,nested_uaf_tag = get_ami_ucp(uaf_data_raw) if is_ami_ucp(uaf_data_raw):
# Parse Nested AMI UCP Structure
if nested_uaf_off is not None:
uaf_dir = os.path.join(extract_path, safe_name(f'{uaf_tag}_nested-UCP')) # Generate extraction directory uaf_dir = os.path.join(extract_path, safe_name(f'{uaf_tag}_nested-UCP')) # Generate extraction directory
ucp_extract(nested_uaf_bin, uaf_dir, nested_uaf_tag, padding + 4, is_checksum) # Call recursively ucp_extract(uaf_data_raw, uaf_dir, padding + 4, checksum) # Call recursively
os.remove(uaf_fname) # Delete raw nested AMI UCP Structure after successful recursion/extraction os.remove(uaf_fname) # Delete raw nested AMI UCP image after successful extraction
return nal_dict return nal_dict
@ -497,7 +514,7 @@ if __name__ == '__main__':
argparser.add_argument('-c', '--checksum', help='verify AMI UCP Checksums (slow)', action='store_true') argparser.add_argument('-c', '--checksum', help='verify AMI UCP Checksums (slow)', action='store_true')
arguments = argparser.parse_args() arguments = argparser.parse_args()
is_checksum = arguments.checksum # Set Checksum verification optional argument checksum = arguments.checksum # Set Checksum verification optional argument
# Initialize script (must be after argparse) # Initialize script (must be after argparse)
exit_code,input_files,output_path,padding = script_init(TITLE, arguments, 4) exit_code,input_files,output_path,padding = script_init(TITLE, arguments, 4)
@ -507,19 +524,17 @@ if __name__ == '__main__':
printer(['***', input_name], padding - 4) printer(['***', input_name], padding - 4)
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()
# Get best AMI UCP Pattern match based on @UAF|@HPU Size if not is_ami_ucp(input_buffer):
main_uaf_off,main_uaf_bin,main_uaf_tag = get_ami_ucp(input_buffer)
if main_uaf_off is None:
printer('Error: This is not an AMI UCP Update executable!', padding) printer('Error: This is not an AMI UCP Update executable!', padding)
continue # Next input file continue # Next input file
extract_path = os.path.join(output_path, input_name) extract_path = os.path.join(output_path, input_name)
ucp_extract(main_uaf_bin, extract_path, main_uaf_tag, padding, is_checksum) ucp_extract(input_buffer, extract_path, padding, checksum)
exit_code -= 1 exit_code -= 1

View file

@ -7,7 +7,7 @@ Award BIOS Module Extractor
Copyright (C) 2018-2022 Plato Mavropoulos Copyright (C) 2018-2022 Plato Mavropoulos
""" """
TITLE = 'Award BIOS Module Extractor v2.0_a3' TITLE = 'Award BIOS Module Extractor v2.0_a4'
import os import os
import sys import sys
@ -18,7 +18,7 @@ sys.dont_write_bytecode = True
from common.comp_szip import szip_decompress from common.comp_szip import szip_decompress
from common.path_ops import make_dirs, safe_name from common.path_ops import make_dirs, safe_name
from common.patterns import PAT_AWARD_LZH from common.patterns import PAT_AWARD_LZH
from common.system import script_init, argparse_init, printer from common.system import argparse_init, printer, script_init
from common.text_ops import file_to_bytes from common.text_ops import file_to_bytes
# Check if input is Award BIOS image # Check if input is Award BIOS image
@ -84,7 +84,8 @@ if __name__ == '__main__':
printer(['***', input_name], padding - 4) printer(['***', input_name], padding - 4)
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()
if not is_award_bios(input_buffer): if not is_award_bios(input_buffer):
printer('Error: This is not an Award BIOS image!', padding) printer('Error: This is not an Award BIOS image!', padding)

View file

@ -3,11 +3,11 @@
""" """
Dell PFS Extract Dell PFS Extract
Dell PFS Update Extractor Dell PFS/PKG Update Extractor
Copyright (C) 2018-2022 Plato Mavropoulos Copyright (C) 2018-2022 Plato Mavropoulos
""" """
TITLE = 'Dell PFS Update Extractor v6.0_a10' TITLE = 'Dell PFS/PKG Update Extractor v6.0_a11'
import os import os
import io import io
@ -21,10 +21,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 safe_name, make_dirs from common.path_ops import make_dirs, path_stem, safe_name
from common.patterns import PAT_DELL_HDR, PAT_DELL_FTR, PAT_DELL_PKG from common.patterns import PAT_DELL_FTR, PAT_DELL_HDR, PAT_DELL_PKG
from common.struct_ops import get_struct, char, uint8_t, uint16_t, uint32_t, uint64_t from common.struct_ops import char, get_struct, uint8_t, uint16_t, uint32_t, uint64_t
from common.system import script_init, argparse_init, printer from common.system import argparse_init, printer, script_init
from common.text_ops import file_to_bytes from common.text_ops import file_to_bytes
from AMI_PFAT_Extract import IntelBiosGuardHeader, IntelBiosGuardSignature2k, parse_bg_script from AMI_PFAT_Extract import IntelBiosGuardHeader, IntelBiosGuardSignature2k, parse_bg_script
@ -190,7 +190,9 @@ 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_pfs_pkg(in_buffer): def is_pfs_pkg(in_file):
in_buffer = file_to_bytes(in_file)
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.
@ -198,28 +200,57 @@ def is_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_pfs_hdr(in_buffer): def is_pfs_hdr(in_file):
return list(PAT_DELL_HDR.finditer(in_buffer)) in_buffer = file_to_bytes(in_file)
return bool(PAT_DELL_HDR.search(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_pfs_ftr(in_buffer): def is_pfs_ftr(in_file):
return PAT_DELL_FTR.search(in_buffer) in_buffer = file_to_bytes(in_file)
return bool(PAT_DELL_FTR.search(in_buffer))
# Check if input is Dell PFS/PKG image # Check if input is Dell PFS/PKG image
def is_dell_pfs(in_file): def is_dell_pfs(in_file):
in_buffer = file_to_bytes(in_file) in_buffer = file_to_bytes(in_file)
return bool(is_pfs_hdr(in_buffer) or is_pfs_pkg(in_buffer)) is_pkg = is_pfs_pkg(in_buffer)
is_hdr = is_pfs_hdr(in_buffer)
is_ftr = is_pfs_ftr(in_buffer)
return bool(is_pkg or is_hdr and is_ftr)
# Extract Dell ThinOS PKG 7zXZ
def thinos_pkg_extract(in_file):
in_buffer = file_to_bytes(in_file)
# Search input image for ThinOS PKG 7zXZ header
thinos_pkg_match = PAT_DELL_PKG.search(in_buffer)
lzma_len_off = thinos_pkg_match.start() + 0x10
lzma_len_int = int.from_bytes(in_buffer[lzma_len_off:lzma_len_off + 0x4], 'little')
lzma_bin_off = thinos_pkg_match.end() - 0x5
lzma_bin_dat = in_buffer[lzma_bin_off:lzma_bin_off + lzma_len_int]
# Check if the compressed 7zXZ stream is complete
if len(lzma_bin_dat) != lzma_len_int:
return in_buffer
return lzma.decompress(lzma_bin_dat)
# Get PFS ZLIB Section Offsets # Get PFS ZLIB Section Offsets
def get_section_offsets(buffer): def get_section_offsets(buffer):
pfs_zlib_init = is_pfs_hdr(buffer)
if not pfs_zlib_init: return [] # No PFS ZLIB detected
pfs_zlib_list = [] # Initialize PFS ZLIB offset list pfs_zlib_list = [] # Initialize PFS ZLIB offset list
pfs_zlib_init = list(PAT_DELL_HDR.finditer(buffer))
if not pfs_zlib_init:
return pfs_zlib_list # No PFS ZLIB detected
# Remove duplicate/nested PFS ZLIB offsets # Remove duplicate/nested PFS ZLIB offsets
for zlib_c in pfs_zlib_init: for zlib_c in pfs_zlib_init:
is_duplicate = False # Initialize duplicate/nested PFS ZLIB offset is_duplicate = False # Initialize duplicate/nested PFS ZLIB offset
@ -228,14 +259,16 @@ def get_section_offsets(buffer):
zlib_o_size = int.from_bytes(buffer[zlib_o.start() - 0x5:zlib_o.start() - 0x1], 'little') zlib_o_size = int.from_bytes(buffer[zlib_o.start() - 0x5:zlib_o.start() - 0x1], 'little')
# If current PFS ZLIB offset is within another PFS ZLIB range (start-end), set as duplicate # If current PFS ZLIB offset is within another PFS ZLIB range (start-end), set as duplicate
if zlib_o.start() < zlib_c.start() < zlib_o.start() + zlib_o_size: is_duplicate = True if zlib_o.start() < zlib_c.start() < zlib_o.start() + zlib_o_size:
is_duplicate = True
if not is_duplicate: pfs_zlib_list.append(zlib_c.start()) if not is_duplicate:
pfs_zlib_list.append(zlib_c.start())
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_structure=True, is_advanced=True): def pfs_section_parse(zlib_data, zlib_start, output_path, pfs_name, pfs_index, pfs_count, is_rec, padding, structure=True, 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)
@ -281,11 +314,8 @@ def pfs_section_parse(zlib_data, zlib_start, output_path, pfs_name, pfs_index, p
# Store the PFS ZLIB section footer contents (16 bytes) # Store the PFS ZLIB section footer contents (16 bytes)
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
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 is_pfs_ftr(footer_data):
printer('Error: This Dell PFS ZLIB section is corrupted!', padding) printer('Error: This Dell PFS ZLIB section is corrupted!', padding)
is_zlib_error = True is_zlib_error = True
@ -304,18 +334,19 @@ def pfs_section_parse(zlib_data, zlib_start, output_path, pfs_name, pfs_index, p
# Decompress PFS ZLIB section payload # Decompress PFS ZLIB section payload
try: try:
if is_zlib_error: raise Exception('ZLIB_ERROR') # ZLIB errors are critical if is_zlib_error:
raise Exception('ZLIB_ERROR') # ZLIB errors are critical
section_data = zlib.decompress(compressed_data) # ZLIB decompression section_data = zlib.decompress(compressed_data) # ZLIB decompression
except: except:
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_structure, is_advanced) pfs_extract(section_data, pfs_index, pfs_name, pfs_count, section_path, padding, structure, 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_structure=True, is_advanced=True): def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, structure=True, advanced=True):
# Show PFS Volume indicator # Show PFS Volume indicator
if is_structure: if structure:
printer('PFS Volume:', pfs_padd) printer('PFS Volume:', pfs_padd)
# Get PFS Header Structure values # Get PFS Header Structure values
@ -328,7 +359,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_structure: if 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)
@ -348,7 +379,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_structure) parse_pfs_entry(pfs_payload, entry_start, pfs_entry_size, pfs_entry_struct, 'PFS Entry', pfs_padd, 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
@ -384,7 +415,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_structure: if 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)
@ -408,7 +439,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
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 Structure info # Show PFS FileName Structure info
if is_structure: if structure:
printer('PFS FileName Entry:\n', pfs_padd + 8) printer('PFS FileName Entry:\n', pfs_padd + 8)
entry_info_mod.struct_print(pfs_padd + 12, entry_name) entry_info_mod.struct_print(pfs_padd + 12, entry_name)
@ -436,7 +467,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_structure: if 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 +491,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_structure: if 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 +507,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_structure: if 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 +517,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 = f'{int.from_bytes(sign_data_raw, "little"):0{sign_size * 2}X}' sign_data_txt = f'{int.from_bytes(sign_data_raw, "little"):0{sign_size * 2}X}'
if is_structure: if structure:
printer('Signature Information:\n', pfs_padd + 8) printer('Signature Information:\n', pfs_padd + 8)
printer(f'Signature Size: 0x{sign_size:X}', pfs_padd + 12, False) printer(f'Signature Size: 0x{sign_size:X}', pfs_padd + 12, False)
printer(f'Signature Data: {sign_data_txt[:32]} [...]', pfs_padd + 12, False) printer(f'Signature Data: {sign_data_txt[:32]} [...]', pfs_padd + 12, False)
@ -500,7 +531,8 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
entry_type = entries_all[index][3] # Get PFS Entry Type entry_type = entries_all[index][3] # Get PFS Entry Type
# Very small PFS Entry Data cannot be of special type # Very small PFS Entry Data cannot be of special type
if len(entry_data) < PFS_HEAD_LEN: continue if len(entry_data) < PFS_HEAD_LEN:
continue
# Check if PFS Entry contains zlib-compressed sub-PFS Volume # Check if PFS Entry contains zlib-compressed sub-PFS Volume
pfs_zlib_offsets = get_section_offsets(entry_data) pfs_zlib_offsets = get_section_offsets(entry_data)
@ -518,7 +550,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_structure) # Parse sub-PFS PFAT Volume entry_data = parse_pfat_pfs(pfat_entry_hdr, entry_data, pfs_padd, 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 +571,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) + safe_name(sub_pfs_name)) sub_pfs_path = os.path.join(output_path, str(pfs_count) + safe_name(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_structure, is_advanced) pfs_section_parse(entry_data, offset, sub_pfs_path, sub_pfs_name, pfs_count, pfs_count, True, pfs_padd + 4, structure, 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)
@ -560,10 +592,12 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
file_name = 'Model Information' file_name = 'Model Information'
elif file_type == 'NAME_INFO': elif file_type == 'NAME_INFO':
file_name = 'Filename Information' file_name = 'Filename Information'
if not is_advanced: continue # Don't store Filename Information in non-advanced user mode if not advanced:
continue # Don't store Filename Information in non-advanced user mode
elif file_type == 'SIG_INFO': elif file_type == 'SIG_INFO':
file_name = 'Signature Information' file_name = 'Signature Information'
if not is_advanced: continue # Don't store Signature Information in non-advanced user mode if not advanced:
continue # Don't store Signature Information in non-advanced user mode
else: else:
file_name = '' file_name = ''
@ -580,6 +614,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
file_version = info_version file_version = info_version
info_all[info_index][0] = 'USED' # PFS with zlib-compressed sub-PFS use the same GUID info_all[info_index][0] = 'USED' # PFS with zlib-compressed sub-PFS use the same GUID
break # Break at 1st Name match to not rename again from next zlib-compressed sub-PFS with the same GUID break # Break at 1st Name match to not rename again from next zlib-compressed sub-PFS with the same GUID
# For both advanced & non-advanced users, the goal is to store final/usable files only # For both advanced & non-advanced users, the goal is to store final/usable files only
@ -590,29 +625,36 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, i
is_zlib = bool(file_type == 'ZLIB') # Determine if PFS Entry Data was zlib-compressed is_zlib = bool(file_type == 'ZLIB') # Determine if PFS Entry Data was zlib-compressed
if file_data and not is_zlib: write_files.append([file_data, 'data']) # PFS Entry Data Payload if file_data and not is_zlib:
if file_data_sig and is_advanced: write_files.append([file_data_sig, 'sign_data']) # PFS Entry Data Signature write_files.append([file_data, 'data']) # PFS Entry Data Payload
if file_meta and (is_zlib or is_advanced): write_files.append([file_meta, 'meta']) # PFS Entry Metadata Payload
if file_meta_sig and is_advanced: write_files.append([file_meta_sig, 'sign_meta']) # PFS Entry Metadata Signature if file_data_sig and advanced:
write_files.append([file_data_sig, 'sign_data']) # PFS Entry Data Signature
if file_meta and (is_zlib or advanced):
write_files.append([file_meta, 'meta']) # PFS Entry Metadata Payload
if file_meta_sig and advanced:
write_files.append([file_meta_sig, 'sign_meta']) # PFS Entry Metadata Signature
# Write/Extract PFS Entry files # Write/Extract PFS Entry files
for file in write_files: for file in write_files:
full_name = f'{pfs_index}{pfs_name} -- {file_index} {file_name} v{file_version}' # Full PFS Entry Name full_name = f'{pfs_index}{pfs_name} -- {file_index} {file_name} v{file_version}' # Full PFS Entry Name
pfs_file_write(file[0], file[1], file_type, full_name, output_path, pfs_padd, is_structure, is_advanced) pfs_file_write(file[0], file[1], file_type, full_name, output_path, pfs_padd, structure, 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_structure) chk_pfs_ftr(pfs_footer, pfs_payload, pfs_hdr.PayloadSize, 'PFS', pfs_padd, 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_structure=True): def parse_pfs_entry(entry_buffer, entry_start, entry_size, entry_struct, text, padding, 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_structure: if 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)
@ -653,13 +695,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_structure=True): def parse_pfat_pfs(entry_hdr, entry_data, padding, structure=True):
# Show PFS Volume indicator # Show PFS Volume indicator
if is_structure: if 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_structure: if 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)
@ -679,11 +721,11 @@ def parse_pfat_pfs(entry_hdr, entry_data, padding, is_structure=True):
_, pfs_entry_size = get_pfs_entry(pfat_payload, 0) # Get initial PFS PFAT Entry Size for loop _, pfs_entry_size = get_pfs_entry(pfat_payload, 0) # Get initial PFS PFAT Entry Size for loop
while len(pfat_payload[pfat_entry_start:pfat_entry_start + pfs_entry_size]) == pfs_entry_size: while len(pfat_payload[pfat_entry_start:pfat_entry_start + pfs_entry_size]) == pfs_entry_size:
# Get sub-PFS PFAT Entry Structure & Size info # Get sub-PFS PFAT Entry Structure & Size info
pfat_entry_struct, pfat_entry_size = get_pfs_entry(pfat_payload, pfat_entry_start) pfat_entry_struct,pfat_entry_size = get_pfs_entry(pfat_payload, pfat_entry_start)
# 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_structure) pfat_entry_start, pfat_entry_size, pfat_entry_struct, 'sub-PFS PFAT Entry', padding + 4, 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 +735,7 @@ def parse_pfat_pfs(entry_hdr, entry_data, padding, is_structure=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_structure: if structure:
printer(f'PFAT Block {pfat_entry_index} Header:\n', padding + 12) printer(f'PFAT Block {pfat_entry_index} Header:\n', padding + 12)
pfat_hdr.struct_print(padding + 16) pfat_hdr.struct_print(padding + 16)
@ -718,15 +760,14 @@ def parse_pfat_pfs(entry_hdr, entry_data, padding, is_structure=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_structure: if structure:
printer(f'PFAT Block {pfat_entry_index} Signature:\n', padding + 12) printer(f'PFAT Block {pfat_entry_index} Signature:\n', 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_structure: if structure:
printer(f'PFAT Block {pfat_entry_index} Script:\n', padding + 12) printer(f'PFAT Block {pfat_entry_index} Script:\n', padding + 12)
# https://github.com/allowitsme/big-tool by Dmitry Frolov
_ = parse_bg_script(pfat_script_data, padding + 16) _ = parse_bg_script(pfat_script_data, padding + 16)
# The payload of sub-PFS PFAT Entries is not in proper order by default # The payload of sub-PFS PFAT Entries is not in proper order by default
@ -740,7 +781,7 @@ def parse_pfat_pfs(entry_hdr, entry_data, padding, is_structure=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_structure: if structure:
printer(f'PFAT Block {pfat_entry_index} Metadata:\n', padding + 12) printer(f'PFAT Block {pfat_entry_index} Metadata:\n', padding + 12)
pfat_met.struct_print(padding + 16) pfat_met.struct_print(padding + 16)
@ -772,14 +813,15 @@ def parse_pfat_pfs(entry_hdr, entry_data, padding, is_structure=True):
pfat_data_all.sort() # Sort all sub-PFS PFAT Entries payloads/data based on their Order/Offset pfat_data_all.sort() # Sort all sub-PFS PFAT Entries payloads/data based on their Order/Offset
entry_data = b'' # Initialize new sub-PFS Entry Data entry_data = b'' # Initialize new sub-PFS Entry Data
for pfat_data in pfat_data_all: entry_data += pfat_data[1] # Merge all sub-PFS PFAT Entry Payload/Raw into the final sub-PFS Entry Data for pfat_data in pfat_data_all:
entry_data += pfat_data[1] # Merge all sub-PFS PFAT Entry Payload/Raw into the final sub-PFS Entry Data
# Verify that the Order/Offset of the last PFAT Entry w/ its Size matches the final sub-PFS Entry Data Size # Verify that the Order/Offset of the last PFAT Entry w/ its Size matches the final sub-PFS Entry Data Size
if len(entry_data) != pfat_data_all[-1][0] + len(pfat_data_all[-1][1]): if len(entry_data) != pfat_data_all[-1][0] + len(pfat_data_all[-1][1]):
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_structure) chk_pfs_ftr(pfat_footer, pfat_payload, entry_hdr.PayloadSize, 'Sub-PFS', padding + 4, structure)
return entry_data return entry_data
@ -787,8 +829,11 @@ def parse_pfat_pfs(entry_hdr, entry_data, padding, is_structure=True):
def get_pfs_entry(buffer, offset): def get_pfs_entry(buffer, offset):
pfs_entry_ver = int.from_bytes(buffer[offset + 0x10:offset + 0x14], 'little') # PFS Entry Version pfs_entry_ver = int.from_bytes(buffer[offset + 0x10:offset + 0x14], 'little') # PFS Entry Version
if pfs_entry_ver == 1: return DellPfsEntryR1, ctypes.sizeof(DellPfsEntryR1) if pfs_entry_ver == 1:
if pfs_entry_ver == 2: return DellPfsEntryR2, ctypes.sizeof(DellPfsEntryR2) return DellPfsEntryR1, ctypes.sizeof(DellPfsEntryR1)
if pfs_entry_ver == 2:
return DellPfsEntryR2, ctypes.sizeof(DellPfsEntryR2)
return DellPfsEntryR2, ctypes.sizeof(DellPfsEntryR2) return DellPfsEntryR2, ctypes.sizeof(DellPfsEntryR2)
@ -801,28 +846,35 @@ def get_entry_ver(version_fields, version_types):
for index,field in enumerate(version_fields): for index,field in enumerate(version_fields):
eol = '' if index == len(version_fields) - 1 else '.' eol = '' if index == len(version_fields) - 1 else '.'
if version_types[index] == 65: version += f'{field:X}{eol}' # 0x41 = ASCII if version_types[index] == 65:
elif version_types[index] == 78: version += f'{field:d}{eol}' # 0x4E = Number version += f'{field:X}{eol}' # 0x41 = ASCII
elif version_types[index] in (0, 32): version = version.strip('.') # 0x00 or 0x20 = Unused elif version_types[index] == 78:
else: version += f'{field:X}{eol}' # Unknown version += f'{field:d}{eol}' # 0x4E = Number
elif version_types[index] in (0, 32):
version = version.strip('.') # 0x00 or 0x20 = Unused
else:
version += f'{field:X}{eol}' # Unknown
return version return version
# Check if Dell PFS Header Version is known # Check if Dell PFS Header Version is known
def chk_hdr_ver(version, text, padding): def chk_hdr_ver(version, text, padding):
if version in (1,2): return if version in (1,2):
return
printer(f'Error: Unknown {text} Header Version {version}!', padding) printer(f'Error: Unknown {text} Header Version {version}!', padding)
return
# Analyze Dell PFS Footer Structure # Analyze Dell PFS Footer Structure
def chk_pfs_ftr(footer_buffer, data_buffer, data_size, text, padding, is_structure=True): def chk_pfs_ftr(footer_buffer, data_buffer, data_size, text, padding, 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_structure: if 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:
@ -840,29 +892,31 @@ def chk_pfs_ftr(footer_buffer, data_buffer, data_size, text, padding, is_structu
printer(f'Error: Invalid {text} Footer Payload Checksum!', padding + 4) printer(f'Error: Invalid {text} Footer Payload Checksum!', 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_structure=True, is_advanced=True): def pfs_file_write(bin_buff, bin_name, bin_type, full_name, out_path, padding, structure=True, 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 = f'{safe_name(full_name)}.{bin_name.split("_")[1]}.sig' final_name = f'{safe_name(full_name)}.{bin_name.split("_")[1]}.sig'
final_path = os.path.join(out_path, final_name) final_path = os.path.join(out_path, final_name)
with open(final_path, 'wb') as pfs_out: pfs_out.write(bin_buff) # Write final Data/Metadata Signature with open(final_path, 'wb') as pfs_out:
pfs_out.write(bin_buff) # Write final Data/Metadata Signature
return # Skip further processing for Signatures return # Skip further processing for Signatures
# Store Data/Metadata Payload # Store Data/Metadata Payload
bin_ext = f'.{bin_name}.bin' if is_advanced else '.bin' # Simpler Data/Metadata Extension for non-advanced users bin_ext = f'.{bin_name}.bin' if 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_structure, is_advanced) is_text,final_data,file_ext,write_mode = bin_is_text(bin_buff, bin_type, bin_name == 'meta', padding, structure, advanced)
final_name = f'{safe_name(full_name)}{bin_ext[:-4] + file_ext if is_text else bin_ext}' final_name = f'{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)
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_structure=True, is_advanced=True): def bin_is_text(buffer, file_type, is_metadata, pfs_padd, structure=True, advanced=True):
is_text = False is_text = False
write_mode = 'wb' write_mode = 'wb'
extension = '.bin' extension = '.bin'
@ -892,12 +946,13 @@ def bin_is_text(buffer, file_type, is_metadata, pfs_padd, is_structure=True, is_
buffer = text_buffer.getvalue() buffer = text_buffer.getvalue()
# Show Model/PCR XML Information, if applicable # Show Model/PCR XML Information, if applicable
if is_structure and is_text and not is_metadata: # Metadata is shown at initial DellPfsMetadata analysis if structure and is_text and not is_metadata: # Metadata is shown at initial DellPfsMetadata analysis
printer(f'PFS { {".txt": "Model", ".xml": "PCR XML"}[extension] } Information:\n', pfs_padd + 8) printer(f'PFS { {".txt": "Model", ".xml": "PCR XML"}[extension] } Information:\n', 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]
# Only for non-advanced users due to signature (.sig) invalidation # Only for non-advanced users due to signature (.sig) invalidation
if is_advanced: return False, buffer_in, '.bin', 'wb' if advanced:
return False, buffer_in, '.bin', 'wb'
return is_text, buffer, extension, write_mode return is_text, buffer, extension, write_mode
@ -918,8 +973,8 @@ if __name__ == '__main__':
argparser.add_argument('-s', '--structure', 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 advanced = arguments.advanced # Set Advanced user mode optional argument
is_structure = arguments.structure # Set Structure output mode optional argument structure = arguments.structure # Set Structure output mode optional argument
# Initialize script (must be after argparse) # Initialize script (must be after argparse)
exit_code,input_files,output_path,padding = script_init(TITLE, arguments, 4) exit_code,input_files,output_path,padding = script_init(TITLE, arguments, 4)
@ -929,42 +984,25 @@ if __name__ == '__main__':
printer(['***', input_name], padding - 4) printer(['***', input_name], padding - 4)
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 if not is_dell_pfs(input_buffer):
lzma_pkg_hdr_match = is_pfs_pkg(input_buffer) printer('Error: This is not a Dell PFS/PKG Update image!', padding)
# Decompress ThinOS PKG 7zXZ section first, if present
if lzma_pkg_hdr_match:
lzma_len_off = lzma_pkg_hdr_match.start() + 0x10
lzma_len_int = int.from_bytes(input_buffer[lzma_len_off:lzma_len_off + 0x4], 'little')
lzma_bin_off = lzma_pkg_hdr_match.end() - 0x5
lzma_bin_dat = input_buffer[lzma_bin_off:lzma_bin_off + lzma_len_int]
# Check if the compressed 7zXZ stream is complete, based on header
if len(lzma_bin_dat) != lzma_len_int:
printer('Error: This Dell ThinOS PKG update image is corrupted!', padding)
continue # Next input file
input_buffer = lzma.decompress(lzma_bin_dat)
# Search input image for PFS ZLIB Sections
pfs_zlib_offsets = get_section_offsets(input_buffer)
if not pfs_zlib_offsets:
printer('Error: This is not a Dell PFS update image!', padding)
continue # Next input file continue # Next input file
extract_path = os.path.join(output_path, f'{input_name}_extracted') extract_path = os.path.join(output_path, f'{input_name}_extracted')
extract_name = ' ' + os.path.splitext(input_name)[0] extract_name = ' ' + path_stem(input_file)
if is_pfs_pkg(input_buffer):
input_buffer = thinos_pkg_extract(input_buffer)
# Parse each PFS ZLIB Section # Parse each PFS ZLIB Section
for offset in pfs_zlib_offsets: for zlib_offset in get_section_offsets(input_buffer):
# 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_structure, is_advanced) pfs_section_parse(input_buffer, zlib_offset, extract_path, extract_name, 1, 1, False, padding, structure, advanced)
exit_code -= 1 exit_code -= 1

View file

@ -7,7 +7,7 @@ Fujitsu UPC BIOS Extractor
Copyright (C) 2021-2022 Plato Mavropoulos Copyright (C) 2021-2022 Plato Mavropoulos
""" """
TITLE = 'Fujitsu UPC BIOS Extractor v2.0_a3' TITLE = 'Fujitsu UPC BIOS Extractor v2.0_a4'
import os import os
import sys import sys
@ -55,7 +55,8 @@ if __name__ == '__main__':
printer(['***', input_name], padding - 4) printer(['***', input_name], padding - 4)
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()
if not is_fujitsu_upc(input_buffer): if not is_fujitsu_upc(input_buffer):
printer('Error: This is not a Fujitsu UPC BIOS image!', padding) printer('Error: This is not a Fujitsu UPC BIOS image!', padding)

222
Insyde_IFD_Extract.py Normal file
View file

@ -0,0 +1,222 @@
#!/usr/bin/env python3
#coding=utf-8
"""
Insyde IFD Extract
Insyde iFlash/iFdPacker Extractor
Copyright (C) 2022 Plato Mavropoulos
"""
TITLE = 'Insyde iFlash/iFdPacker Extractor v2.0_a8'
import os
import sys
import ctypes
# Stop __pycache__ generation
sys.dont_write_bytecode = True
from common.comp_szip import is_szip_supported, szip_decompress
from common.path_ops import get_path_files, make_dirs, safe_name
from common.patterns import PAT_INSYDE_IFL, PAT_INSYDE_SFX
from common.struct_ops import char, get_struct, uint32_t
from common.system import argparse_init, printer, script_init
from common.text_ops import file_to_bytes
class IflashHeader(ctypes.LittleEndianStructure):
_pack_ = 1
_fields_ = [
('Signature', char*8), # 0x00 $_IFLASH
('ImageTag', char*8), # 0x08
('TotalSize', uint32_t), # 0x10 from header end
('ImageSize', uint32_t), # 0x14 from header end
# 0x18
]
def get_image_tag(self):
return self.ImageTag.decode('utf-8','ignore').strip('_')
def struct_print(self, p):
printer(['Signature :', self.Signature.decode('utf-8')], p, False)
printer(['Image Name:', self.get_image_tag()], p, False)
printer(['Image Size:', f'0x{self.ImageSize:X}'], p, False)
printer(['Total Size:', f'0x{self.TotalSize:X}'], p, False)
# Check if input is Insyde iFlash/iFdPacker Update image
def is_insyde_ifd(input_file):
input_buffer = file_to_bytes(input_file)
is_ifl = bool(insyde_iflash_detect(input_buffer))
is_sfx = bool(PAT_INSYDE_SFX.search(input_buffer))
return is_ifl or is_sfx
# Parse & Extract Insyde iFlash/iFdPacker Update images
def insyde_ifd_extract(input_file, output_path, padding=0):
input_buffer = file_to_bytes(input_file)
extract_path = os.path.join(f'{output_path}_extracted')
iflash_code = insyde_iflash_extract(input_buffer, extract_path, padding)
ifdpack_path = os.path.join(extract_path, 'Insyde iFdPacker SFX')
ifdpack_code = insyde_packer_extract(input_buffer, ifdpack_path, padding)
return iflash_code and ifdpack_code
# Detect Insyde iFlash Update image
def insyde_iflash_detect(input_buffer):
iflash_match_all = []
iflash_match_nan = [0x0,0xFFFFFFFF]
for iflash_match in PAT_INSYDE_IFL.finditer(input_buffer):
ifl_bgn = iflash_match.start()
if len(input_buffer[ifl_bgn:]) <= IFL_HDR_LEN:
continue
ifl_hdr = get_struct(input_buffer, ifl_bgn, IflashHeader)
if ifl_hdr.TotalSize in iflash_match_nan \
or ifl_hdr.ImageSize in iflash_match_nan \
or ifl_hdr.TotalSize <= ifl_hdr.ImageSize:
continue
iflash_match_all.append([ifl_bgn, ifl_hdr])
return iflash_match_all
# Extract Insyde iFlash Update image
def insyde_iflash_extract(input_buffer, extract_path, padding=0):
insyde_iflash_all = insyde_iflash_detect(input_buffer)
if not insyde_iflash_all:
return 1
printer('Detected Insyde iFlash Update image!', padding)
make_dirs(extract_path, delete=True)
for insyde_iflash in insyde_iflash_all:
ifl_bgn,ifl_hdr = insyde_iflash
img_bgn = ifl_bgn + IFL_HDR_LEN
img_end = img_bgn + ifl_hdr.ImageSize
img_bin = input_buffer[img_bgn:img_end]
img_val = [ifl_hdr.get_image_tag(), 'bin']
img_tag,img_ext = IFL_IMG_NAMES.get(img_val[0], img_val)
img_name = f'{img_tag} [0x{img_bgn:08X}-0x{img_end:08X}]'
printer(f'{img_name}\n', padding + 4)
ifl_hdr.struct_print(padding + 8)
if img_val == [img_tag,img_ext]:
printer(f'Note: Detected new Insyde iFlash tag {img_tag}!', padding + 12, pause=True)
out_name = f'{img_name}.{img_ext}'
out_path = os.path.join(extract_path, safe_name(out_name))
with open(out_path, 'wb') as out_image:
out_image.write(img_bin)
printer(f'Succesfull Insyde iFlash > {img_tag} extraction!', padding + 12)
return 0
# Extract Insyde iFdPacker 7-Zip SFX 7z Update image
def insyde_packer_extract(input_buffer, extract_path, padding=0):
match_sfx = PAT_INSYDE_SFX.search(input_buffer)
if not match_sfx:
return 127
printer('Detected Insyde iFdPacker Update image!', padding)
make_dirs(extract_path, delete=True)
sfx_buffer = bytearray(input_buffer[match_sfx.end() - 0x5:])
if sfx_buffer[:0x5] == b'\x6E\xF4\x79\x5F\x4E':
printer('Detected Insyde iFdPacker > 7-Zip SFX obfuscation!', padding + 4)
for index,byte in enumerate(sfx_buffer):
sfx_buffer[index] = byte // 2 + (128 if byte % 2 else 0)
printer('Removed Insyde iFdPacker > 7-Zip SFX obfuscation!', padding + 8)
printer('Extracting Insyde iFdPacker > 7-Zip SFX archive...', padding + 4)
sfx_path = os.path.join(extract_path, 'Insyde_iFdPacker_SFX.7z')
with open(sfx_path, 'wb') as sfx_file:
sfx_file.write(sfx_buffer)
if is_szip_supported(sfx_path, padding + 8, check=True):
if szip_decompress(sfx_path, extract_path, 'Insyde iFdPacker > 7-Zip SFX', padding + 8, check=True) == 0:
os.remove(sfx_path)
else:
return 125
else:
return 126
exit_codes = []
for sfx_file in get_path_files(extract_path):
if is_insyde_ifd(sfx_file):
printer(f'{os.path.basename(sfx_file)}', padding + 12)
ifd_code = insyde_ifd_extract(sfx_file, sfx_file, padding + 16)
exit_codes.append(ifd_code)
return sum(exit_codes)
# Insyde iFlash Image Names
IFL_IMG_NAMES = {
'BIOSCER' : ['Certificate', 'bin'],
'BIOSCR2' : ['Certificate 2nd', 'bin'],
'BIOSIMG' : ['BIOS-UEFI', 'bin'],
'DRV_IMG' : ['isflash', 'efi'],
'EC_IMG' : ['Embedded Controller', 'bin'],
'INI_IMG' : ['platform', 'ini'],
'ME_IMG' : ['Management Engine', 'bin'],
'OEM_ID' : ['OEM Identifier', 'bin'],
}
# Get common ctypes Structure Sizes
IFL_HDR_LEN = ctypes.sizeof(IflashHeader)
if __name__ == '__main__':
# Set argparse Arguments
argparser = argparse_init()
arguments = argparser.parse_args()
# Initialize script (must be after argparse)
exit_code,input_files,output_path,padding = script_init(TITLE, arguments, 4)
for input_file in input_files:
input_name = os.path.basename(input_file)
printer(['***', input_name], padding - 4)
with open(input_file, 'rb') as in_file:
input_buffer = in_file.read()
if not is_insyde_ifd(input_buffer):
printer('Error: This is not an Insyde iFlash/iFdPacker Update image!', padding)
continue # Next input file
extract_path = os.path.join(output_path, input_name)
insyde_ifd_extract(input_buffer, extract_path, padding)
exit_code -= 1
printer('Done!', pause=True)
sys.exit(exit_code)

View file

@ -1,148 +0,0 @@
#!/usr/bin/env python3
#coding=utf-8
"""
Insyde iFlash Extract
Insyde iFlash Update Extractor
Copyright (C) 2022 Plato Mavropoulos
"""
TITLE = 'Insyde iFlash Update Extractor v2.0_a2'
import os
import sys
import ctypes
# Stop __pycache__ generation
sys.dont_write_bytecode = True
from common.path_ops import make_dirs, safe_name
from common.patterns import PAT_INSYDE_IFL
from common.struct_ops import get_struct, char, uint32_t
from common.system import script_init, argparse_init, printer
from common.text_ops import file_to_bytes
class IflashHeader(ctypes.LittleEndianStructure):
_pack_ = 1
_fields_ = [
('Signature', char*9), # 0x00 $_IFLASH_
('ImageTag', char*7), # 0x08
('TotalSize', uint32_t), # 0x10 from header end
('ImageSize', uint32_t), # 0x14 from header end
# 0x18
]
def struct_print(self, p):
printer(['Signature :', self.Signature.decode('utf-8','ignore')], p, False)
printer(['Image Name:', self.ImageTag.decode('utf-8','ignore')], p, False)
printer(['Image Size:', f'0x{self.ImageSize:X}'], p, False)
printer(['Total Size:', f'0x{self.TotalSize:X}'], p, False)
# Parse & Extract Insyde iFlash Update image
def insyde_iflash_extract(input_buffer, ins_ifl_all, output_path, padding=0):
extract_path = os.path.join(f'{output_path}_extracted')
make_dirs(extract_path, delete=True)
for ins_ifl_val in ins_ifl_all:
ins_ifl_off,ins_ifl_hdr = ins_ifl_val
mod_bgn = ins_ifl_off + IFL_HDR_LEN
mod_end = mod_bgn + ins_ifl_hdr.ImageSize
mod_bin = input_buffer[mod_bgn:mod_end]
mod_val = [ins_ifl_hdr.ImageTag.decode('utf-8','ignore'), 'bin']
mod_tag,mod_ext = IFL_MOD_NAMES.get(mod_val[0], mod_val)
mod_name = f'{mod_tag} [0x{mod_bgn:08X}-0x{mod_end:08X}]'
printer(f'{mod_name}\n', padding)
ins_ifl_hdr.struct_print(padding + 4)
if mod_val == [mod_tag,mod_ext]:
printer(f'Note: Detected new Insyde iFlash image tag {mod_tag}!', padding + 8, pause=True)
out_name = f'{mod_name}.{mod_ext}'
out_path = os.path.join(extract_path, safe_name(out_name))
with open(out_path, 'wb') as out: out.write(mod_bin)
printer('Succesfull Insyde iFlash image extraction!', padding + 8)
# Get Insyde iFlash Update image matches
def get_insyde_iflash(in_file):
ins_ifl_all = []
ins_ifl_nan = [0x0,0xFFFFFFFF]
buffer = file_to_bytes(in_file)
for ins_ifl_match in PAT_INSYDE_IFL.finditer(buffer):
ins_ifl_off = ins_ifl_match.start()
if len(buffer[ins_ifl_off:]) <= IFL_HDR_LEN:
continue
ins_ifl_hdr = get_struct(buffer, ins_ifl_off, IflashHeader)
if ins_ifl_hdr.TotalSize in ins_ifl_nan \
or ins_ifl_hdr.ImageSize in ins_ifl_nan \
or ins_ifl_hdr.TotalSize <= ins_ifl_hdr.ImageSize:
continue
ins_ifl_all.append([ins_ifl_off, ins_ifl_hdr])
return ins_ifl_all
# Check if input is Insyde iFlash Update image
def is_insyde_iflash(in_file):
buffer = file_to_bytes(in_file)
return bool(get_insyde_iflash(buffer))
IFL_MOD_NAMES = {
'DRV_IMG' : ['isflash', 'efi'],
'INI_IMG' : ['platform', 'ini'],
'BIOSIMG' : ['BIOS-UEFI', 'bin'],
'ME_IMG_' : ['Management Engine', 'bin'],
'EC_IMG_' : ['Embedded Controller', 'bin'],
'OEM_ID_' : ['OEM Identifier', 'bin'],
'BIOSCER' : ['Certificate', 'bin'],
'BIOSCR2' : ['Certificate 2nd', 'bin'],
}
# Get common ctypes Structure Sizes
IFL_HDR_LEN = ctypes.sizeof(IflashHeader)
if __name__ == '__main__':
# Set argparse Arguments
argparser = argparse_init()
arguments = argparser.parse_args()
# Initialize script (must be after argparse)
exit_code,input_files,output_path,padding = script_init(TITLE, arguments, 4)
for input_file in input_files:
input_name = os.path.basename(input_file)
printer(['***', input_name], padding - 4)
with open(input_file, 'rb') as in_file: input_buffer = in_file.read()
ins_ifl_all = get_insyde_iflash(input_buffer)
if not ins_ifl_all:
printer('Error: This is not an Insyde iFlash Update image!', padding)
continue # Next input file
extract_path = os.path.join(output_path, input_name)
insyde_iflash_extract(input_buffer, ins_ifl_all, extract_path, padding)
exit_code -= 1
printer('Done!', pause=True)
sys.exit(exit_code)

View file

@ -7,7 +7,7 @@ Panasonic BIOS Package Extractor
Copyright (C) 2018-2022 Plato Mavropoulos Copyright (C) 2018-2022 Plato Mavropoulos
""" """
TITLE = 'Panasonic BIOS Package Extractor v2.0_a8' TITLE = 'Panasonic BIOS Package Extractor v2.0_a9'
import os import os
import io import io
@ -22,10 +22,10 @@ from common.comp_szip import is_szip_supported, szip_decompress
from common.path_ops import get_path_files, make_dirs, path_stem, safe_name from common.path_ops import get_path_files, make_dirs, path_stem, safe_name
from common.pe_ops import get_pe_file, get_pe_info, is_pe_file, show_pe_info from common.pe_ops import get_pe_file, get_pe_info, is_pe_file, show_pe_info
from common.patterns import PAT_MICROSOFT_CAB from common.patterns import PAT_MICROSOFT_CAB
from common.system import script_init, argparse_init, printer from common.system import argparse_init, printer, script_init
from common.text_ops import file_to_bytes from common.text_ops import file_to_bytes
from AMI_PFAT_Extract import get_ami_pfat, parse_pfat_file from AMI_PFAT_Extract import is_ami_pfat, parse_pfat_file
# Check if input is Panasonic BIOS Package PE # Check if input is Panasonic BIOS Package PE
def is_panasonic_pkg(in_file): def is_panasonic_pkg(in_file):
@ -117,12 +117,10 @@ def panasonic_res_extract(pe_name, pe_file, extract_path, padding=0):
printer('Succesfull PE Resource extraction!', padding + 8) printer('Succesfull PE Resource extraction!', padding + 8)
# Detect & Unpack AMI BIOS Guard (PFAT) BIOS image # Detect & Unpack AMI BIOS Guard (PFAT) BIOS image
pfat_match,pfat_buffer = get_ami_pfat(res_raw) if is_ami_pfat(res_raw):
if pfat_match:
pfat_dir = os.path.join(extract_path, res_tag) pfat_dir = os.path.join(extract_path, res_tag)
parse_pfat_file(pfat_buffer, pfat_dir, padding + 12) parse_pfat_file(res_raw, pfat_dir, padding + 12)
else: else:
if is_pe_file(res_raw): if is_pe_file(res_raw):
res_ext = 'exe' res_ext = 'exe'
@ -219,7 +217,8 @@ if __name__ == '__main__':
printer(['***', input_name], padding - 4) printer(['***', input_name], padding - 4)
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()
# Check if Panasonic BIOS Package pattern was found on executable # Check if Panasonic BIOS Package pattern was found on executable
if not is_panasonic_pkg(input_buffer): if not is_panasonic_pkg(input_buffer):

View file

@ -7,7 +7,7 @@ Phoenix TDK Packer Extractor
Copyright (C) 2021-2022 Plato Mavropoulos Copyright (C) 2021-2022 Plato Mavropoulos
""" """
TITLE = 'Phoenix TDK Packer Extractor v2.0_a8' TITLE = 'Phoenix TDK Packer Extractor v2.0_a9'
import os import os
import sys import sys
@ -17,11 +17,11 @@ import ctypes
# Stop __pycache__ generation # Stop __pycache__ generation
sys.dont_write_bytecode = True sys.dont_write_bytecode = True
from common.path_ops import safe_name, make_dirs from common.path_ops import make_dirs, safe_name
from common.pe_ops import get_pe_file, get_pe_info from common.pe_ops import get_pe_file, get_pe_info
from common.patterns import PAT_PHOENIX_TDK, PAT_MICROSOFT_MZ, PAT_MICROSOFT_PE from common.patterns import PAT_MICROSOFT_MZ, PAT_MICROSOFT_PE, PAT_PHOENIX_TDK
from common.struct_ops import get_struct, char, uint32_t from common.struct_ops import char, get_struct, uint32_t
from common.system import script_init, argparse_init, printer from common.system import argparse_init, printer, script_init
from common.text_ops import file_to_bytes from common.text_ops import file_to_bytes
class PhoenixTdkHeader(ctypes.LittleEndianStructure): class PhoenixTdkHeader(ctypes.LittleEndianStructure):
@ -152,7 +152,9 @@ def is_phoenix_tdk(in_file):
return bool(get_phoenix_tdk(buffer)[1] is not None) return bool(get_phoenix_tdk(buffer)[1] is not None)
# Parse & Extract Phoenix Tools Development Kit (TDK) Packer # Parse & Extract Phoenix Tools Development Kit (TDK) Packer
def phoenix_tdk_extract(input_buffer, output_path, pack_off, base_off=0, padding=0): def phoenix_tdk_extract(input_file, output_path, padding=0):
input_buffer = file_to_bytes(input_file)
exit_code = 0 exit_code = 0
extract_path = os.path.join(f'{output_path}_extracted') extract_path = os.path.join(f'{output_path}_extracted')
@ -161,6 +163,8 @@ def phoenix_tdk_extract(input_buffer, output_path, pack_off, base_off=0, padding
printer('Phoenix Tools Development Kit Packer', padding) printer('Phoenix Tools Development Kit Packer', padding)
base_off,pack_off = get_phoenix_tdk(input_buffer)
# Parse TDK Header structure # Parse TDK Header structure
tdk_hdr = get_struct(input_buffer, pack_off, PhoenixTdkHeader) tdk_hdr = get_struct(input_buffer, pack_off, PhoenixTdkHeader)
@ -224,7 +228,8 @@ def phoenix_tdk_extract(input_buffer, output_path, pack_off, base_off=0, padding
if os.path.isfile(mod_file): mod_file += f'_{entry_index + 1:02d}' if os.path.isfile(mod_file): mod_file += f'_{entry_index + 1:02d}'
# Save TDK Entry data to output file # Save TDK Entry data to output file
with open(mod_file, 'wb') as out_file: out_file.write(mod_data) with open(mod_file, 'wb') as out_file:
out_file.write(mod_data)
return exit_code return exit_code
@ -248,19 +253,18 @@ if __name__ == '__main__':
printer(['***', input_name], padding - 4) printer(['***', input_name], padding - 4)
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()
tdk_base_off,tdk_pack_off = get_phoenix_tdk(input_buffer)
# Check if Phoenix TDK Packer pattern was found on executable # Check if Phoenix TDK Packer pattern was found on executable
if tdk_pack_off is None: if not is_phoenix_tdk(input_buffer):
printer('Error: This is not a Phoenix TDK Packer executable!', padding) printer('Error: This is not a Phoenix TDK Packer executable!', padding)
continue # Next input file continue # Next input file
extract_path = os.path.join(output_path, input_name) extract_path = os.path.join(output_path, input_name)
if phoenix_tdk_extract(input_buffer, extract_path, tdk_pack_off, tdk_base_off, padding) == 0: if phoenix_tdk_extract(input_buffer, extract_path, padding) == 0:
exit_code -= 1 exit_code -= 1
printer('Done!', pause=True) printer('Done!', pause=True)

View file

@ -7,7 +7,7 @@ Portwell EFI Update Extractor
Copyright (C) 2021-2022 Plato Mavropoulos Copyright (C) 2021-2022 Plato Mavropoulos
""" """
TITLE = 'Portwell EFI Update Extractor v2.0_a10' TITLE = 'Portwell EFI Update Extractor v2.0_a11'
import os import os
import sys import sys
@ -16,10 +16,10 @@ import sys
sys.dont_write_bytecode = True sys.dont_write_bytecode = True
from common.comp_efi import efi_decompress, is_efi_compressed from common.comp_efi import efi_decompress, is_efi_compressed
from common.path_ops import safe_name, make_dirs from common.path_ops import make_dirs, safe_name
from common.pe_ops import get_pe_file from common.pe_ops import get_pe_file
from common.patterns import PAT_PORTWELL_EFI, PAT_MICROSOFT_MZ from common.patterns import PAT_MICROSOFT_MZ, PAT_PORTWELL_EFI
from common.system import script_init, argparse_init, printer from common.system import argparse_init, printer, script_init
from common.text_ops import file_to_bytes from common.text_ops import file_to_bytes
FILE_NAMES = { FILE_NAMES = {
@ -34,10 +34,13 @@ FILE_NAMES = {
def is_portwell_efi(in_file): def is_portwell_efi(in_file):
in_buffer = file_to_bytes(in_file) in_buffer = file_to_bytes(in_file)
try: pe_buffer = get_portwell_pe(in_buffer)[1] try:
except: pe_buffer = b'' pe_buffer = get_portwell_pe(in_buffer)[1]
except:
pe_buffer = b''
is_mz = PAT_MICROSOFT_MZ.search(in_buffer[:0x2]) # EFI images start with PE Header MZ is_mz = PAT_MICROSOFT_MZ.search(in_buffer[:0x2]) # EFI images start with PE Header MZ
is_uu = PAT_PORTWELL_EFI.search(pe_buffer[:0x4]) # Portwell EFI files start with <UU> is_uu = PAT_PORTWELL_EFI.search(pe_buffer[:0x4]) # Portwell EFI files start with <UU>
return bool(is_mz and is_uu) return bool(is_mz and is_uu)
@ -104,7 +107,8 @@ def get_unpacker_tag(input_buffer, pe_file):
# Process Portwell UEFI Unpacker payload files # Process Portwell UEFI Unpacker payload files
def parse_efi_files(extract_path, efi_files, padding): def parse_efi_files(extract_path, efi_files, padding):
for file_index,file_data in enumerate(efi_files): for file_index,file_data in enumerate(efi_files):
if file_data in (b'', b'NULL'): continue # Skip empty/unused files if file_data in (b'', b'NULL'):
continue # Skip empty/unused files
file_name = FILE_NAMES.get(file_index, f'Unknown_{file_index}.bin') # Assign Name to EFI file file_name = FILE_NAMES.get(file_index, f'Unknown_{file_index}.bin') # Assign Name to EFI file
@ -115,7 +119,8 @@ def parse_efi_files(extract_path, efi_files, padding):
file_path = os.path.join(extract_path, safe_name(file_name)) # Store EFI file output path file_path = os.path.join(extract_path, safe_name(file_name)) # Store EFI file output path
with open(file_path, 'wb') as out_file: out_file.write(file_data) # Store EFI file data to drive with open(file_path, 'wb') as out_file:
out_file.write(file_data) # Store EFI file data to drive
# Attempt to detect EFI compression & decompress when applicable # Attempt to detect EFI compression & decompress when applicable
if is_efi_compressed(file_data): if is_efi_compressed(file_data):
@ -139,7 +144,8 @@ if __name__ == '__main__':
printer(['***', input_name], padding - 4) printer(['***', input_name], padding - 4)
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()
if not is_portwell_efi(input_buffer): if not is_portwell_efi(input_buffer):
printer('Error: This is not a Portwell EFI Update Package!', padding) printer('Error: This is not a Portwell EFI Update Package!', padding)

View file

@ -6,9 +6,9 @@
* [**AMI BIOS Guard Extractor**](#ami-bios-guard-extractor) * [**AMI BIOS Guard Extractor**](#ami-bios-guard-extractor)
* [**AMI UCP Update Extractor**](#ami-ucp-update-extractor) * [**AMI UCP Update Extractor**](#ami-ucp-update-extractor)
* [**Award BIOS Module Extractor**](#award-bios-module-extractor) * [**Award BIOS Module Extractor**](#award-bios-module-extractor)
* [**Dell PFS Update Extractor**](#dell-pfs-update-extractor) * [**Dell PFS/PKG Update Extractor**](#dell-pfs-pkg-update-extractor)
* [**Fujitsu UPC BIOS Extractor**](#fujitsu-upc-bios-extractor) * [**Fujitsu UPC BIOS Extractor**](#fujitsu-upc-bios-extractor)
* [**Insyde iFlash Update Extractor**](#insyde-iflash-update-extractor) * [**Insyde iFlash/iFdPacker Extractor**](#insyde-iflash-ifdpacker-update-extractor)
* [**Panasonic BIOS Package Extractor**](#panasonic-bios-package-extractor) * [**Panasonic BIOS Package Extractor**](#panasonic-bios-package-extractor)
* [**Phoenix TDK Packer Extractor**](#phoenix-tdk-packer-extractor) * [**Phoenix TDK Packer Extractor**](#phoenix-tdk-packer-extractor)
* [**Portwell EFI Update Extractor**](#portwell-efi-update-extractor) * [**Portwell EFI Update Extractor**](#portwell-efi-update-extractor)
@ -37,7 +37,7 @@ You can either Drag & Drop or manually enter AMI BIOS Guard (PFAT) image file(s)
#### **Compatibility** #### **Compatibility**
Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support. Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support.
#### **Prerequisites** #### **Prerequisites**
@ -49,7 +49,7 @@ Optionally, to decompile the AMI PFAT \> Intel BIOS Guard Scripts, you must have
PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often.
1. Make sure Python 3.8.0 or newer is installed: 1. Make sure Python 3.10.0 or newer is installed:
> python --version > python --version
@ -81,7 +81,7 @@ Some Anti-Virus software may claim that the built/frozen/compiled executable con
#### **Description** #### **Description**
Parses AMI UCP (Utility Configuration Program) Update executables, extracts their firmware components (e.g. SPI/BIOS/UEFI, EC, ME etc) and shows all relevant info. It supports all AMI UCP revisions and formats, including those with nested AMI PFAT, AMI UCP or Insyde SFX structures. The output comprises only final firmware components and utilities which are directly usable by end users. Parses AMI UCP (Utility Configuration Program) Update executables, extracts their firmware components (e.g. SPI/BIOS/UEFI, EC, ME etc) and shows all relevant info. It supports all AMI UCP revisions and formats, including those with nested AMI PFAT, AMI UCP or Insyde iFlash/iFdPacker structures. The output comprises only final firmware components and utilities which are directly usable by end users.
#### **Usage** #### **Usage**
@ -96,7 +96,7 @@ You can either Drag & Drop or manually enter AMI UCP Update executable file(s).
#### **Compatibility** #### **Compatibility**
Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support. Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support.
#### **Prerequisites** #### **Prerequisites**
@ -113,7 +113,7 @@ Optionally, to decompile the AMI UCP \> AMI PFAT \> Intel BIOS Guard Scripts (wh
PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often.
1. Make sure Python 3.8.0 or newer is installed: 1. Make sure Python 3.10.0 or newer is installed:
> python --version > python --version
@ -161,7 +161,7 @@ You can either Drag & Drop or manually enter Award BIOS image file(s). Optional
#### **Compatibility** #### **Compatibility**
Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support. Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support.
#### **Prerequisites** #### **Prerequisites**
@ -173,7 +173,7 @@ To run the utility, you must have the following 3rd party tool at the "external"
PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often.
1. Make sure Python 3.8.0 or newer is installed: 1. Make sure Python 3.10.0 or newer is installed:
> python --version > python --version
@ -199,17 +199,17 @@ Some Anti-Virus software may claim that the built/frozen/compiled executable con
![]() ![]()
## **Dell PFS Update Extractor** ## **Dell PFS/PKG Update Extractor**
![]() ![]()
#### **Description** #### **Description**
Parses Dell PFS Update images and extracts their Firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and Utilities (e.g. Flasher etc) component sections. It supports all Dell PFS revisions and formats, including those which are originally LZMA compressed in ThinOS packages, ZLIB compressed or Intel BIOS Guard (PFAT) protected. The output comprises only final firmware components which are directly usable by end users. Parses Dell PFS/PKG Update images and extracts their Firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and Utilities (e.g. Flasher etc) component sections. It supports all Dell PFS/PKG revisions and formats, including those which are originally LZMA compressed in ThinOS packages, ZLIB compressed or Intel BIOS Guard (PFAT) protected. The output comprises only final firmware components which are directly usable by end users.
#### **Usage** #### **Usage**
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/PKG 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 * -v or --version : show utility name and version
@ -221,7 +221,7 @@ You can either Drag & Drop or manually enter Dell PFS Update images(s). Optional
#### **Compatibility** #### **Compatibility**
Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support. Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support.
#### **Prerequisites** #### **Prerequisites**
@ -233,7 +233,7 @@ Optionally, to decompile the Intel BIOS Guard (PFAT) Scripts, you must have the
PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often.
1. Make sure Python 3.8.0 or newer is installed: 1. Make sure Python 3.10.0 or newer is installed:
> python --version > python --version
@ -279,7 +279,7 @@ You can either Drag & Drop or manually enter Fujitsu UPC BIOS image file(s). Opt
#### **Compatibility** #### **Compatibility**
Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support. Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support.
#### **Prerequisites** #### **Prerequisites**
@ -291,7 +291,7 @@ To run the utility, you must have the following 3rd party tool at the "external"
PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often.
1. Make sure Python 3.8.0 or newer is installed: 1. Make sure Python 3.10.0 or newer is installed:
> python --version > python --version
@ -317,17 +317,17 @@ Some Anti-Virus software may claim that the built/frozen/compiled executable con
![]() ![]()
## **Insyde iFlash Update Extractor** ## **Insyde iFlash/iFdPacker Extractor**
![]() ![]()
#### **Description** #### **Description**
Parses Insyde iFlash Update images and extracts their firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and utilities (e.g. Flasher, Configuration etc) components. The output comprises only final firmware components which are directly usable by end users. Parses Insyde iFlash/iFdPacker Update images and extracts their firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and utilities (e.g. Flasher, Configuration etc) components. It supports all Insyde iFlash/iFdPacker revisions and formats, including those which are \7-Zip SFX 7z compressed in raw or obfuscated form. The output comprises only final firmware components which are directly usable by end users.
#### **Usage** #### **Usage**
You can either Drag & Drop or manually enter Insyde iFlash Update image file(s). Optional arguments: You can either Drag & Drop or manually enter Insyde iFlash/iFdPacker Update 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 * -v or --version : show utility name and version
@ -337,7 +337,7 @@ You can either Drag & Drop or manually enter Insyde iFlash Update image file(s).
#### **Compatibility** #### **Compatibility**
Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support. Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support.
#### **Prerequisites** #### **Prerequisites**
@ -347,7 +347,7 @@ To run the utility, you do not need any prerequisites.
PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often.
1. Make sure Python 3.8.0 or newer is installed: 1. Make sure Python 3.10.0 or newer is installed:
> python --version > python --version
@ -357,7 +357,7 @@ PyInstaller can build/freeze/compile the utility at all three supported platform
3. Build/Freeze/Compile: 3. Build/Freeze/Compile:
> pyinstaller --noupx --onefile \<path-to-project\>\/Insyde_iFlash_Extract.py > pyinstaller --noupx --onefile \<path-to-project\>\/Insyde_IFD_Extract.py
At dist folder you should find the final utility executable At dist folder you should find the final utility executable
@ -389,7 +389,7 @@ You can either Drag & Drop or manually enter Panasonic BIOS Package executable f
#### **Compatibility** #### **Compatibility**
Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support. Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support.
#### **Prerequisites** #### **Prerequisites**
@ -406,7 +406,7 @@ Moreover, you must have the following 3rd party tool at the "external" project d
PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often.
1. Make sure Python 3.8.0 or newer is installed: 1. Make sure Python 3.10.0 or newer is installed:
> python --version > python --version
@ -456,7 +456,7 @@ You can either Drag & Drop or manually enter Phoenix Tools Development Kit (TDK)
#### **Compatibility** #### **Compatibility**
Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support. Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support.
#### **Prerequisites** #### **Prerequisites**
@ -468,7 +468,7 @@ To run the utility, you must have the following 3rd party Python module installe
PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often.
1. Make sure Python 3.8.0 or newer is installed: 1. Make sure Python 3.10.0 or newer is installed:
> python --version > python --version
@ -514,7 +514,7 @@ You can either Drag & Drop or manually enter Portwell UEFI Unpacker EFI executab
#### **Compatibility** #### **Compatibility**
Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support. Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support.
#### **Prerequisites** #### **Prerequisites**
@ -532,7 +532,7 @@ Moreover, you must have the following 3rd party tool at the "external" project d
PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often.
1. Make sure Python 3.8.0 or newer is installed: 1. Make sure Python 3.10.0 or newer is installed:
> python --version > python --version
@ -582,7 +582,7 @@ You can either Drag & Drop or manually enter Toshiba BIOS COM image file(s). Opt
#### **Compatibility** #### **Compatibility**
Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support. Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support.
#### **Prerequisites** #### **Prerequisites**
@ -594,7 +594,7 @@ To run the utility, you must have the following 3rd party tool at the "external"
PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often.
1. Make sure Python 3.8.0 or newer is installed: 1. Make sure Python 3.10.0 or newer is installed:
> python --version > python --version
@ -640,7 +640,7 @@ You can either Drag & Drop or manually enter VAIO Packaging Manager executable f
#### **Compatibility** #### **Compatibility**
Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support. Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support.
#### **Prerequisites** #### **Prerequisites**
@ -650,7 +650,7 @@ To run the utility, you do not need any prerequisites.
PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often. PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often.
1. Make sure Python 3.8.0 or newer is installed: 1. Make sure Python 3.10.0 or newer is installed:
> python --version > python --version

View file

@ -7,7 +7,7 @@ Toshiba BIOS COM Extractor
Copyright (C) 2018-2022 Plato Mavropoulos Copyright (C) 2018-2022 Plato Mavropoulos
""" """
TITLE = 'Toshiba BIOS COM Extractor v2.0_a2' TITLE = 'Toshiba BIOS COM Extractor v2.0_a3'
import os import os
import sys import sys
@ -49,7 +49,8 @@ def toshiba_com_extract(input_file, output_path, padding=0):
try: try:
subprocess.run([get_comextract_path(), input_file, output_file], check=True, stdout=subprocess.DEVNULL) subprocess.run([get_comextract_path(), input_file, output_file], check=True, stdout=subprocess.DEVNULL)
if not os.path.isfile(output_file): raise Exception('EXTRACT_FILE_MISSING') if not os.path.isfile(output_file):
raise Exception('EXTRACT_FILE_MISSING')
except: except:
printer(f'Error: ToshibaComExtractor could not extract file {input_file}!', padding) printer(f'Error: ToshibaComExtractor could not extract file {input_file}!', padding)
@ -72,7 +73,8 @@ if __name__ == '__main__':
printer(['***', input_name], padding - 4) printer(['***', input_name], padding - 4)
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()
if not is_toshiba_com(input_file): if not is_toshiba_com(input_file):
printer('Error: This is not a Toshiba BIOS COM image!', padding) printer('Error: This is not a Toshiba BIOS COM image!', padding)

View file

@ -7,7 +7,7 @@ VAIO Packaging Manager Extractor
Copyright (C) 2019-2022 Plato Mavropoulos Copyright (C) 2019-2022 Plato Mavropoulos
""" """
TITLE = 'VAIO Packaging Manager Extractor v3.0_a6' TITLE = 'VAIO Packaging Manager Extractor v3.0_a7'
import os import os
import sys import sys
@ -17,8 +17,8 @@ sys.dont_write_bytecode = True
from common.comp_szip import is_szip_supported, szip_decompress from common.comp_szip import is_szip_supported, szip_decompress
from common.path_ops import make_dirs from common.path_ops import make_dirs
from common.patterns import PAT_VAIO_CFG, PAT_VAIO_CHK, PAT_VAIO_EXT, PAT_VAIO_CAB from common.patterns import PAT_VAIO_CAB, PAT_VAIO_CFG, PAT_VAIO_CHK, PAT_VAIO_EXT
from common.system import script_init, argparse_init, printer from common.system import argparse_init, printer, script_init
from common.text_ops import file_to_bytes from common.text_ops import file_to_bytes
# Check if input is VAIO Packaging Manager # Check if input is VAIO Packaging Manager
@ -31,7 +31,8 @@ def is_vaio_pkg(in_file):
def vaio_cabinet(name, buffer, extract_path, padding=0): def vaio_cabinet(name, buffer, extract_path, padding=0):
match_cab = PAT_VAIO_CAB.search(buffer) # Microsoft CAB Header XOR 0xFF match_cab = PAT_VAIO_CAB.search(buffer) # Microsoft CAB Header XOR 0xFF
if not match_cab: return 1 if not match_cab:
return 1
printer('Detected obfuscated CAB archive!', padding) printer('Detected obfuscated CAB archive!', padding)
@ -51,7 +52,8 @@ def vaio_cabinet(name, buffer, extract_path, padding=0):
cab_path = os.path.join(extract_path, f'{name}_Temporary.cab') cab_path = os.path.join(extract_path, f'{name}_Temporary.cab')
with open(cab_path, 'wb') as cab_file: cab_file.write(cab_data) # Create temporary CAB archive with open(cab_path, 'wb') as cab_file:
cab_file.write(cab_data) # Create temporary CAB archive
if is_szip_supported(cab_path, padding + 8, check=True): if is_szip_supported(cab_path, padding + 8, check=True):
if szip_decompress(cab_path, extract_path, 'CAB', padding + 8, check=True) == 0: if szip_decompress(cab_path, extract_path, 'CAB', padding + 8, check=True) == 0:
@ -67,7 +69,8 @@ def vaio_cabinet(name, buffer, extract_path, padding=0):
def vaio_unlock(name, buffer, extract_path, padding=0): def vaio_unlock(name, buffer, extract_path, padding=0):
match_cfg = PAT_VAIO_CFG.search(buffer) match_cfg = PAT_VAIO_CFG.search(buffer)
if not match_cfg: return 1 if not match_cfg:
return 1
printer('Attempting to Unlock executable!', padding) printer('Attempting to Unlock executable!', padding)
@ -116,7 +119,8 @@ def vaio_unlock(name, buffer, extract_path, padding=0):
# Store Unlocked VAIO Packaging Manager executable # Store Unlocked VAIO Packaging Manager executable
if vaio_check and user_path: if vaio_check and user_path:
unlock_path = os.path.join(extract_path, f'{name}_Unlocked.exe') unlock_path = os.path.join(extract_path, f'{name}_Unlocked.exe')
with open(unlock_path, 'wb') as unl_file: unl_file.write(buffer) with open(unlock_path, 'wb') as unl_file:
unl_file.write(buffer)
return 0 return 0
@ -149,7 +153,8 @@ if __name__ == '__main__':
printer(['***', input_name], padding - 4) printer(['***', input_name], padding - 4)
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()
# Check if VAIO Packaging Manager pattern was found on executable # Check if VAIO Packaging Manager pattern was found on executable
if not is_vaio_pkg(input_buffer): if not is_vaio_pkg(input_buffer):

View file

@ -22,8 +22,10 @@ def is_efi_compressed(data, strict=True):
check_diff = size_comp < size_orig check_diff = size_comp < size_orig
if strict: check_size = size_comp + 0x8 == len(data) if strict:
else: check_size = size_comp + 0x8 <= len(data) check_size = size_comp + 0x8 == len(data)
else:
check_size = size_comp + 0x8 <= len(data)
return check_diff and check_size return check_diff and check_size
@ -38,9 +40,11 @@ def efi_decompress(in_path, out_path, padding=0, silent=False, comp_type='--uefi
try: try:
subprocess.run([get_tiano_path(), '-d', in_path, '-o', out_path, '-q', comp_type], check=True, stdout=subprocess.DEVNULL) subprocess.run([get_tiano_path(), '-d', in_path, '-o', out_path, '-q', comp_type], check=True, stdout=subprocess.DEVNULL)
with open(in_path, 'rb') as file: _,size_orig = get_compress_sizes(file.read()) with open(in_path, 'rb') as file:
_,size_orig = get_compress_sizes(file.read())
if os.path.getsize(out_path) != size_orig: raise Exception('EFI_DECOMPRESS_ERROR') if os.path.getsize(out_path) != size_orig:
raise Exception('EFI_DECOMPRESS_ERROR')
except: except:
if not silent: if not silent:
printer(f'Error: TianoCompress could not extract file {in_path}!', padding) printer(f'Error: TianoCompress could not extract file {in_path}!', padding)

View file

@ -27,7 +27,8 @@ def is_szip_supported(in_path, padding=0, check=False, silent=False):
try: try:
szip_t = subprocess.run([get_szip_path(), 't', in_path, '-bso0', '-bse0', '-bsp0'], check=False) szip_t = subprocess.run([get_szip_path(), 't', in_path, '-bso0', '-bse0', '-bsp0'], check=False)
if check: check_bad_exit_code(szip_t.returncode) if check:
check_bad_exit_code(szip_t.returncode)
except: except:
if not silent: if not silent:
printer(f'Error: 7-Zip could not check support for file {in_path}!', padding) printer(f'Error: 7-Zip could not check support for file {in_path}!', padding)
@ -38,14 +39,17 @@ def is_szip_supported(in_path, padding=0, check=False, silent=False):
# Archive decompression via 7-Zip # Archive decompression via 7-Zip
def szip_decompress(in_path, out_path, in_name, padding=0, check=False, silent=False): def szip_decompress(in_path, out_path, in_name, padding=0, check=False, silent=False):
if not in_name: in_name = 'archive' if not in_name:
in_name = 'archive'
try: try:
szip_x = subprocess.run([get_szip_path(), 'x', '-aou', '-bso0', '-bse0', '-bsp0', '-o' + out_path, in_path], check=False) szip_x = subprocess.run([get_szip_path(), 'x', '-aou', '-bso0', '-bse0', '-bsp0', '-o' + out_path, in_path], check=False)
if check: check_bad_exit_code(szip_x.returncode) if check:
check_bad_exit_code(szip_x.returncode)
if not os.path.isdir(out_path): raise Exception('EXTRACT_DIR_MISSING') if not os.path.isdir(out_path):
raise Exception('EXTRACT_DIR_MISSING')
except: except:
if not silent: if not silent:
printer(f'Error: 7-Zip could not extract {in_name} file {in_path}!', padding) printer(f'Error: 7-Zip could not extract {in_name} file {in_path}!', padding)

View file

@ -6,6 +6,7 @@ Copyright (C) 2022 Plato Mavropoulos
""" """
# https://github.com/allowitsme/big-tool by Dmitry Frolov # https://github.com/allowitsme/big-tool by Dmitry Frolov
# https://github.com/platomav/BGScriptTool by Plato Mavropoulos
def get_bgs_tool(): def get_bgs_tool():
try: try:
from external.big_script_tool import BigScript from external.big_script_tool import BigScript

View file

@ -84,7 +84,8 @@ def is_path_absolute(in_path):
# Create folder(s), controlling parents, existence and prior deletion # Create folder(s), controlling parents, existence and prior deletion
def make_dirs(in_path, parents=True, exist_ok=False, delete=False): def make_dirs(in_path, parents=True, exist_ok=False, delete=False):
if delete: del_dirs(in_path) if delete:
del_dirs(in_path)
Path.mkdir(Path(in_path), parents=parents, exist_ok=exist_ok) Path.mkdir(Path(in_path), parents=parents, exist_ok=exist_ok)
@ -129,7 +130,8 @@ def get_argparse_path(argparse_path):
# 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 = []
if len(sys_argv) >= 2: if len(sys_argv) >= 2:
# Drag & Drop or CLI # Drag & Drop or CLI

View file

@ -14,6 +14,7 @@ PAT_DELL_FTR = re.compile(br'\xEE\xAA\xEE\x8F\x49\x1B\xE8\xAE\x14\x37\x90')
PAT_DELL_HDR = re.compile(br'\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.\x78\x9C', re.DOTALL) PAT_DELL_HDR = re.compile(br'\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.\x78\x9C', re.DOTALL)
PAT_DELL_PKG = re.compile(br'\x72\x13\x55\x00.{45}7zXZ', re.DOTALL) PAT_DELL_PKG = re.compile(br'\x72\x13\x55\x00.{45}7zXZ', re.DOTALL)
PAT_INSYDE_IFL = re.compile(br'\$_IFLASH_') PAT_INSYDE_IFL = re.compile(br'\$_IFLASH_')
PAT_INSYDE_SFX = re.compile(br'\x0D\x0A;!@InstallEnd@!\x0D\x0A(7z\xBC\xAF\x27|\x6E\xF4\x79\x5F\x4E)')
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)
PAT_MICROSOFT_CAB = re.compile(br'MSCF\x00{4}') PAT_MICROSOFT_CAB = re.compile(br'MSCF\x00{4}')
PAT_MICROSOFT_MZ = re.compile(br'MZ') PAT_MICROSOFT_MZ = re.compile(br'MZ')

View file

@ -15,7 +15,8 @@ uint64_t = ctypes.c_uint64
# https://github.com/skochinsky/me-tools/blob/master/me_unpack.py by Igor Skochinsky # https://github.com/skochinsky/me-tools/blob/master/me_unpack.py by Igor Skochinsky
def get_struct(buffer, start_offset, class_name, param_list=None): def get_struct(buffer, start_offset, class_name, param_list=None):
if param_list is None: param_list = [] if param_list is None:
param_list = []
structure = class_name(*param_list) # Unpack parameter list structure = class_name(*param_list) # Unpack parameter list
struct_len = ctypes.sizeof(structure) struct_len = ctypes.sizeof(structure)

View file

@ -56,7 +56,8 @@ def check_sys_os():
sys.exit(126) sys.exit(126)
# 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 # Initialize common argparse arguments
def argparse_init(): def argparse_init():
@ -85,10 +86,12 @@ def script_init(title, arguments, padding=0):
printer(title, new_line=False) printer(title, new_line=False)
# Show Utility Version on demand # Show Utility Version on demand
if arguments.version: sys.exit(0) if arguments.version:
sys.exit(0)
# Set console/terminal window title (Windows only) # Set console/terminal window title (Windows only)
if get_os_ver()[1]: ctypes.windll.kernel32.SetConsoleTitleW(title) if get_os_ver()[1]:
ctypes.windll.kernel32.SetConsoleTitleW(title)
# 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)

View file

@ -1,2 +1,2 @@
lznt1==0.2 lznt1==0.2
pefile==2021.9.3 pefile==2022.5.30