mirror of
https://github.com/platomav/BIOSUtilities.git
synced 2025-05-13 06:34:42 -04:00
Improved AMI UCP > NAL unpacking
Fix potential illegal path traversals
This commit is contained in:
parent
672b4b2321
commit
40686d5edf
13 changed files with 102 additions and 43 deletions
|
@ -7,7 +7,7 @@ AMI UCP BIOS Extractor
|
|||
Copyright (C) 2021-2022 Plato Mavropoulos
|
||||
"""
|
||||
|
||||
title = 'AMI UCP BIOS Extractor v2.0_a6'
|
||||
title = 'AMI UCP BIOS Extractor v2.0_a7'
|
||||
|
||||
import os
|
||||
import re
|
||||
|
@ -16,6 +16,7 @@ import shutil
|
|||
import struct
|
||||
import ctypes
|
||||
import contextlib
|
||||
from pathlib import Path, PurePath
|
||||
|
||||
# Stop __pycache__ generation
|
||||
sys.dont_write_bytecode = True
|
||||
|
@ -23,10 +24,11 @@ sys.dont_write_bytecode = True
|
|||
from common.a7z_comp import a7z_decompress, is_7z_supported
|
||||
from common.checksums import get_chk_16
|
||||
from common.efi_comp import efi_decompress, is_efi_compressed
|
||||
from common.path_ops import safe_name
|
||||
from common.path_ops import get_safe_name, get_safe_path
|
||||
from common.patterns import PAT_AMI_UCP, PAT_INTEL_ENG
|
||||
from common.struct_ops import get_struct, char, uint8_t, uint16_t, uint32_t
|
||||
from common.system import script_init, argparse_init, printer
|
||||
from common.text_ops import to_string
|
||||
|
||||
from AMI_PFAT_Extract import get_ami_pfat, parse_pfat_file
|
||||
|
||||
|
@ -211,7 +213,7 @@ def ucp_extract(buffer, out_path, ucp_tag='@UAF', padding=0, is_checksum=False):
|
|||
|
||||
printer('Utility Configuration Program', padding)
|
||||
|
||||
extract_path = os.path.join(out_path + '_extracted', '')
|
||||
extract_path = os.path.join(out_path + '_extracted')
|
||||
|
||||
if os.path.isdir(extract_path): shutil.rmtree(extract_path)
|
||||
|
||||
|
@ -259,7 +261,7 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
|
|||
|
||||
is_comp = uaf_mod.CompressSize != uaf_mod.OriginalSize # Detect @UAF|@HPU Module EFI Compression
|
||||
|
||||
if uaf_tag in nal_dict: uaf_name = nal_dict[uaf_tag] # Always prefer @NAL naming first
|
||||
if uaf_tag in nal_dict: uaf_name = nal_dict[uaf_tag][1] # Always prefer @NAL naming first
|
||||
elif uaf_tag in UAF_TAG_DICT: uaf_name = UAF_TAG_DICT[uaf_tag][0] # Otherwise use built-in naming
|
||||
elif uaf_tag == '@ROM': uaf_name = 'BIOS.bin' # BIOS/PFAT Firmware (w/o Signature)
|
||||
elif uaf_tag.startswith('@R0'): uaf_name = 'BIOS_0%s.bin' % uaf_tag[3:] # BIOS/PFAT Firmware
|
||||
|
@ -278,10 +280,16 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
|
|||
|
||||
# Check if unknown @UAF|@HPU Module Tag is present in @NAL but not in built-in dictionary
|
||||
if uaf_tag in nal_dict and uaf_tag not in UAF_TAG_DICT and not uaf_tag.startswith(('@ROM','@R0','@S0','@DR','@DS')):
|
||||
printer('Note: Detected new AMI UCP Module %s (%s) in @NAL!' % (uaf_tag, nal_dict[uaf_tag]), padding + 4, pause=True)
|
||||
printer('Note: Detected new AMI UCP Module %s (%s) in @NAL!' % (uaf_tag, nal_dict[uaf_tag][1]), padding + 4, pause=True)
|
||||
|
||||
# Generate @UAF|@HPU Module File name, depending on whether decompression will be required
|
||||
uaf_fname = os.path.join(extract_path, safe_name(uaf_name + ('.temp' if is_comp else uaf_fext)))
|
||||
uaf_sname = get_safe_name(uaf_name + ('.temp' if is_comp else uaf_fext))
|
||||
if uaf_tag in nal_dict:
|
||||
uaf_npath = get_safe_path(extract_path, nal_dict[uaf_tag][0])
|
||||
Path.mkdir(Path(uaf_npath), parents=True, exist_ok=True)
|
||||
uaf_fname = get_safe_path(uaf_npath, uaf_sname)
|
||||
else:
|
||||
uaf_fname = get_safe_path(extract_path, uaf_sname)
|
||||
|
||||
if is_checksum: chk16_validate(uaf_data_all, uaf_tag, padding + 4)
|
||||
|
||||
|
@ -375,15 +383,19 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
|
|||
|
||||
# Parse all @NAL Module Entries
|
||||
for info in nal_info:
|
||||
info_tag,info_val = info.split(':',1)
|
||||
info_tag,info_value = info.split(':',1)
|
||||
|
||||
printer(info_tag + ' : ' + info_val, padding + 8, False) # Print @NAL Module Tag-Path Info
|
||||
printer(info_tag + ' : ' + info_value, padding + 8, False) # Print @NAL Module Tag-Path Info
|
||||
|
||||
nal_dict[info_tag] = os.path.basename(info_val) # Assign a file name (w/o path) to each Tag
|
||||
info_part = PurePath(info_value.replace('\\', os.sep)).parts # Split path in parts
|
||||
info_path = to_string(info_part[1:-1], os.sep) # Get path without drive/root or file
|
||||
info_name = info_part[-1] # Get file from last path part
|
||||
|
||||
nal_dict[info_tag] = (info_path,info_name) # Assign a file path & name to each Tag
|
||||
|
||||
# Parse Insyde BIOS @UAF|@HPU Module (@INS)
|
||||
if uaf_tag == '@INS' and is_7z_supported(uaf_fname):
|
||||
ins_dir = os.path.join(extract_path, safe_name(uaf_tag + '_nested-SFX')) # Generate extraction directory
|
||||
ins_dir = os.path.join(extract_path, get_safe_name(uaf_tag + '_nested-SFX')) # Generate extraction directory
|
||||
|
||||
printer('Insyde BIOS 7z SFX Archive:', padding + 4)
|
||||
|
||||
|
@ -394,7 +406,7 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
|
|||
pfat_match,pfat_buffer = get_ami_pfat(uaf_data_raw)
|
||||
|
||||
if pfat_match:
|
||||
pfat_dir = os.path.join(extract_path, safe_name(uaf_name))
|
||||
pfat_dir = os.path.join(extract_path, get_safe_name(uaf_name))
|
||||
|
||||
parse_pfat_file(pfat_buffer, pfat_dir, padding + 4)
|
||||
|
||||
|
@ -410,7 +422,7 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
|
|||
|
||||
# Parse Nested AMI UCP Structure
|
||||
if nested_uaf_off:
|
||||
uaf_dir = os.path.join(extract_path, safe_name(uaf_tag + '_nested-UCP')) # Generate extraction directory
|
||||
uaf_dir = os.path.join(extract_path, get_safe_name(uaf_tag + '_nested-UCP')) # Generate extraction directory
|
||||
|
||||
ucp_extract(nested_uaf_bin, uaf_dir, nested_uaf_tag, padding + 4, is_checksum) # Call recursively
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue