diff --git a/volatility/framework/symbols/__init__.py b/volatility/framework/symbols/__init__.py index 626039acb..4a988e725 100644 --- a/volatility/framework/symbols/__init__.py +++ b/volatility/framework/symbols/__init__.py @@ -4,7 +4,7 @@ import enum import logging from volatility.framework import constants, exceptions, interfaces, objects -from volatility.framework.symbols import native, windows +from volatility.framework.symbols import native, windows, linux vollog = logging.getLogger(__name__) diff --git a/volatility/framework/symbols/linux/__init__.py b/volatility/framework/symbols/linux/__init__.py new file mode 100644 index 000000000..e6799d10b --- /dev/null +++ b/volatility/framework/symbols/linux/__init__.py @@ -0,0 +1,19 @@ +from volatility.framework.configuration import requirements +from volatility.framework.symbols import intermed +from volatility.framework.symbols.linux import extensions + + +class LinuxKernelIntermedSymbols(intermed.IntermediateSymbolTable): + provides = {"type": "interface"} + + def __init__(self, context, config_path, name, isf_filepath): + super().__init__(context = context, config_path = config_path, name = name, isf_filepath = isf_filepath) + + # Set-up Linux specific types + self.set_type_class('list_head', extensions.list_head) + + + @classmethod + def get_requirements(cls): + return [requirements.StringRequirement("isf_filepath", + description = "JSON file containing the symbols encoded in the Intermediate Symbol Format")] diff --git a/volatility/framework/symbols/linux/extensions/__init__.py b/volatility/framework/symbols/linux/extensions/__init__.py new file mode 100644 index 000000000..bf35b3928 --- /dev/null +++ b/volatility/framework/symbols/linux/extensions/__init__.py @@ -0,0 +1,36 @@ +import collections.abc + +from volatility.framework import objects + + +# Keep these in a basic module, to prevent import cycles when symbol providers require them + + +class list_head(objects.Struct, collections.abc.Iterable): + def to_list(self, symbol_type, member, forward = True, sentinel = True, layer = None): + """Returns an iterator of the entries in the list""" + + if layer is None: + layer = self.vol.layer_name + + relative_offset = self._context.symbol_space.get_type(symbol_type).relative_child_offset(member) + + direction = 'prev' + if forward: + direction = 'next' + link = getattr(self, direction).dereference() + + if not sentinel: + yield self._context.object(symbol_type, layer, offset = self.vol.offset - relative_offset) + + seen = {self.vol.offset} + while link.vol.offset not in seen: + + obj = self._context.object(symbol_type, layer, offset = link.vol.offset - relative_offset) + yield obj + + seen.add(link.vol.offset) + link = getattr(link, direction).dereference() + + def __iter__(self): + return self.to_list(self.vol.parent.vol.type_name, self.vol.member_name) diff --git a/volatility/plugins/linux/pslist.py b/volatility/plugins/linux/pslist.py new file mode 100644 index 000000000..06b9d9c09 --- /dev/null +++ b/volatility/plugins/linux/pslist.py @@ -0,0 +1,44 @@ +import volatility.framework.interfaces.plugins as plugins +from volatility.framework.configuration import requirements +from volatility.framework.renderers import TreeGrid +from volatility.framework.objects.utility import array_to_string + + +class PsList(plugins.PluginInterface): + @classmethod + def get_requirements(cls): + return [requirements.TranslationLayerRequirement(name = 'primary', + description = 'Kernel Address Space', + architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "vmlinux", + description = "Linux Kernel")] + + def update_configuration(self): + """No operation since all values provided by config/requirements initially""" + + def _generator(self): + for task in self.list_tasks(): + pid = task.pid + ppid = 0 + if task.parent: + ppid = task.parent.pid + name = array_to_string(task.comm) + yield (0, (pid, ppid, name)) + + def list_tasks(self): + """Lists all the tasks in the primary layer""" + + layer_name = self.config['primary'] + + # TODO: Will need to compute a non-zero offset for ASLR kernels + vmlinux = self.context.module("vmlinux", "primary", 0) + init_task = vmlinux.object(symbol_name="init_task") + + for task in init_task.tasks: + yield task + + def run(self): + return TreeGrid([("PID", int), + ("PPID", int), + ("COMM", str)], + self._generator())