mirror of
https://github.com/platomav/BIOSUtilities.git
synced 2025-05-13 14:44:46 -04:00
Added AMI BIOS Guard Extractor
Parses AMI BIOS Guard (a.k.a. PFAT) images and extracts a proper SPI/BIOS image.
This commit is contained in:
parent
09c02caa9a
commit
d702d7f8a8
2 changed files with 227 additions and 2 deletions
185
AMI BIOS Guard Extractor/AMI_PFAT_Extract.py
Normal file
185
AMI BIOS Guard Extractor/AMI_PFAT_Extract.py
Normal file
|
@ -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('<I', val), 'little') for val in reversed(self.PublicKey))
|
||||||
|
RSASignature = ''.join('%0.8X' % int.from_bytes(struct.pack('<I', val), 'little') for val in reversed(self.Signature))
|
||||||
|
|
||||||
|
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 [...]' % RSAPublicKey[:8])
|
||||||
|
print(' Exponent : 0x%X' % self.Exponent)
|
||||||
|
print(' Signature : %s [...]' % RSASignature[:8])
|
||||||
|
|
||||||
|
# Process ctypes Structure Classes
|
||||||
|
def get_struct(buffer, start_offset, class_name, param_list = None) :
|
||||||
|
if param_list is None : param_list = []
|
||||||
|
|
||||||
|
structure = class_name(*param_list) # Unpack parameter list
|
||||||
|
struct_len = ctypes.sizeof(structure)
|
||||||
|
struct_data = buffer[start_offset:start_offset + struct_len]
|
||||||
|
fit_len = min(len(struct_data), struct_len)
|
||||||
|
|
||||||
|
if (start_offset >= 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('<I', val), 'little') for val in reversed(block_rsa.PublicKey))), 16)
|
||||||
|
#block_rsa_sign = int((''.join('%0.8X' % int.from_bytes(struct.pack('<I', val), 'little') for val in reversed(block_rsa.Signature))), 16)
|
||||||
|
#block_rsa_sign_dec = '%X' % pow(block_rsa_sign, block_rsa_exp, block_rsa_pkey) # Decrypted signature is 4096 bits
|
||||||
|
block_rsa.pfat_print()
|
||||||
|
|
||||||
|
final_image += buffer[block_data_start:block_data_end]
|
||||||
|
|
||||||
|
block_name = blocks[i][0]
|
||||||
|
block_start = block_data_end + block_rsa_size
|
||||||
|
|
||||||
|
with open('%s_unpacked.bin' % os.path.basename(input_file), 'wb') as final : final.write(final_image)
|
||||||
|
|
||||||
|
else :
|
||||||
|
input('\nDone!')
|
44
README.md
44
README.md
|
@ -5,7 +5,7 @@ Various BIOS Utilities for Modding/Research
|
||||||
|
|
||||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DJDZD3PRGCSCL)
|
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DJDZD3PRGCSCL)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## **Dell HDR Module Extractor**
|
## **Dell HDR Module Extractor**
|
||||||
|
|
||||||
|
@ -49,6 +49,46 @@ PyInstaller can build/freeze/compile the utility at all three supported platform
|
||||||
|
|
||||||
At dist folder you should find the final utility executable
|
At dist folder you should find the final utility executable
|
||||||
|
|
||||||
|
## **AMI BIOS Guard Extractor**
|
||||||
|
|
||||||
|
#### **Description**
|
||||||
|
|
||||||
|
Parses AMI BIOS Guard (a.k.a. PFAT) images and extracts a proper SPI/BIOS image.
|
||||||
|
|
||||||
|
#### **Usage**
|
||||||
|
|
||||||
|
You can either Drag & Drop or manually enter the full path of a folder containing AMI PFAT images.
|
||||||
|
|
||||||
|
#### **Download**
|
||||||
|
|
||||||
|
An already built/frozen/compiled binary is provided by me for Windows only. Thus, **you don't need to manually build/freeze/compile it under Windows**. Instead, download the latest version from the [Releases](https://github.com/platomav/BIOSUtilities/releases) tab. To extract the already built/frozen/compiled archive, you need to use programs which support RAR5 compression. Note that you need to manually apply any prerequisites.
|
||||||
|
|
||||||
|
#### **Compatibility**
|
||||||
|
|
||||||
|
Should work at all Windows, Linux or macOS operating systems which have Python 3.6 support. Windows users who plan to use the already built/frozen/compiled binary must make sure that they have the latest Windows Updates installed which include all required "Universal C Runtime (CRT)" libraries.
|
||||||
|
|
||||||
|
#### **Prerequisites**
|
||||||
|
|
||||||
|
To run the utility, you do not need any 3rd party tool.
|
||||||
|
|
||||||
|
#### **Build/Freeze/Compile with PyInstaller**
|
||||||
|
|
||||||
|
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.6.0 or newer is installed:
|
||||||
|
|
||||||
|
> 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**
|
## **Apple EFI Sucatalog Link Grabber**
|
||||||
|
|
||||||
#### **Description**
|
#### **Description**
|
||||||
|
@ -93,7 +133,7 @@ At dist folder you should find the final utility executable
|
||||||
|
|
||||||
#### **Description**
|
#### **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**
|
#### **Usage**
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue