Files
volatility3/volatility/framework/symbols/linux/__init__.py
T
Jack Wengerandikelos 53c36d91c3 added hashdump
Added documentation and logging

added cachedump and lsadump

Fixed requested issues

fixed encoding issues

added requirement

Framework: Move cache_clear function to the framework

Documentation: Document self.config slightly better

Linux/Mac: Refactor *nix Utilities classes

Automagic: Fix issue in recent refactor

Add elf parsing and symbol retrieval for linux kernel modules

Fixes on coding style

Linux: Restore accidentally dropped kobject definition

Core: Rerun yapf across the codebase.

First attempt and better DTB and ASLR validation. Debugging statements left in.

Mac: Stash the verified ASLR shift and improve logging

Linux: Support stashing the KASLR

Remove extra debug prints

added hashdump

Added documentation and logging

Linux - stash the Linux kernel virtual address

Hashdump: Reformat and convert to proper byte handling

Registry: Fix error message

Caching: Only cache remote files

Yarascan: Move most of yarascanning into a versionable plugin

This refactors common yara tasks, so we can use the plugin versioning to
keep track of changes to the YaraScanner class.

Core: Refactor versioning and associated requirements

Configuration: Improve the VersionableInterface documentation

Plugins: Remove unnecessary dependency for yarascan

Objects: Add a convenience function for validating enum values

Objects: Update enumeration method to is_valid_choice

Core: Maintain 3.5.3 compatibility

created tty_check.py; edited automagic/linux.py to add kernel tracking abilities

fixed some formatting for tty_check.py

Fixed tty_check not finding the ttyhook module

added some documentation

Removed unnecessary code from tty_check.py

added docs to automagic methods, fixed missing return types, changed parameters to be more specific

added kernel string to linux constants file; changed automagic methods so that they reconstruct the kernel object within the method for consistancy with other methods

added parameter type to generate_kernel_handler_info

Updated imports to reflect new location of utility class; plugins are no longer outputing anything so commiting for Andrew to take a look at

removed debugging print statements

fixed bug causing no output when tty_check is run

Windows.info: Refactor windows.info as classmethods

Linux: Fix plugin case and re-run yapf

created keyboard_notifiers

removed extra whitespace

Yapf: Minor reformats for recent plugins

Codebase: Ensure all conversions to bytes handle unicode

All conversions using `latin-1` have been converted to
`raw_unicode_escape` which is like `latin-1`, but handles unicode
characters appropriately (with a `\u` prefix).

Since this is like `latin-1` it should have no impact on things that ran
previously, but those that would fail with a unicode error now will
present an encoded unicode string.  There may be situations where the
binary representation of unicode would be better (timeliner file
output?), but those can be changed when/if it's determined necessary.

Fixes #274.

Linux: Fix keyboard_notifiers copyright year

Renderers: Fix the pretty renderer when no rows are emitted

Timeliner: Sort results and provide a filter

Sorts the results (as stated).  Note that user interfaces may decide to
sort their results in an order of their choosing.

Also added a parameter that can be provided multiple times to only allow
plugins that match (any of) the parameters provided.

Timeliner: Actually make use of the TextIoWrapper

Windows: Add a version to the info plugin now its got classmethods

CLI: Add additional help about 'vol.py plugin --help'

created linux_check_idt; plugin currently is not finding the module names for each entry in idt table

fix copyright year

fixed poor variable name, removed unnecessary code

added address mask to fix issue with kernel tracking

CLI: Revert epilog changes

Update lsadump.py

I'm not sure why your are getting this error since it works fine for me, but this may fix it
2020-08-23 21:32:27 +01:00

260 lines
9.2 KiB
Python

# 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 volatility.framework import exceptions, constants, interfaces, objects, contexts
from volatility.framework.objects import utility
from volatility.framework.symbols import intermed
from volatility.framework.symbols.linux import extensions
from volatility.framework.objects import utility
class LinuxKernelIntermedSymbols(intermed.IntermediateSymbolTable):
provides = {"type": "interface"}
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
# Set-up Linux specific types
self.set_type_class('file', extensions.struct_file)
self.set_type_class('list_head', extensions.list_head)
self.set_type_class('mm_struct', extensions.mm_struct)
self.set_type_class('super_block', extensions.super_block)
self.set_type_class('task_struct', extensions.task_struct)
self.set_type_class('vm_area_struct', extensions.vm_area_struct)
self.set_type_class('qstr', extensions.qstr)
self.set_type_class('dentry', extensions.dentry)
self.set_type_class('fs_struct', extensions.fs_struct)
self.set_type_class('files_struct', extensions.files_struct)
self.set_type_class('vfsmount', extensions.vfsmount)
self.set_type_class('kobject', extensions.kobject)
if 'module' in self.types:
self.set_type_class('module', extensions.module)
if 'mount' in self.types:
self.set_type_class('mount', extensions.mount)
class LinuxUtilities(interfaces.configuration.VersionableInterface):
"""Class with multiple useful linux functions."""
_verison = (1, 0, 0)
# based on __d_path from the Linux kernel
@classmethod
def _do_get_path(cls, rdentry, rmnt, dentry, vfsmnt) -> str:
ret_path = [] # type: List[str]
while dentry != rdentry or vfsmnt != rmnt:
dname = dentry.path()
if dname == "":
break
ret_path.insert(0, dname.strip('/'))
if dentry == vfsmnt.get_mnt_root() or dentry == dentry.d_parent:
if vfsmnt.get_mnt_parent() == vfsmnt:
break
dentry = vfsmnt.get_mnt_mountpoint()
vfsmnt = vfsmnt.get_mnt_parent()
continue
parent = dentry.d_parent
dentry = parent
# if we did not gather any valid dentrys in the path, then the entire file is
# either 1) smeared out of memory or 2) de-allocated and corresponding structures overwritten
# we return an empty string in this case to avoid confusion with something like a handle to the root
# directory (e.g., "/")
if not ret_path:
return ""
ret_val = '/'.join([str(p) for p in ret_path if p != ""])
if ret_val.startswith(("socket:", "pipe:")):
if ret_val.find("]") == -1:
try:
inode = dentry.d_inode
ino = inode.i_ino
except exceptions.InvalidAddressException:
ino = 0
ret_val = ret_val[:-1] + ":[{0}]".format(ino)
else:
ret_val = ret_val.replace("/", "")
elif ret_val != "inotify":
ret_val = '/' + ret_val
return ret_val
# method used by 'older' kernels
# TODO: lookup when dentry_operations->d_name was merged into the mainline kernel for exact version
@classmethod
def _get_path_file(cls, task, filp) -> str:
rdentry = task.fs.get_root_dentry()
rmnt = task.fs.get_root_mnt()
dentry = filp.get_dentry()
vfsmnt = filp.get_vfsmnt()
return LinuxUtilities._do_get_path(rdentry, rmnt, dentry, vfsmnt)
@classmethod
def _get_new_sock_pipe_path(cls, context, task, filp) -> str:
dentry = filp.get_dentry()
sym_addr = dentry.d_op.d_dname
symbol_table_arr = sym_addr.vol.type_name.split("!")
symbol_table = None
if len(symbol_table_arr) == 2:
symbol_table = symbol_table_arr[0]
symbs = list(context.symbol_space.get_symbols_by_location(sym_addr, table_name = symbol_table))
if len(symbs) == 1:
sym = symbs[0].split(constants.BANG)[1]
if sym == "sockfs_dname":
pre_name = "socket"
elif sym == "anon_inodefs_dname":
pre_name = "anon_inode"
elif sym == "pipefs_dname":
pre_name = "pipe"
elif sym == "simple_dname":
pre_name = cls._get_path_file(task, filp)
else:
pre_name = "<unsupported d_op symbol: {0}>".format(sym)
ret = "{0}:[{1:d}]".format(pre_name, dentry.d_inode.i_ino)
else:
ret = "<invalid d_dname pointer> {0:x}".format(sym_addr)
return ret
# a 'file' structure doesn't have enough information to properly restore its full path
# we need the root mount information from task_struct to determine this
@classmethod
def path_for_file(cls, context, task, filp) -> str:
try:
dentry = filp.get_dentry()
except exceptions.InvalidAddressException:
return ""
if dentry == 0:
return ""
dname_is_valid = False
# TODO COMPARE THIS IN LSOF OUTPUT TO VOL2
try:
if dentry.d_op and dentry.d_op.has_member("d_dname") and dentry.d_op.d_dname:
dname_is_valid = True
except exceptions.InvalidAddressException:
dname_is_valid = False
if dname_is_valid:
ret = LinuxUtilities._get_new_sock_pipe_path(context, task, filp)
else:
ret = LinuxUtilities._get_path_file(task, filp)
return ret
@classmethod
def files_descriptors_for_process(cls, context: interfaces.context.ContextInterface, symbol_table: str,
task: interfaces.objects.ObjectInterface):
fd_table = task.files.get_fds()
if fd_table == 0:
return
max_fds = task.files.get_max_fds()
# corruption check
if max_fds > 500000:
return
file_type = symbol_table + constants.BANG + 'file'
fds = objects.utility.array_of_pointers(fd_table, count = max_fds, subtype = file_type, context = context)
for (fd_num, filp) in enumerate(fds):
if filp != 0:
full_path = LinuxUtilities.path_for_file(context, task, filp)
yield fd_num, filp, full_path
@classmethod
def mask_mods_list(cls, context: interfaces.context.ContextInterface, layer_name: str,
mods: Iterator[interfaces.objects.ObjectInterface]) -> List[Tuple[str, int, int]]:
"""
A helper function to mask the starting and end address of kernel modules
"""
mask = context.layers[layer_name].address_mask
return [(utility.array_to_string(mod.name), mod.get_module_base() & mask,
(mod.get_module_base() & mask) + mod.get_core_size()) for mod in mods]
@classmethod
def generate_kernel_handler_info(
cls, context: interfaces.context.ContextInterface, layer_name: str, kernel_name: str,
mods_list: Iterator[interfaces.objects.ObjectInterface]) -> List[Tuple[str, int, int]]:
"""
A helper function that gets the beginning and end address of the kernel module
"""
kernel = contexts.Module(context, kernel_name, layer_name, 0)
mask = context.layers[layer_name].address_mask
start_addr = kernel.object_from_symbol("_text")
start_addr = start_addr.vol.offset & mask
end_addr = kernel.object_from_symbol("_etext")
end_addr = end_addr.vol.offset & mask
return [(constants.linux.KERNEL_NAME, start_addr, end_addr)] + \
LinuxUtilities.mask_mods_list(context, layer_name, mods_list)
@classmethod
def lookup_module_address(cls, context: interfaces.context.ContextInterface, handlers: List[Tuple[str, int, int]],
target_address: int):
"""
Searches between the start and end address of the kernel module using target_address.
Returns the module and symbol name of the address provided.
"""
mod_name = "UNKNOWN"
symbol_name = "N/A"
for name, start, end in handlers:
if start <= target_address <= end:
mod_name = name
if name == constants.linux.KERNEL_NAME:
symbols = list(context.symbol_space.get_symbols_by_location(target_address))
if len(symbols):
symbol_name = symbols[0].split(constants.BANG)[1] if constants.BANG in symbols[0] else \
symbols[0]
break
return mod_name, symbol_name
@classmethod
def walk_internal_list(cls, vmlinux, struct_name, list_member, list_start):
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)