From d702d7f8a8b36a0e3bb3e8a4cb745e442a50a93b Mon Sep 17 00:00:00 2001 From: Plato Mavropoulos Date: Sat, 13 Oct 2018 23:48:34 +0300 Subject: [PATCH] Added AMI BIOS Guard Extractor Parses AMI BIOS Guard (a.k.a. PFAT) images and extracts a proper SPI/BIOS image. --- AMI BIOS Guard Extractor/AMI_PFAT_Extract.py | 185 +++++++++++++++++++ README.md | 44 ++++- 2 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 AMI BIOS Guard Extractor/AMI_PFAT_Extract.py diff --git a/AMI BIOS Guard Extractor/AMI_PFAT_Extract.py b/AMI BIOS Guard Extractor/AMI_PFAT_Extract.py new file mode 100644 index 0000000..e3fc6f1 --- /dev/null +++ b/AMI BIOS Guard Extractor/AMI_PFAT_Extract.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 + +""" +AMI PFAT Extract +AMI BIOS Guard Extractor +Copyright (C) 2018 Plato Mavropoulos +""" + +print('AMI BIOS Guard Extractor v1.0') + +import os +import sys +import ctypes +import struct + +# Set ctypes Structure types +char = ctypes.c_char +uint8_t = ctypes.c_ubyte +uint16_t = ctypes.c_ushort +uint32_t = ctypes.c_uint +uint64_t = ctypes.c_uint64 + +# noinspection PyTypeChecker +class PFAT_Header(ctypes.LittleEndianStructure) : + _pack_ = 1 + _fields_ = [ + ('Size', uint32_t), # 0x00 + ('Validation', uint32_t), # 0x04 Unknown 16-bit Checksum ? + ('Tag', char*8), # 0x04 _AMIPFAT + ('Control', uint8_t), # 0x10 0x4 + # 0x11 + ] + + def pfat_print(self) : + print('\nPFAT Main Header:\n') + print(' Size : 0x%X' % self.Size) + print(' Validation : 0x%X' % self.Validation) + print(' Tag : %s' % self.Tag.decode('utf-8')) + print(' Control : 0x%X' % self.Control) + +# noinspection PyTypeChecker +class PFAT_Block_Header(ctypes.LittleEndianStructure) : + _pack_ = 1 + _fields_ = [ + ('Revision', uint32_t), # 0x00 PFAT + ('Platform', char*16), # 0x04 + ('Unknown0', uint32_t), # 0x14 + ('Unknown1', uint32_t), # 0x18 + ('FlagsSize', uint32_t), # 0x1C From Block Header end + ('DataSize', uint32_t), # 0x20 From Block Flags end + ('Unknown2', uint32_t), # 0x24 + ('Unknown3', uint32_t), # 0x28 + ('Unknown4', uint32_t), # 0x2C + # 0x30 + ] + + def __init__(self, count, *args, **kwargs): + super().__init__(*args, **kwargs) + self.count = count + + def pfat_print(self) : + print('\n PFAT Block %s Header:\n' % self.count) + print(' Revision : %d' % self.Revision) + print(' Platform : %s' % self.Platform.decode('utf-8')) + print(' Unknown 0 : 0x%X' % self.Unknown0) + print(' Unknown 1 : 0x%X' % self.Unknown1) + print(' Flags Size : 0x%X' % self.FlagsSize) + print(' Data Size : 0x%X' % self.DataSize) + print(' Unknown 2 : 0x%X' % self.Unknown2) + print(' Unknown 3 : 0x%X' % self.Unknown3) + print(' Unknown 4 : 0x%X' % self.Unknown4) + +# noinspection PyTypeChecker +class PFAT_Block_RSA(ctypes.LittleEndianStructure) : + _pack_ = 1 + _fields_ = [ + ('Unknown0', uint32_t), # 0x00 + ('Unknown1', uint32_t), # 0x04 + ('PublicKey', uint32_t*64), # 0x08 + ('Exponent', uint32_t), # 0x108 + ('Signature', uint32_t*64), # 0x10C + # 0x20C + ] + + def __init__(self, count, *args, **kwargs): + super().__init__(*args, **kwargs) + self.count = count + + def pfat_print(self) : + RSAPublicKey = ''.join('%0.8X' % int.from_bytes(struct.pack('= len(buffer)) or (fit_len < struct_len) : + print('Error: Offset 0x%X out of bounds at %s, possibly incomplete image!' % (start_offset, class_name)) + sys.exit(1) + + ctypes.memmove(ctypes.addressof(structure), struct_data, fit_len) + + return structure + +if len(sys.argv) >= 2 : + # Drag & Drop or CLI + pfat = sys.argv[1:] +else : + # Folder path + pfat = [] + in_path = input('\nEnter the full folder path: ') + print('\nWorking...') + for root, dirs, files in os.walk(in_path): + for name in files : + pfat.append(os.path.join(root, name)) + +for input_file in pfat : + with open(input_file, 'rb') as in_file : buffer = in_file.read() + final_image = b'' + block_name = '' + block_count = 0 + blocks = [] + + pfat_hdr = get_struct(buffer, 0, PFAT_Header) + + if pfat_hdr.Tag.decode('utf-8', 'ignore') != '_AMIPFAT' : continue + + hdr_size = pfat_hdr.Size + hdr_data = buffer[0x11:hdr_size].decode('utf-8').splitlines() + + pfat_hdr.pfat_print() + print(' Title : %s' % hdr_data[0]) + + for entry in hdr_data[1:] : + entry_data = entry.split(' ') + entry_data = [s for s in entry_data if s != ''] + entry_flash = int(entry_data[0]) + entry_param = entry_data[1] + entry_blocks = int(entry_data[2]) + entry_name = entry_data[3][1:] + + for i in range(entry_blocks) : blocks.append([entry_name, entry_param, entry_flash, i + 1, entry_blocks]) + + block_count += entry_blocks + + block_start = hdr_size + for i in range(block_count) : + if blocks[i][0] != block_name : print('\n%s (Parameter: %s, Update: %s)' % (blocks[i][0], blocks[i][1], ['No','Yes'][blocks[i][2]])) + block_hdr = get_struct(buffer, block_start, PFAT_Block_Header, ['%d/%d' % (blocks[i][3], blocks[i][4])]) + block_hdr_size = ctypes.sizeof(PFAT_Block_Header) + block_flag_size = block_hdr.FlagsSize + flag_data = buffer[block_start + block_hdr_size:block_start + block_hdr_size + block_flag_size] # Flags not parsed + block_data_start = block_start + block_hdr_size + block_flag_size + block_data_end = block_data_start + block_hdr.DataSize + block_hdr.pfat_print() + + block_rsa = get_struct(buffer, block_data_end, PFAT_Block_RSA, ['%d/%d' % (blocks[i][3], blocks[i][4])]) + block_rsa_size = ctypes.sizeof(PFAT_Block_RSA) + #block_rsa_exp = block_rsa.Exponent + #block_rsa_pkey = int((''.join('%0.8X' % int.from_bytes(struct.pack(' python --version + +2. Use pip to install PyInstaller: + +> pip3 install pyinstaller + +3. Build/Freeze/Compile: + +> pyinstaller --noupx --onefile AMI_PFAT_Extract.py + +At dist folder you should find the final utility executable + ## **Apple EFI Sucatalog Link Grabber** #### **Description** @@ -93,7 +133,7 @@ At dist folder you should find the final utility executable #### **Description** -Parses Apple EFI files and renames them based on Apple's official $IBIOSI$ tag as follows: Model_Version_Build_Year_Month_Day_Hour_Minute_Checksum. The checksum is calculated and added by the utility in order to differentiate any EFI files with the same $IBIOSI$ tag. In rare cases in which the $IBIOSI$ tag is compressed, the utility automatically first uses [LongSoft's UEFIFind and UEFIExtract](https://github.com/LongSoft/UEFITool) tools. +Parses Apple EFI files and renames them based on Intel's official $IBIOSI$ tag as follows: Model_Version_Build_Year_Month_Day_Hour_Minute_Checksum. The checksum is calculated and added by the utility in order to differentiate any EFI files with the same $IBIOSI$ tag. In rare cases in which the $IBIOSI$ tag is compressed, the utility automatically first uses [LongSoft's UEFIFind and UEFIExtract](https://github.com/LongSoft/UEFITool) tools. #### **Usage**