mirror of
https://github.com/platomav/BIOSUtilities.git
synced 2025-05-13 22:54:46 -04:00
Added Apple EFI Image Identifier v2.0_a3
Fixed argparse lock of input files
This commit is contained in:
parent
48562b0f68
commit
c144ad804c
5 changed files with 283 additions and 5 deletions
193
Apple_EFI_Identify.py
Normal file
193
Apple_EFI_Identify.py
Normal file
|
@ -0,0 +1,193 @@
|
|||
#!/usr/bin/env python3
|
||||
#coding=utf-8
|
||||
|
||||
"""
|
||||
Apple EFI Identify
|
||||
Apple EFI Image Identifier
|
||||
Copyright (C) 2018-2022 Plato Mavropoulos
|
||||
"""
|
||||
|
||||
TITLE = 'Apple EFI Image Identifier v2.0_a3'
|
||||
|
||||
import os
|
||||
import sys
|
||||
import zlib
|
||||
import struct
|
||||
import ctypes
|
||||
import subprocess
|
||||
|
||||
# Stop __pycache__ generation
|
||||
sys.dont_write_bytecode = True
|
||||
|
||||
from common.externals import get_uefifind_path, get_uefiextract_path
|
||||
from common.path_ops import del_dirs, path_parent, path_suffixes
|
||||
from common.patterns import PAT_APPLE_EFI
|
||||
from common.struct_ops import char, get_struct, uint8_t
|
||||
from common.system import argparse_init, printer, script_init
|
||||
from common.text_ops import file_to_bytes
|
||||
|
||||
class IntelBiosId(ctypes.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
('Signature', char*8), # 0x00
|
||||
('BoardID', uint8_t*16), # 0x08
|
||||
('Dot1', uint8_t*2), # 0x18
|
||||
('BoardExt', uint8_t*6), # 0x1A
|
||||
('Dot2', uint8_t*2), # 0x20
|
||||
('VersionMajor', uint8_t*8), # 0x22
|
||||
('Dot3', uint8_t*2), # 0x2A
|
||||
('BuildType', uint8_t*2), # 0x2C
|
||||
('VersionMinor', uint8_t*4), # 0x2E
|
||||
('Dot4', uint8_t*2), # 0x32
|
||||
('Year', uint8_t*4), # 0x34
|
||||
('Month', uint8_t*4), # 0x38
|
||||
('Day', uint8_t*4), # 0x3C
|
||||
('Hour', uint8_t*4), # 0x40
|
||||
('Minute', uint8_t*4), # 0x44
|
||||
('NullTerminator', uint8_t*2), # 0x48
|
||||
# 0x4A
|
||||
]
|
||||
|
||||
# https://github.com/tianocore/edk2-platforms/blob/master/Platform/Intel/BoardModulePkg/Include/Guid/BiosId.h
|
||||
|
||||
@staticmethod
|
||||
def decode(field):
|
||||
return struct.pack('B' * len(field), *field).decode('utf-16','ignore').strip('\x00 ')
|
||||
|
||||
def get_bios_id(self):
|
||||
BoardID = self.decode(self.BoardID)
|
||||
BoardExt = self.decode(self.BoardExt)
|
||||
VersionMajor = self.decode(self.VersionMajor)
|
||||
BuildType = self.decode(self.BuildType)
|
||||
VersionMinor = self.decode(self.VersionMinor)
|
||||
BuildDate = f'20{self.decode(self.Year)}-{self.decode(self.Month)}-{self.decode(self.Day)}'
|
||||
BuildTime = f'{self.decode(self.Hour)}-{self.decode(self.Minute)}'
|
||||
|
||||
return BoardID, BoardExt, VersionMajor, BuildType, VersionMinor, BuildDate, BuildTime
|
||||
|
||||
def struct_print(self, p):
|
||||
BoardID,BoardExt,VersionMajor,BuildType,VersionMinor,BuildDate,BuildTime = self.get_bios_id()
|
||||
|
||||
printer(['Intel Signature:', self.Signature.decode('utf-8')], p, False)
|
||||
printer(['Board Identity: ', BoardID], p, False)
|
||||
printer(['Apple Identity: ', BoardExt], p, False)
|
||||
printer(['Major Version: ', VersionMajor], p, False)
|
||||
printer(['Minor Version: ', VersionMinor], p, False)
|
||||
printer(['Build Type: ', BuildType], p, False)
|
||||
printer(['Build Date: ', BuildDate], p, False)
|
||||
printer(['Build Time: ', BuildTime.replace('-',':')], p, False)
|
||||
|
||||
# Check if input is Apple EFI image
|
||||
def is_apple_efi(input_file):
|
||||
input_buffer = file_to_bytes(input_file)
|
||||
|
||||
if PAT_APPLE_EFI.search(input_buffer):
|
||||
return True
|
||||
|
||||
if not os.path.isfile(input_file):
|
||||
return False
|
||||
|
||||
try:
|
||||
_ = subprocess.run([get_uefifind_path(), input_file, 'body', 'list', PAT_UEFIFIND],
|
||||
check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
# Parse & Identify (or Rename) Apple EFI image
|
||||
def apple_efi_identify(input_file, output_path, padding=0, rename=False):
|
||||
if not os.path.isfile(input_file):
|
||||
printer('Error: Could not find input file path!', padding)
|
||||
|
||||
return 1
|
||||
|
||||
input_buffer = file_to_bytes(input_file)
|
||||
|
||||
bios_id_match = PAT_APPLE_EFI.search(input_buffer) # Detect $IBIOSI$ pattern
|
||||
|
||||
if bios_id_match:
|
||||
bios_id_res = f'0x{bios_id_match.start():X}'
|
||||
|
||||
bios_id_hdr = get_struct(input_buffer, bios_id_match.start(), IntelBiosId)
|
||||
else:
|
||||
# The $IBIOSI$ pattern is within EFI compressed modules so we need to use UEFIFind and UEFIExtract
|
||||
try:
|
||||
bios_id_res = subprocess.check_output([get_uefifind_path(), input_file, 'body', 'list', PAT_UEFIFIND],
|
||||
text=True)[:36]
|
||||
|
||||
temp_dir = os.path.join(f'{output_path}_uefiextract')
|
||||
|
||||
del_dirs(temp_dir) # UEFIExtract must create its output folder itself, make sure it is not present
|
||||
|
||||
_ = subprocess.run([get_uefiextract_path(), input_file, bios_id_res, '-o', temp_dir, '-m', 'body'],
|
||||
check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
|
||||
with open(os.path.join(temp_dir, 'body.bin'), 'rb') as raw_body:
|
||||
body_buffer = raw_body.read()
|
||||
|
||||
bios_id_match = PAT_APPLE_EFI.search(body_buffer) # Detect decompressed $IBIOSI$ pattern
|
||||
|
||||
bios_id_hdr = get_struct(body_buffer, bios_id_match.start(), IntelBiosId)
|
||||
|
||||
del_dirs(temp_dir) # Successful UEFIExtract extraction, remove its output (temp) folder
|
||||
except:
|
||||
printer('Error: Failed to parse compressed $IBIOSI$ pattern!', padding)
|
||||
|
||||
return 2
|
||||
|
||||
printer(f'Detected $IBIOSI$ at {bios_id_res}\n', padding)
|
||||
|
||||
bios_id_hdr.struct_print(padding + 4)
|
||||
|
||||
if rename:
|
||||
input_parent = path_parent(input_file)
|
||||
|
||||
input_suffix = path_suffixes(input_file)[0]
|
||||
|
||||
input_adler32 = zlib.adler32(input_buffer)
|
||||
|
||||
ID,Ext,Major,Type,Minor,Date,Time = bios_id_hdr.get_bios_id()
|
||||
|
||||
output_name = f'{ID}_{Ext}_{Major}_{Type}{Minor}_{Date}_{Time}_{input_adler32:08X}{input_suffix}'
|
||||
|
||||
output_file = os.path.join(input_parent, output_name)
|
||||
|
||||
if not os.path.isfile(output_file):
|
||||
os.replace(input_file, output_file) # Rename input file based on its EFI tag
|
||||
|
||||
printer(f'Renamed input to {output_name}', padding)
|
||||
|
||||
return 0
|
||||
|
||||
PAT_UEFIFIND = f'244942494F534924{"."*32}2E00{"."*12}2E00{"."*16}2E00{"."*12}2E00{"."*40}0000'
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Set argparse Arguments
|
||||
argparser = argparse_init()
|
||||
argparser.add_argument('-r', '--rename', help='rename EFI image based on its tag', action='store_true')
|
||||
arguments = argparser.parse_args()
|
||||
|
||||
rename = arguments.rename # Set EFI image tag renaming optional argument
|
||||
|
||||
# Initialize script (must be after argparse)
|
||||
exit_code,input_files,output_path,padding = script_init(TITLE, arguments, 4)
|
||||
|
||||
for input_file in input_files:
|
||||
input_name = os.path.basename(input_file)
|
||||
|
||||
printer(['***', input_name], padding - 4)
|
||||
|
||||
if not is_apple_efi(input_file):
|
||||
printer('Error: This is not an Apple EFI image!', padding)
|
||||
|
||||
continue # Next input file
|
||||
|
||||
extract_path = os.path.join(output_path, input_name)
|
||||
|
||||
if apple_efi_identify(input_file, extract_path, padding, rename) == 0:
|
||||
exit_code -= 1
|
||||
|
||||
printer('Done!', pause=True)
|
||||
|
||||
sys.exit(exit_code)
|
70
README.md
70
README.md
|
@ -5,6 +5,7 @@
|
|||
|
||||
* [**AMI BIOS Guard Extractor**](#ami-bios-guard-extractor)
|
||||
* [**AMI UCP Update Extractor**](#ami-ucp-update-extractor)
|
||||
* [**Apple EFI Image Identifier**](#apple-efi-image-identifier)
|
||||
* [**Award BIOS Module Extractor**](#award-bios-module-extractor)
|
||||
* [**Dell PFS/PKG Update Extractor**](#dell-pfspkg-update-extractor)
|
||||
* [**Fujitsu SFX BIOS Extractor**](#fujitsu-sfx-bios-extractor)
|
||||
|
@ -103,7 +104,7 @@ Should work at all Windows, Linux or macOS operating systems which have Python 3
|
|||
|
||||
To run the utility, you must have the following 3rd party tools at the "external" project directory:
|
||||
|
||||
* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (e.g. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux)
|
||||
* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux)
|
||||
* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zzs for Linux)
|
||||
|
||||
Optionally, to decompile the AMI UCP \> AMI PFAT \> Intel BIOS Guard Scripts (when applicable), you must have the following 3rd party utility at the "external" project directory:
|
||||
|
@ -142,6 +143,67 @@ Some Anti-Virus software may claim that the built/frozen/compiled executable con
|
|||
|
||||
![]()
|
||||
|
||||
## **Apple EFI Image Identifier**
|
||||
|
||||
![]()
|
||||
|
||||
#### **Description**
|
||||
|
||||
Parses Apple EFI images and identifies them based on Intel's official $IBIOSI$ tag, which contains info such as Model, Version, Build, Date and Time. Optionally, the utility can rename the input Apple EFI image based on the retrieved $IBIOSI$ tag info, while also making sure to differentiate any EFI images with the same $IBIOSI$ tag (e.g. Production, Pre-Production) by appending a checksum of their data.
|
||||
|
||||
#### **Usage**
|
||||
|
||||
You can either Drag & Drop or manually enter Apple EFI image file(s). Optional arguments:
|
||||
|
||||
* -h or --help : show help message and exit
|
||||
* -v or --version : show utility name and version
|
||||
* -i or --input-dir : extract from given input directory
|
||||
* -o or --output-dir : extract in given output directory
|
||||
* -e or --auto-exit : skip press enter to exit prompts
|
||||
* -r or --rename : rename EFI image based on its tag
|
||||
|
||||
#### **Compatibility**
|
||||
|
||||
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 support.
|
||||
|
||||
#### **Prerequisites**
|
||||
|
||||
To run the utility, you must have the following 3rd party tools at the "external" project directory:
|
||||
|
||||
* [UEFIFind](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIFind.exe for Windows or UEFIFind for Linux](https://github.com/LongSoft/UEFITool/releases))
|
||||
* [UEFIExtract](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIExtract.exe for Windows or UEFIExtract for Linux](https://github.com/LongSoft/UEFITool/releases))
|
||||
|
||||
#### **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.10.0 or newer is installed:
|
||||
|
||||
> python --version
|
||||
|
||||
2. Use pip to install PyInstaller:
|
||||
|
||||
> pip3 install pyinstaller
|
||||
|
||||
3. Place prerequisites at the "external" project directory:
|
||||
|
||||
> UEFIFind\
|
||||
> UEFIExtract
|
||||
|
||||
4. Build/Freeze/Compile:
|
||||
|
||||
> pyinstaller --add-data="external/*;external/" --noupx --onefile \<path-to-project\>\/Apple_EFI_Identify.py
|
||||
|
||||
You should find the final utility executable at "dist" folder
|
||||
|
||||
#### **Anti-Virus False Positives**
|
||||
|
||||
Some Anti-Virus software may claim that the built/frozen/compiled executable contains viruses. Any such detections are false positives, usually of PyInstaller. You can switch to a better Anti-Virus software, report the false positive to their support, add the executable to the exclusions, build/freeze/compile yourself or use the Python script directly.
|
||||
|
||||
#### **Pictures**
|
||||
|
||||
![]()
|
||||
|
||||
## **Award BIOS Module Extractor**
|
||||
|
||||
![]()
|
||||
|
@ -344,7 +406,7 @@ Should work at all Windows, Linux or macOS operating systems which have Python 3
|
|||
|
||||
To run the utility, you must have the following 3rd party tool at the "external" project directory:
|
||||
|
||||
* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (e.g. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux)
|
||||
* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux)
|
||||
|
||||
#### **Build/Freeze/Compile with PyInstaller**
|
||||
|
||||
|
@ -585,7 +647,7 @@ To run the utility, you must have the following 3rd party Python module installe
|
|||
|
||||
Moreover, you must have the following 3rd party tool at the "external" project directory:
|
||||
|
||||
* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (e.g. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux)
|
||||
* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux)
|
||||
|
||||
#### **Build/Freeze/Compile with PyInstaller**
|
||||
|
||||
|
@ -647,7 +709,7 @@ Should work at all Windows, Linux or macOS operating systems which have Python 3
|
|||
|
||||
To run the utility, you must have the following 3rd party tool at the "external" project directory:
|
||||
|
||||
* [ToshibaComExtractor](https://github.com/LongSoft/ToshibaComExtractor) (e.g. comextract.exe for Windows or comextract for Linux)
|
||||
* [ToshibaComExtractor](https://github.com/LongSoft/ToshibaComExtractor) (i.e. [comextract.exe for Windows or comextract for Linux](https://github.com/LongSoft/ToshibaComExtractor/releases))
|
||||
|
||||
#### **Build/Freeze/Compile with PyInstaller**
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
Copyright (C) 2022 Plato Mavropoulos
|
||||
"""
|
||||
|
||||
from common.path_ops import project_root, safe_path
|
||||
from common.system import get_os_ver
|
||||
|
||||
# https://github.com/allowitsme/big-tool by Dmitry Frolov
|
||||
# https://github.com/platomav/BGScriptTool by Plato Mavropoulos
|
||||
def get_bgs_tool():
|
||||
|
@ -14,3 +17,15 @@ def get_bgs_tool():
|
|||
BigScript = None
|
||||
|
||||
return BigScript
|
||||
|
||||
# Get UEFIFind path
|
||||
def get_uefifind_path():
|
||||
exec_name = f'UEFIFind{".exe" if get_os_ver()[1] else ""}'
|
||||
|
||||
return safe_path(project_root(), ['external',exec_name])
|
||||
|
||||
# Get UEFIExtract path
|
||||
def get_uefiextract_path():
|
||||
exec_name = f'UEFIExtract{".exe" if get_os_ver()[1] else ""}'
|
||||
|
||||
return safe_path(project_root(), ['external',exec_name])
|
||||
|
|
|
@ -136,6 +136,8 @@ def get_argparse_path(argparse_path):
|
|||
|
||||
# Process input files (argparse object)
|
||||
def process_input_files(argparse_args, sys_argv=None):
|
||||
input_files = []
|
||||
|
||||
if sys_argv is None:
|
||||
sys_argv = []
|
||||
|
||||
|
@ -146,7 +148,12 @@ def process_input_files(argparse_args, sys_argv=None):
|
|||
input_path_full = get_argparse_path(input_path_user) if input_path_user else ''
|
||||
input_files = get_path_files(input_path_full)
|
||||
else:
|
||||
input_files = [file.name for file in argparse_args.files]
|
||||
# Parse list of input files (i.e. argparse FileType objects)
|
||||
for file_object in argparse_args.files:
|
||||
# Store each argparse FileType object's name (i.e. path)
|
||||
input_files.append(file_object.name)
|
||||
# Close each argparse FileType object (i.e. allow input file changes)
|
||||
file_object.close()
|
||||
|
||||
# Set output fallback value for missing argparse Output and Input Path
|
||||
output_fallback = path_parent(input_files[0]) if input_files else None
|
||||
|
|
|
@ -9,6 +9,7 @@ import re
|
|||
|
||||
PAT_AMI_PFAT = re.compile(br'_AMIPFAT.AMI_BIOS_GUARD_FLASH_CONFIGURATIONS', re.DOTALL)
|
||||
PAT_AMI_UCP = re.compile(br'@(UAF|HPU).{12}@', re.DOTALL)
|
||||
PAT_APPLE_EFI = re.compile(br'\$IBIOSI\$.{16}\x2E\x00.{6}\x2E\x00.{8}\x2E\x00.{6}\x2E\x00.{20}\x00{2}', re.DOTALL)
|
||||
PAT_AWARD_LZH = re.compile(br'-lh[04567]-')
|
||||
PAT_DELL_FTR = re.compile(br'\xEE\xAA\xEE\x8F\x49\x1B\xE8\xAE\x14\x37\x90')
|
||||
PAT_DELL_HDR = re.compile(br'\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.\x78\x9C', re.DOTALL)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue