Import Address Table Plugin

This commit is contained in:
k1nd0ne
2023-12-14 14:50:17 +01:00
parent 47ddf5d0e5
commit 604c23bcbc
@@ -0,0 +1,132 @@
# This file is Copyright 2019 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
import io
from typing import Callable, List
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.symbols.windows import pdbutil
from volatility3.framework.symbols.windows.extensions import pe
import pefile
vollog = logging.getLogger(__name__)
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)
@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("Layer must be a string not None")
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
# 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()
yield (
0,
(
proc_id,
proc.ImageFileName.cast(
"string",
max_length=proc.ImageFileName.vol.count,
errors="replace",
),
dll_entry,
import_name,
),
)
except exceptions.InvalidAddressException as excp:
vollog.debug(
"Process {}: invalid address {} in layer {}".format(
proc_id, excp.invalid_address, excp.layer_name
)
)
continue
def run(self):
kernel = self.context.modules[self.config["kernel"]]
return renderers.TreeGrid(
[("PID", int), ("Process", str), ("Library", str), ("Function", str)],
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)
),
)
),
)