mirror of
https://github.com/platomav/BIOSUtilities.git
synced 2025-05-13 06:34:42 -04:00
148 lines
4.7 KiB
Python
148 lines
4.7 KiB
Python
#!/usr/bin/env python3
|
|
#coding=utf-8
|
|
|
|
"""
|
|
Insyde iFlash Extract
|
|
Insyde iFlash Update Extractor
|
|
Copyright (C) 2022 Plato Mavropoulos
|
|
"""
|
|
|
|
TITLE = 'Insyde iFlash Update Extractor v2.0_a2'
|
|
|
|
import os
|
|
import sys
|
|
import ctypes
|
|
|
|
# Stop __pycache__ generation
|
|
sys.dont_write_bytecode = True
|
|
|
|
from common.path_ops import make_dirs, safe_name
|
|
from common.patterns import PAT_INSYDE_IFL
|
|
from common.struct_ops import get_struct, char, uint32_t
|
|
from common.system import script_init, argparse_init, printer
|
|
from common.text_ops import file_to_bytes
|
|
|
|
class IflashHeader(ctypes.LittleEndianStructure):
|
|
_pack_ = 1
|
|
_fields_ = [
|
|
('Signature', char*9), # 0x00 $_IFLASH_
|
|
('ImageTag', char*7), # 0x08
|
|
('TotalSize', uint32_t), # 0x10 from header end
|
|
('ImageSize', uint32_t), # 0x14 from header end
|
|
# 0x18
|
|
]
|
|
|
|
def struct_print(self, p):
|
|
printer(['Signature :', self.Signature.decode('utf-8','ignore')], p, False)
|
|
printer(['Image Name:', self.ImageTag.decode('utf-8','ignore')], p, False)
|
|
printer(['Image Size:', f'0x{self.ImageSize:X}'], p, False)
|
|
printer(['Total Size:', f'0x{self.TotalSize:X}'], p, False)
|
|
|
|
# Parse & Extract Insyde iFlash Update image
|
|
def insyde_iflash_extract(input_buffer, ins_ifl_all, output_path, padding=0):
|
|
extract_path = os.path.join(f'{output_path}_extracted')
|
|
|
|
make_dirs(extract_path, delete=True)
|
|
|
|
for ins_ifl_val in ins_ifl_all:
|
|
ins_ifl_off,ins_ifl_hdr = ins_ifl_val
|
|
|
|
mod_bgn = ins_ifl_off + IFL_HDR_LEN
|
|
mod_end = mod_bgn + ins_ifl_hdr.ImageSize
|
|
mod_bin = input_buffer[mod_bgn:mod_end]
|
|
|
|
mod_val = [ins_ifl_hdr.ImageTag.decode('utf-8','ignore'), 'bin']
|
|
mod_tag,mod_ext = IFL_MOD_NAMES.get(mod_val[0], mod_val)
|
|
|
|
mod_name = f'{mod_tag} [0x{mod_bgn:08X}-0x{mod_end:08X}]'
|
|
|
|
printer(f'{mod_name}\n', padding)
|
|
|
|
ins_ifl_hdr.struct_print(padding + 4)
|
|
|
|
if mod_val == [mod_tag,mod_ext]:
|
|
printer(f'Note: Detected new Insyde iFlash image tag {mod_tag}!', padding + 8, pause=True)
|
|
|
|
out_name = f'{mod_name}.{mod_ext}'
|
|
|
|
out_path = os.path.join(extract_path, safe_name(out_name))
|
|
|
|
with open(out_path, 'wb') as out: out.write(mod_bin)
|
|
|
|
printer('Succesfull Insyde iFlash image extraction!', padding + 8)
|
|
|
|
# Get Insyde iFlash Update image matches
|
|
def get_insyde_iflash(in_file):
|
|
ins_ifl_all = []
|
|
ins_ifl_nan = [0x0,0xFFFFFFFF]
|
|
|
|
buffer = file_to_bytes(in_file)
|
|
|
|
for ins_ifl_match in PAT_INSYDE_IFL.finditer(buffer):
|
|
ins_ifl_off = ins_ifl_match.start()
|
|
|
|
if len(buffer[ins_ifl_off:]) <= IFL_HDR_LEN:
|
|
continue
|
|
|
|
ins_ifl_hdr = get_struct(buffer, ins_ifl_off, IflashHeader)
|
|
|
|
if ins_ifl_hdr.TotalSize in ins_ifl_nan \
|
|
or ins_ifl_hdr.ImageSize in ins_ifl_nan \
|
|
or ins_ifl_hdr.TotalSize <= ins_ifl_hdr.ImageSize:
|
|
continue
|
|
|
|
ins_ifl_all.append([ins_ifl_off, ins_ifl_hdr])
|
|
|
|
return ins_ifl_all
|
|
|
|
# Check if input is Insyde iFlash Update image
|
|
def is_insyde_iflash(in_file):
|
|
buffer = file_to_bytes(in_file)
|
|
|
|
return bool(get_insyde_iflash(buffer))
|
|
|
|
IFL_MOD_NAMES = {
|
|
'DRV_IMG' : ['isflash', 'efi'],
|
|
'INI_IMG' : ['platform', 'ini'],
|
|
'BIOSIMG' : ['BIOS-UEFI', 'bin'],
|
|
'ME_IMG_' : ['Management Engine', 'bin'],
|
|
'EC_IMG_' : ['Embedded Controller', 'bin'],
|
|
'OEM_ID_' : ['OEM Identifier', 'bin'],
|
|
'BIOSCER' : ['Certificate', 'bin'],
|
|
'BIOSCR2' : ['Certificate 2nd', 'bin'],
|
|
}
|
|
|
|
# Get common ctypes Structure Sizes
|
|
IFL_HDR_LEN = ctypes.sizeof(IflashHeader)
|
|
|
|
if __name__ == '__main__':
|
|
# Set argparse Arguments
|
|
argparser = argparse_init()
|
|
arguments = argparser.parse_args()
|
|
|
|
# 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)
|
|
|
|
with open(input_file, 'rb') as in_file: input_buffer = in_file.read()
|
|
|
|
ins_ifl_all = get_insyde_iflash(input_buffer)
|
|
|
|
if not ins_ifl_all:
|
|
printer('Error: This is not an Insyde iFlash Update image!', padding)
|
|
|
|
continue # Next input file
|
|
|
|
extract_path = os.path.join(output_path, input_name)
|
|
|
|
insyde_iflash_extract(input_buffer, ins_ifl_all, extract_path, padding)
|
|
|
|
exit_code -= 1
|
|
|
|
printer('Done!', pause=True)
|
|
|
|
sys.exit(exit_code)
|