AMI UCP BIOS Extractor v2.0_a3

Added support for HP-modded AMI UCP (HP Flash Utility v4)
This commit is contained in:
platomav 2022-04-09 22:22:25 +03:00
parent f2be701423
commit 2a98460d71
2 changed files with 117 additions and 96 deletions

View file

@ -7,9 +7,10 @@ AMI UCP BIOS Extractor
Copyright (C) 2021-2022 Plato Mavropoulos Copyright (C) 2021-2022 Plato Mavropoulos
""" """
title = 'AMI UCP BIOS Extractor v2.0_a2' title = 'AMI UCP BIOS Extractor v2.0_a3'
import os import os
import re
import sys import sys
import shutil import shutil
import struct import struct
@ -37,17 +38,28 @@ class UafHeader(ctypes.LittleEndianStructure):
('Checksum', uint16_t), # 0x08 ('Checksum', uint16_t), # 0x08
('Unknown0', uint8_t), # 0x0A ('Unknown0', uint8_t), # 0x0A
('Unknown1', uint8_t), # 0x0A ('Unknown1', uint8_t), # 0x0A
('Reserved', uint32_t), # 0x0C ('Reserved', uint8_t*4), # 0x0C
# 0x10 # 0x10
] ]
def _get_reserved(self):
res_bytes = bytes(self.Reserved)
res_str = re.sub(r'[\n\t\r\x00 ]', '', res_bytes.decode('utf-8','ignore'))
res_hex = '0x%0.*X' % (0x4 * 2, int.from_bytes(res_bytes, 'big'))
res_out = res_hex + (' (%s)' % res_str if len(res_str) else '')
return res_out
def struct_print(self, p): def struct_print(self, p):
printer(['Tag :', self.ModuleTag.decode('utf-8')], p, False) printer(['Tag :', self.ModuleTag.decode('utf-8')], p, False)
printer(['Size :', '0x%X' % self.ModuleSize], p, False) printer(['Size :', '0x%X' % self.ModuleSize], p, False)
printer(['Checksum :', '0x%0.4X' % self.Checksum], p, False) printer(['Checksum :', '0x%0.4X' % self.Checksum], p, False)
printer(['Unknown 0 :', '0x%0.2X' % self.Unknown0], p, False) printer(['Unknown 0 :', '0x%0.2X' % self.Unknown0], p, False)
printer(['Unknown 1 :', '0x%0.2X' % self.Unknown1], p, False) printer(['Unknown 1 :', '0x%0.2X' % self.Unknown1], p, False)
printer(['Reserved :', '0x%0.8X' % self.Reserved], p, False) printer(['Reserved :', self._get_reserved()], p, False)
class UafModule(ctypes.LittleEndianStructure): class UafModule(ctypes.LittleEndianStructure):
_pack_ = 1 _pack_ = 1
@ -57,10 +69,11 @@ class UafModule(ctypes.LittleEndianStructure):
# 0x08 # 0x08
] ]
def struct_print(self, p, filename): def struct_print(self, p, filename, description):
printer(['Compress Size:', '0x%X' % self.CompressSize], p, False) printer(['Compress Size:', '0x%X' % self.CompressSize], p, False)
printer(['Original Size:', '0x%X' % self.OriginalSize], p, False) printer(['Original Size:', '0x%X' % self.OriginalSize], p, False)
printer(['File Name :', filename], p, False) printer(['Filename :', filename], p, False)
printer(['Description :', description], p, False)
class UiiHeader(ctypes.LittleEndianStructure): class UiiHeader(ctypes.LittleEndianStructure):
_pack_ = 1 _pack_ = 1
@ -139,7 +152,7 @@ class DisModule(ctypes.LittleEndianStructure):
printer(['Command :', self.Command.decode('utf-8').strip()], p, False) printer(['Command :', self.Command.decode('utf-8').strip()], p, False)
printer(['Description:', self.Description.decode('utf-8').strip()], p, False) printer(['Description:', self.Description.decode('utf-8').strip()], p, False)
# Validate @UAF Module Checksum-16 # Validate UCP Module Checksum-16
def chk16_validate(data, tag, padd=0): def chk16_validate(data, tag, padd=0):
if get_chk_16(data) != 0: if get_chk_16(data) != 0:
printer('Error: Invalid UCP Module %s Checksum!' % tag, padd, pause=True) printer('Error: Invalid UCP Module %s Checksum!' % tag, padd, pause=True)
@ -148,9 +161,10 @@ def chk16_validate(data, tag, padd=0):
# Get all input file AMI UCP patterns # Get all input file AMI UCP patterns
def get_ami_ucp(buffer): def get_ami_ucp(buffer):
uaf_len_max = 0x0 # Length of largest detected @UAF uaf_len_max = 0x0 # Length of largest detected @UAF|@HPU
uaf_hdr_off = 0x0 # Offset of largest detected @UAF uaf_hdr_off = 0x0 # Offset of largest detected @UAF|@HPU
uaf_buf_bin = b'' # Buffer of largest detected @UAF uaf_buf_bin = b'' # Buffer of largest detected @UAF|@HPU
uaf_buf_tag = '@UAF' # Tag of largest detected @UAF|@HPU
for uaf in PAT_AMI_UCP.finditer(buffer): for uaf in PAT_AMI_UCP.finditer(buffer):
uaf_len_cur = int.from_bytes(buffer[uaf.start() + 0x4:uaf.start() + 0x8], 'little') uaf_len_cur = int.from_bytes(buffer[uaf.start() + 0x4:uaf.start() + 0x8], 'little')
@ -159,85 +173,89 @@ def get_ami_ucp(buffer):
uaf_len_max = uaf_len_cur uaf_len_max = uaf_len_cur
uaf_hdr_off = uaf.start() uaf_hdr_off = uaf.start()
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')
return uaf_hdr_off, uaf_buf_bin return uaf_hdr_off, uaf_buf_bin, uaf_buf_tag
# Get list of @UAF Modules # Get list of @UAF|@HPU Modules
def get_uaf_mod(buffer, uaf_off=0x0): def get_uaf_mod(buffer, uaf_off=0x0):
uaf_all = [] # Initialize list of all @UAF Modules uaf_all = [] # Initialize list of all @UAF|@HPU Modules
while buffer[uaf_off] == 0x40: # ASCII of @ is 0x40 while buffer[uaf_off] == 0x40: # ASCII of @ is 0x40
uaf_hdr = get_struct(buffer, uaf_off, UafHeader) # Parse @UAF Module Structure uaf_hdr = get_struct(buffer, uaf_off, UafHeader) # Parse @UAF|@HPU Module Structure
uaf_tag = uaf_hdr.ModuleTag.decode('utf-8') # Get unique @UAF Module Tag uaf_tag = uaf_hdr.ModuleTag.decode('utf-8') # Get unique @UAF|@HPU Module Tag
uaf_all.append([uaf_tag, uaf_off, uaf_hdr]) # Store @UAF Module Info uaf_all.append([uaf_tag, uaf_off, uaf_hdr]) # Store @UAF|@HPU Module Info
uaf_off += uaf_hdr.ModuleSize # Adjust to next @UAF 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 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 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, output_path, padding=0, is_checksum=False): def ucp_extract(buffer, out_path, ucp_tag='@UAF', padding=0, is_checksum=False):
nal_dict = {} # Initialize @NAL Dictionary per UCP nal_dict = {} # Initialize @NAL Dictionary per UCP
printer('Utility Configuration Program', padding) printer('Utility Configuration Program', padding)
extract_path = os.path.join(output_path + '_extracted', '') extract_path = os.path.join(out_path + '_extracted', '')
if os.path.isdir(extract_path): shutil.rmtree(extract_path) if os.path.isdir(extract_path): shutil.rmtree(extract_path)
os.mkdir(extract_path) os.mkdir(extract_path)
uaf_hdr = get_struct(buffer, 0, UafHeader) # Parse @UAF Header Structure uaf_hdr = get_struct(buffer, 0, UafHeader) # Parse @UAF|@HPU Header Structure
printer('Utility Auxiliary File > @UAF:\n', padding + 4) printer('Utility Auxiliary File > %s:\n' % ucp_tag, 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(buffer), len(buffer)) # Generate UafModule Structure
uaf_mod = get_struct(fake, 0x0, UafModule) # Parse UAF Module EFI Structure uaf_mod = get_struct(fake, 0x0, UafModule) # Parse @UAF|@HPU Module EFI Structure
uaf_mod.struct_print(padding + 8, UAF_TAG_DICT['@UAF'][0]) # Print @UAF Module EFI Info uaf_name = UAF_TAG_DICT[ucp_tag][0] # Get @UAF|@HPU Module Filename
uaf_desc = UAF_TAG_DICT[ucp_tag][1] # Get @UAF|@HPU Module Description
if is_checksum: chk16_validate(buffer, '@UAF', padding + 8) 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)
uaf_all = get_uaf_mod(buffer, UAF_HDR_LEN) uaf_all = get_uaf_mod(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(buffer, extract_path, mod_info, padding + 8, is_checksum, nal_dict)
# Parse & Extract AMI UCP > @UAF 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, is_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
uaf_data_all = buffer[uaf_off:uaf_off + uaf_hdr.ModuleSize] # @UAF Module Entire Data uaf_data_all = buffer[uaf_off:uaf_off + uaf_hdr.ModuleSize] # @UAF|@HPU Module Entire Data
uaf_data_mod = uaf_data_all[UAF_HDR_LEN:] # @UAF Module EFI Data uaf_data_mod = uaf_data_all[UAF_HDR_LEN:] # @UAF|@HPU Module EFI Data
uaf_data_raw = uaf_data_mod[UAF_MOD_LEN:] # @UAF Module Raw Data uaf_data_raw = uaf_data_mod[UAF_MOD_LEN:] # @UAF|@HPU Module Raw Data
printer('Utility Auxiliary File > %s:\n' % uaf_tag, padding) printer('Utility Auxiliary File > %s:\n' % uaf_tag, padding)
uaf_hdr.struct_print(padding + 4) # Print @UAF Module Info uaf_hdr.struct_print(padding + 4) # Print @UAF|@HPU Module Info
uaf_mod = get_struct(buffer, uaf_off + UAF_HDR_LEN, UafModule) # Parse UAF Module EFI Structure uaf_mod = get_struct(buffer, uaf_off + UAF_HDR_LEN, UafModule) # Parse UAF Module EFI Structure
is_comp = uaf_mod.CompressSize != uaf_mod.OriginalSize # Detect @UAF 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] # Always prefer NAL naming first if uaf_tag in nal_dict: uaf_name = nal_dict[uaf_tag] # Always prefer @NAL naming first
elif uaf_tag in UAF_TAG_DICT: uaf_name = UAF_TAG_DICT[uaf_tag][0] # Otherwise use built-in naming elif uaf_tag in UAF_TAG_DICT: uaf_name = UAF_TAG_DICT[uaf_tag][0] # Otherwise use built-in naming
elif uaf_tag == '@ROM': uaf_name = 'BIOS.bin' # BIOS/PFAT Firmware (w/o Signature) elif uaf_tag == '@ROM': uaf_name = 'BIOS.bin' # BIOS/PFAT Firmware (w/o Signature)
elif uaf_tag.startswith('@R0'): uaf_name = 'BIOS_0%s.bin' % uaf_tag[3:] # BIOS/PFAT Firmware elif uaf_tag.startswith('@R0'): uaf_name = 'BIOS_0%s.bin' % uaf_tag[3:] # BIOS/PFAT Firmware
@ -246,22 +264,24 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
elif uaf_tag.startswith('@DS'): uaf_name = 'DROM_0%s.sig' % uaf_tag[3:] # Thunderbolt Retimer Signature elif uaf_tag.startswith('@DS'): uaf_name = 'DROM_0%s.sig' % uaf_tag[3:] # Thunderbolt Retimer Signature
elif uaf_tag.startswith('@EC'): uaf_name = 'EC_0%s.bin' % uaf_tag[3:] # Embedded Controller Firmware elif uaf_tag.startswith('@EC'): uaf_name = 'EC_0%s.bin' % uaf_tag[3:] # Embedded Controller Firmware
elif uaf_tag.startswith('@ME'): uaf_name = 'ME_0%s.bin' % uaf_tag[3:] # Management Engine Firmware elif uaf_tag.startswith('@ME'): uaf_name = 'ME_0%s.bin' % uaf_tag[3:] # Management Engine Firmware
else: uaf_name = uaf_tag # Could not name the @UAF Module, use Tag instead 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'
uaf_mod.struct_print(padding + 4, uaf_name + uaf_fext) # Print @UAF Module EFI Info uaf_fdesc = UAF_TAG_DICT[uaf_tag][1] if uaf_tag in UAF_TAG_DICT else uaf_name
# Check if unknown @UAF Module Tag is present in NAL but not in built-in dictionary uaf_mod.struct_print(padding + 4, uaf_name + uaf_fext, uaf_fdesc) # Print @UAF|@HPU Module EFI Info
# Check if unknown @UAF|@HPU Module Tag is present in @NAL but not in built-in dictionary
if uaf_tag in nal_dict and uaf_tag not in UAF_TAG_DICT and not uaf_tag.startswith(('@ROM','@R0','@S0','@DR','@DS')): if uaf_tag in nal_dict and uaf_tag not in UAF_TAG_DICT and not uaf_tag.startswith(('@ROM','@R0','@S0','@DR','@DS')):
printer('Note: Detected new AMI UCP Module %s (%s) in NAL!' % (uaf_tag, nal_dict[uaf_tag]), padding, pause=True) printer('Note: Detected new AMI UCP Module %s (%s) in @NAL!' % (uaf_tag, nal_dict[uaf_tag]), padding + 4, pause=True)
# Generate @UAF Module File name, depending on whether decompression will be required # Generate @UAF|@HPU Module File name, depending on whether decompression will be required
uaf_fname = os.path.join(extract_path, safe_name(uaf_name + ('.temp' if is_comp else uaf_fext))) uaf_fname = os.path.join(extract_path, safe_name(uaf_name + ('.temp' if is_comp else uaf_fext)))
if is_checksum: chk16_validate(uaf_data_all, uaf_tag, padding + 4) if is_checksum: chk16_validate(uaf_data_all, uaf_tag, padding + 4)
# Parse Utility Identification Information @UAF Module (@UII) # Parse Utility Identification Information @UAF|@HPU Module (@UII)
if uaf_tag == '@UII': if uaf_tag == '@UII':
info_hdr = get_struct(uaf_data_raw, 0, UiiHeader) # Parse @UII Module Raw Structure info_hdr = get_struct(uaf_data_raw, 0, UiiHeader) # Parse @UII Module Raw Structure
@ -281,38 +301,38 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
with contextlib.redirect_stdout(uii_out): with contextlib.redirect_stdout(uii_out):
info_hdr.struct_print(0, info_desc) # Store @UII Module Info info_hdr.struct_print(0, info_desc) # Store @UII Module Info
# Adjust @UAF Module Raw Data for extraction # Adjust @UAF|@HPU Module Raw Data for extraction
if is_comp: if is_comp:
# Some Compressed @UAF Module EFI data lack necessary EOF padding # Some Compressed @UAF|@HPU Module EFI data lack necessary EOF padding
if uaf_mod.CompressSize > len(uaf_data_raw): if uaf_mod.CompressSize > len(uaf_data_raw):
comp_padd = b'\x00' * (uaf_mod.CompressSize - len(uaf_data_raw)) comp_padd = b'\x00' * (uaf_mod.CompressSize - len(uaf_data_raw))
uaf_data_raw = uaf_data_mod[:UAF_MOD_LEN] + uaf_data_raw + comp_padd # Add missing padding for decompression uaf_data_raw = uaf_data_mod[:UAF_MOD_LEN] + uaf_data_raw + comp_padd # Add missing padding for decompression
else: else:
uaf_data_raw = uaf_data_mod[:UAF_MOD_LEN] + uaf_data_raw # Add the EFI/Tiano Compression info before Raw Data uaf_data_raw = uaf_data_mod[:UAF_MOD_LEN] + uaf_data_raw # Add the EFI/Tiano Compression info before Raw Data
else: else:
uaf_data_raw = uaf_data_raw[:uaf_mod.OriginalSize] # No compression, extend to end of Original @UAF Module size uaf_data_raw = uaf_data_raw[:uaf_mod.OriginalSize] # No compression, extend to end of Original @UAF|@HPU Module size
# Store/Save @UAF 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 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 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 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 Module file os.remove(uaf_fname) # Successful decompression, delete compressed @UAF|@HPU Module file
uaf_fname = dec_fname # Adjust @UAF Module file path to the decompressed one uaf_fname = dec_fname # Adjust @UAF|@HPU Module file path to the decompressed one
# Process and Print known text only @UAF Modules (after EFI/Tiano Decompression) # Process and Print known text only @UAF|@HPU Modules (after EFI/Tiano Decompression)
if uaf_tag in UAF_TAG_DICT and UAF_TAG_DICT[uaf_tag][2] == 'Text': if uaf_tag in UAF_TAG_DICT and UAF_TAG_DICT[uaf_tag][2] == 'Text':
printer(UAF_TAG_DICT[uaf_tag][1] + ':', padding + 4) printer(UAF_TAG_DICT[uaf_tag][1] + ':', padding + 4)
printer(uaf_data_raw.decode('utf-8','ignore'), padding + 8) printer(uaf_data_raw.decode('utf-8','ignore'), padding + 8)
# Parse Default Command Status @UAF Module (@DIS) # Parse Default Command Status @UAF|@HPU Module (@DIS)
if len(uaf_data_raw) and uaf_tag == '@DIS': if len(uaf_data_raw) and uaf_tag == '@DIS':
dis_hdr = get_struct(uaf_data_raw, 0x0, DisHeader) # Parse @DIS Module Raw Header Structure dis_hdr = get_struct(uaf_data_raw, 0x0, DisHeader) # Parse @DIS Module Raw Header Structure
@ -343,11 +363,11 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
os.remove(uaf_fname) # Delete @DIS Module binary, info exported as text os.remove(uaf_fname) # Delete @DIS Module binary, info exported as text
# Parse Name|Non-AMI List (?) @UAF Module (@NAL) # Parse Name List @UAF|@HPU Module (@NAL)
if len(uaf_data_raw) >= 5 and (uaf_tag,uaf_data_raw[0],uaf_data_raw[4]) == ('@NAL',0x40,0x3A): if len(uaf_data_raw) >= 5 and (uaf_tag,uaf_data_raw[0],uaf_data_raw[4]) == ('@NAL',0x40,0x3A):
nal_info = uaf_data_raw.decode('utf-8','ignore').replace('\r','').strip().split('\n') nal_info = uaf_data_raw.decode('utf-8','ignore').replace('\r','').strip().split('\n')
printer('@UAF Module Name List:\n', padding + 4) printer('AMI UCP Module Name List:\n', padding + 4)
# Parse all @NAL Module Entries # Parse all @NAL Module Entries
for info in nal_info: for info in nal_info:
@ -357,7 +377,7 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
nal_dict[info_tag] = os.path.basename(info_val) # Assign a file name (w/o path) to each Tag nal_dict[info_tag] = os.path.basename(info_val) # Assign a file name (w/o path) to each Tag
# Parse Insyde BIOS @UAF Module (@INS) # Parse Insyde BIOS @UAF|@HPU Module (@INS)
if uaf_tag == '@INS' and is_7z_supported(uaf_fname): if uaf_tag == '@INS' and is_7z_supported(uaf_fname):
ins_dir = os.path.join(extract_path, safe_name(uaf_tag + '_nested-SFX')) # Generate extraction directory ins_dir = os.path.join(extract_path, safe_name(uaf_tag + '_nested-SFX')) # Generate extraction directory
@ -381,14 +401,14 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
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 Size # Get best Nested AMI UCP Pattern match based on @UAF|@HPU Size
nested_uaf_off,nested_uaf_bin = get_ami_ucp(uaf_data_raw) nested_uaf_off,nested_uaf_bin,nested_uaf_tag = get_ami_ucp(uaf_data_raw)
# Parse Nested AMI UCP Structure # Parse Nested AMI UCP Structure
if nested_uaf_off: if nested_uaf_off:
uaf_dir = os.path.join(extract_path, safe_name(uaf_tag + '_nested-UCP')) # Generate extraction directory uaf_dir = os.path.join(extract_path, safe_name(uaf_tag + '_nested-UCP')) # Generate extraction directory
ucp_extract(nested_uaf_bin, uaf_dir, padding + 4, is_checksum) # Call recursively ucp_extract(nested_uaf_bin, uaf_dir, nested_uaf_tag, padding + 4, is_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 Structure after successful recursion/extraction
@ -403,57 +423,58 @@ UII_HDR_LEN = ctypes.sizeof(UiiHeader)
# AMI UCP Tag Dictionary # AMI UCP Tag Dictionary
UAF_TAG_DICT = { UAF_TAG_DICT = {
'@3FI' : ['HpBiosUpdate32.efi', '', ''], '@3FI' : ['HpBiosUpdate32.efi', 'HpBiosUpdate32.efi', ''],
'@3S2' : ['HpBiosUpdate32.s12', '', ''], '@3S2' : ['HpBiosUpdate32.s12', 'HpBiosUpdate32.s12', ''],
'@3S4' : ['HpBiosUpdate32.s14', '', ''], '@3S4' : ['HpBiosUpdate32.s14', 'HpBiosUpdate32.s14', ''],
'@3S9' : ['HpBiosUpdate32.s09', '', ''], '@3S9' : ['HpBiosUpdate32.s09', 'HpBiosUpdate32.s09', ''],
'@3SG' : ['HpBiosUpdate32.sig', '', ''], '@3SG' : ['HpBiosUpdate32.sig', 'HpBiosUpdate32.sig', ''],
'@AMI' : ['UCP_Nested.bin', 'Nested AMI UCP', ''], '@AMI' : ['UCP_Nested.bin', 'Nested AMI UCP', ''],
'@B12' : ['BiosMgmt.s12', '', ''], '@B12' : ['BiosMgmt.s12', 'BiosMgmt.s12', ''],
'@B14' : ['BiosMgmt.s14', '', ''], '@B14' : ['BiosMgmt.s14', 'BiosMgmt.s14', ''],
'@B32' : ['BiosMgmt32.s12', '', ''], '@B32' : ['BiosMgmt32.s12', 'BiosMgmt32.s12', ''],
'@B34' : ['BiosMgmt32.s14', '', ''], '@B34' : ['BiosMgmt32.s14', 'BiosMgmt32.s14', ''],
'@B39' : ['BiosMgmt32.s09', '', ''], '@B39' : ['BiosMgmt32.s09', 'BiosMgmt32.s09', ''],
'@B3E' : ['BiosMgmt32.efi', '', ''], '@B3E' : ['BiosMgmt32.efi', 'BiosMgmt32.efi', ''],
'@BM9' : ['BiosMgmt.s09', '', ''], '@BM9' : ['BiosMgmt.s09', 'BiosMgmt.s09', ''],
'@BME' : ['BiosMgmt.efi', '', ''], '@BME' : ['BiosMgmt.efi', 'BiosMgmt.efi', ''],
'@CKV' : ['Check_Version.txt', 'Check Version', 'Text'], '@CKV' : ['Check_Version.txt', 'Check Version', 'Text'],
'@CMD' : ['AFU_Command.txt', 'AMI AFU Command', 'Text'], '@CMD' : ['AFU_Command.txt', 'AMI AFU Command', 'Text'],
'@CPM' : ['AC_Message.txt', 'Confirm Power Message', ''], '@CPM' : ['AC_Message.txt', 'Confirm Power Message', ''],
'@DCT' : ['DevCon32.exe', 'Device Console WIN32', ''], '@DCT' : ['DevCon32.exe', 'Device Console WIN32', ''],
'@DCX' : ['DevCon64.exe', 'Device Console WIN64', ''], '@DCX' : ['DevCon64.exe', 'Device Console WIN64', ''],
'@DFE' : ['HpDevFwUpdate.efi', '', ''], '@DFE' : ['HpDevFwUpdate.efi', 'HpDevFwUpdate.efi', ''],
'@DFS' : ['HpDevFwUpdate.s12', '', ''], '@DFS' : ['HpDevFwUpdate.s12', 'HpDevFwUpdate.s12', ''],
'@DIS' : ['Command_Status.bin', 'Default Command Status', ''], '@DIS' : ['Command_Status.bin', 'Default Command Status', ''],
'@ENB' : ['ENBG64.exe', '', ''], '@ENB' : ['ENBG64.exe', 'ENBG64.exe', ''],
'@HPU' : ['UCP_Main.bin', 'Utility Auxiliary File (HP)', ''],
'@INS' : ['Insyde_Nested.bin', 'Nested Insyde SFX', ''], '@INS' : ['Insyde_Nested.bin', 'Nested Insyde SFX', ''],
'@M32' : ['HpBiosMgmt32.s12', '', ''], '@M32' : ['HpBiosMgmt32.s12', 'HpBiosMgmt32.s12', ''],
'@M34' : ['HpBiosMgmt32.s14', '', ''], '@M34' : ['HpBiosMgmt32.s14', 'HpBiosMgmt32.s14', ''],
'@M39' : ['HpBiosMgmt32.s09', '', ''], '@M39' : ['HpBiosMgmt32.s09', 'HpBiosMgmt32.s09', ''],
'@M3I' : ['HpBiosMgmt32.efi', '', ''], '@M3I' : ['HpBiosMgmt32.efi', 'HpBiosMgmt32.efi', ''],
'@MEC' : ['FWUpdLcl.txt', 'Intel FWUpdLcl Command', 'Text'], '@MEC' : ['FWUpdLcl.txt', 'Intel FWUpdLcl Command', 'Text'],
'@MED' : ['FWUpdLcl_DOS.exe', 'Intel FWUpdLcl DOS', ''], '@MED' : ['FWUpdLcl_DOS.exe', 'Intel FWUpdLcl DOS', ''],
'@MET' : ['FWUpdLcl_WIN32.exe', 'Intel FWUpdLcl WIN32', ''], '@MET' : ['FWUpdLcl_WIN32.exe', 'Intel FWUpdLcl WIN32', ''],
'@MFI' : ['HpBiosMgmt.efi', '', ''], '@MFI' : ['HpBiosMgmt.efi', 'HpBiosMgmt.efi', ''],
'@MS2' : ['HpBiosMgmt.s12', '', ''], '@MS2' : ['HpBiosMgmt.s12', 'HpBiosMgmt.s12', ''],
'@MS4' : ['HpBiosMgmt.s14', '', ''], '@MS4' : ['HpBiosMgmt.s14', 'HpBiosMgmt.s14', ''],
'@MS9' : ['HpBiosMgmt.s09', '', ''], '@MS9' : ['HpBiosMgmt.s09', 'HpBiosMgmt.s09', ''],
'@NAL' : ['UAF_List.txt', 'Name List', ''], '@NAL' : ['UCP_List.txt', 'AMI UCP Module Name List', ''],
'@OKM' : ['OK_Message.txt', 'OK Message', ''], '@OKM' : ['OK_Message.txt', 'OK Message', ''],
'@PFC' : ['BGT_Command.txt', 'AMI BGT Command', 'Text'], '@PFC' : ['BGT_Command.txt', 'AMI BGT Command', 'Text'],
'@R3I' : ['CryptRSA32.efi', '', ''], '@R3I' : ['CryptRSA32.efi', 'CryptRSA32.efi', ''],
'@RFI' : ['CryptRSA.efi', '', ''], '@RFI' : ['CryptRSA.efi', 'CryptRSA.efi', ''],
'@UAF' : ['UCP_Main.bin', 'Utility Auxiliary File', ''], '@UAF' : ['UCP_Main.bin', 'Utility Auxiliary File (AMI)', ''],
'@UFI' : ['HpBiosUpdate.efi', '', ''], '@UFI' : ['HpBiosUpdate.efi', 'HpBiosUpdate.efi', ''],
'@UII' : ['UCP_Info.txt', 'Utility Identification Information', ''], '@UII' : ['UCP_Info.txt', 'Utility Identification Information', ''],
'@US2' : ['HpBiosUpdate.s12', '', ''], '@US2' : ['HpBiosUpdate.s12', 'HpBiosUpdate.s12', ''],
'@US4' : ['HpBiosUpdate.s14', '', ''], '@US4' : ['HpBiosUpdate.s14', 'HpBiosUpdate.s14', ''],
'@US9' : ['HpBiosUpdate.s09', '', ''], '@US9' : ['HpBiosUpdate.s09', 'HpBiosUpdate.s09', ''],
'@USG' : ['HpBiosUpdate.sig', '', ''], '@USG' : ['HpBiosUpdate.sig', 'HpBiosUpdate.sig', ''],
'@VER' : ['OEM_Version.txt', 'OEM Version', 'Text'], '@VER' : ['OEM_Version.txt', 'OEM Version', 'Text'],
'@VXD' : ['amifldrv.vxd', '', ''], '@VXD' : ['amifldrv.vxd', 'amifldrv.vxd', ''],
'@W32' : ['amifldrv32.sys', '', ''], '@W32' : ['amifldrv32.sys', 'amifldrv32.sys', ''],
'@W64' : ['amifldrv64.sys', '', ''], '@W64' : ['amifldrv64.sys', 'amifldrv64.sys', ''],
} }
if __name__ == '__main__': if __name__ == '__main__':
@ -477,8 +498,8 @@ if __name__ == '__main__':
with open(input_file, 'rb') as in_file: input_buffer = in_file.read() with open(input_file, 'rb') as in_file: input_buffer = in_file.read()
# Get best AMI UCP Pattern match based on @UAF Size # Get best AMI UCP Pattern match based on @UAF|@HPU Size
main_uaf_off,main_uaf_bin = get_ami_ucp(input_buffer) main_uaf_off,main_uaf_bin,main_uaf_tag = get_ami_ucp(input_buffer)
if not main_uaf_off: if not main_uaf_off:
printer('Error: This is not an AMI UCP BIOS executable!', padding) printer('Error: This is not an AMI UCP BIOS executable!', padding)
@ -487,7 +508,7 @@ if __name__ == '__main__':
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, padding, is_checksum) ucp_extract(main_uaf_bin, extract_path, main_uaf_tag, padding, is_checksum)
printer('Extracted AMI UCP BIOS executable!', padding) printer('Extracted AMI UCP BIOS executable!', padding)

View file

@ -4,7 +4,7 @@
import re import re
PAT_AMI_PFAT = re.compile(b'_AMIPFAT.AMI_BIOS_GUARD_FLASH_CONFIGURATIONS', re.DOTALL) PAT_AMI_PFAT = re.compile(b'_AMIPFAT.AMI_BIOS_GUARD_FLASH_CONFIGURATIONS', re.DOTALL)
PAT_AMI_UCP = re.compile(br'\x40\x55\x41\x46.{12}\x40', re.DOTALL) PAT_AMI_UCP = re.compile(br'@(UAF|HPU).{12}\x40', re.DOTALL)
PAT_DELL_PKG = re.compile(br'\x72\x13\x55\x00.{45}\x37\x7A\x58\x5A', re.DOTALL) PAT_DELL_PKG = re.compile(br'\x72\x13\x55\x00.{45}\x37\x7A\x58\x5A', re.DOTALL)
PAT_DELL_HDR = re.compile(br'\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.\x78\x9C', re.DOTALL) PAT_DELL_HDR = re.compile(br'\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.\x78\x9C', re.DOTALL)
PAT_DELL_FTR = re.compile(br'\xEE\xAA\xEE\x8F\x49\x1B\xE8\xAE\x14\x37\x90') PAT_DELL_FTR = re.compile(br'\xEE\xAA\xEE\x8F\x49\x1B\xE8\xAE\x14\x37\x90')