mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-06 17:57:38 +02:00
Merge branch 'volatilityfoundation:develop' into feature/vadwalk
This commit is contained in:
@@ -26,7 +26,7 @@ except ImportError:
|
||||
|
||||
# Volatility must be findable in sys.path in order for collect_submodules to work
|
||||
# This adds the current working directory, which should usually do the trick
|
||||
sys.path.append(os.getcwd())
|
||||
sys.path.append(os.path.dirname(os.path.abspath(SPEC)))
|
||||
|
||||
vol_analysis = Analysis(['vol.py'],
|
||||
pathex = [],
|
||||
|
||||
@@ -37,9 +37,9 @@ class WarningFindSpec(abc.MetaPathFinder):
|
||||
first."""
|
||||
if fullname.startswith("volatility3.framework.plugins."):
|
||||
warning = "Please do not use the volatility3.framework.plugins namespace directly, only use volatility3.plugins"
|
||||
# Pyinstaller uses walk_packages to import, but needs to read the modules to figure out dependencies
|
||||
# As such, we only print the warning when directly imported rather than from within walk_packages
|
||||
if inspect.stack()[-2].function != 'walk_packages':
|
||||
# Pyinstaller uses walk_packages/_collect_submodules to import, but needs to read the modules to figure out dependencies
|
||||
# As such, we only print the warning when directly imported rather than from within walk_packages/_collect_submodules
|
||||
if inspect.stack()[-2].function in ['walk_packages', '_collect_submodules']:
|
||||
raise Warning(warning)
|
||||
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ class ObjectTemplate(interfaces.objects.Template):
|
||||
object_info: interfaces.objects.ObjectInformation) -> interfaces.objects.ObjectInterface:
|
||||
"""Constructs the object.
|
||||
|
||||
Returns: an object adhereing to the :class:`~volatility3.framework.interfaces.objects.ObjectInterface`
|
||||
Returns: an object adhering to the :class:`~volatility3.framework.interfaces.objects.ObjectInterface`
|
||||
"""
|
||||
arguments: Dict[str, Any] = {}
|
||||
for arg in self.vol:
|
||||
|
||||
@@ -80,7 +80,7 @@ class Check_syscall(plugins.PluginInterface):
|
||||
|
||||
def _get_table_info_disassembly(self, ptr_sz, vmlinux):
|
||||
"""Find the size of the system call table by disassembling functions
|
||||
that immediately reference it in their first isntruction This is in the
|
||||
that immediately reference it in their first instruction This is in the
|
||||
form 'cmp reg,NR_syscalls'."""
|
||||
table_size = 0
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# This file is Copyright 2021 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
# Author: Gustavo Moreira
|
||||
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -40,7 +40,7 @@ class PsAux(plugins.PluginInterface):
|
||||
name: string name of the process (from task.comm)
|
||||
"""
|
||||
|
||||
# kernel theads never have an mm as they do not have userland mappings
|
||||
# kernel threads never have an mm as they do not have userland mappings
|
||||
try:
|
||||
mm = task.mm
|
||||
except exceptions.InvalidAddressException:
|
||||
|
||||
@@ -19,7 +19,7 @@ class PsTree(pslist.PsList):
|
||||
"""Finds how deep the PID is in the tasks hierarchy.
|
||||
|
||||
Args:
|
||||
pid: PID to find the level in the hierachy
|
||||
pid: PID to find the level in the hierarchy
|
||||
"""
|
||||
seen = set([pid])
|
||||
level = 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# This file is opyright 2020 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# This file is Copyright 2020 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ class Timeliner(interfaces.plugins.PluginInterface):
|
||||
|
||||
return [sortable(timestamp) for timestamp in data[2:]]
|
||||
|
||||
def _generator(self, runable_plugins: List[TimeLinerInterface]) -> Optional[Iterable[Tuple[int, Tuple]]]:
|
||||
def _generator(self, runnable_plugins: List[TimeLinerInterface]) -> Optional[Iterable[Tuple[int, Tuple]]]:
|
||||
"""Takes a timeline, sorts it and output the data from each relevant
|
||||
row from each plugin."""
|
||||
# Generate the results for each plugin
|
||||
@@ -115,9 +115,9 @@ class Timeliner(interfaces.plugins.PluginInterface):
|
||||
file_data = None
|
||||
fp = None
|
||||
|
||||
for plugin in runable_plugins:
|
||||
for plugin in runnable_plugins:
|
||||
plugin_name = plugin.__class__.__name__
|
||||
self._progress_callback((runable_plugins.index(plugin) * 100) // len(runable_plugins),
|
||||
self._progress_callback((runnable_plugins.index(plugin) * 100) // len(runnable_plugins),
|
||||
f"Running plugin {plugin_name}...")
|
||||
try:
|
||||
vollog.log(logging.INFO, f"Running {plugin_name}")
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
# For a thorough walkthrough on how the R&D was performed to develop this plugin,
|
||||
# please see our blogpost here:
|
||||
#
|
||||
# <insert blog URL once published>
|
||||
# https://volatility-labs.blogspot.com/2021/10/memory-forensics-r-illustrated.html
|
||||
|
||||
import io
|
||||
import logging
|
||||
|
||||
@@ -95,10 +95,10 @@ class SSDT(plugins.PluginInterface):
|
||||
if is_kernel_64:
|
||||
array_subtype = "long"
|
||||
|
||||
def kvo_calulator(func: int) -> int:
|
||||
def kvo_calculator(func: int) -> int:
|
||||
return kvo + service_table_address + (func >> 4)
|
||||
|
||||
find_address = kvo_calulator
|
||||
find_address = kvo_calculator
|
||||
else:
|
||||
array_subtype = "unsigned long"
|
||||
|
||||
|
||||
@@ -38,4 +38,4 @@ class WindowsMetadata(interfaces.symbols.MetadataInterface):
|
||||
|
||||
|
||||
class LinuxMetadata(interfaces.symbols.MetadataInterface):
|
||||
"""Class to handle the etadata from a Linux symbol table."""
|
||||
"""Class to handle the metadata from a Linux symbol table."""
|
||||
|
||||
@@ -10,10 +10,10 @@ import os
|
||||
import re
|
||||
import struct
|
||||
from typing import Any, Dict, Generator, List, Optional, Tuple, Union
|
||||
from urllib import request, parse
|
||||
from urllib import parse, request
|
||||
|
||||
from volatility3 import symbols
|
||||
from volatility3.framework import constants, interfaces, exceptions
|
||||
from volatility3.framework import constants, contexts, exceptions, interfaces
|
||||
from volatility3.framework.configuration.requirements import SymbolTableRequirement
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.framework.symbols.windows import pdbconv
|
||||
@@ -24,7 +24,7 @@ vollog = logging.getLogger(__name__)
|
||||
class PDBUtility(interfaces.configuration.VersionableInterface):
|
||||
"""Class to handle and manage all getting symbols based on MZ header"""
|
||||
|
||||
_version = (1, 0, 0)
|
||||
_version = (1, 0, 1)
|
||||
_required_framework_version = (2, 0, 0)
|
||||
|
||||
@classmethod
|
||||
@@ -131,14 +131,14 @@ class PDBUtility(interfaces.configuration.VersionableInterface):
|
||||
# Check it is actually the MZ header
|
||||
if mz_sig != b"MZ":
|
||||
return None
|
||||
|
||||
|
||||
nt_header_start, = struct.unpack("<I", layer.read(offset + 0x3C, 4))
|
||||
pe_sig = layer.read(offset + nt_header_start, 2)
|
||||
|
||||
|
||||
# Check it is actually the Nt Headers
|
||||
if pe_sig != b"PE":
|
||||
return None
|
||||
|
||||
|
||||
optional_header_size, = struct.unpack('<H', layer.read(offset + nt_header_start + 0x14, 2))
|
||||
# Just enough to tell us the max size
|
||||
pe_header = layer.read(offset, nt_header_start + 0x16 + optional_header_size)
|
||||
@@ -146,7 +146,7 @@ class PDBUtility(interfaces.configuration.VersionableInterface):
|
||||
max_size = pe_data.OPTIONAL_HEADER.SizeOfImage
|
||||
|
||||
# Proper data
|
||||
virtual_data = layer.read(offset, max_size, pad=True)
|
||||
virtual_data = layer.read(offset, max_size, pad = True)
|
||||
pe_data = pefile.PE(data = virtual_data)
|
||||
|
||||
# De-virtualize the memory
|
||||
@@ -291,7 +291,7 @@ class PDBUtility(interfaces.configuration.VersionableInterface):
|
||||
|
||||
@classmethod
|
||||
def symbol_table_from_pdb(cls, context: interfaces.context.ContextInterface, config_path: str, layer_name: str,
|
||||
pdb_name: str, module_offset: int, module_size: int) -> str:
|
||||
pdb_name: str, module_offset: int = None, module_size: int = None) -> str:
|
||||
"""Creates symbol table for a module in the specified layer_name.
|
||||
|
||||
Searches the memory section of the loaded module for its PDB GUID
|
||||
@@ -307,6 +307,19 @@ class PDBUtility(interfaces.configuration.VersionableInterface):
|
||||
Returns:
|
||||
The name of the constructed and loaded symbol table
|
||||
"""
|
||||
_, symbol_table_name = cls._modtable_from_pdb(context, config_path, layer_name, pdb_name, module_offset,
|
||||
module_size)
|
||||
return symbol_table_name
|
||||
|
||||
@classmethod
|
||||
def _modtable_from_pdb(cls, context: interfaces.context.ContextInterface, config_path: str, layer_name: str,
|
||||
pdb_name: str, module_offset: int = None, module_size: int = None,
|
||||
create_module: bool = False) -> Tuple[Optional[str], Optional[str]]:
|
||||
|
||||
if module_offset is None:
|
||||
module_offset = context.layers[layer_name].minimum_address
|
||||
if module_size is None:
|
||||
module_size = context.layers[layer_name].maximum_address - module_offset
|
||||
|
||||
guids = list(
|
||||
cls.pdbname_scan(context,
|
||||
@@ -323,12 +336,46 @@ class PDBUtility(interfaces.configuration.VersionableInterface):
|
||||
|
||||
vollog.debug(f"Found {guid['pdb_name']}: {guid['GUID']}-{guid['age']}")
|
||||
|
||||
return cls.load_windows_symbol_table(context,
|
||||
guid["GUID"],
|
||||
guid["age"],
|
||||
guid["pdb_name"],
|
||||
"volatility3.framework.symbols.intermed.IntermediateSymbolTable",
|
||||
config_path = config_path)
|
||||
module_name = guid["pdb_name"].strip('.pdb')
|
||||
|
||||
symbol_table_name = cls.load_windows_symbol_table(context,
|
||||
guid["GUID"],
|
||||
guid["age"],
|
||||
guid["pdb_name"],
|
||||
"volatility3.framework.symbols.intermed.IntermediateSymbolTable",
|
||||
config_path = config_path)
|
||||
|
||||
new_module_name = None
|
||||
if create_module:
|
||||
new_module = contexts.Module.create(context, module_name, layer_name, offset = guid['mz_offset'],
|
||||
symbol_table_name = symbol_table_name)
|
||||
new_module_name = new_module.name
|
||||
|
||||
return new_module_name, symbol_table_name
|
||||
|
||||
@classmethod
|
||||
def module_from_pdb(cls, context: interfaces.context.ContextInterface, config_path: str, layer_name: str,
|
||||
pdb_name: str, module_offset: int = None, module_size: int = None) -> str:
|
||||
"""Creates a module in the specified layer_name based on a pdb name.
|
||||
|
||||
Searches the memory section of the loaded module for its PDB GUID
|
||||
and loads the associated symbol table into the symbol space.
|
||||
|
||||
Args:
|
||||
context: The context to retrieve required elements (layers, symbol tables) from
|
||||
config_path: The config path where to find symbol files
|
||||
layer_name: The name of the layer on which to operate
|
||||
module_offset: This memory dump's module image offset
|
||||
module_size: The size of the module for this dump
|
||||
|
||||
Returns:
|
||||
The name of the constructed and loaded symbol table
|
||||
"""
|
||||
|
||||
module_name, _ = cls._modtable_from_pdb(context, config_path, layer_name, pdb_name, module_offset,
|
||||
module_size, create_module = True)
|
||||
|
||||
return module_name
|
||||
|
||||
|
||||
class PdbSignatureScanner(interfaces.layers.ScannerInterface):
|
||||
|
||||
Reference in New Issue
Block a user