From 70844b0a2401437bb44b55884cd580ce434e46c2 Mon Sep 17 00:00:00 2001 From: Plato Mavropoulos Date: Tue, 19 Jan 2021 16:30:19 +0200 Subject: [PATCH] AMI BIOS Guard Extractor v3.2 Each input file name is now shown at the top Each output file now includes the input file name Applied a few small static analysis code fixes --- AMI BIOS Guard Extractor/AMI_PFAT_Extract.py | 102 ++++++++++--------- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/AMI BIOS Guard Extractor/AMI_PFAT_Extract.py b/AMI BIOS Guard Extractor/AMI_PFAT_Extract.py index b1a6da4..bd1a1f0 100644 --- a/AMI BIOS Guard Extractor/AMI_PFAT_Extract.py +++ b/AMI BIOS Guard Extractor/AMI_PFAT_Extract.py @@ -7,7 +7,7 @@ AMI BIOS Guard Extractor Copyright (C) 2018-2021 Plato Mavropoulos """ -print('AMI BIOS Guard Extractor v3.1') +print('AMI BIOS Guard Extractor v3.2') import sys @@ -15,7 +15,7 @@ import sys sys_ver = sys.version_info if sys_ver < (3,7) : sys.stdout.write('\n\nError: Python >= 3.7 required, not %d.%d!\n' % (sys_ver[0], sys_ver[1])) - (raw_input if sys_ver[0] <= 2 else input)('\nPress enter to exit') + (raw_input if sys_ver[0] <= 2 else input)('\nPress enter to exit') # pylint: disable=E0602 sys.exit(1) import os @@ -64,11 +64,11 @@ class PFAT_Header(ctypes.LittleEndianStructure) : ] def pfat_print(self) : - print('\nPFAT Main Header:\n') - print(' Size : 0x%X' % self.Size) - print(' Checksum : 0x%0.4X' % self.Checksum) - print(' Tag : %s' % self.Tag.decode('utf-8')) - print(' Flags : 0x%0.2X' % self.Flags) + print('\n PFAT Main Header:\n') + print(' Size : 0x%X' % self.Size) + print(' Checksum : 0x%0.4X' % self.Checksum) + print(' Tag : %s' % self.Tag.decode('utf-8')) + print(' Flags : 0x%0.2X' % self.Flags) class PFAT_Block_Header(ctypes.LittleEndianStructure) : _pack_ = 1 @@ -108,20 +108,20 @@ class PFAT_Block_Header(ctypes.LittleEndianStructure) : PlatformID = '%0.*X' % (0x10 * 2, int.from_bytes(self.PlatformID, 'big')) PlatformID = '{%s-%s-%s-%s-%s}' % (PlatformID[:8], PlatformID[8:12], PlatformID[12:16], PlatformID[16:20], PlatformID[20:]) - print('\n PFAT Block %s Header:\n' % self.count) - print(' PFAT Version : %d.%d' % (self.PFATVerMajor, self.PFATVerMinor)) - print(' Platform ID : %s' % PlatformID) - print(' Signed Flash Address Map : %s' % no_yes[f1]) - print(' Protected EC OpCodes : %s' % no_yes[f2]) - print(' Graphics Security Disable : %s' % no_yes[f3]) - print(' Fault Tolerant Update : %s' % no_yes[f4]) - print(' Attributes Reserved : 0x%X' % f5) - print(' Script Version : %d.%d' % (self.ScriptVerMajor, self.ScriptVerMinor)) - print(' Script Size : 0x%X' % self.ScriptSize) - print(' Data Size : 0x%X' % self.DataSize) - print(' BIOS SVN : 0x%X' % self.BIOSSVN) - print(' EC SVN : 0x%X' % self.ECSVN) - print(' Vendor Info : 0x%X' % self.VendorInfo) + print('\n PFAT Block %s Header:\n' % self.count) + print(' PFAT Version : %d.%d' % (self.PFATVerMajor, self.PFATVerMinor)) + print(' Platform ID : %s' % PlatformID) + print(' Signed Flash Address Map : %s' % no_yes[f1]) + print(' Protected EC OpCodes : %s' % no_yes[f2]) + print(' Graphics Security Disable : %s' % no_yes[f3]) + print(' Fault Tolerant Update : %s' % no_yes[f4]) + print(' Attributes Reserved : 0x%X' % f5) + print(' Script Version : %d.%d' % (self.ScriptVerMajor, self.ScriptVerMinor)) + print(' Script Size : 0x%X' % self.ScriptSize) + print(' Data Size : 0x%X' % self.DataSize) + print(' BIOS SVN : 0x%X' % self.BIOSSVN) + print(' EC SVN : 0x%X' % self.ECSVN) + print(' Vendor Info : 0x%X' % self.VendorInfo) class PFAT_Block_Header_Attributes(ctypes.LittleEndianStructure): _fields_ = [ @@ -157,12 +157,12 @@ class PFAT_Block_RSA(ctypes.LittleEndianStructure) : PublicKey = '%0.*X' % (0x100 * 2, int.from_bytes(self.PublicKey, 'little')) Signature = '%0.*X' % (0x100 * 2, int.from_bytes(self.Signature, 'little')) - print('\n PFAT Block %s Signature:\n' % self.count) - print(' Unknown 0 : 0x%X' % self.Unknown0) - print(' Unknown 1 : 0x%X' % self.Unknown1) - print(' Public Key : %s [...]' % PublicKey[:8]) - print(' Exponent : 0x%X' % self.Exponent) - print(' Signature : %s [...]' % Signature[:8]) + print('\n PFAT Block %s Signature:\n' % self.count) + print(' Unknown 0 : 0x%X' % self.Unknown0) + print(' Unknown 1 : 0x%X' % self.Unknown1) + print(' Public Key : %s [...]' % PublicKey[:8]) + print(' Exponent : 0x%X' % self.Exponent) + print(' Signature : %s [...]' % Signature[:8]) # 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) : @@ -174,7 +174,7 @@ def get_struct(buffer, start_offset, class_name, param_list = None) : fit_len = min(len(struct_data), struct_len) if (start_offset >= len(buffer)) or (fit_len < struct_len) : - input('\nError: Offset 0x%X out of bounds at %s, possibly incomplete image!' % (start_offset, class_name.__name__)) + input('\n Error: Offset 0x%X out of bounds at %s, possibly incomplete image!' % (start_offset, class_name.__name__)) sys.exit(1) ctypes.memmove(ctypes.addressof(structure), struct_data, fit_len) @@ -189,20 +189,19 @@ else : ami_pfat = [] in_path = input('\nEnter the full folder path: ') print('\nWorking...') - for root, dirs, files in os.walk(in_path): + for root, _, files in os.walk(in_path): for name in files : ami_pfat.append(os.path.join(root, name)) pfat_index = 1 +input_name = '' +input_extension = '' output_path = '' block_hdr_size = ctypes.sizeof(PFAT_Block_Header) block_rsa_size = ctypes.sizeof(PFAT_Block_RSA) pfat_pat = re.compile(b'_AMIPFAT.AMI_BIOS_GUARD_FLASH_CONFIGURATIONS', re.DOTALL) for input_file in ami_pfat : - input_name,input_extension = os.path.splitext(os.path.basename(input_file)) - input_dir = os.path.dirname(os.path.abspath(input_file)) - file_data = b'' final_data = b'' block_name = '' @@ -214,6 +213,22 @@ for input_file in ami_pfat : pfat_match = pfat_pat.search(buffer) + if pfat_index == 1 : + input_name,input_extension = os.path.splitext(os.path.basename(input_file)) + input_dir = os.path.dirname(os.path.abspath(input_file)) + + print('\n*** %s%s' % (input_name, input_extension)) + + if not pfat_match : + print('\n Error: This is not an AMI BIOS Guard (PFAT) image!') + continue + + output_path = os.path.join(input_dir, '%s%s' % (input_name, input_extension) + '_extracted') # Set extraction directory + + if os.path.isdir(output_path) : shutil.rmtree(output_path) # Delete any existing extraction directory + + os.mkdir(output_path) # Create extraction directory + if not pfat_match : continue buffer = buffer[pfat_match.start() - 0x8:] @@ -224,16 +239,9 @@ for input_file in ami_pfat : hdr_data = buffer[0x11:hdr_size].decode('utf-8').splitlines() pfat_hdr.pfat_print() - print(' Title : %s' % hdr_data[0]) - - if pfat_index == 1 : - output_path = os.path.join(input_dir, '%s%s' % (input_name, input_extension) + '_extracted') # Set extraction directory + print(' Title : %s' % hdr_data[0]) - if os.path.isdir(output_path) : shutil.rmtree(output_path) # Delete any existing extraction directory - - os.mkdir(output_path) # Create extraction directory - - file_path = os.path.join(output_path, '%d' % pfat_index) + file_path = os.path.join(output_path, '%s%s -- %d' % (input_name, input_extension, pfat_index)) for entry in hdr_data[1:] : entry_data = entry.split(' ') @@ -251,7 +259,7 @@ for input_file in ami_pfat : for i in range(block_count) : is_file_start = blocks[i][0] != block_name - if is_file_start : print('\n %s (Parameter: %s, Flags: 0x%X)' % (blocks[i][0], blocks[i][1], blocks[i][2])) + if is_file_start : print('\n %s (Parameter: %s, Flags: 0x%X)' % (blocks[i][0], blocks[i][1], blocks[i][2])) block_hdr = get_struct(buffer, block_start, PFAT_Block_Header, ['%d/%d' % (blocks[i][3], blocks[i][4])]) block_hdr.pfat_print() @@ -265,22 +273,22 @@ for input_file in ami_pfat : block_rsa = get_struct(buffer, block_data_end, PFAT_Block_RSA, ['%d/%d' % (blocks[i][3], blocks[i][4])]) block_rsa.pfat_print() - print('\n PFAT Block %d/%d Script:\n' % (blocks[i][3], blocks[i][4])) + print('\n PFAT Block %d/%d Script:\n' % (blocks[i][3], blocks[i][4])) is_opcode_div = len(block_script_data) % 8 == 0 is_begin_end = block_script_data[:8] + block_script_data[-8:] == b'\x01' + b'\x00' * 7 + b'\xFF' + b'\x00' * 7 if is_opcode_div and is_begin_end and is_bgst : block_script_decomp = BigScript(code_bytes=block_script_data) block_script_lines = block_script_decomp.to_string().replace('\t',' ').split('\n') for line in block_script_lines : - spacing = ' ' * 12 if line.endswith(('begin','end',':')) else ' ' * 20 + spacing = ' ' * 16 if line.endswith(('begin','end',':')) else ' ' * 24 operands = [op for op in line.split(' ') if op != ''] print(spacing + ('{:<12s}' + '{:<11s}' * (len(operands) - 1)).format(*operands)) elif not is_opcode_div : - print(' Error: Script not divisible by OpCode length!') + print(' Error: Script not divisible by OpCode length!') elif not is_begin_end : - print(' Error: Script lacks Begin and/or End OpCodes!') + print(' Error: Script lacks Begin and/or End OpCodes!') elif not is_bgst : - print(' Error: BIOS Guard Script Tool dependency missing!') + print(' Error: BIOS Guard Script Tool dependency missing!') file_data += block_data final_data += block_data