BIOSUtilities/AMI_UCP_Extract.py

571 lines
22 KiB
Python
Raw Normal View History

#!/usr/bin/env python3 -B
# coding=utf-8
"""
AMI UCP Extract
AMI UCP Update Extractor
Copyright (C) 2021-2024 Plato Mavropoulos
"""
import contextlib
import ctypes
import os
import re
import struct
from common.checksums import get_chk_16
from common.comp_efi import efi_decompress, is_efi_compressed
from common.path_ops import agnostic_path, get_extract_path, make_dirs, safe_name, safe_path
from common.patterns import PAT_AMI_UCP, PAT_INTEL_ENG
from common.struct_ops import Char, get_struct, UInt8, UInt16, UInt32
from common.system import printer
from common.templates import BIOSUtility
from common.text_ops import file_to_bytes, to_string
from AMI_PFAT_Extract import is_ami_pfat, parse_pfat_file
from Insyde_IFD_Extract import insyde_ifd_extract, is_insyde_ifd
TITLE = 'AMI UCP Update Extractor v3.0'
class UafHeader(ctypes.LittleEndianStructure):
""" UAF Header """
_pack_ = 1
_fields_ = [
('ModuleTag', Char * 4), # 0x00
('ModuleSize', UInt32), # 0x04
('Checksum', UInt16), # 0x08
('Unknown0', UInt8), # 0x0A
('Unknown1', UInt8), # 0x0A
('Reserved', UInt8 * 4), # 0x0C
# 0x10
]
def _get_reserved(self):
res_bytes = bytes(self.Reserved)
res_hex = f'0x{int.from_bytes(res_bytes, "big"):0{0x4 * 2}X}'
res_str = re.sub(r'[\n\t\r\x00 ]', '', res_bytes.decode('utf-8', 'ignore'))
res_txt = f' ({res_str})' if len(res_str) else ''
return f'{res_hex}{res_txt}'
def struct_print(self, padd):
""" Display structure information """
printer(['Tag :', self.ModuleTag.decode('utf-8')], padd, False)
printer(['Size :', f'0x{self.ModuleSize:X}'], padd, False)
printer(['Checksum :', f'0x{self.Checksum:04X}'], padd, False)
printer(['Unknown 0 :', f'0x{self.Unknown0:02X}'], padd, False)
printer(['Unknown 1 :', f'0x{self.Unknown1:02X}'], padd, False)
printer(['Reserved :', self._get_reserved()], padd, False)
class UafModule(ctypes.LittleEndianStructure):
""" UAF Module """
_pack_ = 1
_fields_ = [
('CompressSize', UInt32), # 0x00
('OriginalSize', UInt32), # 0x04
# 0x08
]
def struct_print(self, padd, filename, description):
""" Display structure information """
printer(['Compress Size:', f'0x{self.CompressSize:X}'], padd, False)
printer(['Original Size:', f'0x{self.OriginalSize:X}'], padd, False)
printer(['Filename :', filename], padd, False)
printer(['Description :', description], padd, False)
class UiiHeader(ctypes.LittleEndianStructure):
""" UII Header """
_pack_ = 1
_fields_ = [
('UIISize', UInt16), # 0x00
('Checksum', UInt16), # 0x02
('UtilityVersion', UInt32), # 0x04 AFU|BGT (Unknown, Signed)
('InfoSize', UInt16), # 0x08
('SupportBIOS', UInt8), # 0x0A
('SupportOS', UInt8), # 0x0B
('DataBusWidth', UInt8), # 0x0C
('ProgramType', UInt8), # 0x0D
('ProgramMode', UInt8), # 0x0E
('SourceSafeRel', UInt8), # 0x0F
# 0x10
]
SBI = {1: 'ALL', 2: 'AMIBIOS8', 3: 'UEFI', 4: 'AMIBIOS8/UEFI'}
SOS = {1: 'DOS', 2: 'EFI', 3: 'Windows', 4: 'Linux', 5: 'FreeBSD', 6: 'MacOS', 128: 'Multi-Platform'}
DBW = {1: '16b', 2: '16/32b', 3: '32b', 4: '64b'}
PTP = {1: 'Executable', 2: 'Library', 3: 'Driver'}
PMD = {1: 'API', 2: 'Console', 3: 'GUI', 4: 'Console/GUI'}
def struct_print(self, padd, description):
""" Display structure information """
support_bios = self.SBI.get(self.SupportBIOS, f'Unknown ({self.SupportBIOS})')
support_os = self.SOS.get(self.SupportOS, f'Unknown ({self.SupportOS})')
data_bus_width = self.DBW.get(self.DataBusWidth, f'Unknown ({self.DataBusWidth})')
program_type = self.PTP.get(self.ProgramType, f'Unknown ({self.ProgramType})')
program_mode = self.PMD.get(self.ProgramMode, f'Unknown ({self.ProgramMode})')
printer(['UII Size :', f'0x{self.UIISize:X}'], padd, False)
printer(['Checksum :', f'0x{self.Checksum:04X}'], padd, False)
printer(['Tool Version :', f'0x{self.UtilityVersion:08X}'], padd, False)
printer(['Info Size :', f'0x{self.InfoSize:X}'], padd, False)
printer(['Supported BIOS:', support_bios], padd, False)
printer(['Supported OS :', support_os], padd, False)
printer(['Data Bus Width:', data_bus_width], padd, False)
printer(['Program Type :', program_type], padd, False)
printer(['Program Mode :', program_mode], padd, False)
printer(['SourceSafe Tag:', f'{self.SourceSafeRel:02d}'], padd, False)
printer(['Description :', description], padd, False)
class DisHeader(ctypes.LittleEndianStructure):
""" DIS Header """
_pack_ = 1
_fields_ = [
('PasswordSize', UInt16), # 0x00
('EntryCount', UInt16), # 0x02
('Password', Char * 12), # 0x04
# 0x10
]
def struct_print(self, padd):
""" Display structure information """
printer(['Password Size:', f'0x{self.PasswordSize:X}'], padd, False)
printer(['Entry Count :', self.EntryCount], padd, False)
printer(['Password :', self.Password.decode('utf-8')], padd, False)
class DisModule(ctypes.LittleEndianStructure):
""" DIS Module """
_pack_ = 1
_fields_ = [
('EnabledDisabled', UInt8), # 0x00
('ShownHidden', UInt8), # 0x01
('Command', Char * 32), # 0x02
('Description', Char * 256), # 0x22
# 0x122
]
ENDIS = {0: 'Disabled', 1: 'Enabled'}
SHOWN = {0: 'Hidden', 1: 'Shown', 2: 'Shown Only'}
def struct_print(self, padd):
""" Display structure information """
enabled_disabled = self.ENDIS.get(self.EnabledDisabled, f'Unknown ({self.EnabledDisabled})')
shown_hidden = self.SHOWN.get(self.ShownHidden, f'Unknown ({self.ShownHidden})')
printer(['State :', enabled_disabled], padd, False)
printer(['Display :', shown_hidden], padd, False)
printer(['Command :', self.Command.decode('utf-8').strip()], padd, False)
printer(['Description:', self.Description.decode('utf-8').strip()], padd, False)
def chk16_validate(data, tag, padd=0):
""" Validate UCP Module Checksum-16 """
if get_chk_16(data) != 0:
printer(f'Error: Invalid UCP Module {tag} Checksum!', padd, pause=True)
else:
printer(f'Checksum of UCP Module {tag} is valid!', padd)
def is_ami_ucp(in_file):
""" Check if input is AMI UCP image """
buffer = file_to_bytes(in_file)
return bool(get_ami_ucp(buffer)[0] is not None)
def get_ami_ucp(in_file):
""" Get all input file AMI UCP patterns """
buffer = file_to_bytes(in_file)
uaf_len_max = 0x0 # Length 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
for uaf in PAT_AMI_UCP.finditer(buffer):
uaf_len_cur = int.from_bytes(buffer[uaf.start() + 0x4:uaf.start() + 0x8], 'little')
if uaf_len_cur > uaf_len_max:
uaf_len_max = uaf_len_cur
uaf_hdr_off = uaf.start()
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_buf_bin, uaf_buf_tag
def get_uaf_mod(buffer, uaf_off=0x0):
""" Get list of @UAF|@HPU Modules """
uaf_all = [] # Initialize list of all @UAF|@HPU Modules
while buffer[uaf_off] == 0x40: # ASCII of @ is 0x40
uaf_hdr = get_struct(buffer, uaf_off, UafHeader) # Parse @UAF|@HPU Module Structure
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|@HPU Module Info
uaf_off += uaf_hdr.ModuleSize # Adjust to next @UAF|@HPU Module offset
if uaf_off >= len(buffer):
break # Stop parsing at EOF
# Check if @UAF|@HPU Module @NAL exists and place it first
# Parsing @NAL first allows naming all @UAF|@HPU Modules
for mod_idx, mod_val in enumerate(uaf_all):
if mod_val[0] == '@NAL':
uaf_all.insert(1, uaf_all.pop(mod_idx)) # After UII for visual purposes
break # @NAL found, skip the rest
return uaf_all
def ucp_extract(in_file, extract_path, padding=0, checksum=False):
""" Parse & Extract AMI UCP structures """
input_buffer = file_to_bytes(in_file)
nal_dict = {} # Initialize @NAL Dictionary per UCP
printer('Utility Configuration Program', padding)
make_dirs(extract_path, delete=True)
# 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)
uaf_hdr.struct_print(padding + 8)
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_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
uaf_mod.struct_print(padding + 8, uaf_name, uaf_desc) # Print @UAF|@HPU Module EFI Info
if checksum:
chk16_validate(ucp_buffer, ucp_tag, padding + 8)
uaf_all = get_uaf_mod(ucp_buffer, UAF_HDR_LEN)
for mod_info in uaf_all:
nal_dict = uaf_extract(ucp_buffer, extract_path, mod_info, padding + 8, checksum, nal_dict)
def uaf_extract(buffer, extract_path, mod_info, padding=0, checksum=False, nal_dict=None):
""" Parse & Extract AMI UCP > @UAF|@HPU Module/Section """
if nal_dict is None:
nal_dict = {}
uaf_tag, uaf_off, uaf_hdr = mod_info
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|@HPU Module EFI Data
uaf_data_raw = uaf_data_mod[UAF_MOD_LEN:] # @UAF|@HPU Module Raw Data
printer(f'Utility Auxiliary File > {uaf_tag}:\n', padding)
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
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
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.startswith('@R0'):
uaf_name = f'BIOS_0{uaf_tag[3:]}.bin' # BIOS/PFAT Firmware
elif uaf_tag.startswith('@S0'):
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_fdesc = UAF_TAG_DICT[uaf_tag][1] if uaf_tag in UAF_TAG_DICT else uaf_name
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')):
printer(f'Note: Detected new AMI UCP Module {uaf_tag} ({nal_dict[uaf_tag][1]}) in @NAL!',
padding + 4, pause=True)
# Generate @UAF|@HPU Module File name, depending on whether decompression will be required
uaf_sname = safe_name(uaf_name + ('.temp' if is_comp else uaf_fext))
if uaf_tag in nal_dict:
uaf_npath = safe_path(extract_path, nal_dict[uaf_tag][0])
make_dirs(uaf_npath, exist_ok=True)
uaf_fname = safe_path(uaf_npath, uaf_sname)
else:
uaf_fname = safe_path(extract_path, uaf_sname)
if checksum:
chk16_validate(uaf_data_all, uaf_tag, padding + 4)
# Parse Utility Identification Information @UAF|@HPU Module (@UII)
if uaf_tag == '@UII':
info_hdr = get_struct(uaf_data_raw, 0, UiiHeader) # Parse @UII Module Raw Structure
info_data = uaf_data_raw[max(UII_HDR_LEN, info_hdr.InfoSize):info_hdr.UIISize] # @UII Module Info Data
# Get @UII Module Info/Description text field
info_desc = info_data.decode('utf-8', 'ignore').strip('\x00 ')
printer('Utility Identification Information:\n', padding + 4)
info_hdr.struct_print(padding + 8, info_desc) # Print @UII Module Info
if checksum:
chk16_validate(uaf_data_raw, '@UII > Info', padding + 8)
# Store/Save @UII Module Info in file
with open(uaf_fname[:-4] + '.txt', 'a', encoding='utf-8') as uii_out:
with contextlib.redirect_stdout(uii_out):
info_hdr.struct_print(0, info_desc) # Store @UII Module Info
# Adjust @UAF|@HPU Module Raw Data for extraction
if is_comp:
# Some Compressed @UAF|@HPU Module EFI data lack necessary EOF padding
if uaf_mod.CompressSize > len(uaf_data_raw):
comp_padd = b'\x00' * (uaf_mod.CompressSize - len(uaf_data_raw))
# Add missing padding for decompression
uaf_data_raw = uaf_data_mod[:UAF_MOD_LEN] + uaf_data_raw + comp_padd
else:
# Add the EFI/Tiano Compression info before Raw Data
uaf_data_raw = uaf_data_mod[:UAF_MOD_LEN] + uaf_data_raw
else:
# No compression, extend to end of Original @UAF|@HPU Module size
uaf_data_raw = uaf_data_raw[:uaf_mod.OriginalSize]
# Store/Save @UAF|@HPU Module file
if uaf_tag != '@UII': # Skip @UII binary, already parsed
with open(uaf_fname, 'wb') as uaf_out:
uaf_out.write(uaf_data_raw)
# @UAF|@HPU Module EFI/Tiano Decompression
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
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
os.remove(uaf_fname) # Successful decompression, delete compressed @UAF|@HPU Module file
uaf_fname = dec_fname # Adjust @UAF|@HPU Module file path to the decompressed one
# 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':
printer(f'{UAF_TAG_DICT[uaf_tag][1]}:', padding + 4)
printer(uaf_data_raw.decode('utf-8', 'ignore'), padding + 8)
# Parse Default Command Status @UAF|@HPU Module (@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
printer('Default Command Status Header:\n', padding + 4)
dis_hdr.struct_print(padding + 8) # Print @DIS Module Raw Header Info
# Store/Save @DIS Module Header Info in file
with open(uaf_fname[:-3] + 'txt', 'a', encoding='utf-8') as dis:
with contextlib.redirect_stdout(dis):
dis_hdr.struct_print(0) # Store @DIS Module Header Info
dis_data = uaf_data_raw[DIS_HDR_LEN:] # @DIS Module Entries Data
# Parse all @DIS Module Entries
for mod_idx in range(dis_hdr.EntryCount):
dis_mod = get_struct(dis_data, mod_idx * DIS_MOD_LEN, DisModule) # Parse @DIS Module Raw Entry Structure
printer(f'Default Command Status Entry {mod_idx + 1:02d}/{dis_hdr.EntryCount:02d}:\n', padding + 8)
dis_mod.struct_print(padding + 12) # Print @DIS Module Raw Entry Info
# Store/Save @DIS Module Entry Info in file
with open(uaf_fname[:-3] + 'txt', 'a', encoding='utf-8') as dis:
with contextlib.redirect_stdout(dis):
printer()
dis_mod.struct_print(4) # Store @DIS Module Entry Info
os.remove(uaf_fname) # Delete @DIS Module binary, info exported as text
# 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):
nal_info = uaf_data_raw.decode('utf-8', 'ignore').replace('\r', '').strip().split('\n')
printer('AMI UCP Module Name List:\n', padding + 4)
# Parse all @NAL Module Entries
for info in nal_info:
info_tag, info_value = info.split(':', 1)
printer(f'{info_tag} : {info_value}', padding + 8, False) # Print @NAL Module Tag-Path Info
info_part = agnostic_path(info_value).parts # Split OS agnostic path in parts
info_path = to_string(info_part[1:-1], os.sep) # Get path without drive/root or file
info_name = info_part[-1] # Get file from last path part
nal_dict[info_tag] = (info_path, info_name) # Assign a file path & name to each Tag
# Parse Insyde BIOS @UAF|@HPU Module (@INS)
if uaf_tag == '@INS' and is_insyde_ifd(uaf_fname):
ins_dir = os.path.join(extract_path, safe_name(f'{uaf_tag}_nested-IFD')) # Generate extraction directory
if insyde_ifd_extract(uaf_fname, get_extract_path(ins_dir), padding + 4) == 0:
os.remove(uaf_fname) # Delete raw nested Insyde IFD image after successful extraction
# Detect & Unpack AMI BIOS Guard (PFAT) BIOS image
if is_ami_pfat(uaf_data_raw):
pfat_dir = os.path.join(extract_path, safe_name(uaf_name))
parse_pfat_file(uaf_data_raw, get_extract_path(pfat_dir), padding + 4)
os.remove(uaf_fname) # Delete raw PFAT BIOS image after successful extraction
# Detect Intel Engine firmware image and show ME Analyzer advice
if uaf_tag.startswith('@ME') and PAT_INTEL_ENG.search(uaf_data_raw):
printer('Intel Management Engine (ME) Firmware:\n', padding + 4)
printer('Use "ME Analyzer" from https://github.com/platomav/MEAnalyzer', padding + 8, False)
# Parse Nested AMI UCP image
if is_ami_ucp(uaf_data_raw):
uaf_dir = os.path.join(extract_path, safe_name(f'{uaf_tag}_nested-UCP')) # Generate extraction directory
ucp_extract(uaf_data_raw, get_extract_path(uaf_dir), padding + 4, checksum) # Call recursively
os.remove(uaf_fname) # Delete raw nested AMI UCP image after successful extraction
return nal_dict
# Get common ctypes Structure Sizes
UAF_HDR_LEN = ctypes.sizeof(UafHeader)
UAF_MOD_LEN = ctypes.sizeof(UafModule)
DIS_HDR_LEN = ctypes.sizeof(DisHeader)
DIS_MOD_LEN = ctypes.sizeof(DisModule)
UII_HDR_LEN = ctypes.sizeof(UiiHeader)
# AMI UCP Tag Dictionary
UAF_TAG_DICT = {
'@3FI': ['HpBiosUpdate32.efi', 'HpBiosUpdate32.efi', ''],
'@3S2': ['HpBiosUpdate32.s12', 'HpBiosUpdate32.s12', ''],
'@3S4': ['HpBiosUpdate32.s14', 'HpBiosUpdate32.s14', ''],
'@3S9': ['HpBiosUpdate32.s09', 'HpBiosUpdate32.s09', ''],
'@3SG': ['HpBiosUpdate32.sig', 'HpBiosUpdate32.sig', ''],
'@AMI': ['UCP_Nested.bin', 'Nested AMI UCP', ''],
'@B12': ['BiosMgmt.s12', 'BiosMgmt.s12', ''],
'@B14': ['BiosMgmt.s14', 'BiosMgmt.s14', ''],
'@B32': ['BiosMgmt32.s12', 'BiosMgmt32.s12', ''],
'@B34': ['BiosMgmt32.s14', 'BiosMgmt32.s14', ''],
'@B39': ['BiosMgmt32.s09', 'BiosMgmt32.s09', ''],
'@B3E': ['BiosMgmt32.efi', 'BiosMgmt32.efi', ''],
'@BM9': ['BiosMgmt.s09', 'BiosMgmt.s09', ''],
'@BME': ['BiosMgmt.efi', 'BiosMgmt.efi', ''],
'@CKV': ['Check_Version.txt', 'Check Version', 'Text'],
'@CMD': ['AFU_Command.txt', 'AMI AFU Command', 'Text'],
'@CML': ['CMOSD4.txt', 'CMOS Item Number-Value (MSI)', 'Text'],
'@CMS': ['CMOSD4.exe', 'Get or Set CMOS Item (MSI)', ''],
'@CPM': ['AC_Message.txt', 'Confirm Power Message', ''],
'@DCT': ['DevCon32.exe', 'Device Console WIN32', ''],
'@DCX': ['DevCon64.exe', 'Device Console WIN64', ''],
'@DFE': ['HpDevFwUpdate.efi', 'HpDevFwUpdate.efi', ''],
'@DFS': ['HpDevFwUpdate.s12', 'HpDevFwUpdate.s12', ''],
'@DIS': ['Command_Status.bin', 'Default Command Status', ''],
'@ENB': ['ENBG64.exe', 'ENBG64.exe', ''],
'@HPU': ['UCP_Main.bin', 'Utility Auxiliary File (HP)', ''],
'@INS': ['Insyde_Nested.bin', 'Nested Insyde SFX', ''],
'@M32': ['HpBiosMgmt32.s12', 'HpBiosMgmt32.s12', ''],
'@M34': ['HpBiosMgmt32.s14', 'HpBiosMgmt32.s14', ''],
'@M39': ['HpBiosMgmt32.s09', 'HpBiosMgmt32.s09', ''],
'@M3I': ['HpBiosMgmt32.efi', 'HpBiosMgmt32.efi', ''],
'@MEC': ['FWUpdLcl.txt', 'Intel FWUpdLcl Command', 'Text'],
'@MED': ['FWUpdLcl_DOS.exe', 'Intel FWUpdLcl DOS', ''],
'@MET': ['FWUpdLcl_WIN32.exe', 'Intel FWUpdLcl WIN32', ''],
'@MFI': ['HpBiosMgmt.efi', 'HpBiosMgmt.efi', ''],
'@MS2': ['HpBiosMgmt.s12', 'HpBiosMgmt.s12', ''],
'@MS4': ['HpBiosMgmt.s14', 'HpBiosMgmt.s14', ''],
'@MS9': ['HpBiosMgmt.s09', 'HpBiosMgmt.s09', ''],
'@NAL': ['UCP_List.txt', 'AMI UCP Module Name List', ''],
'@OKM': ['OK_Message.txt', 'OK Message', ''],
'@PFC': ['BGT_Command.txt', 'AMI BGT Command', 'Text'],
'@R3I': ['CryptRSA32.efi', 'CryptRSA32.efi', ''],
'@RFI': ['CryptRSA.efi', 'CryptRSA.efi', ''],
'@UAF': ['UCP_Main.bin', 'Utility Auxiliary File (AMI)', ''],
'@UFI': ['HpBiosUpdate.efi', 'HpBiosUpdate.efi', ''],
'@UII': ['UCP_Info.txt', 'Utility Identification Information', ''],
'@US2': ['HpBiosUpdate.s12', 'HpBiosUpdate.s12', ''],
'@US4': ['HpBiosUpdate.s14', 'HpBiosUpdate.s14', ''],
'@US9': ['HpBiosUpdate.s09', 'HpBiosUpdate.s09', ''],
'@USG': ['HpBiosUpdate.sig', 'HpBiosUpdate.sig', ''],
'@VER': ['OEM_Version.txt', 'OEM Version', 'Text'],
'@VXD': ['amifldrv.vxd', 'amifldrv.vxd', ''],
'@W32': ['amifldrv32.sys', 'amifldrv32.sys', ''],
'@W64': ['amifldrv64.sys', 'amifldrv64.sys', ''],
'@D64': ['amifldrv64.sys', 'amifldrv64.sys', ''],
}
if __name__ == '__main__':
utility_args = [(['-c', '--checksum'], {'help': 'verify AMI UCP Checksums (slow)', 'action': 'store_true'})]
utility = BIOSUtility(title=TITLE, check=is_ami_ucp, main=ucp_extract, args=utility_args)
utility.run_utility()