major updates and new plugins

This commit is contained in:
Andrew Case
2018-11-08 00:19:17 +00:00
committed by ikelos
parent 63e9cd4604
commit 98e472e211
10 changed files with 561 additions and 214 deletions
+61
View File
@@ -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)))
+60
View File
@@ -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())
+18 -29
View File
@@ -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)))
+75
View File
@@ -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)))
+20 -12
View File
@@ -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)))
+24 -6
View File
@@ -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:
+52
View File
@@ -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)