From 70404b1485ea026e153af9296f73677c1c1643bc Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Fri, 30 Apr 2021 22:02:43 -0400 Subject: [PATCH 1/6] Moved helper code out of __init__.py Preparing for the terse executable loader --- __init__.py | 231 +--------------------------------------------------- helper.py | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+), 229 deletions(-) create mode 100644 helper.py diff --git a/__init__.py b/__init__.py index 6861999..12190ad 100644 --- a/__init__.py +++ b/__init__.py @@ -1,231 +1,4 @@ -""" -Binary Ninja plugin that aids in analysis of UEFI PEI and DXE modules -""" - -import os -import csv -import glob -import uuid -from binaryninja import (PluginCommand, BackgroundTaskThread, SegmentFlag, SectionSemantics, BinaryReader, Symbol, - SymbolType, HighLevelILOperation, BinaryView) -from binaryninja.highlevelil import HighLevelILInstruction -from binaryninja.types import (Type, FunctionParameter) - -class UEFIHelper(BackgroundTaskThread): - """Class for analyzing UEFI firmware to automate GUID annotation, segment fixup, type imports, and more - """ - - def __init__(self, bv: BinaryView): - BackgroundTaskThread.__init__(self, '', False) - self.bv = bv - self.br = BinaryReader(self.bv) - self.dirname = os.path.dirname(os.path.abspath(__file__)) - self.guids = self._load_guids() - - def _fix_segments(self): - """UEFI modules run during boot, without page protections. Everything is RWX despite that the PE is built with - the segments not being writable. It needs to be RWX so calls through global function pointers are displayed - properly. - """ - - for seg in self.bv.segments: - # Make segment RWX - self.bv.add_user_segment(seg.start, seg.data_length, seg.data_offset, seg.data_length, - SegmentFlag.SegmentWritable|SegmentFlag.SegmentReadable|SegmentFlag.SegmentExecutable) - - # Make section semantics ReadWriteDataSectionSemantics - for section in self.bv.get_sections_at(seg.start): - self.bv.add_user_section(section.name, section.end-section.start, SectionSemantics.ReadWriteDataSectionSemantics) - - def _import_types_from_headers(self): - """Parse EDKII types from header files - """ - - hdrs_path = os.path.join(self.dirname, 'headers') - headers = glob.glob(os.path.join(hdrs_path, '*.h')) - for hdr in headers: - _types = self.bv.platform.parse_types_from_source_file(hdr) - for name, _type in _types.types.items(): - self.bv.define_user_type(name, _type) - - def _set_entry_point_prototype(self): - """Apply correct prototype to the module entry point - """ - - _start = self.bv.get_function_at(self.bv.entry_point) - _start.function_type = "EFI_STATUS ModuleEntryPoint(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)" - - def _load_guids(self): - """Read known GUIDs from CSV and convert string GUIDs to bytes - - :return: Dictionary containing GUID bytes and associated names - """ - - guids_path = os.path.join(self.dirname, 'guids.csv') - with open(guids_path) as f: - reader = csv.reader(f, skipinitialspace=True) - guids = dict(reader) - - # Convert to bytes for faster lookup - guid_bytes = dict() - for guid, name in guids.items(): - guid_bytes[name] = uuid.UUID(guid).bytes_le - - return guid_bytes - - def _apply_guid_name_if_data(self, name: str, address: int): - """Check if there is a function at the address. If not, then apply the EFI_GUID type and name it - - :param name: Name/symbol to apply to the GUID - :param address: Address of the GUID - """ - - print(f'Found {name} at 0x{hex(address)} ({uuid.UUID(bytes_le=self.guids[name])})') - - # Just to avoid a unlikely false positive and screwing up disassembly - if self.bv.get_functions_at(address) != []: - print(f'There is code at {address}, not applying GUID type and name') - return - - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, address, 'g'+name)) - t = self.bv.parse_type_string("EFI_GUID") - self.bv.define_user_data_var(address, t[0]) - - def _find_known_guids(self): - """Search for known GUIDs and apply names to matches not within a function - """ - - names_list = list(self.guids.keys()) - guids_list = list(self.guids.values()) - def _check_guid_and_get_name(guid): - try: - return names_list[guids_list.index(guid)] - except ValueError: - return None - - for seg in self.bv.segments: - for i in range(seg.start, seg.end): - self.br.seek(i) - data = self.br.read(16) - if not data or len(data) != 16: - continue - - found_name = _check_guid_and_get_name(data) - if found_name: - self._apply_guid_name_if_data(found_name, i) - - def _set_if_uefi_core_type(self, instr: HighLevelILInstruction): - """Using HLIL, scrutinize the instruction to determine if it's a move of a local variable to a global variable. - If it is, check if the source operand type is a UEFI core type and apply the type to the destination global - variable. - - :param instr: High level IL instruction object - """ - - if instr.operation != HighLevelILOperation.HLIL_ASSIGN: - return - - if instr.dest.operation != HighLevelILOperation.HLIL_DEREF: - return - - if instr.dest.src.operation != HighLevelILOperation.HLIL_CONST_PTR: - return - - if instr.src.operation != HighLevelILOperation.HLIL_VAR: - return - - _type = instr.src.var.type - if len(_type.tokens) == 1 and str(_type.tokens[0]) == 'EFI_HANDLE': - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gImageHandle')) - elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_BOOT_SERVICES': - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gBS')) - elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_RUNTIME_SERVICES': - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gRS')) - elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_SYSTEM_TABLE': - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gST')) - else: - return - - self.bv.define_user_data_var(instr.dest.src.constant, instr.src.var.type) - print(f'Found global assignment - offset:0x{hex(instr.dest.src.constant)} type:{instr.src.var.type}') - - def _check_and_prop_types_on_call(self, instr: HighLevelILInstruction): - """Most UEFI modules don't assign globals in the entry function and instead call a initialization routine and - pass the system table to it where global assignments are made. This function ensures that the types are applied - to the initialization function params so that we can catch global assignments outside of the module entry - - :param instr: High level IL instruction object - """ - - if instr.operation not in [HighLevelILOperation.HLIL_TAILCALL, HighLevelILOperation.HLIL_CALL]: - return - - if instr.dest.operation != HighLevelILOperation.HLIL_CONST_PTR: - return - - argv_is_passed = False - for arg in instr.params: - if 'ImageHandle' in str(arg) or 'SystemTable' in str(arg): - argv_is_passed = True - break - - if not argv_is_passed: - return - - func = self.bv.get_function_at(instr.dest.constant) - old = func.function_type - call_args = instr.params - new_params = [] - for arg, param in zip(call_args, old.parameters): - if hasattr(arg, 'var'): - new_type = arg.var.type - else: - new_type = param.type - new_type.confidence = 256 - new_params.append(FunctionParameter(new_type, param.name)) - - # TODO: this is a hack to account for odd behavior. func.function_type should be able to set directly to - # Type.Function(...). However, during testing this isn't the case. I am only able to get it to work if I - # set function_type to a string and update analysis. - gross_hack = str( - Type.function(old.return_value, new_params, old.calling_convention, old.has_variable_arguments, old.stack_adjustment) - ).replace('(', '{}('.format(func.name)) - func.function_type = gross_hack - self.bv.update_analysis_and_wait() - - def _set_global_variables(self): - """On entry, UEFI modules usually set global variables for EFI_BOOT_SERVICES, EFI_RUNTIME_SERIVCES, and - EFI_SYSTEM_TABLE. This function attempts to identify these assignments and apply types. - """ - - func = self.bv.get_function_at(self.bv.entry_point) - for block in func.high_level_il: - for instr in block: - self._check_and_prop_types_on_call(instr) - - for func in self.bv.functions: - for block in func.high_level_il: - for instr in block: - self._set_if_uefi_core_type(instr) - - def run(self): - """Run the task in the background - """ - - self.progress = "UEFI Helper: Fixing up segments, applying types, and searching for known GUIDs ..." - self._fix_segments() - self._import_types_from_headers() - self._set_entry_point_prototype() - self._find_known_guids() - self.progress = "UEFI Helper: searching for global assignments for UEFI core services ..." - self._set_global_variables() - print('UEFI Helper completed successfully!') - -def run_uefi_helper(bv: BinaryView): - """Run UEFI helper utilities in the background - """ - - task = UEFIHelper(bv) - task.start() +from binaryninja import PluginCommand +from .helper import run_uefi_helper PluginCommand.register('UEFI Helper', 'Run UEFI Helper analysis', run_uefi_helper) diff --git a/helper.py b/helper.py new file mode 100644 index 0000000..0e13b64 --- /dev/null +++ b/helper.py @@ -0,0 +1,230 @@ +""" +Binary Ninja plugin that aids in analysis of UEFI PEI and DXE modules +""" + +import os +import csv +import glob +import uuid +from binaryninja import (BackgroundTaskThread, SegmentFlag, SectionSemantics, BinaryReader, Symbol, + SymbolType, HighLevelILOperation, BinaryView) +from binaryninja.highlevelil import HighLevelILInstruction +from binaryninja.types import (Type, FunctionParameter) + +class UEFIHelper(BackgroundTaskThread): + """Class for analyzing UEFI firmware to automate GUID annotation, segment fixup, type imports, and more + """ + + def __init__(self, bv: BinaryView): + BackgroundTaskThread.__init__(self, '', False) + self.bv = bv + self.br = BinaryReader(self.bv) + self.dirname = os.path.dirname(os.path.abspath(__file__)) + self.guids = self._load_guids() + + def _fix_segments(self): + """UEFI modules run during boot, without page protections. Everything is RWX despite that the PE is built with + the segments not being writable. It needs to be RWX so calls through global function pointers are displayed + properly. + """ + + for seg in self.bv.segments: + # Make segment RWX + self.bv.add_user_segment(seg.start, seg.data_length, seg.data_offset, seg.data_length, + SegmentFlag.SegmentWritable|SegmentFlag.SegmentReadable|SegmentFlag.SegmentExecutable) + + # Make section semantics ReadWriteDataSectionSemantics + for section in self.bv.get_sections_at(seg.start): + self.bv.add_user_section(section.name, section.end-section.start, SectionSemantics.ReadWriteDataSectionSemantics) + + def _import_types_from_headers(self): + """Parse EDKII types from header files + """ + + hdrs_path = os.path.join(self.dirname, 'headers') + headers = glob.glob(os.path.join(hdrs_path, '*.h')) + for hdr in headers: + _types = self.bv.platform.parse_types_from_source_file(hdr) + for name, _type in _types.types.items(): + self.bv.define_user_type(name, _type) + + def _set_entry_point_prototype(self): + """Apply correct prototype to the module entry point + """ + + _start = self.bv.get_function_at(self.bv.entry_point) + _start.function_type = "EFI_STATUS ModuleEntryPoint(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)" + + def _load_guids(self): + """Read known GUIDs from CSV and convert string GUIDs to bytes + + :return: Dictionary containing GUID bytes and associated names + """ + + guids_path = os.path.join(self.dirname, 'guids.csv') + with open(guids_path) as f: + reader = csv.reader(f, skipinitialspace=True) + guids = dict(reader) + + # Convert to bytes for faster lookup + guid_bytes = dict() + for guid, name in guids.items(): + guid_bytes[name] = uuid.UUID(guid).bytes_le + + return guid_bytes + + def _apply_guid_name_if_data(self, name: str, address: int): + """Check if there is a function at the address. If not, then apply the EFI_GUID type and name it + + :param name: Name/symbol to apply to the GUID + :param address: Address of the GUID + """ + + print(f'Found {name} at 0x{hex(address)} ({uuid.UUID(bytes_le=self.guids[name])})') + + # Just to avoid a unlikely false positive and screwing up disassembly + if self.bv.get_functions_at(address) != []: + print(f'There is code at {address}, not applying GUID type and name') + return + + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, address, 'g'+name)) + t = self.bv.parse_type_string("EFI_GUID") + self.bv.define_user_data_var(address, t[0]) + + def _find_known_guids(self): + """Search for known GUIDs and apply names to matches not within a function + """ + + names_list = list(self.guids.keys()) + guids_list = list(self.guids.values()) + def _check_guid_and_get_name(guid): + try: + return names_list[guids_list.index(guid)] + except ValueError: + return None + + for seg in self.bv.segments: + for i in range(seg.start, seg.end): + self.br.seek(i) + data = self.br.read(16) + if not data or len(data) != 16: + continue + + found_name = _check_guid_and_get_name(data) + if found_name: + self._apply_guid_name_if_data(found_name, i) + + def _set_if_uefi_core_type(self, instr: HighLevelILInstruction): + """Using HLIL, scrutinize the instruction to determine if it's a move of a local variable to a global variable. + If it is, check if the source operand type is a UEFI core type and apply the type to the destination global + variable. + + :param instr: High level IL instruction object + """ + + if instr.operation != HighLevelILOperation.HLIL_ASSIGN: + return + + if instr.dest.operation != HighLevelILOperation.HLIL_DEREF: + return + + if instr.dest.src.operation != HighLevelILOperation.HLIL_CONST_PTR: + return + + if instr.src.operation != HighLevelILOperation.HLIL_VAR: + return + + _type = instr.src.var.type + if len(_type.tokens) == 1 and str(_type.tokens[0]) == 'EFI_HANDLE': + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gImageHandle')) + elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_BOOT_SERVICES': + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gBS')) + elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_RUNTIME_SERVICES': + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gRS')) + elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_SYSTEM_TABLE': + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gST')) + else: + return + + self.bv.define_user_data_var(instr.dest.src.constant, instr.src.var.type) + print(f'Found global assignment - offset:0x{hex(instr.dest.src.constant)} type:{instr.src.var.type}') + + def _check_and_prop_types_on_call(self, instr: HighLevelILInstruction): + """Most UEFI modules don't assign globals in the entry function and instead call a initialization routine and + pass the system table to it where global assignments are made. This function ensures that the types are applied + to the initialization function params so that we can catch global assignments outside of the module entry + + :param instr: High level IL instruction object + """ + + if instr.operation not in [HighLevelILOperation.HLIL_TAILCALL, HighLevelILOperation.HLIL_CALL]: + return + + if instr.dest.operation != HighLevelILOperation.HLIL_CONST_PTR: + return + + argv_is_passed = False + for arg in instr.params: + if 'ImageHandle' in str(arg) or 'SystemTable' in str(arg): + argv_is_passed = True + break + + if not argv_is_passed: + return + + func = self.bv.get_function_at(instr.dest.constant) + old = func.function_type + call_args = instr.params + new_params = [] + for arg, param in zip(call_args, old.parameters): + if hasattr(arg, 'var'): + new_type = arg.var.type + else: + new_type = param.type + new_type.confidence = 256 + new_params.append(FunctionParameter(new_type, param.name)) + + # TODO: this is a hack to account for odd behavior. func.function_type should be able to set directly to + # Type.Function(...). However, during testing this isn't the case. I am only able to get it to work if I + # set function_type to a string and update analysis. + gross_hack = str( + Type.function(old.return_value, new_params, old.calling_convention, old.has_variable_arguments, old.stack_adjustment) + ).replace('(', '{}('.format(func.name)) + func.function_type = gross_hack + self.bv.update_analysis_and_wait() + + def _set_global_variables(self): + """On entry, UEFI modules usually set global variables for EFI_BOOT_SERVICES, EFI_RUNTIME_SERIVCES, and + EFI_SYSTEM_TABLE. This function attempts to identify these assignments and apply types. + """ + + func = self.bv.get_function_at(self.bv.entry_point) + for block in func.high_level_il: + for instr in block: + self._check_and_prop_types_on_call(instr) + + for func in self.bv.functions: + for block in func.high_level_il: + for instr in block: + self._set_if_uefi_core_type(instr) + + def run(self): + """Run the task in the background + """ + + self.progress = "UEFI Helper: Fixing up segments, applying types, and searching for known GUIDs ..." + self._fix_segments() + self._import_types_from_headers() + self._set_entry_point_prototype() + self._find_known_guids() + self.progress = "UEFI Helper: searching for global assignments for UEFI core services ..." + self._set_global_variables() + print('UEFI Helper completed successfully!') + +def run_uefi_helper(bv: BinaryView): + """Run UEFI helper utilities in the background + """ + + task = UEFIHelper(bv) + task.start() + From ecf61e85c58c025f8360fd655dccfd2b45e42b0f Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Sat, 1 May 2021 01:26:54 -0400 Subject: [PATCH 2/6] Initial loader for terse executables Does a failry good job as is. I need to read more about the TE spec to see if there is anything else that I should care about. I also need to modify the UEFI helper to import different types for PEI --- __init__.py | 3 + teloader.py | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 teloader.py diff --git a/__init__.py b/__init__.py index 12190ad..cc3a6f9 100644 --- a/__init__.py +++ b/__init__.py @@ -1,4 +1,7 @@ from binaryninja import PluginCommand from .helper import run_uefi_helper +from .teloader import TerseExecutableView PluginCommand.register('UEFI Helper', 'Run UEFI Helper analysis', run_uefi_helper) +TerseExecutableView.register() + diff --git a/teloader.py b/teloader.py new file mode 100644 index 0000000..d8ef572 --- /dev/null +++ b/teloader.py @@ -0,0 +1,168 @@ +"""BinaryView for UEFI Terse Executables +""" + +from binaryninja import BinaryView, Architecture, platform, SegmentFlag, SectionSemantics, Symbol, SymbolType +import struct + +TERSE_IMAGE_HEADER_SIZE = 40 +SECTION_HEADER_SIZE = 40 + +class TerseExecutableView(BinaryView): + """This class implements the BinaryView for Terse Executables + """ + + name = 'TE' + long_name = 'Terse Executable' + + def __init__(self, data: bytes): + BinaryView.__init__(self, parent_view=data, file_metadata=data.file) + self.raw = data + + @classmethod + def is_valid_for_data(self, data: bytes) -> bool: + """Determine if the loaded binary is a Terse Executable + + :param data: Raw binary data + :return: True if the binary is a TE, otherwise False + """ + + if data[0:2].decode('utf-8') == 'VZ': + return True + + return False + + def set_platform(self, machine_type: int): + """Set platform/architecture from machine type + + :param machine_type: Machine type from TE header + """ + + if machine_type == 332: + self.platform = platform.Platform['windows-x86'] + elif machine_type == -31132: + self.platform = platform.Platform['windows-x86_64'] + elif machine_type == -21916: + self.platform = platform.Platform['windows-aarch64'] + + def create_segments(self, image_base: int, num_of_sections: int): + """There's really only one segment in a TE and it's RWX. However, we set the header to read only jsut to make + sure it isn't disassembled as code. + + :param image_base: Virtual base address + :param num_of_sections: Number of sections (for header region size calculation) + """ + + headers_size = TERSE_IMAGE_HEADER_SIZE + num_of_sections * SECTION_HEADER_SIZE + self.add_auto_segment(image_base, headers_size, 0, headers_size, SegmentFlag.SegmentReadable) + code_region_size = len(self.raw)-headers_size + self.add_auto_segment(image_base+headers_size, code_region_size, headers_size, code_region_size, + SegmentFlag.SegmentReadable|SegmentFlag.SegmentWritable|SegmentFlag.SegmentExecutable) + + def create_sections(self, image_base: int, num_of_sections: int): + """Create sections + + :param image_base: Virtual base address + :param num_of_sections: Number of sections + """ + + base = TERSE_IMAGE_HEADER_SIZE + for _ in range(0, num_of_sections): + name = self.raw[base:base+8].decode('utf-8') + virtual_size = struct.unpack(' bool: + """Terse Executables are executable, return true + + :return: True + """ + + return True + + def perform_get_entry_point(self) -> int: + """Determine the address of the entry point function + + :return: Address of the entry point + """ + image_base = struct.unpack(' Date: Sun, 2 May 2021 00:53:25 -0400 Subject: [PATCH 3/6] Adding PEIM types to TE loader Using the default PEIM prototype for entry of terse executables instead of the DXE prototype. Adding EFI types in the loader on load. Modified the helper script to prevent overriding the entry prototype for TEs --- ...stem_table_x64.h => efi_system_table_64.h} | 0 helper.py | 20 +++++-- teloader.py | 59 ++++++++++++++----- 3 files changed, 58 insertions(+), 21 deletions(-) rename headers/{efi_system_table_x64.h => efi_system_table_64.h} (100%) diff --git a/headers/efi_system_table_x64.h b/headers/efi_system_table_64.h similarity index 100% rename from headers/efi_system_table_x64.h rename to headers/efi_system_table_64.h diff --git a/helper.py b/helper.py index 0e13b64..cc798e9 100644 --- a/helper.py +++ b/helper.py @@ -53,7 +53,8 @@ def _set_entry_point_prototype(self): """ _start = self.bv.get_function_at(self.bv.entry_point) - _start.function_type = "EFI_STATUS ModuleEntryPoint(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)" + if self.bv.view_type != 'TE': + _start.function_type = "EFI_STATUS ModuleEntryPoint(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)" def _load_guids(self): """Read known GUIDs from CSV and convert string GUIDs to bytes @@ -136,13 +137,17 @@ def _set_if_uefi_core_type(self, instr: HighLevelILInstruction): _type = instr.src.var.type if len(_type.tokens) == 1 and str(_type.tokens[0]) == 'EFI_HANDLE': - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gImageHandle')) + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gHandle')) elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_BOOT_SERVICES': self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gBS')) elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_RUNTIME_SERVICES': self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gRS')) elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_SYSTEM_TABLE': self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gST')) + elif len(_type.tokens) == 1 and str(_type.tokens[0]) == 'EFI_PEI_FILE_HANDLE': + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gHandle')) + elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_PEI_SERVICES': + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gPeiServices')) else: return @@ -165,7 +170,7 @@ def _check_and_prop_types_on_call(self, instr: HighLevelILInstruction): argv_is_passed = False for arg in instr.params: - if 'ImageHandle' in str(arg) or 'SystemTable' in str(arg): + if 'ImageHandle' in str(arg) or 'SystemTable' or 'FileHandle' or 'PeiServices' in str(arg): argv_is_passed = True break @@ -190,8 +195,11 @@ def _check_and_prop_types_on_call(self, instr: HighLevelILInstruction): gross_hack = str( Type.function(old.return_value, new_params, old.calling_convention, old.has_variable_arguments, old.stack_adjustment) ).replace('(', '{}('.format(func.name)) - func.function_type = gross_hack - self.bv.update_analysis_and_wait() + try: + func.function_type = gross_hack + self.bv.update_analysis_and_wait() + except SyntaxError: + pass # BN can't parse int48_t and other types despite that it uses it. Ran into this from a sidt instruction def _set_global_variables(self): """On entry, UEFI modules usually set global variables for EFI_BOOT_SERVICES, EFI_RUNTIME_SERIVCES, and @@ -223,6 +231,8 @@ def run(self): def run_uefi_helper(bv: BinaryView): """Run UEFI helper utilities in the background + + :param bv: BinaryView """ task = UEFIHelper(bv) diff --git a/teloader.py b/teloader.py index d8ef572..5193505 100644 --- a/teloader.py +++ b/teloader.py @@ -1,8 +1,10 @@ """BinaryView for UEFI Terse Executables """ -from binaryninja import BinaryView, Architecture, platform, SegmentFlag, SectionSemantics, Symbol, SymbolType +import glob +import os import struct +from binaryninja import BinaryView, platform, SegmentFlag, SectionSemantics, Symbol, SymbolType TERSE_IMAGE_HEADER_SIZE = 40 SECTION_HEADER_SIZE = 40 @@ -26,12 +28,15 @@ def is_valid_for_data(self, data: bytes) -> bool: :return: True if the binary is a TE, otherwise False """ - if data[0:2].decode('utf-8') == 'VZ': - return True + if len(data) < TERSE_IMAGE_HEADER_SIZE: + return False - return False + if data[0:2].decode('utf-8', 'replace') != 'VZ': + return False - def set_platform(self, machine_type: int): + return True + + def _set_platform(self, machine_type: int): """Set platform/architecture from machine type :param machine_type: Machine type from TE header @@ -44,7 +49,7 @@ def set_platform(self, machine_type: int): elif machine_type == -21916: self.platform = platform.Platform['windows-aarch64'] - def create_segments(self, image_base: int, num_of_sections: int): + def _create_segments(self, image_base: int, num_of_sections: int): """There's really only one segment in a TE and it's RWX. However, we set the header to read only jsut to make sure it isn't disassembled as code. @@ -58,7 +63,7 @@ def create_segments(self, image_base: int, num_of_sections: int): self.add_auto_segment(image_base+headers_size, code_region_size, headers_size, code_region_size, SegmentFlag.SegmentReadable|SegmentFlag.SegmentWritable|SegmentFlag.SegmentExecutable) - def create_sections(self, image_base: int, num_of_sections: int): + def _create_sections(self, image_base: int, num_of_sections: int): """Create sections :param image_base: Virtual base address @@ -70,8 +75,6 @@ def create_sections(self, image_base: int, num_of_sections: int): name = self.raw[base:base+8].decode('utf-8') virtual_size = struct.unpack(' bool: From f1f86a164c37125a321ad8eacd9e7530e56faee4 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Sun, 2 May 2021 00:55:53 -0400 Subject: [PATCH 4/6] Adding the EFI_PEI_SERVICES C headers --- headers/efi_pei_services_64.h | 322 ++++++++++++++++++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 headers/efi_pei_services_64.h diff --git a/headers/efi_pei_services_64.h b/headers/efi_pei_services_64.h new file mode 100644 index 0000000..cd3fd7f --- /dev/null +++ b/headers/efi_pei_services_64.h @@ -0,0 +1,322 @@ +typedef unsigned char undefined; + +typedef unsigned char byte; +typedef unsigned int dword; +typedef unsigned long long qword; +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long long ulonglong; +typedef unsigned char undefined1; +typedef unsigned int undefined4; +typedef unsigned short ushort; +typedef unsigned short word; + +struct EFI_PEI_PPI_DESCRIPTOR; +struct EFI_STATUS_CODE_DATA; +struct EFI_FV_FILE_INFO; +struct EFI_FV_FILE_INFO2; +struct EFI_PEI_PCI_CFG2_PPI; +struct EFI_PEI_CPU_IO_PPI; +struct EFI_FV_INFO; + +struct _EFI_PEI_SERVICES; +typedef struct _EFI_PEI_SERVICES EFI_PEI_SERVICES; + +typedef UINT64 UINTN; + +typedef UINTN RETURN_STATUS; + +typedef RETURN_STATUS EFI_STATUS; + +typedef EFI_STATUS (* EFI_PEI_INSTALL_PPI)(EFI_PEI_SERVICES * *, struct EFI_PEI_PPI_DESCRIPTOR *); + +typedef EFI_STATUS (* EFI_PEI_REINSTALL_PPI)(EFI_PEI_SERVICES * *, struct EFI_PEI_PPI_DESCRIPTOR *, struct EFI_PEI_PPI_DESCRIPTOR *); + +typedef GUID EFI_GUID; + +typedef EFI_STATUS (* EFI_PEI_LOCATE_PPI)(EFI_PEI_SERVICES * *, EFI_GUID *, UINTN, struct EFI_PEI_PPI_DESCRIPTOR * *, void * *); + +struct _EFI_PEI_NOTIFY_DESCRIPTOR; +typedef struct _EFI_PEI_NOTIFY_DESCRIPTOR EFI_PEI_NOTIFY_DESCRIPTOR; + +typedef EFI_STATUS (* EFI_PEI_NOTIFY_PPI)(EFI_PEI_SERVICES * *, EFI_PEI_NOTIFY_DESCRIPTOR *); + +typedef UINT32 EFI_BOOT_MODE; + +typedef EFI_STATUS (* EFI_PEI_GET_BOOT_MODE)(EFI_PEI_SERVICES * *, EFI_BOOT_MODE *); + +typedef EFI_STATUS (* EFI_PEI_SET_BOOT_MODE)(EFI_PEI_SERVICES * *, EFI_BOOT_MODE); + +typedef EFI_STATUS (* EFI_PEI_GET_HOB_LIST)(EFI_PEI_SERVICES * *, void * *); + +typedef EFI_STATUS (* EFI_PEI_CREATE_HOB)(EFI_PEI_SERVICES * *, UINT16, UINT16, void * *); + +typedef void * EFI_PEI_FV_HANDLE; + +typedef EFI_STATUS (* EFI_PEI_FFS_FIND_NEXT_VOLUME2)(EFI_PEI_SERVICES * *, UINTN, EFI_PEI_FV_HANDLE *); + +typedef UINT8 EFI_FV_FILETYPE; + +typedef void * EFI_PEI_FILE_HANDLE; + +typedef EFI_STATUS (* EFI_PEI_FFS_FIND_NEXT_FILE2)(EFI_PEI_SERVICES * *, EFI_FV_FILETYPE, EFI_PEI_FV_HANDLE, EFI_PEI_FILE_HANDLE *); + +typedef UINT8 EFI_SECTION_TYPE; + +typedef EFI_STATUS (* EFI_PEI_FFS_FIND_SECTION_DATA2)(EFI_PEI_SERVICES * *, EFI_SECTION_TYPE, EFI_PEI_FILE_HANDLE, void * *); + +typedef UINT64 EFI_PHYSICAL_ADDRESS; + +typedef EFI_STATUS (* EFI_PEI_INSTALL_PEI_MEMORY)(EFI_PEI_SERVICES * *, EFI_PHYSICAL_ADDRESS, UINT64); + +enum enum_16 { + EfiBootServicesCode=3, + EfiRuntimeServicesData=6, + EfiMemoryMappedIOPortSpace=12, + EfiLoaderData=2, + EfiBootServicesData=4, + EfiLoaderCode=1, + EfiReservedMemoryType=0, + EfiRuntimeServicesCode=5, + EfiACPIReclaimMemory=9, + EfiMaxMemoryType=15, + EfiConventionalMemory=7, + EfiMemoryMappedIO=11, + EfiPalCode=13, + EfiPersistentMemory=14, + EfiACPIMemoryNVS=10, + EfiUnusableMemory=8 +}; + +typedef enum enum_16 EFI_MEMORY_TYPE; + +typedef EFI_STATUS (* EFI_PEI_ALLOCATE_PAGES)(EFI_PEI_SERVICES * *, EFI_MEMORY_TYPE, UINTN, EFI_PHYSICAL_ADDRESS *); + +typedef EFI_STATUS (* EFI_PEI_ALLOCATE_POOL)(EFI_PEI_SERVICES * *, UINTN, void * *); + +typedef void (* EFI_PEI_COPY_MEM)(void *, void *, UINTN); + +typedef void (* EFI_PEI_SET_MEM)(void *, UINTN, UINT8); + +typedef UINT32 EFI_STATUS_CODE_TYPE; + +typedef UINT32 EFI_STATUS_CODE_VALUE; + +typedef EFI_STATUS (* EFI_PEI_REPORT_STATUS_CODE)(EFI_PEI_SERVICES * *, EFI_STATUS_CODE_TYPE, EFI_STATUS_CODE_VALUE, UINT32, EFI_GUID *, struct EFI_STATUS_CODE_DATA *); + +typedef EFI_STATUS (* EFI_PEI_RESET_SYSTEM)(EFI_PEI_SERVICES * *); + + +typedef EFI_STATUS (* EFI_PEI_FFS_FIND_BY_NAME)(EFI_GUID *, EFI_PEI_FV_HANDLE, EFI_PEI_FILE_HANDLE *); + +typedef EFI_STATUS (* EFI_PEI_FFS_GET_FILE_INFO)(EFI_PEI_FILE_HANDLE, struct EFI_FV_FILE_INFO *); + +typedef EFI_STATUS (* EFI_PEI_FFS_GET_VOLUME_INFO)(EFI_PEI_FV_HANDLE, struct EFI_FV_INFO *); + +typedef EFI_STATUS (* EFI_PEI_REGISTER_FOR_SHADOW)(EFI_PEI_FILE_HANDLE); + +typedef EFI_STATUS (* EFI_PEI_FFS_FIND_SECTION_DATA3)(EFI_PEI_SERVICES * *, EFI_SECTION_TYPE, UINTN, EFI_PEI_FILE_HANDLE, void * *, UINT32 *); + +typedef EFI_STATUS (* EFI_PEI_FFS_GET_FILE_INFO2)(EFI_PEI_FILE_HANDLE, struct EFI_FV_FILE_INFO2 *); + +enum enum_17 { + EfiResetCold=0, + EfiResetShutdown=2, + EfiResetWarm=1, + EfiResetPlatformSpecific=3 +}; + +typedef enum enum_17 EFI_RESET_TYPE; + +typedef void (* EFI_PEI_RESET2_SYSTEM)(EFI_RESET_TYPE, EFI_STATUS, UINTN, void *); + +typedef EFI_STATUS (* EFI_PEI_FREE_PAGES)(EFI_PEI_SERVICES * *, EFI_PHYSICAL_ADDRESS, UINTN); + +typedef EFI_STATUS (* EFI_PEIM_NOTIFY_ENTRY_POINT)(EFI_PEI_SERVICES * *, EFI_PEI_NOTIFY_DESCRIPTOR *, void *); + +typedef UINT8 (* EFI_PEI_CPU_IO_PPI_IO_READ8)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef UINT16 (* EFI_PEI_CPU_IO_PPI_IO_READ16)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef UINT32 (* EFI_PEI_CPU_IO_PPI_IO_READ32)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef UINT64 (* EFI_PEI_CPU_IO_PPI_IO_READ64)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef void (* EFI_PEI_CPU_IO_PPI_IO_WRITE8)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT8); + +typedef void (* EFI_PEI_CPU_IO_PPI_IO_WRITE16)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT16); + +typedef void (* EFI_PEI_CPU_IO_PPI_IO_WRITE32)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT32); + +typedef void (* EFI_PEI_CPU_IO_PPI_IO_WRITE64)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT64); + +typedef UINT8 (* EFI_PEI_CPU_IO_PPI_MEM_READ8)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef UINT16 (* EFI_PEI_CPU_IO_PPI_MEM_READ16)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef UINT32 (* EFI_PEI_CPU_IO_PPI_MEM_READ32)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef UINT64 (* EFI_PEI_CPU_IO_PPI_MEM_READ64)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef void (* EFI_PEI_CPU_IO_PPI_MEM_WRITE8)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT8); + +typedef void (* EFI_PEI_CPU_IO_PPI_MEM_WRITE16)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT16); + +typedef void (* EFI_PEI_CPU_IO_PPI_MEM_WRITE32)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT32); + +typedef void (* EFI_PEI_CPU_IO_PPI_MEM_WRITE64)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT64); + +enum enum_897 { + EfiPeiPciCfgWidthUint64=3, + EfiPeiPciCfgWidthUint32=2, + EfiPeiPciCfgWidthUint8=0, + EfiPeiPciCfgWidthUint16=1, + EfiPeiPciCfgWidthMaximum=4 +}; + +typedef enum enum_897 EFI_PEI_PCI_CFG_PPI_WIDTH; + +typedef EFI_STATUS (* EFI_PEI_PCI_CFG2_PPI_IO)(EFI_PEI_SERVICES * *, EFI_PEI_PCI_CFG2_PPI *, EFI_PEI_PCI_CFG_PPI_WIDTH, UINT64, void *); + +typedef EFI_STATUS (* EFI_PEI_PCI_CFG2_PPI_RW)(EFI_PEI_SERVICES * *, EFI_PEI_PCI_CFG2_PPI *, EFI_PEI_PCI_CFG_PPI_WIDTH, UINT64, void *, void *); + +typedef UINT32 EFI_FV_FILE_ATTRIBUTES; + +typedef UINT32 EFI_FVB_ATTRIBUTES_2; + +enum enum_868 { + EfiPeiCpuIoWidthFifoUint16=5, + EfiPeiCpuIoWidthFillUint32=10, + EfiPeiCpuIoWidthFillUint16=9, + EfiPeiCpuIoWidthFifoUint64=7, + EfiPeiCpuIoWidthFifoUint32=6, + EfiPeiCpuIoWidthFillUint8=8, + EfiPeiCpuIoWidthUint8=0, + EfiPeiCpuIoWidthUint16=1, + EfiPeiCpuIoWidthMaximum=12, + EfiPeiCpuIoWidthUint64=3, + EfiPeiCpuIoWidthUint32=2, + EfiPeiCpuIoWidthFifoUint8=4, + EfiPeiCpuIoWidthFillUint64=11 +}; + +typedef enum enum_868 EFI_PEI_CPU_IO_PPI_WIDTH; + +typedef EFI_STATUS (* EFI_PEI_CPU_IO_PPI_IO_MEM)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, EFI_PEI_CPU_IO_PPI_WIDTH, UINT64, UINTN, void *); + +struct _EFI_PEI_NOTIFY_DESCRIPTOR { + UINTN Flags; + EFI_GUID * Guid; + EFI_PEIM_NOTIFY_ENTRY_POINT Notify; +}; + +struct EFI_FV_FILE_INFO2 { + EFI_GUID FileName; + EFI_FV_FILETYPE FileType; + EFI_FV_FILE_ATTRIBUTES FileAttributes; + void * Buffer; + UINT32 BufferSize; + UINT32 AuthenticationStatus; +}; + +struct EFI_TABLE_HEADER { + UINT64 Signature; + UINT32 Revision; + UINT32 HeaderSize; + UINT32 CRC32; + UINT32 Reserved; +}; + +struct EFI_PEI_CPU_IO_PPI_ACCESS { + EFI_PEI_CPU_IO_PPI_IO_MEM Read; + EFI_PEI_CPU_IO_PPI_IO_MEM Write; +}; + +struct EFI_PEI_CPU_IO_PPI { + struct EFI_PEI_CPU_IO_PPI_ACCESS Mem; + struct EFI_PEI_CPU_IO_PPI_ACCESS Io; + EFI_PEI_CPU_IO_PPI_IO_READ8 IoRead8; + EFI_PEI_CPU_IO_PPI_IO_READ16 IoRead16; + EFI_PEI_CPU_IO_PPI_IO_READ32 IoRead32; + EFI_PEI_CPU_IO_PPI_IO_READ64 IoRead64; + EFI_PEI_CPU_IO_PPI_IO_WRITE8 IoWrite8; + EFI_PEI_CPU_IO_PPI_IO_WRITE16 IoWrite16; + EFI_PEI_CPU_IO_PPI_IO_WRITE32 IoWrite32; + EFI_PEI_CPU_IO_PPI_IO_WRITE64 IoWrite64; + EFI_PEI_CPU_IO_PPI_MEM_READ8 MemRead8; + EFI_PEI_CPU_IO_PPI_MEM_READ16 MemRead16; + EFI_PEI_CPU_IO_PPI_MEM_READ32 MemRead32; + EFI_PEI_CPU_IO_PPI_MEM_READ64 MemRead64; + EFI_PEI_CPU_IO_PPI_MEM_WRITE8 MemWrite8; + EFI_PEI_CPU_IO_PPI_MEM_WRITE16 MemWrite16; + EFI_PEI_CPU_IO_PPI_MEM_WRITE32 MemWrite32; + EFI_PEI_CPU_IO_PPI_MEM_WRITE64 MemWrite64; +}; + +struct EFI_FV_INFO { + EFI_FVB_ATTRIBUTES_2 FvAttributes; + EFI_GUID FvFormat; + EFI_GUID FvName; + void * FvStart; + UINT64 FvSize; +}; + +struct EFI_PEI_PCI_CFG2_PPI { + EFI_PEI_PCI_CFG2_PPI_IO Read; + EFI_PEI_PCI_CFG2_PPI_IO Write; + EFI_PEI_PCI_CFG2_PPI_RW Modify; + UINT16 Segment; +}; + +struct EFI_PEI_PPI_DESCRIPTOR { + UINTN Flags; + EFI_GUID * Guid; + void * Ppi; +}; + +struct EFI_FV_FILE_INFO { + EFI_GUID FileName; + EFI_FV_FILETYPE FileType; + EFI_FV_FILE_ATTRIBUTES FileAttributes; + void * Buffer; + UINT32 BufferSize; +}; + +struct _EFI_PEI_SERVICES { + struct EFI_TABLE_HEADER Hdr; + EFI_PEI_INSTALL_PPI InstallPpi; + EFI_PEI_REINSTALL_PPI ReInstallPpi; + EFI_PEI_LOCATE_PPI LocatePpi; + EFI_PEI_NOTIFY_PPI NotifyPpi; + EFI_PEI_GET_BOOT_MODE GetBootMode; + EFI_PEI_SET_BOOT_MODE SetBootMode; + EFI_PEI_GET_HOB_LIST GetHobList; + EFI_PEI_CREATE_HOB CreateHob; + EFI_PEI_FFS_FIND_NEXT_VOLUME2 FfsFindNextVolume; + EFI_PEI_FFS_FIND_NEXT_FILE2 FfsFindNextFile; + EFI_PEI_FFS_FIND_SECTION_DATA2 FfsFindSectionData; + EFI_PEI_INSTALL_PEI_MEMORY InstallPeiMemory; + EFI_PEI_ALLOCATE_PAGES AllocatePages; + EFI_PEI_ALLOCATE_POOL AllocatePool; + EFI_PEI_COPY_MEM CopyMem; + EFI_PEI_SET_MEM SetMem; + EFI_PEI_REPORT_STATUS_CODE ReportStatusCode; + EFI_PEI_RESET_SYSTEM ResetSystem; + EFI_PEI_CPU_IO_PPI * CpuIo; + EFI_PEI_PCI_CFG2_PPI * PciCfg; + EFI_PEI_FFS_FIND_BY_NAME FfsFindFileByName; + EFI_PEI_FFS_GET_FILE_INFO FfsGetFileInfo; + EFI_PEI_FFS_GET_VOLUME_INFO FfsGetVolumeInfo; + EFI_PEI_REGISTER_FOR_SHADOW RegisterForShadow; + EFI_PEI_FFS_FIND_SECTION_DATA3 FindSectionData3; + EFI_PEI_FFS_GET_FILE_INFO2 FfsGetFileInfo2; + EFI_PEI_RESET2_SYSTEM ResetSystem2; + EFI_PEI_FREE_PAGES FreePages; +}; + +struct EFI_STATUS_CODE_DATA { + UINT16 HeaderSize; + UINT16 Size; + EFI_GUID Type; +}; + From 5621f8419042b4924a5e22a90c12c60339271940 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Sun, 2 May 2021 00:58:55 -0400 Subject: [PATCH 5/6] Updated the README and plugin JSON --- README.md | 1 + plugin.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 598d345..dd4be48 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Helper plugin for analyzing UEFI firmware. This plugin contains the following fe * Locate known protocol GUIDs and assign the GUID type and a symbol * Locate global assigments in entry and initialization functions and assign types * `EFI_SYSTEM_TABLE`, `EFI_RUNTIME_SERVICES`, `EFI_BOOT_SERVICES`, etc... +* Loader for Terse Executables ![demo bn-uefi-helper](screen.gif) diff --git a/plugin.json b/plugin.json index 9935cd3..763195f 100644 --- a/plugin.json +++ b/plugin.json @@ -24,6 +24,6 @@ "Windows": "", "Linux": "" }, - "version": "0.1", + "version": "0.2", "minimumbinaryninjaversion": 2660 -} \ No newline at end of file +} From d1553b822df7ecbc3b935e1727c98db13c37373b Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Sun, 2 May 2021 01:00:43 -0400 Subject: [PATCH 6/6] Removed windows line endings --- headers/efi_pei_services_64.h | 644 +++++++++++++++++----------------- helper.py | 480 ++++++++++++------------- 2 files changed, 562 insertions(+), 562 deletions(-) diff --git a/headers/efi_pei_services_64.h b/headers/efi_pei_services_64.h index cd3fd7f..5702ce8 100644 --- a/headers/efi_pei_services_64.h +++ b/headers/efi_pei_services_64.h @@ -1,322 +1,322 @@ -typedef unsigned char undefined; - -typedef unsigned char byte; -typedef unsigned int dword; -typedef unsigned long long qword; -typedef unsigned char uchar; -typedef unsigned int uint; -typedef unsigned long long ulonglong; -typedef unsigned char undefined1; -typedef unsigned int undefined4; -typedef unsigned short ushort; -typedef unsigned short word; - -struct EFI_PEI_PPI_DESCRIPTOR; -struct EFI_STATUS_CODE_DATA; -struct EFI_FV_FILE_INFO; -struct EFI_FV_FILE_INFO2; -struct EFI_PEI_PCI_CFG2_PPI; -struct EFI_PEI_CPU_IO_PPI; -struct EFI_FV_INFO; - -struct _EFI_PEI_SERVICES; -typedef struct _EFI_PEI_SERVICES EFI_PEI_SERVICES; - -typedef UINT64 UINTN; - -typedef UINTN RETURN_STATUS; - -typedef RETURN_STATUS EFI_STATUS; - -typedef EFI_STATUS (* EFI_PEI_INSTALL_PPI)(EFI_PEI_SERVICES * *, struct EFI_PEI_PPI_DESCRIPTOR *); - -typedef EFI_STATUS (* EFI_PEI_REINSTALL_PPI)(EFI_PEI_SERVICES * *, struct EFI_PEI_PPI_DESCRIPTOR *, struct EFI_PEI_PPI_DESCRIPTOR *); - -typedef GUID EFI_GUID; - -typedef EFI_STATUS (* EFI_PEI_LOCATE_PPI)(EFI_PEI_SERVICES * *, EFI_GUID *, UINTN, struct EFI_PEI_PPI_DESCRIPTOR * *, void * *); - -struct _EFI_PEI_NOTIFY_DESCRIPTOR; -typedef struct _EFI_PEI_NOTIFY_DESCRIPTOR EFI_PEI_NOTIFY_DESCRIPTOR; - -typedef EFI_STATUS (* EFI_PEI_NOTIFY_PPI)(EFI_PEI_SERVICES * *, EFI_PEI_NOTIFY_DESCRIPTOR *); - -typedef UINT32 EFI_BOOT_MODE; - -typedef EFI_STATUS (* EFI_PEI_GET_BOOT_MODE)(EFI_PEI_SERVICES * *, EFI_BOOT_MODE *); - -typedef EFI_STATUS (* EFI_PEI_SET_BOOT_MODE)(EFI_PEI_SERVICES * *, EFI_BOOT_MODE); - -typedef EFI_STATUS (* EFI_PEI_GET_HOB_LIST)(EFI_PEI_SERVICES * *, void * *); - -typedef EFI_STATUS (* EFI_PEI_CREATE_HOB)(EFI_PEI_SERVICES * *, UINT16, UINT16, void * *); - -typedef void * EFI_PEI_FV_HANDLE; - -typedef EFI_STATUS (* EFI_PEI_FFS_FIND_NEXT_VOLUME2)(EFI_PEI_SERVICES * *, UINTN, EFI_PEI_FV_HANDLE *); - -typedef UINT8 EFI_FV_FILETYPE; - -typedef void * EFI_PEI_FILE_HANDLE; - -typedef EFI_STATUS (* EFI_PEI_FFS_FIND_NEXT_FILE2)(EFI_PEI_SERVICES * *, EFI_FV_FILETYPE, EFI_PEI_FV_HANDLE, EFI_PEI_FILE_HANDLE *); - -typedef UINT8 EFI_SECTION_TYPE; - -typedef EFI_STATUS (* EFI_PEI_FFS_FIND_SECTION_DATA2)(EFI_PEI_SERVICES * *, EFI_SECTION_TYPE, EFI_PEI_FILE_HANDLE, void * *); - -typedef UINT64 EFI_PHYSICAL_ADDRESS; - -typedef EFI_STATUS (* EFI_PEI_INSTALL_PEI_MEMORY)(EFI_PEI_SERVICES * *, EFI_PHYSICAL_ADDRESS, UINT64); - -enum enum_16 { - EfiBootServicesCode=3, - EfiRuntimeServicesData=6, - EfiMemoryMappedIOPortSpace=12, - EfiLoaderData=2, - EfiBootServicesData=4, - EfiLoaderCode=1, - EfiReservedMemoryType=0, - EfiRuntimeServicesCode=5, - EfiACPIReclaimMemory=9, - EfiMaxMemoryType=15, - EfiConventionalMemory=7, - EfiMemoryMappedIO=11, - EfiPalCode=13, - EfiPersistentMemory=14, - EfiACPIMemoryNVS=10, - EfiUnusableMemory=8 -}; - -typedef enum enum_16 EFI_MEMORY_TYPE; - -typedef EFI_STATUS (* EFI_PEI_ALLOCATE_PAGES)(EFI_PEI_SERVICES * *, EFI_MEMORY_TYPE, UINTN, EFI_PHYSICAL_ADDRESS *); - -typedef EFI_STATUS (* EFI_PEI_ALLOCATE_POOL)(EFI_PEI_SERVICES * *, UINTN, void * *); - -typedef void (* EFI_PEI_COPY_MEM)(void *, void *, UINTN); - -typedef void (* EFI_PEI_SET_MEM)(void *, UINTN, UINT8); - -typedef UINT32 EFI_STATUS_CODE_TYPE; - -typedef UINT32 EFI_STATUS_CODE_VALUE; - -typedef EFI_STATUS (* EFI_PEI_REPORT_STATUS_CODE)(EFI_PEI_SERVICES * *, EFI_STATUS_CODE_TYPE, EFI_STATUS_CODE_VALUE, UINT32, EFI_GUID *, struct EFI_STATUS_CODE_DATA *); - -typedef EFI_STATUS (* EFI_PEI_RESET_SYSTEM)(EFI_PEI_SERVICES * *); - - -typedef EFI_STATUS (* EFI_PEI_FFS_FIND_BY_NAME)(EFI_GUID *, EFI_PEI_FV_HANDLE, EFI_PEI_FILE_HANDLE *); - -typedef EFI_STATUS (* EFI_PEI_FFS_GET_FILE_INFO)(EFI_PEI_FILE_HANDLE, struct EFI_FV_FILE_INFO *); - -typedef EFI_STATUS (* EFI_PEI_FFS_GET_VOLUME_INFO)(EFI_PEI_FV_HANDLE, struct EFI_FV_INFO *); - -typedef EFI_STATUS (* EFI_PEI_REGISTER_FOR_SHADOW)(EFI_PEI_FILE_HANDLE); - -typedef EFI_STATUS (* EFI_PEI_FFS_FIND_SECTION_DATA3)(EFI_PEI_SERVICES * *, EFI_SECTION_TYPE, UINTN, EFI_PEI_FILE_HANDLE, void * *, UINT32 *); - -typedef EFI_STATUS (* EFI_PEI_FFS_GET_FILE_INFO2)(EFI_PEI_FILE_HANDLE, struct EFI_FV_FILE_INFO2 *); - -enum enum_17 { - EfiResetCold=0, - EfiResetShutdown=2, - EfiResetWarm=1, - EfiResetPlatformSpecific=3 -}; - -typedef enum enum_17 EFI_RESET_TYPE; - -typedef void (* EFI_PEI_RESET2_SYSTEM)(EFI_RESET_TYPE, EFI_STATUS, UINTN, void *); - -typedef EFI_STATUS (* EFI_PEI_FREE_PAGES)(EFI_PEI_SERVICES * *, EFI_PHYSICAL_ADDRESS, UINTN); - -typedef EFI_STATUS (* EFI_PEIM_NOTIFY_ENTRY_POINT)(EFI_PEI_SERVICES * *, EFI_PEI_NOTIFY_DESCRIPTOR *, void *); - -typedef UINT8 (* EFI_PEI_CPU_IO_PPI_IO_READ8)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); - -typedef UINT16 (* EFI_PEI_CPU_IO_PPI_IO_READ16)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); - -typedef UINT32 (* EFI_PEI_CPU_IO_PPI_IO_READ32)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); - -typedef UINT64 (* EFI_PEI_CPU_IO_PPI_IO_READ64)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); - -typedef void (* EFI_PEI_CPU_IO_PPI_IO_WRITE8)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT8); - -typedef void (* EFI_PEI_CPU_IO_PPI_IO_WRITE16)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT16); - -typedef void (* EFI_PEI_CPU_IO_PPI_IO_WRITE32)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT32); - -typedef void (* EFI_PEI_CPU_IO_PPI_IO_WRITE64)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT64); - -typedef UINT8 (* EFI_PEI_CPU_IO_PPI_MEM_READ8)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); - -typedef UINT16 (* EFI_PEI_CPU_IO_PPI_MEM_READ16)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); - -typedef UINT32 (* EFI_PEI_CPU_IO_PPI_MEM_READ32)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); - -typedef UINT64 (* EFI_PEI_CPU_IO_PPI_MEM_READ64)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); - -typedef void (* EFI_PEI_CPU_IO_PPI_MEM_WRITE8)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT8); - -typedef void (* EFI_PEI_CPU_IO_PPI_MEM_WRITE16)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT16); - -typedef void (* EFI_PEI_CPU_IO_PPI_MEM_WRITE32)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT32); - -typedef void (* EFI_PEI_CPU_IO_PPI_MEM_WRITE64)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT64); - -enum enum_897 { - EfiPeiPciCfgWidthUint64=3, - EfiPeiPciCfgWidthUint32=2, - EfiPeiPciCfgWidthUint8=0, - EfiPeiPciCfgWidthUint16=1, - EfiPeiPciCfgWidthMaximum=4 -}; - -typedef enum enum_897 EFI_PEI_PCI_CFG_PPI_WIDTH; - -typedef EFI_STATUS (* EFI_PEI_PCI_CFG2_PPI_IO)(EFI_PEI_SERVICES * *, EFI_PEI_PCI_CFG2_PPI *, EFI_PEI_PCI_CFG_PPI_WIDTH, UINT64, void *); - -typedef EFI_STATUS (* EFI_PEI_PCI_CFG2_PPI_RW)(EFI_PEI_SERVICES * *, EFI_PEI_PCI_CFG2_PPI *, EFI_PEI_PCI_CFG_PPI_WIDTH, UINT64, void *, void *); - -typedef UINT32 EFI_FV_FILE_ATTRIBUTES; - -typedef UINT32 EFI_FVB_ATTRIBUTES_2; - -enum enum_868 { - EfiPeiCpuIoWidthFifoUint16=5, - EfiPeiCpuIoWidthFillUint32=10, - EfiPeiCpuIoWidthFillUint16=9, - EfiPeiCpuIoWidthFifoUint64=7, - EfiPeiCpuIoWidthFifoUint32=6, - EfiPeiCpuIoWidthFillUint8=8, - EfiPeiCpuIoWidthUint8=0, - EfiPeiCpuIoWidthUint16=1, - EfiPeiCpuIoWidthMaximum=12, - EfiPeiCpuIoWidthUint64=3, - EfiPeiCpuIoWidthUint32=2, - EfiPeiCpuIoWidthFifoUint8=4, - EfiPeiCpuIoWidthFillUint64=11 -}; - -typedef enum enum_868 EFI_PEI_CPU_IO_PPI_WIDTH; - -typedef EFI_STATUS (* EFI_PEI_CPU_IO_PPI_IO_MEM)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, EFI_PEI_CPU_IO_PPI_WIDTH, UINT64, UINTN, void *); - -struct _EFI_PEI_NOTIFY_DESCRIPTOR { - UINTN Flags; - EFI_GUID * Guid; - EFI_PEIM_NOTIFY_ENTRY_POINT Notify; -}; - -struct EFI_FV_FILE_INFO2 { - EFI_GUID FileName; - EFI_FV_FILETYPE FileType; - EFI_FV_FILE_ATTRIBUTES FileAttributes; - void * Buffer; - UINT32 BufferSize; - UINT32 AuthenticationStatus; -}; - -struct EFI_TABLE_HEADER { - UINT64 Signature; - UINT32 Revision; - UINT32 HeaderSize; - UINT32 CRC32; - UINT32 Reserved; -}; - -struct EFI_PEI_CPU_IO_PPI_ACCESS { - EFI_PEI_CPU_IO_PPI_IO_MEM Read; - EFI_PEI_CPU_IO_PPI_IO_MEM Write; -}; - -struct EFI_PEI_CPU_IO_PPI { - struct EFI_PEI_CPU_IO_PPI_ACCESS Mem; - struct EFI_PEI_CPU_IO_PPI_ACCESS Io; - EFI_PEI_CPU_IO_PPI_IO_READ8 IoRead8; - EFI_PEI_CPU_IO_PPI_IO_READ16 IoRead16; - EFI_PEI_CPU_IO_PPI_IO_READ32 IoRead32; - EFI_PEI_CPU_IO_PPI_IO_READ64 IoRead64; - EFI_PEI_CPU_IO_PPI_IO_WRITE8 IoWrite8; - EFI_PEI_CPU_IO_PPI_IO_WRITE16 IoWrite16; - EFI_PEI_CPU_IO_PPI_IO_WRITE32 IoWrite32; - EFI_PEI_CPU_IO_PPI_IO_WRITE64 IoWrite64; - EFI_PEI_CPU_IO_PPI_MEM_READ8 MemRead8; - EFI_PEI_CPU_IO_PPI_MEM_READ16 MemRead16; - EFI_PEI_CPU_IO_PPI_MEM_READ32 MemRead32; - EFI_PEI_CPU_IO_PPI_MEM_READ64 MemRead64; - EFI_PEI_CPU_IO_PPI_MEM_WRITE8 MemWrite8; - EFI_PEI_CPU_IO_PPI_MEM_WRITE16 MemWrite16; - EFI_PEI_CPU_IO_PPI_MEM_WRITE32 MemWrite32; - EFI_PEI_CPU_IO_PPI_MEM_WRITE64 MemWrite64; -}; - -struct EFI_FV_INFO { - EFI_FVB_ATTRIBUTES_2 FvAttributes; - EFI_GUID FvFormat; - EFI_GUID FvName; - void * FvStart; - UINT64 FvSize; -}; - -struct EFI_PEI_PCI_CFG2_PPI { - EFI_PEI_PCI_CFG2_PPI_IO Read; - EFI_PEI_PCI_CFG2_PPI_IO Write; - EFI_PEI_PCI_CFG2_PPI_RW Modify; - UINT16 Segment; -}; - -struct EFI_PEI_PPI_DESCRIPTOR { - UINTN Flags; - EFI_GUID * Guid; - void * Ppi; -}; - -struct EFI_FV_FILE_INFO { - EFI_GUID FileName; - EFI_FV_FILETYPE FileType; - EFI_FV_FILE_ATTRIBUTES FileAttributes; - void * Buffer; - UINT32 BufferSize; -}; - -struct _EFI_PEI_SERVICES { - struct EFI_TABLE_HEADER Hdr; - EFI_PEI_INSTALL_PPI InstallPpi; - EFI_PEI_REINSTALL_PPI ReInstallPpi; - EFI_PEI_LOCATE_PPI LocatePpi; - EFI_PEI_NOTIFY_PPI NotifyPpi; - EFI_PEI_GET_BOOT_MODE GetBootMode; - EFI_PEI_SET_BOOT_MODE SetBootMode; - EFI_PEI_GET_HOB_LIST GetHobList; - EFI_PEI_CREATE_HOB CreateHob; - EFI_PEI_FFS_FIND_NEXT_VOLUME2 FfsFindNextVolume; - EFI_PEI_FFS_FIND_NEXT_FILE2 FfsFindNextFile; - EFI_PEI_FFS_FIND_SECTION_DATA2 FfsFindSectionData; - EFI_PEI_INSTALL_PEI_MEMORY InstallPeiMemory; - EFI_PEI_ALLOCATE_PAGES AllocatePages; - EFI_PEI_ALLOCATE_POOL AllocatePool; - EFI_PEI_COPY_MEM CopyMem; - EFI_PEI_SET_MEM SetMem; - EFI_PEI_REPORT_STATUS_CODE ReportStatusCode; - EFI_PEI_RESET_SYSTEM ResetSystem; - EFI_PEI_CPU_IO_PPI * CpuIo; - EFI_PEI_PCI_CFG2_PPI * PciCfg; - EFI_PEI_FFS_FIND_BY_NAME FfsFindFileByName; - EFI_PEI_FFS_GET_FILE_INFO FfsGetFileInfo; - EFI_PEI_FFS_GET_VOLUME_INFO FfsGetVolumeInfo; - EFI_PEI_REGISTER_FOR_SHADOW RegisterForShadow; - EFI_PEI_FFS_FIND_SECTION_DATA3 FindSectionData3; - EFI_PEI_FFS_GET_FILE_INFO2 FfsGetFileInfo2; - EFI_PEI_RESET2_SYSTEM ResetSystem2; - EFI_PEI_FREE_PAGES FreePages; -}; - -struct EFI_STATUS_CODE_DATA { - UINT16 HeaderSize; - UINT16 Size; - EFI_GUID Type; -}; - +typedef unsigned char undefined; + +typedef unsigned char byte; +typedef unsigned int dword; +typedef unsigned long long qword; +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long long ulonglong; +typedef unsigned char undefined1; +typedef unsigned int undefined4; +typedef unsigned short ushort; +typedef unsigned short word; + +struct EFI_PEI_PPI_DESCRIPTOR; +struct EFI_STATUS_CODE_DATA; +struct EFI_FV_FILE_INFO; +struct EFI_FV_FILE_INFO2; +struct EFI_PEI_PCI_CFG2_PPI; +struct EFI_PEI_CPU_IO_PPI; +struct EFI_FV_INFO; + +struct _EFI_PEI_SERVICES; +typedef struct _EFI_PEI_SERVICES EFI_PEI_SERVICES; + +typedef UINT64 UINTN; + +typedef UINTN RETURN_STATUS; + +typedef RETURN_STATUS EFI_STATUS; + +typedef EFI_STATUS (* EFI_PEI_INSTALL_PPI)(EFI_PEI_SERVICES * *, struct EFI_PEI_PPI_DESCRIPTOR *); + +typedef EFI_STATUS (* EFI_PEI_REINSTALL_PPI)(EFI_PEI_SERVICES * *, struct EFI_PEI_PPI_DESCRIPTOR *, struct EFI_PEI_PPI_DESCRIPTOR *); + +typedef GUID EFI_GUID; + +typedef EFI_STATUS (* EFI_PEI_LOCATE_PPI)(EFI_PEI_SERVICES * *, EFI_GUID *, UINTN, struct EFI_PEI_PPI_DESCRIPTOR * *, void * *); + +struct _EFI_PEI_NOTIFY_DESCRIPTOR; +typedef struct _EFI_PEI_NOTIFY_DESCRIPTOR EFI_PEI_NOTIFY_DESCRIPTOR; + +typedef EFI_STATUS (* EFI_PEI_NOTIFY_PPI)(EFI_PEI_SERVICES * *, EFI_PEI_NOTIFY_DESCRIPTOR *); + +typedef UINT32 EFI_BOOT_MODE; + +typedef EFI_STATUS (* EFI_PEI_GET_BOOT_MODE)(EFI_PEI_SERVICES * *, EFI_BOOT_MODE *); + +typedef EFI_STATUS (* EFI_PEI_SET_BOOT_MODE)(EFI_PEI_SERVICES * *, EFI_BOOT_MODE); + +typedef EFI_STATUS (* EFI_PEI_GET_HOB_LIST)(EFI_PEI_SERVICES * *, void * *); + +typedef EFI_STATUS (* EFI_PEI_CREATE_HOB)(EFI_PEI_SERVICES * *, UINT16, UINT16, void * *); + +typedef void * EFI_PEI_FV_HANDLE; + +typedef EFI_STATUS (* EFI_PEI_FFS_FIND_NEXT_VOLUME2)(EFI_PEI_SERVICES * *, UINTN, EFI_PEI_FV_HANDLE *); + +typedef UINT8 EFI_FV_FILETYPE; + +typedef void * EFI_PEI_FILE_HANDLE; + +typedef EFI_STATUS (* EFI_PEI_FFS_FIND_NEXT_FILE2)(EFI_PEI_SERVICES * *, EFI_FV_FILETYPE, EFI_PEI_FV_HANDLE, EFI_PEI_FILE_HANDLE *); + +typedef UINT8 EFI_SECTION_TYPE; + +typedef EFI_STATUS (* EFI_PEI_FFS_FIND_SECTION_DATA2)(EFI_PEI_SERVICES * *, EFI_SECTION_TYPE, EFI_PEI_FILE_HANDLE, void * *); + +typedef UINT64 EFI_PHYSICAL_ADDRESS; + +typedef EFI_STATUS (* EFI_PEI_INSTALL_PEI_MEMORY)(EFI_PEI_SERVICES * *, EFI_PHYSICAL_ADDRESS, UINT64); + +enum enum_16 { + EfiBootServicesCode=3, + EfiRuntimeServicesData=6, + EfiMemoryMappedIOPortSpace=12, + EfiLoaderData=2, + EfiBootServicesData=4, + EfiLoaderCode=1, + EfiReservedMemoryType=0, + EfiRuntimeServicesCode=5, + EfiACPIReclaimMemory=9, + EfiMaxMemoryType=15, + EfiConventionalMemory=7, + EfiMemoryMappedIO=11, + EfiPalCode=13, + EfiPersistentMemory=14, + EfiACPIMemoryNVS=10, + EfiUnusableMemory=8 +}; + +typedef enum enum_16 EFI_MEMORY_TYPE; + +typedef EFI_STATUS (* EFI_PEI_ALLOCATE_PAGES)(EFI_PEI_SERVICES * *, EFI_MEMORY_TYPE, UINTN, EFI_PHYSICAL_ADDRESS *); + +typedef EFI_STATUS (* EFI_PEI_ALLOCATE_POOL)(EFI_PEI_SERVICES * *, UINTN, void * *); + +typedef void (* EFI_PEI_COPY_MEM)(void *, void *, UINTN); + +typedef void (* EFI_PEI_SET_MEM)(void *, UINTN, UINT8); + +typedef UINT32 EFI_STATUS_CODE_TYPE; + +typedef UINT32 EFI_STATUS_CODE_VALUE; + +typedef EFI_STATUS (* EFI_PEI_REPORT_STATUS_CODE)(EFI_PEI_SERVICES * *, EFI_STATUS_CODE_TYPE, EFI_STATUS_CODE_VALUE, UINT32, EFI_GUID *, struct EFI_STATUS_CODE_DATA *); + +typedef EFI_STATUS (* EFI_PEI_RESET_SYSTEM)(EFI_PEI_SERVICES * *); + + +typedef EFI_STATUS (* EFI_PEI_FFS_FIND_BY_NAME)(EFI_GUID *, EFI_PEI_FV_HANDLE, EFI_PEI_FILE_HANDLE *); + +typedef EFI_STATUS (* EFI_PEI_FFS_GET_FILE_INFO)(EFI_PEI_FILE_HANDLE, struct EFI_FV_FILE_INFO *); + +typedef EFI_STATUS (* EFI_PEI_FFS_GET_VOLUME_INFO)(EFI_PEI_FV_HANDLE, struct EFI_FV_INFO *); + +typedef EFI_STATUS (* EFI_PEI_REGISTER_FOR_SHADOW)(EFI_PEI_FILE_HANDLE); + +typedef EFI_STATUS (* EFI_PEI_FFS_FIND_SECTION_DATA3)(EFI_PEI_SERVICES * *, EFI_SECTION_TYPE, UINTN, EFI_PEI_FILE_HANDLE, void * *, UINT32 *); + +typedef EFI_STATUS (* EFI_PEI_FFS_GET_FILE_INFO2)(EFI_PEI_FILE_HANDLE, struct EFI_FV_FILE_INFO2 *); + +enum enum_17 { + EfiResetCold=0, + EfiResetShutdown=2, + EfiResetWarm=1, + EfiResetPlatformSpecific=3 +}; + +typedef enum enum_17 EFI_RESET_TYPE; + +typedef void (* EFI_PEI_RESET2_SYSTEM)(EFI_RESET_TYPE, EFI_STATUS, UINTN, void *); + +typedef EFI_STATUS (* EFI_PEI_FREE_PAGES)(EFI_PEI_SERVICES * *, EFI_PHYSICAL_ADDRESS, UINTN); + +typedef EFI_STATUS (* EFI_PEIM_NOTIFY_ENTRY_POINT)(EFI_PEI_SERVICES * *, EFI_PEI_NOTIFY_DESCRIPTOR *, void *); + +typedef UINT8 (* EFI_PEI_CPU_IO_PPI_IO_READ8)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef UINT16 (* EFI_PEI_CPU_IO_PPI_IO_READ16)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef UINT32 (* EFI_PEI_CPU_IO_PPI_IO_READ32)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef UINT64 (* EFI_PEI_CPU_IO_PPI_IO_READ64)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef void (* EFI_PEI_CPU_IO_PPI_IO_WRITE8)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT8); + +typedef void (* EFI_PEI_CPU_IO_PPI_IO_WRITE16)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT16); + +typedef void (* EFI_PEI_CPU_IO_PPI_IO_WRITE32)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT32); + +typedef void (* EFI_PEI_CPU_IO_PPI_IO_WRITE64)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT64); + +typedef UINT8 (* EFI_PEI_CPU_IO_PPI_MEM_READ8)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef UINT16 (* EFI_PEI_CPU_IO_PPI_MEM_READ16)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef UINT32 (* EFI_PEI_CPU_IO_PPI_MEM_READ32)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef UINT64 (* EFI_PEI_CPU_IO_PPI_MEM_READ64)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64); + +typedef void (* EFI_PEI_CPU_IO_PPI_MEM_WRITE8)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT8); + +typedef void (* EFI_PEI_CPU_IO_PPI_MEM_WRITE16)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT16); + +typedef void (* EFI_PEI_CPU_IO_PPI_MEM_WRITE32)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT32); + +typedef void (* EFI_PEI_CPU_IO_PPI_MEM_WRITE64)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, UINT64, UINT64); + +enum enum_897 { + EfiPeiPciCfgWidthUint64=3, + EfiPeiPciCfgWidthUint32=2, + EfiPeiPciCfgWidthUint8=0, + EfiPeiPciCfgWidthUint16=1, + EfiPeiPciCfgWidthMaximum=4 +}; + +typedef enum enum_897 EFI_PEI_PCI_CFG_PPI_WIDTH; + +typedef EFI_STATUS (* EFI_PEI_PCI_CFG2_PPI_IO)(EFI_PEI_SERVICES * *, EFI_PEI_PCI_CFG2_PPI *, EFI_PEI_PCI_CFG_PPI_WIDTH, UINT64, void *); + +typedef EFI_STATUS (* EFI_PEI_PCI_CFG2_PPI_RW)(EFI_PEI_SERVICES * *, EFI_PEI_PCI_CFG2_PPI *, EFI_PEI_PCI_CFG_PPI_WIDTH, UINT64, void *, void *); + +typedef UINT32 EFI_FV_FILE_ATTRIBUTES; + +typedef UINT32 EFI_FVB_ATTRIBUTES_2; + +enum enum_868 { + EfiPeiCpuIoWidthFifoUint16=5, + EfiPeiCpuIoWidthFillUint32=10, + EfiPeiCpuIoWidthFillUint16=9, + EfiPeiCpuIoWidthFifoUint64=7, + EfiPeiCpuIoWidthFifoUint32=6, + EfiPeiCpuIoWidthFillUint8=8, + EfiPeiCpuIoWidthUint8=0, + EfiPeiCpuIoWidthUint16=1, + EfiPeiCpuIoWidthMaximum=12, + EfiPeiCpuIoWidthUint64=3, + EfiPeiCpuIoWidthUint32=2, + EfiPeiCpuIoWidthFifoUint8=4, + EfiPeiCpuIoWidthFillUint64=11 +}; + +typedef enum enum_868 EFI_PEI_CPU_IO_PPI_WIDTH; + +typedef EFI_STATUS (* EFI_PEI_CPU_IO_PPI_IO_MEM)(EFI_PEI_SERVICES * *, EFI_PEI_CPU_IO_PPI *, EFI_PEI_CPU_IO_PPI_WIDTH, UINT64, UINTN, void *); + +struct _EFI_PEI_NOTIFY_DESCRIPTOR { + UINTN Flags; + EFI_GUID * Guid; + EFI_PEIM_NOTIFY_ENTRY_POINT Notify; +}; + +struct EFI_FV_FILE_INFO2 { + EFI_GUID FileName; + EFI_FV_FILETYPE FileType; + EFI_FV_FILE_ATTRIBUTES FileAttributes; + void * Buffer; + UINT32 BufferSize; + UINT32 AuthenticationStatus; +}; + +struct EFI_TABLE_HEADER { + UINT64 Signature; + UINT32 Revision; + UINT32 HeaderSize; + UINT32 CRC32; + UINT32 Reserved; +}; + +struct EFI_PEI_CPU_IO_PPI_ACCESS { + EFI_PEI_CPU_IO_PPI_IO_MEM Read; + EFI_PEI_CPU_IO_PPI_IO_MEM Write; +}; + +struct EFI_PEI_CPU_IO_PPI { + struct EFI_PEI_CPU_IO_PPI_ACCESS Mem; + struct EFI_PEI_CPU_IO_PPI_ACCESS Io; + EFI_PEI_CPU_IO_PPI_IO_READ8 IoRead8; + EFI_PEI_CPU_IO_PPI_IO_READ16 IoRead16; + EFI_PEI_CPU_IO_PPI_IO_READ32 IoRead32; + EFI_PEI_CPU_IO_PPI_IO_READ64 IoRead64; + EFI_PEI_CPU_IO_PPI_IO_WRITE8 IoWrite8; + EFI_PEI_CPU_IO_PPI_IO_WRITE16 IoWrite16; + EFI_PEI_CPU_IO_PPI_IO_WRITE32 IoWrite32; + EFI_PEI_CPU_IO_PPI_IO_WRITE64 IoWrite64; + EFI_PEI_CPU_IO_PPI_MEM_READ8 MemRead8; + EFI_PEI_CPU_IO_PPI_MEM_READ16 MemRead16; + EFI_PEI_CPU_IO_PPI_MEM_READ32 MemRead32; + EFI_PEI_CPU_IO_PPI_MEM_READ64 MemRead64; + EFI_PEI_CPU_IO_PPI_MEM_WRITE8 MemWrite8; + EFI_PEI_CPU_IO_PPI_MEM_WRITE16 MemWrite16; + EFI_PEI_CPU_IO_PPI_MEM_WRITE32 MemWrite32; + EFI_PEI_CPU_IO_PPI_MEM_WRITE64 MemWrite64; +}; + +struct EFI_FV_INFO { + EFI_FVB_ATTRIBUTES_2 FvAttributes; + EFI_GUID FvFormat; + EFI_GUID FvName; + void * FvStart; + UINT64 FvSize; +}; + +struct EFI_PEI_PCI_CFG2_PPI { + EFI_PEI_PCI_CFG2_PPI_IO Read; + EFI_PEI_PCI_CFG2_PPI_IO Write; + EFI_PEI_PCI_CFG2_PPI_RW Modify; + UINT16 Segment; +}; + +struct EFI_PEI_PPI_DESCRIPTOR { + UINTN Flags; + EFI_GUID * Guid; + void * Ppi; +}; + +struct EFI_FV_FILE_INFO { + EFI_GUID FileName; + EFI_FV_FILETYPE FileType; + EFI_FV_FILE_ATTRIBUTES FileAttributes; + void * Buffer; + UINT32 BufferSize; +}; + +struct _EFI_PEI_SERVICES { + struct EFI_TABLE_HEADER Hdr; + EFI_PEI_INSTALL_PPI InstallPpi; + EFI_PEI_REINSTALL_PPI ReInstallPpi; + EFI_PEI_LOCATE_PPI LocatePpi; + EFI_PEI_NOTIFY_PPI NotifyPpi; + EFI_PEI_GET_BOOT_MODE GetBootMode; + EFI_PEI_SET_BOOT_MODE SetBootMode; + EFI_PEI_GET_HOB_LIST GetHobList; + EFI_PEI_CREATE_HOB CreateHob; + EFI_PEI_FFS_FIND_NEXT_VOLUME2 FfsFindNextVolume; + EFI_PEI_FFS_FIND_NEXT_FILE2 FfsFindNextFile; + EFI_PEI_FFS_FIND_SECTION_DATA2 FfsFindSectionData; + EFI_PEI_INSTALL_PEI_MEMORY InstallPeiMemory; + EFI_PEI_ALLOCATE_PAGES AllocatePages; + EFI_PEI_ALLOCATE_POOL AllocatePool; + EFI_PEI_COPY_MEM CopyMem; + EFI_PEI_SET_MEM SetMem; + EFI_PEI_REPORT_STATUS_CODE ReportStatusCode; + EFI_PEI_RESET_SYSTEM ResetSystem; + EFI_PEI_CPU_IO_PPI * CpuIo; + EFI_PEI_PCI_CFG2_PPI * PciCfg; + EFI_PEI_FFS_FIND_BY_NAME FfsFindFileByName; + EFI_PEI_FFS_GET_FILE_INFO FfsGetFileInfo; + EFI_PEI_FFS_GET_VOLUME_INFO FfsGetVolumeInfo; + EFI_PEI_REGISTER_FOR_SHADOW RegisterForShadow; + EFI_PEI_FFS_FIND_SECTION_DATA3 FindSectionData3; + EFI_PEI_FFS_GET_FILE_INFO2 FfsGetFileInfo2; + EFI_PEI_RESET2_SYSTEM ResetSystem2; + EFI_PEI_FREE_PAGES FreePages; +}; + +struct EFI_STATUS_CODE_DATA { + UINT16 HeaderSize; + UINT16 Size; + EFI_GUID Type; +}; + diff --git a/helper.py b/helper.py index cc798e9..8985c89 100644 --- a/helper.py +++ b/helper.py @@ -1,240 +1,240 @@ -""" -Binary Ninja plugin that aids in analysis of UEFI PEI and DXE modules -""" - -import os -import csv -import glob -import uuid -from binaryninja import (BackgroundTaskThread, SegmentFlag, SectionSemantics, BinaryReader, Symbol, - SymbolType, HighLevelILOperation, BinaryView) -from binaryninja.highlevelil import HighLevelILInstruction -from binaryninja.types import (Type, FunctionParameter) - -class UEFIHelper(BackgroundTaskThread): - """Class for analyzing UEFI firmware to automate GUID annotation, segment fixup, type imports, and more - """ - - def __init__(self, bv: BinaryView): - BackgroundTaskThread.__init__(self, '', False) - self.bv = bv - self.br = BinaryReader(self.bv) - self.dirname = os.path.dirname(os.path.abspath(__file__)) - self.guids = self._load_guids() - - def _fix_segments(self): - """UEFI modules run during boot, without page protections. Everything is RWX despite that the PE is built with - the segments not being writable. It needs to be RWX so calls through global function pointers are displayed - properly. - """ - - for seg in self.bv.segments: - # Make segment RWX - self.bv.add_user_segment(seg.start, seg.data_length, seg.data_offset, seg.data_length, - SegmentFlag.SegmentWritable|SegmentFlag.SegmentReadable|SegmentFlag.SegmentExecutable) - - # Make section semantics ReadWriteDataSectionSemantics - for section in self.bv.get_sections_at(seg.start): - self.bv.add_user_section(section.name, section.end-section.start, SectionSemantics.ReadWriteDataSectionSemantics) - - def _import_types_from_headers(self): - """Parse EDKII types from header files - """ - - hdrs_path = os.path.join(self.dirname, 'headers') - headers = glob.glob(os.path.join(hdrs_path, '*.h')) - for hdr in headers: - _types = self.bv.platform.parse_types_from_source_file(hdr) - for name, _type in _types.types.items(): - self.bv.define_user_type(name, _type) - - def _set_entry_point_prototype(self): - """Apply correct prototype to the module entry point - """ - - _start = self.bv.get_function_at(self.bv.entry_point) - if self.bv.view_type != 'TE': - _start.function_type = "EFI_STATUS ModuleEntryPoint(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)" - - def _load_guids(self): - """Read known GUIDs from CSV and convert string GUIDs to bytes - - :return: Dictionary containing GUID bytes and associated names - """ - - guids_path = os.path.join(self.dirname, 'guids.csv') - with open(guids_path) as f: - reader = csv.reader(f, skipinitialspace=True) - guids = dict(reader) - - # Convert to bytes for faster lookup - guid_bytes = dict() - for guid, name in guids.items(): - guid_bytes[name] = uuid.UUID(guid).bytes_le - - return guid_bytes - - def _apply_guid_name_if_data(self, name: str, address: int): - """Check if there is a function at the address. If not, then apply the EFI_GUID type and name it - - :param name: Name/symbol to apply to the GUID - :param address: Address of the GUID - """ - - print(f'Found {name} at 0x{hex(address)} ({uuid.UUID(bytes_le=self.guids[name])})') - - # Just to avoid a unlikely false positive and screwing up disassembly - if self.bv.get_functions_at(address) != []: - print(f'There is code at {address}, not applying GUID type and name') - return - - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, address, 'g'+name)) - t = self.bv.parse_type_string("EFI_GUID") - self.bv.define_user_data_var(address, t[0]) - - def _find_known_guids(self): - """Search for known GUIDs and apply names to matches not within a function - """ - - names_list = list(self.guids.keys()) - guids_list = list(self.guids.values()) - def _check_guid_and_get_name(guid): - try: - return names_list[guids_list.index(guid)] - except ValueError: - return None - - for seg in self.bv.segments: - for i in range(seg.start, seg.end): - self.br.seek(i) - data = self.br.read(16) - if not data or len(data) != 16: - continue - - found_name = _check_guid_and_get_name(data) - if found_name: - self._apply_guid_name_if_data(found_name, i) - - def _set_if_uefi_core_type(self, instr: HighLevelILInstruction): - """Using HLIL, scrutinize the instruction to determine if it's a move of a local variable to a global variable. - If it is, check if the source operand type is a UEFI core type and apply the type to the destination global - variable. - - :param instr: High level IL instruction object - """ - - if instr.operation != HighLevelILOperation.HLIL_ASSIGN: - return - - if instr.dest.operation != HighLevelILOperation.HLIL_DEREF: - return - - if instr.dest.src.operation != HighLevelILOperation.HLIL_CONST_PTR: - return - - if instr.src.operation != HighLevelILOperation.HLIL_VAR: - return - - _type = instr.src.var.type - if len(_type.tokens) == 1 and str(_type.tokens[0]) == 'EFI_HANDLE': - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gHandle')) - elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_BOOT_SERVICES': - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gBS')) - elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_RUNTIME_SERVICES': - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gRS')) - elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_SYSTEM_TABLE': - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gST')) - elif len(_type.tokens) == 1 and str(_type.tokens[0]) == 'EFI_PEI_FILE_HANDLE': - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gHandle')) - elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_PEI_SERVICES': - self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gPeiServices')) - else: - return - - self.bv.define_user_data_var(instr.dest.src.constant, instr.src.var.type) - print(f'Found global assignment - offset:0x{hex(instr.dest.src.constant)} type:{instr.src.var.type}') - - def _check_and_prop_types_on_call(self, instr: HighLevelILInstruction): - """Most UEFI modules don't assign globals in the entry function and instead call a initialization routine and - pass the system table to it where global assignments are made. This function ensures that the types are applied - to the initialization function params so that we can catch global assignments outside of the module entry - - :param instr: High level IL instruction object - """ - - if instr.operation not in [HighLevelILOperation.HLIL_TAILCALL, HighLevelILOperation.HLIL_CALL]: - return - - if instr.dest.operation != HighLevelILOperation.HLIL_CONST_PTR: - return - - argv_is_passed = False - for arg in instr.params: - if 'ImageHandle' in str(arg) or 'SystemTable' or 'FileHandle' or 'PeiServices' in str(arg): - argv_is_passed = True - break - - if not argv_is_passed: - return - - func = self.bv.get_function_at(instr.dest.constant) - old = func.function_type - call_args = instr.params - new_params = [] - for arg, param in zip(call_args, old.parameters): - if hasattr(arg, 'var'): - new_type = arg.var.type - else: - new_type = param.type - new_type.confidence = 256 - new_params.append(FunctionParameter(new_type, param.name)) - - # TODO: this is a hack to account for odd behavior. func.function_type should be able to set directly to - # Type.Function(...). However, during testing this isn't the case. I am only able to get it to work if I - # set function_type to a string and update analysis. - gross_hack = str( - Type.function(old.return_value, new_params, old.calling_convention, old.has_variable_arguments, old.stack_adjustment) - ).replace('(', '{}('.format(func.name)) - try: - func.function_type = gross_hack - self.bv.update_analysis_and_wait() - except SyntaxError: - pass # BN can't parse int48_t and other types despite that it uses it. Ran into this from a sidt instruction - - def _set_global_variables(self): - """On entry, UEFI modules usually set global variables for EFI_BOOT_SERVICES, EFI_RUNTIME_SERIVCES, and - EFI_SYSTEM_TABLE. This function attempts to identify these assignments and apply types. - """ - - func = self.bv.get_function_at(self.bv.entry_point) - for block in func.high_level_il: - for instr in block: - self._check_and_prop_types_on_call(instr) - - for func in self.bv.functions: - for block in func.high_level_il: - for instr in block: - self._set_if_uefi_core_type(instr) - - def run(self): - """Run the task in the background - """ - - self.progress = "UEFI Helper: Fixing up segments, applying types, and searching for known GUIDs ..." - self._fix_segments() - self._import_types_from_headers() - self._set_entry_point_prototype() - self._find_known_guids() - self.progress = "UEFI Helper: searching for global assignments for UEFI core services ..." - self._set_global_variables() - print('UEFI Helper completed successfully!') - -def run_uefi_helper(bv: BinaryView): - """Run UEFI helper utilities in the background - - :param bv: BinaryView - """ - - task = UEFIHelper(bv) - task.start() - +""" +Binary Ninja plugin that aids in analysis of UEFI PEI and DXE modules +""" + +import os +import csv +import glob +import uuid +from binaryninja import (BackgroundTaskThread, SegmentFlag, SectionSemantics, BinaryReader, Symbol, + SymbolType, HighLevelILOperation, BinaryView) +from binaryninja.highlevelil import HighLevelILInstruction +from binaryninja.types import (Type, FunctionParameter) + +class UEFIHelper(BackgroundTaskThread): + """Class for analyzing UEFI firmware to automate GUID annotation, segment fixup, type imports, and more + """ + + def __init__(self, bv: BinaryView): + BackgroundTaskThread.__init__(self, '', False) + self.bv = bv + self.br = BinaryReader(self.bv) + self.dirname = os.path.dirname(os.path.abspath(__file__)) + self.guids = self._load_guids() + + def _fix_segments(self): + """UEFI modules run during boot, without page protections. Everything is RWX despite that the PE is built with + the segments not being writable. It needs to be RWX so calls through global function pointers are displayed + properly. + """ + + for seg in self.bv.segments: + # Make segment RWX + self.bv.add_user_segment(seg.start, seg.data_length, seg.data_offset, seg.data_length, + SegmentFlag.SegmentWritable|SegmentFlag.SegmentReadable|SegmentFlag.SegmentExecutable) + + # Make section semantics ReadWriteDataSectionSemantics + for section in self.bv.get_sections_at(seg.start): + self.bv.add_user_section(section.name, section.end-section.start, SectionSemantics.ReadWriteDataSectionSemantics) + + def _import_types_from_headers(self): + """Parse EDKII types from header files + """ + + hdrs_path = os.path.join(self.dirname, 'headers') + headers = glob.glob(os.path.join(hdrs_path, '*.h')) + for hdr in headers: + _types = self.bv.platform.parse_types_from_source_file(hdr) + for name, _type in _types.types.items(): + self.bv.define_user_type(name, _type) + + def _set_entry_point_prototype(self): + """Apply correct prototype to the module entry point + """ + + _start = self.bv.get_function_at(self.bv.entry_point) + if self.bv.view_type != 'TE': + _start.function_type = "EFI_STATUS ModuleEntryPoint(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)" + + def _load_guids(self): + """Read known GUIDs from CSV and convert string GUIDs to bytes + + :return: Dictionary containing GUID bytes and associated names + """ + + guids_path = os.path.join(self.dirname, 'guids.csv') + with open(guids_path) as f: + reader = csv.reader(f, skipinitialspace=True) + guids = dict(reader) + + # Convert to bytes for faster lookup + guid_bytes = dict() + for guid, name in guids.items(): + guid_bytes[name] = uuid.UUID(guid).bytes_le + + return guid_bytes + + def _apply_guid_name_if_data(self, name: str, address: int): + """Check if there is a function at the address. If not, then apply the EFI_GUID type and name it + + :param name: Name/symbol to apply to the GUID + :param address: Address of the GUID + """ + + print(f'Found {name} at 0x{hex(address)} ({uuid.UUID(bytes_le=self.guids[name])})') + + # Just to avoid a unlikely false positive and screwing up disassembly + if self.bv.get_functions_at(address) != []: + print(f'There is code at {address}, not applying GUID type and name') + return + + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, address, 'g'+name)) + t = self.bv.parse_type_string("EFI_GUID") + self.bv.define_user_data_var(address, t[0]) + + def _find_known_guids(self): + """Search for known GUIDs and apply names to matches not within a function + """ + + names_list = list(self.guids.keys()) + guids_list = list(self.guids.values()) + def _check_guid_and_get_name(guid): + try: + return names_list[guids_list.index(guid)] + except ValueError: + return None + + for seg in self.bv.segments: + for i in range(seg.start, seg.end): + self.br.seek(i) + data = self.br.read(16) + if not data or len(data) != 16: + continue + + found_name = _check_guid_and_get_name(data) + if found_name: + self._apply_guid_name_if_data(found_name, i) + + def _set_if_uefi_core_type(self, instr: HighLevelILInstruction): + """Using HLIL, scrutinize the instruction to determine if it's a move of a local variable to a global variable. + If it is, check if the source operand type is a UEFI core type and apply the type to the destination global + variable. + + :param instr: High level IL instruction object + """ + + if instr.operation != HighLevelILOperation.HLIL_ASSIGN: + return + + if instr.dest.operation != HighLevelILOperation.HLIL_DEREF: + return + + if instr.dest.src.operation != HighLevelILOperation.HLIL_CONST_PTR: + return + + if instr.src.operation != HighLevelILOperation.HLIL_VAR: + return + + _type = instr.src.var.type + if len(_type.tokens) == 1 and str(_type.tokens[0]) == 'EFI_HANDLE': + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gHandle')) + elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_BOOT_SERVICES': + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gBS')) + elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_RUNTIME_SERVICES': + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gRS')) + elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_SYSTEM_TABLE': + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gST')) + elif len(_type.tokens) == 1 and str(_type.tokens[0]) == 'EFI_PEI_FILE_HANDLE': + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gHandle')) + elif len(_type.tokens) > 2 and str(_type.tokens[2]) == 'EFI_PEI_SERVICES': + self.bv.define_user_symbol(Symbol(SymbolType.DataSymbol, instr.dest.src.constant, 'gPeiServices')) + else: + return + + self.bv.define_user_data_var(instr.dest.src.constant, instr.src.var.type) + print(f'Found global assignment - offset:0x{hex(instr.dest.src.constant)} type:{instr.src.var.type}') + + def _check_and_prop_types_on_call(self, instr: HighLevelILInstruction): + """Most UEFI modules don't assign globals in the entry function and instead call a initialization routine and + pass the system table to it where global assignments are made. This function ensures that the types are applied + to the initialization function params so that we can catch global assignments outside of the module entry + + :param instr: High level IL instruction object + """ + + if instr.operation not in [HighLevelILOperation.HLIL_TAILCALL, HighLevelILOperation.HLIL_CALL]: + return + + if instr.dest.operation != HighLevelILOperation.HLIL_CONST_PTR: + return + + argv_is_passed = False + for arg in instr.params: + if 'ImageHandle' in str(arg) or 'SystemTable' or 'FileHandle' or 'PeiServices' in str(arg): + argv_is_passed = True + break + + if not argv_is_passed: + return + + func = self.bv.get_function_at(instr.dest.constant) + old = func.function_type + call_args = instr.params + new_params = [] + for arg, param in zip(call_args, old.parameters): + if hasattr(arg, 'var'): + new_type = arg.var.type + else: + new_type = param.type + new_type.confidence = 256 + new_params.append(FunctionParameter(new_type, param.name)) + + # TODO: this is a hack to account for odd behavior. func.function_type should be able to set directly to + # Type.Function(...). However, during testing this isn't the case. I am only able to get it to work if I + # set function_type to a string and update analysis. + gross_hack = str( + Type.function(old.return_value, new_params, old.calling_convention, old.has_variable_arguments, old.stack_adjustment) + ).replace('(', '{}('.format(func.name)) + try: + func.function_type = gross_hack + self.bv.update_analysis_and_wait() + except SyntaxError: + pass # BN can't parse int48_t and other types despite that it uses it. Ran into this from a sidt instruction + + def _set_global_variables(self): + """On entry, UEFI modules usually set global variables for EFI_BOOT_SERVICES, EFI_RUNTIME_SERIVCES, and + EFI_SYSTEM_TABLE. This function attempts to identify these assignments and apply types. + """ + + func = self.bv.get_function_at(self.bv.entry_point) + for block in func.high_level_il: + for instr in block: + self._check_and_prop_types_on_call(instr) + + for func in self.bv.functions: + for block in func.high_level_il: + for instr in block: + self._set_if_uefi_core_type(instr) + + def run(self): + """Run the task in the background + """ + + self.progress = "UEFI Helper: Fixing up segments, applying types, and searching for known GUIDs ..." + self._fix_segments() + self._import_types_from_headers() + self._set_entry_point_prototype() + self._find_known_guids() + self.progress = "UEFI Helper: searching for global assignments for UEFI core services ..." + self._set_global_variables() + print('UEFI Helper completed successfully!') + +def run_uefi_helper(bv: BinaryView): + """Run UEFI helper utilities in the background + + :param bv: BinaryView + """ + + task = UEFIHelper(bv) + task.start() +