mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-08-31 20:29:46 +02:00
170 lines
5.5 KiB
Python
170 lines
5.5 KiB
Python
# 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
|
|
from typing import Iterable, Tuple
|
|
|
|
from volatility3.framework import interfaces, renderers, constants, exceptions
|
|
from volatility3.framework.configuration import requirements
|
|
from volatility3.framework.renderers import format_hints
|
|
from volatility3.framework.objects import utility
|
|
from volatility3.framework.symbols import intermed
|
|
from volatility3.framework.symbols.linux.extensions import elf
|
|
from volatility3.plugins.linux import pslist
|
|
|
|
|
|
vollog = logging.getLogger(__name__)
|
|
|
|
|
|
class LibraryList(interfaces.plugins.PluginInterface):
|
|
"""Enumerate libraries loaded into processes"""
|
|
|
|
_required_framework_version = (2, 0, 0)
|
|
|
|
_version = (1, 0, 0)
|
|
|
|
@classmethod
|
|
def get_requirements(cls):
|
|
return [
|
|
requirements.ModuleRequirement(
|
|
name="kernel",
|
|
description="Linux kernel",
|
|
architectures=["Intel32", "Intel64"],
|
|
),
|
|
requirements.PluginRequirement(
|
|
name="pslist", plugin=pslist.PsList, version=(2, 2, 0)
|
|
),
|
|
requirements.ListRequirement(
|
|
name="pids",
|
|
description="Filter on specific process IDs",
|
|
element_type=int,
|
|
optional=True,
|
|
),
|
|
]
|
|
|
|
def _get_libdl_libraries(
|
|
self, proc_layer_name: str, vma_start: int
|
|
) -> interfaces.objects.ObjectInterface:
|
|
"""Get the ELF link map objects for the given VMA address
|
|
|
|
Args:
|
|
proc_layer_name (str): Name of the process layer
|
|
vma_start (int): VMA start address
|
|
|
|
Yields:
|
|
ELF link map objects for the given VMA address
|
|
"""
|
|
elf_table_name = intermed.IntermediateSymbolTable.create(
|
|
self.context,
|
|
self.config_path,
|
|
"linux",
|
|
"elf",
|
|
class_types=elf.class_types,
|
|
)
|
|
elf_object = self.context.object(
|
|
elf_table_name + constants.BANG + "Elf",
|
|
offset=vma_start,
|
|
layer_name=proc_layer_name,
|
|
)
|
|
|
|
if not elf_object or not elf_object.is_valid():
|
|
return None
|
|
|
|
kernel = self.context.modules[self.config["kernel"]]
|
|
|
|
try:
|
|
for link_map in elf_object.get_link_maps(kernel.symbol_table_name):
|
|
if link_map.l_addr and link_map.l_name:
|
|
yield link_map
|
|
except exceptions.InvalidAddressException:
|
|
# Protection against memory smear in this VMA
|
|
pass
|
|
|
|
def _get_libdl_maps(
|
|
self, task: interfaces.objects.ObjectInterface, proc_layer_name: str
|
|
) -> interfaces.objects.ObjectInterface:
|
|
"""Get the ELF link maps objects for a task
|
|
|
|
Args:
|
|
task (task_struct): A reference task
|
|
proc_layer_name (str): Name of the process layer
|
|
|
|
Yields:
|
|
ELF link map objects
|
|
"""
|
|
|
|
link_map_seen = set()
|
|
for vma in task.mm.get_vma_iter():
|
|
for link_map in self._get_libdl_libraries(proc_layer_name, vma.vm_start):
|
|
if link_map.l_addr in link_map_seen:
|
|
continue
|
|
|
|
yield link_map
|
|
link_map_seen.add(link_map.l_addr)
|
|
|
|
def _get_task_libraries(
|
|
self, task: interfaces.objects.ObjectInterface
|
|
) -> Tuple[int, str]:
|
|
"""Get the task libraries from the ELF headers found within the memory maps
|
|
|
|
Args:
|
|
task (task_struct): The reference task
|
|
|
|
Yields:
|
|
Tuples with a ELF link map address and name
|
|
"""
|
|
proc_layer_name = task.add_process_layer()
|
|
if not proc_layer_name:
|
|
return
|
|
|
|
for elf_link_map in self._get_libdl_maps(task, proc_layer_name):
|
|
name = elf_link_map.get_name()
|
|
if not name:
|
|
continue
|
|
yield elf_link_map.l_addr, name
|
|
|
|
def _get_tasks_libraries(
|
|
self,
|
|
tasks: Iterable[interfaces.objects.ObjectInterface],
|
|
) -> Iterable[Tuple[str, int, int, str]]:
|
|
"""Get the task libraries from the ELF headers found within the memory maps for
|
|
all the tasks.
|
|
|
|
Args:
|
|
tasks: An iterable of tasks
|
|
|
|
Yields:
|
|
Tuples with a task name, task tgid, an ELF link map address and name
|
|
"""
|
|
for task in tasks:
|
|
task_name = utility.array_to_string(task.comm)
|
|
for linkmap_addr, linkmap_name in self._get_task_libraries(task):
|
|
yield task_name, task.tgid, linkmap_addr, linkmap_name
|
|
|
|
def _format_fields(self, fields):
|
|
task_name, task_pid, addr, name = fields
|
|
return task_name, task_pid, format_hints.Hex(addr), name
|
|
|
|
def _generator(
|
|
self, tasks: Iterable[interfaces.objects.ObjectInterface]
|
|
) -> Iterable[Tuple[int, Tuple]]:
|
|
for fields in self._get_tasks_libraries(tasks):
|
|
yield 0, self._format_fields(fields)
|
|
|
|
def run(self):
|
|
pids = self.config.get("pids")
|
|
pid_filter = pslist.PsList.create_pid_filter(pids)
|
|
tasks = pslist.PsList.list_tasks(
|
|
self.context, self.config["kernel"], filter_func=pid_filter
|
|
)
|
|
|
|
headers = [
|
|
("Name", str),
|
|
("Pid", int),
|
|
("LoadAddress", format_hints.Hex),
|
|
("Path", str),
|
|
]
|
|
|
|
return renderers.TreeGrid(headers, self._generator(tasks))
|