Source code for volatility3.plugins.windows.iat

# This file is Copyright 2024 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0

import logging, io, pefile
from volatility3.framework.symbols import intermed
from volatility3.framework import renderers, interfaces, exceptions, constants
from volatility3.framework.configuration import requirements
from volatility3.plugins.windows import pslist
from volatility3.framework.renderers import format_hints
from volatility3.framework.symbols.windows.extensions import pe

vollog = logging.getLogger(__name__)


[docs]class IAT(interfaces.plugins.PluginInterface): """Extract Import Address Table to list API (functions) used by a program contained in external libraries""" _required_framework_version = (2, 4, 0)
[docs] @classmethod def get_requirements(cls): return [ requirements.ModuleRequirement( name="kernel", description="Windows kernel", architectures=["Intel32", "Intel64"], ), requirements.VersionRequirement( name="pslist", component=pslist.PsList, version=(2, 0, 0) ), requirements.ListRequirement( name="pid", element_type=int, description="Process ID to include (all other processes are excluded)", optional=True, ), ]
def _generator(self, procs): kernel = self.context.modules[self.config["kernel"]] for proc in procs: try: proc_id = proc.UniqueProcessId proc_layer_name = proc.add_process_layer() peb = self.context.object( kernel.symbol_table_name + constants.BANG + "_PEB", layer_name=proc_layer_name, offset=proc.Peb, ) if proc_layer_name is None: raise TypeError("add_process_layer failed") pe_table_name = intermed.IntermediateSymbolTable.create( self.context, self.config_path, "windows", "pe", class_types=pe.class_types, ) pe_data = io.BytesIO() dos_header = self.context.object( pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", offset=peb.ImageBaseAddress, layer_name=proc_layer_name, ) for offset, data in dos_header.reconstruct(): pe_data.seek(offset) pe_data.write(data) pe_obj = pefile.PE(data=pe_data.getvalue(), fast_load=True) pe_obj.parse_data_directories( [pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_IMPORT"]] ) if hasattr(pe_obj, "DIRECTORY_ENTRY_IMPORT"): for entry in pe_obj.DIRECTORY_ENTRY_IMPORT: dll_entry = entry.dll if dll_entry: dll_entry = dll_entry.decode() else: dll_entry = renderers.NotAvailableValue bound = True # Initially set to 0 if not bound time_date_stamp = entry.struct.TimeDateStamp if not time_date_stamp: bound = False # Iterate over imported functions for imp in entry.imports: import_name = imp.name if import_name: import_name = imp.name.decode() else: import_name = renderers.NotAvailableValue() function_address = ( pe_obj.OPTIONAL_HEADER.ImageBase + imp.address ) if not function_address: function_address = renderers.NotAvailableValue yield ( 0, ( proc_id, proc.ImageFileName.cast( "string", max_length=proc.ImageFileName.vol.count, errors="replace", ), dll_entry, bound, import_name, format_hints.Hex(function_address), ), ) except exceptions.InvalidAddressException as excp: vollog.debug( "Process {}: invalid address {} in layer {}".format( proc_id, excp.invalid_address, excp.layer_name ) ) continue
[docs] def run(self): kernel = self.context.modules[self.config["kernel"]] return renderers.TreeGrid( [ ("PID", int), ("Name", str), ("Library", str), ("Bound", bool), ("Function", str), ("Address", format_hints.Hex), ], self._generator( pslist.PsList.list_processes( context=self.context, layer_name=kernel.layer_name, symbol_table=kernel.symbol_table_name, filter_func=pslist.PsList.create_pid_filter( self.config.get("pid", None) ), ) ), )