mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-28 20:44:52 +02:00
major updates and new plugins
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
"""A module containing a collection of plugins that produce data
|
||||
typically found in Linux's /proc file system.
|
||||
"""
|
||||
|
||||
from volatility.framework import renderers
|
||||
from volatility.framework.interfaces import plugins
|
||||
from volatility.framework.objects import utility
|
||||
from volatility.framework.renderers import format_hints
|
||||
from volatility.framework.automagic import linux
|
||||
from volatility.plugins.linux import pslist
|
||||
|
||||
class Elfs(plugins.PluginInterface):
|
||||
"""Lists all memory mapped ELF files for all processes"""
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return pslist.PsList.get_requirements() + []
|
||||
|
||||
def _generator(self, tasks):
|
||||
for task in tasks:
|
||||
proc_layer_name = task.add_process_layer()
|
||||
if proc_layer_name == None:
|
||||
continue
|
||||
|
||||
proc_layer = self.context.memory[proc_layer_name]
|
||||
|
||||
name = utility.array_to_string(task.comm)
|
||||
|
||||
for vma in task.mm.mmap_iter:
|
||||
hdr = proc_layer.read(vma.vm_start, 4, pad = True)
|
||||
if not (hdr[0] == 0x7f and hdr[1] == 0x45 and hdr[2] == 0x4c and hdr[3] == 0x46):
|
||||
continue
|
||||
|
||||
path = vma.get_name(task)
|
||||
|
||||
yield (
|
||||
0,
|
||||
(task.pid,
|
||||
name,
|
||||
format_hints.Hex(vma.vm_start),
|
||||
format_hints.Hex(vma.vm_end),
|
||||
path
|
||||
))
|
||||
|
||||
def run(self):
|
||||
filter = pslist.PsList.create_filter([self.config.get('pid', None)])
|
||||
|
||||
plugin = pslist.PsList.list_tasks
|
||||
|
||||
return renderers.TreeGrid(
|
||||
[("PID", int),
|
||||
("Process", str),
|
||||
("Start", format_hints.Hex),
|
||||
("End", format_hints.Hex),
|
||||
("File Path", str)],
|
||||
self._generator(plugin(self.context,
|
||||
self.config['primary'],
|
||||
self.config['vmlinux'],
|
||||
filter = filter)))
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
"""A module containing a collection of plugins that produce data
|
||||
typically found in Linux's /proc file system.
|
||||
"""
|
||||
import datetime, os
|
||||
|
||||
from volatility.framework import renderers, constants, interfaces
|
||||
from volatility.framework.configuration import requirements
|
||||
from volatility.framework.interfaces import plugins
|
||||
from volatility.framework.objects import utility
|
||||
from volatility.framework.renderers import format_hints
|
||||
from volatility.framework.automagic import linux
|
||||
from volatility.plugins.linux import pslist
|
||||
|
||||
class Lsmod(plugins.PluginInterface):
|
||||
"""Lists loaded kernel modules"""
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Kernel Address Space',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolRequirement(name = "vmlinux",
|
||||
description = "Linux Kernel")]
|
||||
|
||||
@classmethod
|
||||
def list_modules(cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
layer_name: str,
|
||||
vmlinux_symbols: str):
|
||||
"""Lists all the modules in the primary layer"""
|
||||
|
||||
_, aslr_shift = linux.LinuxUtilities.find_aslr(context, vmlinux_symbols, layer_name)
|
||||
vmlinux = context.module(vmlinux_symbols, layer_name, aslr_shift)
|
||||
|
||||
module_head_addr = vmlinux.object(symbol_name = "modules").vol.offset
|
||||
|
||||
modules = vmlinux.object(type_name = "list_head", offset = module_head_addr)
|
||||
|
||||
table_name = modules.vol.type_name.split(constants.BANG)[0]
|
||||
|
||||
for module in modules.to_list("{}{}module".format(table_name, constants.BANG), "list"):
|
||||
yield module
|
||||
|
||||
def _generator(self):
|
||||
for module in self.list_modules(self.context,
|
||||
self.config['primary'],
|
||||
self.config['vmlinux']):
|
||||
|
||||
mod_size = module.get_init_size() + module.get_core_size()
|
||||
|
||||
mod_name = utility.array_to_string(module.name)
|
||||
|
||||
yield 0, (format_hints.Hex(module.vol.offset), mod_name, mod_size)
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
[("Offset", format_hints.Hex),
|
||||
("Name", str),
|
||||
("Size", int)],
|
||||
self._generator())
|
||||
@@ -3,12 +3,15 @@ typically found in Linux's /proc file system.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from volatility.framework import interfaces
|
||||
from volatility.framework.interfaces import plugins
|
||||
from volatility.framework import renderers
|
||||
from volatility.framework import constants
|
||||
from volatility.framework.automagic import linux
|
||||
from volatility.framework.renderers import format_hints
|
||||
from volatility.framework.objects import utility
|
||||
from volatility.framework.symbols import utility as symbols_utility
|
||||
|
||||
from volatility.plugins.linux import pslist
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
@@ -21,43 +24,29 @@ class Lsof(plugins.PluginInterface):
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return pslist.PsList.get_requirements() + []
|
||||
|
||||
# yields list of data, e.g.: calculate
|
||||
def _generator(self, tasks):
|
||||
layer_name = self.config['primary.memory_layer']
|
||||
|
||||
_, aslr_shift = linux.LinuxUtilities.find_aslr(self.context, self.config["vmlinux"], layer_name)
|
||||
vmlinux = self.context.module(self.config["vmlinux"], self.config["primary"], aslr_shift)
|
||||
pointer_template = self.context.symbol_space[self.config['vmlinux']].get_type('pointer')
|
||||
|
||||
for task in tasks:
|
||||
fd_table = task.files.get_fds()
|
||||
if fd_table == 0:
|
||||
continue
|
||||
name = str(task.comm)
|
||||
pid = int(task.pid)
|
||||
|
||||
max_fds = task.files.get_max_fds()
|
||||
|
||||
proc_name = utility.array_to_string(task.comm)
|
||||
|
||||
# corruption check
|
||||
if max_fds > 500000:
|
||||
continue
|
||||
|
||||
fds = vmlinux.object(type_name="array", offset = fd_table.vol.offset, subtype = pointer_template, count = max_fds)
|
||||
|
||||
for (i, fd_ptr) in enumerate(fds):
|
||||
if fd_ptr:
|
||||
filp = fd_ptr.dereference().cast(self.config["vmlinux"] + constants.BANG + 'file')
|
||||
|
||||
full_path = task.path_for_file(filp, layer_name)
|
||||
|
||||
yield (0, (task.pid, proc_name, i, full_path))
|
||||
for fd_num, _, full_path in linux.LinuxUtilities.files_descriptors_for_process(self.config, self.context, task):
|
||||
yield (0, (pid, name, fd_num, full_path))
|
||||
|
||||
def run(self):
|
||||
plugin = pslist.PsList(self.context, "plugins.Lsof")
|
||||
linux.LinuxUtilities.aslr_mask_symbol_table(self.config, self.context)
|
||||
|
||||
filter = pslist.PsList.create_filter([self.config.get('pid', None)])
|
||||
|
||||
plugin = pslist.PsList.list_tasks
|
||||
|
||||
return renderers.TreeGrid(
|
||||
[("PID", int),
|
||||
("Process", str),
|
||||
("FD", int),
|
||||
("Path", str)],
|
||||
self._generator(plugin.list_tasks()))
|
||||
self._generator(plugin(self.context,
|
||||
self.config['primary'],
|
||||
self.config['vmlinux'],
|
||||
filter = filter)))
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import volatility.framework.interfaces.plugins as interfaces_plugins
|
||||
import volatility.framework.interfaces.renderers as interfaces_renderers
|
||||
import volatility.plugins.linux.pslist as pslist
|
||||
from volatility.framework import constants
|
||||
from volatility.framework import renderers
|
||||
from volatility.framework.objects import utility
|
||||
from volatility.framework.renderers import format_hints
|
||||
|
||||
class Malfind(interfaces_plugins.PluginInterface):
|
||||
"""Lists process memory ranges that potentially contain injected code"""
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return pslist.PsList.get_requirements() + []
|
||||
|
||||
def list_injections(self, task):
|
||||
"""Generate memory regions for a process that may contain
|
||||
injected code.
|
||||
"""
|
||||
|
||||
proc_layer_name = task.add_process_layer()
|
||||
if proc_layer_name == None:
|
||||
return
|
||||
|
||||
proc_layer = self.context.memory[proc_layer_name]
|
||||
|
||||
for vma in task.mm.mmap_iter:
|
||||
if vma.is_suspicious() and vma.get_name(task) != "[vdso]":
|
||||
data = proc_layer.read(vma.vm_start, 64, pad = True)
|
||||
yield vma, data
|
||||
|
||||
def _generator(self, tasks):
|
||||
# determine if we're on a 32 or 64 bit kernel
|
||||
if self.context.symbol_space.get_type(self.config["vmlinux"] + constants.BANG + "pointer").size == 4:
|
||||
is_32bit_arch = True
|
||||
else:
|
||||
is_32bit_arch = False
|
||||
|
||||
for task in tasks:
|
||||
process_name = utility.array_to_string(task.comm)
|
||||
|
||||
for vma, data in self.list_injections(task):
|
||||
if is_32bit_arch:
|
||||
architecture = "intel"
|
||||
else:
|
||||
architecture = "intel64"
|
||||
|
||||
disasm = interfaces_renderers.Disassembly(data, vma.vm_start, architecture)
|
||||
|
||||
yield (0, (task.pid,
|
||||
process_name,
|
||||
format_hints.Hex(vma.vm_start),
|
||||
format_hints.Hex(vma.vm_end),
|
||||
vma.get_protection(),
|
||||
format_hints.HexBytes(data),
|
||||
disasm))
|
||||
|
||||
def run(self):
|
||||
filter = pslist.PsList.create_filter([self.config.get('pid', None)])
|
||||
|
||||
plugin = pslist.PsList.list_tasks
|
||||
|
||||
return renderers.TreeGrid([("PID", int),
|
||||
("Process", str),
|
||||
("Start", format_hints.Hex),
|
||||
("End", format_hints.Hex),
|
||||
("Protection", str),
|
||||
("Hexdump", format_hints.HexBytes),
|
||||
("Disasm", interfaces_renderers.Disassembly)],
|
||||
self._generator(plugin(self.context,
|
||||
self.config['primary'],
|
||||
self.config['vmlinux'],
|
||||
filter = filter)))
|
||||
|
||||
@@ -7,9 +7,9 @@ from volatility.framework.configuration import requirements
|
||||
from volatility.framework.interfaces import plugins
|
||||
from volatility.framework.objects import utility
|
||||
from volatility.framework.renderers import format_hints
|
||||
from volatility.framework.automagic import linux
|
||||
from volatility.plugins.linux import pslist
|
||||
|
||||
|
||||
class Maps(plugins.PluginInterface):
|
||||
"""Lists all memory maps for all processes"""
|
||||
|
||||
@@ -30,20 +30,22 @@ class Maps(plugins.PluginInterface):
|
||||
name = utility.array_to_string(task.comm)
|
||||
|
||||
for vma in task.mm.mmap_iter:
|
||||
flags = vma.protection()
|
||||
page_offset = vma.page_offset()
|
||||
flags = vma.get_protection()
|
||||
page_offset = vma.get_page_offset()
|
||||
major = 0
|
||||
minor = 0
|
||||
inode = 0
|
||||
path = ""
|
||||
|
||||
if vma.vm_file != 0:
|
||||
inode_object = vma.vm_file.f_path.dentry.d_inode
|
||||
major = inode_object.i_sb.major
|
||||
minor = inode_object.i_sb.minor
|
||||
inode = inode_object.i_ino
|
||||
# TODO - update the second parameter to hopefully go away once extension is updated
|
||||
path = task.path_for_file(vma.vm_file, "")
|
||||
dentry = vma.vm_file.get_dentry()
|
||||
if dentry != 0:
|
||||
inode_object = dentry.d_inode
|
||||
major = inode_object.i_sb.major
|
||||
minor = inode_object.i_sb.minor
|
||||
inode = inode_object.i_ino
|
||||
|
||||
path = vma.get_name(task)
|
||||
|
||||
yield (
|
||||
0,
|
||||
@@ -60,6 +62,10 @@ class Maps(plugins.PluginInterface):
|
||||
))
|
||||
|
||||
def run(self):
|
||||
filter = pslist.PsList.create_filter([self.config.get('pid', None)])
|
||||
|
||||
plugin = pslist.PsList.list_tasks
|
||||
|
||||
return renderers.TreeGrid(
|
||||
[("PID", int),
|
||||
("Process", str),
|
||||
@@ -71,6 +77,8 @@ class Maps(plugins.PluginInterface):
|
||||
("Minor", int),
|
||||
("Inode", int),
|
||||
("File Path", str)],
|
||||
self._generator(pslist.PsList.list_tasks(self.context,
|
||||
self.config['primary'],
|
||||
self.config['vmlinux'])))
|
||||
self._generator(plugin(self.context,
|
||||
self.config['primary'],
|
||||
self.config['vmlinux'],
|
||||
filter = filter)))
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import volatility.framework.interfaces.plugins as interfaces_plugins
|
||||
from volatility.framework import renderers
|
||||
from volatility.framework import renderers, interfaces
|
||||
from volatility.framework.automagic import linux
|
||||
from volatility.framework.configuration import requirements
|
||||
from volatility.framework.objects import utility
|
||||
@@ -16,8 +16,21 @@ class PsList(interfaces_plugins.PluginInterface):
|
||||
requirements.SymbolRequirement(name = "vmlinux",
|
||||
description = "Linux Kernel")]
|
||||
|
||||
@classmethod
|
||||
def create_filter(cls, pid_list: typing.List[int] = None) -> typing.Callable[[int], bool]:
|
||||
filter = lambda _: False
|
||||
# FIXME: mypy #4973 or #2608
|
||||
pid_list = pid_list or []
|
||||
filter_list = [x for x in pid_list if x is not None]
|
||||
if filter_list:
|
||||
filter = lambda x: x not in filter_list
|
||||
return filter
|
||||
|
||||
def _generator(self):
|
||||
for task in self.list_tasks(self.context, self.config['primary'], self.config['vmlinux']):
|
||||
for task in self.list_tasks(self.context,
|
||||
self.config['primary'],
|
||||
self.config['vmlinux'],
|
||||
filter = self.create_filter([self.config.get('pid', None)])):
|
||||
pid = task.pid
|
||||
ppid = 0
|
||||
if task.parent:
|
||||
@@ -26,13 +39,18 @@ class PsList(interfaces_plugins.PluginInterface):
|
||||
yield (0, (pid, ppid, name))
|
||||
|
||||
@classmethod
|
||||
def list_tasks(cls, context, primary_layer: str, vmlinux_table: str):
|
||||
def list_tasks(cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
layer_name: str,
|
||||
vmlinux_symbols: str,
|
||||
filter: typing.Callable[[int], bool] = lambda _: False) -> \
|
||||
typing.Iterable[interfaces.objects.ObjectInterface]:
|
||||
|
||||
"""Lists all the tasks in the primary layer"""
|
||||
|
||||
layer_name = context.memory[primary_layer].config['memory_layer']
|
||||
|
||||
_, aslr_shift = linux.LinuxUtilities.find_aslr(context, vmlinux_table, layer_name)
|
||||
vmlinux = context.module(vmlinux_table, primary_layer, aslr_shift)
|
||||
_, aslr_shift = linux.LinuxUtilities.find_aslr(context, vmlinux_symbols, layer_name)
|
||||
vmlinux = context.module(vmlinux_symbols, layer_name, aslr_shift)
|
||||
init_task = vmlinux.object(symbol_name = "init_task")
|
||||
|
||||
for task in init_task.tasks:
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
from volatility.framework.renderers import format_hints
|
||||
from volatility.framework.objects import utility
|
||||
from volatility.plugins.linux import pslist
|
||||
|
||||
class PsTree(pslist.PsList):
|
||||
"""Plugin for listing processes in a tree based on their parent process ID """
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._processes = {}
|
||||
self._levels = {}
|
||||
self._children = {}
|
||||
|
||||
def find_level(self, pid):
|
||||
"""Finds how deep the pid is in the processes list"""
|
||||
seen = set([])
|
||||
seen.add(pid)
|
||||
level = 0
|
||||
proc = self._processes.get(pid, None)
|
||||
while proc is not None and proc.parent != 0 and proc.parent.pid not in seen:
|
||||
ppid = int(proc.parent.pid)
|
||||
|
||||
child_list = self._children.get(ppid, set([]))
|
||||
child_list.add(proc.pid)
|
||||
self._children[ppid] = child_list
|
||||
proc = self._processes.get(ppid, None)
|
||||
level += 1
|
||||
self._levels[pid] = level
|
||||
|
||||
def _generator(self):
|
||||
"""Generates the """
|
||||
for proc in self.list_tasks(self.context, self.config['primary'], self.config['vmlinux']):
|
||||
self._processes[proc.pid] = proc
|
||||
|
||||
# Build the child/level maps
|
||||
for pid in self._processes:
|
||||
self.find_level(pid)
|
||||
|
||||
def yield_processes(pid):
|
||||
proc = self._processes[pid]
|
||||
row = (proc.pid,
|
||||
proc.parent.pid,
|
||||
utility.array_to_string(proc.comm))
|
||||
|
||||
yield (self._levels[pid] - 1, row)
|
||||
for child_pid in self._children.get(pid, []):
|
||||
yield from yield_processes(child_pid)
|
||||
|
||||
for pid in self._levels:
|
||||
if self._levels[pid] == 1:
|
||||
yield from yield_processes(pid)
|
||||
|
||||
Reference in New Issue
Block a user