diff --git a/Insyde_IFD_Extract.py b/Insyde_IFD_Extract.py index 0189ed9..ba9c28e 100644 --- a/Insyde_IFD_Extract.py +++ b/Insyde_IFD_Extract.py @@ -7,7 +7,7 @@ Insyde iFlash/iFdPacker Extractor Copyright (C) 2022 Plato Mavropoulos """ -TITLE = 'Insyde iFlash/iFdPacker Extractor v2.0_a8' +TITLE = 'Insyde iFlash/iFdPacker Extractor v2.0_a9' import os import sys @@ -33,6 +33,9 @@ class IflashHeader(ctypes.LittleEndianStructure): # 0x18 ] + def _get_padd_len(self): + return self.TotalSize - self.ImageSize + def get_image_tag(self): return self.ImageTag.decode('utf-8','ignore').strip('_') @@ -41,6 +44,7 @@ class IflashHeader(ctypes.LittleEndianStructure): printer(['Image Name:', self.get_image_tag()], p, False) printer(['Image Size:', f'0x{self.ImageSize:X}'], p, False) printer(['Total Size:', f'0x{self.TotalSize:X}'], p, False) + printer(['Padd Size :', f'0x{self._get_padd_len():X}'], p, False) # Check if input is Insyde iFlash/iFdPacker Update image def is_insyde_ifd(input_file): @@ -73,15 +77,16 @@ def insyde_iflash_detect(input_buffer): for iflash_match in PAT_INSYDE_IFL.finditer(input_buffer): ifl_bgn = iflash_match.start() - - if len(input_buffer[ifl_bgn:]) <= IFL_HDR_LEN: + + if len(input_buffer[ifl_bgn:]) <= INS_IFL_LEN: continue ifl_hdr = get_struct(input_buffer, ifl_bgn, IflashHeader) if ifl_hdr.TotalSize in iflash_match_nan \ or ifl_hdr.ImageSize in iflash_match_nan \ - or ifl_hdr.TotalSize <= ifl_hdr.ImageSize: + or ifl_hdr.TotalSize < ifl_hdr.ImageSize \ + or ifl_bgn + INS_IFL_LEN + ifl_hdr.TotalSize > len(input_buffer): continue iflash_match_all.append([ifl_bgn, ifl_hdr]) @@ -93,21 +98,28 @@ def insyde_iflash_extract(input_buffer, extract_path, padding=0): insyde_iflash_all = insyde_iflash_detect(input_buffer) if not insyde_iflash_all: - return 1 + return 127 printer('Detected Insyde iFlash Update image!', padding) make_dirs(extract_path, delete=True) + exit_codes = [] + for insyde_iflash in insyde_iflash_all: + exit_code = 0 + ifl_bgn,ifl_hdr = insyde_iflash - img_bgn = ifl_bgn + IFL_HDR_LEN + img_bgn = ifl_bgn + INS_IFL_LEN img_end = img_bgn + ifl_hdr.ImageSize img_bin = input_buffer[img_bgn:img_end] + if len(img_bin) != ifl_hdr.ImageSize: + exit_code = 1 + img_val = [ifl_hdr.get_image_tag(), 'bin'] - img_tag,img_ext = IFL_IMG_NAMES.get(img_val[0], img_val) + img_tag,img_ext = INS_IFL_IMG.get(img_val[0], img_val) img_name = f'{img_tag} [0x{img_bgn:08X}-0x{img_end:08X}]' @@ -126,8 +138,10 @@ def insyde_iflash_extract(input_buffer, extract_path, padding=0): out_image.write(img_bin) printer(f'Succesfull Insyde iFlash > {img_tag} extraction!', padding + 12) + + exit_codes.append(exit_code) - return 0 + return sum(exit_codes) # Extract Insyde iFdPacker 7-Zip SFX 7z Update image def insyde_packer_extract(input_buffer, extract_path, padding=0): @@ -143,22 +157,27 @@ def insyde_packer_extract(input_buffer, extract_path, padding=0): sfx_buffer = bytearray(input_buffer[match_sfx.end() - 0x5:]) if sfx_buffer[:0x5] == b'\x6E\xF4\x79\x5F\x4E': - printer('Detected Insyde iFdPacker > 7-Zip SFX obfuscation!', padding + 4) + printer('Detected Insyde iFdPacker > 7-Zip SFX > Obfuscation!', padding + 4) for index,byte in enumerate(sfx_buffer): sfx_buffer[index] = byte // 2 + (128 if byte % 2 else 0) - printer('Removed Insyde iFdPacker > 7-Zip SFX obfuscation!', padding + 8) + printer('Removed Insyde iFdPacker > 7-Zip SFX > Obfuscation!', padding + 8) printer('Extracting Insyde iFdPacker > 7-Zip SFX archive...', padding + 4) + if bytes(INS_SFX_PWD, 'utf-16le') in input_buffer[:match_sfx.start()]: + printer('Detected Insyde iFdPacker > 7-Zip SFX > Password!', padding + 8) + printer(INS_SFX_PWD, padding + 12) + sfx_path = os.path.join(extract_path, 'Insyde_iFdPacker_SFX.7z') with open(sfx_path, 'wb') as sfx_file: sfx_file.write(sfx_buffer) - if is_szip_supported(sfx_path, padding + 8, check=True): - if szip_decompress(sfx_path, extract_path, 'Insyde iFdPacker > 7-Zip SFX', padding + 8, check=True) == 0: + if is_szip_supported(sfx_path, padding + 8, password=INS_SFX_PWD, check=True): + if szip_decompress(sfx_path, extract_path, 'Insyde iFdPacker > 7-Zip SFX', + padding + 8, password=INS_SFX_PWD, check=True) == 0: os.remove(sfx_path) else: return 125 @@ -170,13 +189,18 @@ def insyde_packer_extract(input_buffer, extract_path, padding=0): for sfx_file in get_path_files(extract_path): if is_insyde_ifd(sfx_file): printer(f'{os.path.basename(sfx_file)}', padding + 12) + ifd_code = insyde_ifd_extract(sfx_file, sfx_file, padding + 16) + exit_codes.append(ifd_code) return sum(exit_codes) -# Insyde iFlash Image Names -IFL_IMG_NAMES = { +# Insyde iFdPacker known 7-Zip SFX Password +INS_SFX_PWD = 'Y`t~i!L@i#t$U%h^s7A*l(f)E-d=y+S_n?i' + +# Insyde iFlash known Image Names +INS_IFL_IMG = { 'BIOSCER' : ['Certificate', 'bin'], 'BIOSCR2' : ['Certificate 2nd', 'bin'], 'BIOSIMG' : ['BIOS-UEFI', 'bin'], @@ -188,7 +212,7 @@ IFL_IMG_NAMES = { } # Get common ctypes Structure Sizes -IFL_HDR_LEN = ctypes.sizeof(IflashHeader) +INS_IFL_LEN = ctypes.sizeof(IflashHeader) if __name__ == '__main__': # Set argparse Arguments diff --git a/README.md b/README.md index 30530b6..96ecc1f 100644 --- a/README.md +++ b/README.md @@ -323,7 +323,7 @@ Some Anti-Virus software may claim that the built/frozen/compiled executable con #### **Description** -Parses Insyde iFlash/iFdPacker Update images and extracts their firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and utilities (e.g. H2OFFT, FlsHook, iscflash, platform.ini etc) components. It supports all Insyde iFlash/iFdPacker revisions and formats, including those which are 7-Zip SFX 7z compressed in raw or obfuscated form. The output comprises only final firmware components which are directly usable by end users. +Parses Insyde iFlash/iFdPacker Update images and extracts their firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and utilities (e.g. InsydeFlash, H2OFFT, FlsHook, iscflash, platform.ini etc) components. It supports all Insyde iFlash/iFdPacker revisions and formats, including those which are 7-Zip SFX 7z compressed in raw, obfuscated or password-protected form. The output comprises only final firmware components which are directly usable by end users. #### **Usage** diff --git a/common/comp_szip.py b/common/comp_szip.py index a3cb6ad..4a3d26b 100644 --- a/common/comp_szip.py +++ b/common/comp_szip.py @@ -23,9 +23,11 @@ def check_bad_exit_code(exit_code): raise Exception(f'BAD_EXIT_CODE_{exit_code}') # Check if file is 7-Zip supported -def is_szip_supported(in_path, padding=0, check=False, silent=False): +def is_szip_supported(in_path, padding=0, password='', check=False, silent=False): try: - szip_t = subprocess.run([get_szip_path(), 't', in_path, '-bso0', '-bse0', '-bsp0'], check=False) + szip_c = [get_szip_path(), 't', in_path, f'-p{password}', '-bso0', '-bse0', '-bsp0'] + + szip_t = subprocess.run(szip_c, check=False) if check: check_bad_exit_code(szip_t.returncode) @@ -38,12 +40,14 @@ def is_szip_supported(in_path, padding=0, check=False, silent=False): return True # Archive decompression via 7-Zip -def szip_decompress(in_path, out_path, in_name, padding=0, check=False, silent=False): +def szip_decompress(in_path, out_path, in_name, padding=0, password='', check=False, silent=False): if not in_name: in_name = 'archive' try: - szip_x = subprocess.run([get_szip_path(), 'x', '-aou', '-bso0', '-bse0', '-bsp0', '-o' + out_path, in_path], check=False) + szip_c = [get_szip_path(), 'x', f'-p{password}', '-aou', '-bso0', '-bse0', '-bsp0', f'-o{out_path}', in_path] + + szip_x = subprocess.run(szip_c, check=False) if check: check_bad_exit_code(szip_x.returncode) diff --git a/common/patterns.py b/common/patterns.py index 9252c91..3e11e84 100644 --- a/common/patterns.py +++ b/common/patterns.py @@ -13,7 +13,7 @@ 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) PAT_DELL_PKG = re.compile(br'\x72\x13\x55\x00.{45}7zXZ', re.DOTALL) -PAT_INSYDE_IFL = re.compile(br'\$_IFLASH_') +PAT_INSYDE_IFL = re.compile(br'\$_IFLASH') PAT_INSYDE_SFX = re.compile(br'\x0D\x0A;!@InstallEnd@!\x0D\x0A(7z\xBC\xAF\x27|\x6E\xF4\x79\x5F\x4E)') PAT_INTEL_ENG = re.compile(br'\x04\x00{3}[\xA1\xE1]\x00{3}.{8}\x86\x80.{9}\x00\$((MN2)|(MAN))', re.DOTALL) PAT_MICROSOFT_CAB = re.compile(br'MSCF\x00{4}')