Merge branch 'volatilityfoundation:develop' into feature/reg-cert

This commit is contained in:
Donghyun Kim
2022-05-23 10:35:38 +09:00
committed by GitHub
4 changed files with 119 additions and 6 deletions
+1 -1
View File
@@ -321,7 +321,7 @@ class SizedModule(Module):
The mapping should be sorted and should be quicker than reading
the data We turn it into JSON to make a common string and use a
quick hash, because collissions are unlikely
quick hash, because collisions are unlikely
"""
layer = self._context.layers[self.layer_name]
if not isinstance(layer, interfaces.layers.TranslationLayerInterface):
+1 -1
View File
@@ -169,7 +169,7 @@ class BaseSymbolTableInterface:
def optional_set_type_class(self, name: str, clazz: Type[objects.ObjectInterface]) -> bool:
"""Calls the set_type_class function but does not throw an exception.
Returns whether setting the type class was successfull.
Returns whether setting the type class was successful.
Args:
name: The name of the type to override the class for
clazz: The actual class to override for the provided type name
@@ -0,0 +1,111 @@
# This file is Copyright 2022 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
from typing import Optional
from volatility3.framework.configuration import requirements
from volatility3.framework import symbols, exceptions, renderers, interfaces
from volatility3.framework.objects import utility
from volatility3.plugins.linux import pslist
from volatility3.framework.interfaces import plugins
class PsAux(plugins.PluginInterface):
""" Lists processes with their command line arguments """
_required_framework_version = (2, 0, 0)
@classmethod
def get_requirements(cls):
# Since we're calling the plugin, make sure we have the plugin's requirements
return [
requirements.ModuleRequirement(name = 'kernel', description = 'Linux kernel',
architectures = ["Intel32", "Intel64"]),
requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0)),
requirements.ListRequirement(name = 'pid',
description = 'Filter on specific process IDs',
element_type = int,
optional = True)
]
def _get_command_line_args(self, task: interfaces.objects.ObjectInterface,
name: str) -> Optional[str]:
"""
Reads the command line arguments of a process
These are stored on the userland stack
Kernel threads re-use the process data structure, but do not have a valid 'mm' pointer
Parameters:
task: task_struct object of the process
name: string name of the process (from task.comm)
"""
# kernel theads never have an mm as they do not have userland mappings
try:
mm = task.mm
except exceptions.InvalidAddressException:
mm = None
if mm:
proc_layer_name = task.add_process_layer()
if proc_layer_name is None:
return renderers.UnreadableValue()
proc_layer = self.context.layers[proc_layer_name]
# read argv from userland
start = task.mm.arg_start
# get the size of the arguments with sanity checking
size_to_read = task.mm.arg_end - task.mm.arg_start
if not (0 < size_to_read <= 4096):
return renderers.UnreadableValue()
# attempt to read it all as partial values are invalid and misleading
try:
argv = proc_layer.read(start, size_to_read)
except exceptions.InvalidAddressException:
return renderers.UnreadableValue()
# the arguments are null byte terminated, replace the nulls with spaces
s = argv.decode().split('\x00')
args = " ".join(s)
else:
# kernel thread
# [ ] mimics ps on a live system
# also helps identify malware masquerading as a kernel thread, which is fairly common
args = "[" + name + "]"
# remove trailing space, if present
if len(args) > 1 and args[-1] == " ":
args = args[:-1]
return args
def _generator(self, tasks):
""" Generates a listing of processes along with command line arguments """
# walk the process list and report the arguments
for task in tasks:
pid = task.pid
try:
ppid = task.parent.pid
except exceptions.InvalidAddressException:
ppid = 0
name = utility.array_to_string(task.comm)
args = self._get_command_line_args(task, name)
yield (0, (pid, ppid, name, args))
def run(self):
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
return renderers.TreeGrid([("PID", int), ("PPID", int), ("COMM", str), ("ARGS", str)],
self._generator(
pslist.PsList.list_tasks(self.context,
self.config['kernel'],
filter_func = filter_func)))
@@ -1,10 +1,10 @@
# 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
#
from typing import List, Tuple, Iterator
from typing import Iterator, List, Tuple
from volatility3 import framework
from volatility3.framework import exceptions, constants, interfaces, objects
from volatility3.framework import constants, exceptions, interfaces, objects
from volatility3.framework.objects import utility
from volatility3.framework.symbols import intermed
from volatility3.framework.symbols.linux import extensions
@@ -29,7 +29,9 @@ class LinuxKernelIntermedSymbols(intermed.IntermediateSymbolTable):
self.set_type_class('files_struct', extensions.files_struct)
self.set_type_class('vfsmount', extensions.vfsmount)
self.set_type_class('kobject', extensions.kobject)
self.set_type_class('mnt_namespace', extensions.mnt_namespace)
if 'mnt_namespace' in self.types:
self.set_type_class('mnt_namespace', extensions.mnt_namespace)
if 'module' in self.types:
self.set_type_class('module', extensions.module)
@@ -267,4 +269,4 @@ class LinuxUtilities(interfaces.configuration.VersionableInterface):
while list_start:
list_struct = vmlinux.object(object_type = struct_name, offset = list_start.vol.offset)
yield list_struct
list_start = getattr(list_struct, list_member)
list_start = getattr(list_struct, list_member)