mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-22 09:34:52 +02:00
Merge pull request #551 from volatilityfoundation/feature/windows-kernel-module
Windows: Update to kernel ModuleRequirement for ease of config
This commit is contained in:
@@ -20,17 +20,15 @@ vollog = logging.getLogger(__name__)
|
||||
class BigPools(interfaces.plugins.PluginInterface):
|
||||
"""List big page pools."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.StringRequirement(name = 'tags',
|
||||
description = "Comma separated list of pool tags to filter pools returned",
|
||||
optional = True,
|
||||
@@ -108,9 +106,11 @@ class BigPools(interfaces.plugins.PluginInterface):
|
||||
else:
|
||||
tags = None
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for big_pool in self.list_big_pools(context = self.context,
|
||||
layer_name = self.config["primary"],
|
||||
symbol_table = self.config["nt_symbols"],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
tags = tags):
|
||||
|
||||
num_bytes = big_pool.get_number_of_bytes()
|
||||
|
||||
@@ -21,16 +21,14 @@ vollog = logging.getLogger(__name__)
|
||||
class Cachedump(interfaces.plugins.PluginInterface):
|
||||
"""Dumps lsa secrets from memory"""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0)),
|
||||
requirements.PluginRequirement(name = 'lsadump', plugin = lsadump.Lsadump, version = (1, 0, 0)),
|
||||
requirements.PluginRequirement(name = 'hashdump', plugin = hashdump.Hashdump, version = (1, 1, 0))
|
||||
@@ -46,7 +44,7 @@ class Cachedump(interfaces.plugins.PluginInterface):
|
||||
hmac_md5 = HMAC.new(nlkm, ch)
|
||||
rc4key = hmac_md5.digest()
|
||||
rc4 = ARC4.new(rc4key)
|
||||
data = rc4.encrypt(edata) # lgtm [py/weak-cryptographic-algorithm]
|
||||
data = rc4.encrypt(edata) # lgtm [py/weak-cryptographic-algorithm]
|
||||
else:
|
||||
# based on Based on code from http://lab.mediaservice.net/code/cachedump.rb
|
||||
aes = AES.new(nlkm[16:32], AES.MODE_CBC, ch)
|
||||
@@ -90,7 +88,10 @@ class Cachedump(interfaces.plugins.PluginInterface):
|
||||
vollog.warning('Unable to find bootkey')
|
||||
return
|
||||
|
||||
vista_or_later = versions.is_vista_or_later(context = self.context, symbol_table = self.config['nt_symbols'])
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
vista_or_later = versions.is_vista_or_later(context = self.context,
|
||||
symbol_table = kernel.symbol_table_name)
|
||||
|
||||
lsakey = lsadump.Lsadump.get_lsa_key(sechive, bootkey, vista_or_later)
|
||||
if not lsakey:
|
||||
@@ -129,10 +130,12 @@ class Cachedump(interfaces.plugins.PluginInterface):
|
||||
|
||||
syshive = sechive = None
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for hive in hivelist.HiveList.list_hives(self.context,
|
||||
self.config_path,
|
||||
self.config['primary'],
|
||||
self.config['nt_symbols'],
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
hive_offsets = None if offset is None else [offset]):
|
||||
|
||||
if hive.get_name().split('\\')[-1].upper() == 'SYSTEM':
|
||||
@@ -147,5 +150,5 @@ class Cachedump(interfaces.plugins.PluginInterface):
|
||||
vollog.warning('Unable to locate SECURITY hive')
|
||||
return
|
||||
|
||||
return renderers.TreeGrid([("Username", str), ("Domain", str), ("Domain name", str), ('Hashh', bytes)],
|
||||
return renderers.TreeGrid([("Username", str), ("Domain", str), ("Domain name", str), ('Hash', bytes)],
|
||||
self._generator(syshive, sechive))
|
||||
|
||||
@@ -19,16 +19,14 @@ vollog = logging.getLogger(__name__)
|
||||
class Callbacks(interfaces.plugins.PluginInterface):
|
||||
"""Lists kernel callbacks and notification routines."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'ssdt', plugin = ssdt.SSDT, version = (1, 0, 0)),
|
||||
requirements.PluginRequirement(name = 'svcscan', plugin = svcscan.SvcScan, version = (1, 0, 0))
|
||||
]
|
||||
@@ -191,7 +189,8 @@ class Callbacks(interfaces.plugins.PluginInterface):
|
||||
continue
|
||||
|
||||
try:
|
||||
component: Union[interfaces.renderers.BaseAbsentValue, interfaces.objects.ObjectInterface] = ntkrnlmp.object(
|
||||
component: Union[
|
||||
interfaces.renderers.BaseAbsentValue, interfaces.objects.ObjectInterface] = ntkrnlmp.object(
|
||||
"string", absolute = True, offset = callback.Component, max_length = 64, errors = "replace"
|
||||
)
|
||||
except exceptions.InvalidAddressException:
|
||||
@@ -244,17 +243,20 @@ class Callbacks(interfaces.plugins.PluginInterface):
|
||||
|
||||
def _generator(self):
|
||||
|
||||
callback_table_name = self.create_callback_table(self.context, self.config["nt_symbols"], self.config_path)
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
collection = ssdt.SSDT.build_module_collection(self.context, self.config['primary'], self.config['nt_symbols'])
|
||||
callback_table_name = self.create_callback_table(self.context, kernel.symbol_table_name,
|
||||
self.config_path)
|
||||
|
||||
collection = ssdt.SSDT.build_module_collection(self.context, kernel.layer_name, kernel.symbol_table_name)
|
||||
|
||||
callback_methods = (self.list_notify_routines, self.list_bugcheck_callbacks,
|
||||
self.list_bugcheck_reason_callbacks, self.list_registry_callbacks)
|
||||
|
||||
for callback_method in callback_methods:
|
||||
for callback_type, callback_address, callback_detail in callback_method(self.context,
|
||||
self.config['primary'],
|
||||
self.config['nt_symbols'],
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
callback_table_name):
|
||||
|
||||
if callback_detail is None:
|
||||
|
||||
@@ -15,17 +15,15 @@ vollog = logging.getLogger(__name__)
|
||||
class CmdLine(interfaces.plugins.PluginInterface):
|
||||
"""Lists process command line arguments."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0)),
|
||||
requirements.ListRequirement(name = 'pid',
|
||||
element_type = int,
|
||||
@@ -57,13 +55,15 @@ class CmdLine(interfaces.plugins.PluginInterface):
|
||||
|
||||
def _generator(self, procs):
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for proc in procs:
|
||||
process_name = utility.array_to_string(proc.ImageFileName)
|
||||
proc_id = "Unknown"
|
||||
|
||||
try:
|
||||
proc_id = proc.UniqueProcessId
|
||||
result_text = self.get_cmdline(self.context, self.config["nt_symbols"], proc)
|
||||
result_text = self.get_cmdline(self.context, kernel.symbol_table_name, proc)
|
||||
|
||||
except exceptions.SwappedInvalidAddressException as exp:
|
||||
result_text = f"Required memory at {exp.invalid_address:#x} is inaccessible (swapped)"
|
||||
@@ -78,11 +78,14 @@ class CmdLine(interfaces.plugins.PluginInterface):
|
||||
yield (0, (proc.UniqueProcessId, process_name, result_text))
|
||||
|
||||
def run(self):
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
|
||||
|
||||
return renderers.TreeGrid([("PID", int), ("Process", str), ("Args", str)],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_func = filter_func)))
|
||||
|
||||
@@ -20,17 +20,15 @@ vollog = logging.getLogger(__name__)
|
||||
class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Lists the loaded modules in a particular windows memory image."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (2, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.VersionRequirement(name = 'pslist', component = pslist.PsList, version = (2, 0, 0)),
|
||||
requirements.VersionRequirement(name = 'info', component = info.Info, version = (1, 0, 0)),
|
||||
requirements.ListRequirement(name = 'pid',
|
||||
@@ -94,7 +92,9 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"pe",
|
||||
class_types = pe.class_types)
|
||||
|
||||
kuser = info.Info.get_kuser_structure(self.context, self.config['primary'], self.config['nt_symbols'])
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
kuser = info.Info.get_kuser_structure(self.context, kernel.layer_name, kernel.symbol_table_name)
|
||||
nt_major_version = int(kuser.NtMajorVersion)
|
||||
nt_minor_version = int(kuser.NtMinorVersion)
|
||||
# LoadTime only applies to versions higher or equal to Window 7 (6.1 and higher)
|
||||
@@ -144,10 +144,12 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
format_hints.Hex(entry.SizeOfImage), BaseDllName, FullDllName, DllLoadTime, file_output))
|
||||
|
||||
def generate_timeline(self):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for row in self._generator(
|
||||
pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'])):
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name)):
|
||||
_depth, row_data = row
|
||||
if not isinstance(row_data[6], datetime.datetime):
|
||||
continue
|
||||
@@ -157,12 +159,13 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
|
||||
def run(self):
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
return renderers.TreeGrid([("PID", int), ("Process", str), ("Base", format_hints.Hex),
|
||||
("Size", format_hints.Hex), ("Name", str), ("Path", str),
|
||||
("LoadTime", datetime.datetime), ("File output", str)],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_func = filter_func)))
|
||||
|
||||
@@ -22,25 +22,23 @@ MAJOR_FUNCTIONS = [
|
||||
class DriverIrp(interfaces.plugins.PluginInterface):
|
||||
"""List IRPs for drivers in a particular windows memory image."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'ssdt', plugin = ssdt.SSDT, version = (1, 0, 0)),
|
||||
requirements.PluginRequirement(name = 'driverscan', plugin = driverscan.DriverScan, version = (1, 0, 0)),
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
]
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
collection = ssdt.SSDT.build_module_collection(self.context, self.config['primary'], self.config['nt_symbols'])
|
||||
collection = ssdt.SSDT.build_module_collection(self.context, kernel.layer_name, kernel.symbol_table_name)
|
||||
|
||||
for driver in driverscan.DriverScan.scan_drivers(self.context, self.config['primary'],
|
||||
self.config['nt_symbols']):
|
||||
for driver in driverscan.DriverScan.scan_drivers(self.context, kernel.layer_name, kernel.symbol_table_name):
|
||||
|
||||
try:
|
||||
driver_name = driver.get_driver_name()
|
||||
|
||||
@@ -13,16 +13,14 @@ from volatility3.plugins.windows import poolscanner
|
||||
class DriverScan(interfaces.plugins.PluginInterface):
|
||||
"""Scans for drivers present in a particular windows memory image."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'poolscanner', plugin = poolscanner.PoolScanner, version = (1, 0, 0)),
|
||||
]
|
||||
|
||||
@@ -51,7 +49,9 @@ class DriverScan(interfaces.plugins.PluginInterface):
|
||||
yield mem_object
|
||||
|
||||
def _generator(self):
|
||||
for driver in self.scan_drivers(self.context, self.config['primary'], self.config['nt_symbols']):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for driver in self.scan_drivers(self.context, kernel.layer_name, kernel.symbol_table_name):
|
||||
|
||||
try:
|
||||
driver_name = driver.get_driver_name()
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
|
||||
import logging
|
||||
import ntpath
|
||||
from typing import List, Tuple, Type, Optional, Generator
|
||||
|
||||
from volatility3.framework import interfaces, renderers, exceptions, constants
|
||||
from volatility3.plugins.windows import handles
|
||||
from volatility3.plugins.windows import pslist
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from typing import List, Tuple, Type, Optional, Generator
|
||||
from volatility3.plugins.windows import handles
|
||||
from volatility3.plugins.windows import pslist
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -25,17 +26,15 @@ EXTENSION_CACHE_MAP = {
|
||||
class DumpFiles(interfaces.plugins.PluginInterface):
|
||||
"""Dumps cached file contents from Windows memory samples."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.IntRequirement(name = 'pid',
|
||||
description = "Process ID to include (all other processes are excluded)",
|
||||
optional = True),
|
||||
@@ -167,6 +166,7 @@ class DumpFiles(interfaces.plugins.PluginInterface):
|
||||
file_output)
|
||||
|
||||
def _generator(self, procs: List, offsets: List):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
if procs:
|
||||
# The handles plugin doesn't expose any staticmethod/classmethod, and it also requires stashing
|
||||
@@ -175,11 +175,11 @@ class DumpFiles(interfaces.plugins.PluginInterface):
|
||||
# results instead of just dealing with them as direct objects here.
|
||||
handles_plugin = handles.Handles(context = self.context, config_path = self._config_path)
|
||||
type_map = handles_plugin.get_type_map(context = self.context,
|
||||
layer_name = self.config["primary"],
|
||||
symbol_table = self.config["nt_symbols"])
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name)
|
||||
cookie = handles_plugin.find_cookie(context = self.context,
|
||||
layer_name = self.config["primary"],
|
||||
symbol_table = self.config["nt_symbols"])
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name)
|
||||
|
||||
for proc in procs:
|
||||
|
||||
@@ -195,7 +195,7 @@ class DumpFiles(interfaces.plugins.PluginInterface):
|
||||
obj_type = entry.get_object_type(type_map, cookie)
|
||||
if obj_type == "File":
|
||||
file_obj = entry.Body.cast("_FILE_OBJECT")
|
||||
for result in self.process_file_object(self.context, self.config["primary"], self.open,
|
||||
for result in self.process_file_object(self.context, kernel.layer_name, self.open,
|
||||
file_obj):
|
||||
yield (0, result)
|
||||
except exceptions.InvalidAddressException:
|
||||
@@ -219,7 +219,7 @@ class DumpFiles(interfaces.plugins.PluginInterface):
|
||||
if not file_obj.is_valid():
|
||||
continue
|
||||
|
||||
for result in self.process_file_object(self.context, self.config["primary"], self.open,
|
||||
for result in self.process_file_object(self.context, kernel.layer_name, self.open,
|
||||
file_obj):
|
||||
yield (0, result)
|
||||
except exceptions.InvalidAddressException:
|
||||
@@ -230,16 +230,17 @@ class DumpFiles(interfaces.plugins.PluginInterface):
|
||||
# Now process any offsets explicitly requested by the user.
|
||||
for offset, is_virtual in offsets:
|
||||
try:
|
||||
layer_name = self.config["primary"]
|
||||
layer_name = kernel.layer_name
|
||||
# switch to a memory layer if the user provided --physaddr instead of --virtaddr
|
||||
if not is_virtual:
|
||||
layer_name = self.context.layers[layer_name].config["memory_layer"]
|
||||
|
||||
file_obj = self.context.object(self.config["nt_symbols"] + constants.BANG + "_FILE_OBJECT",
|
||||
layer_name = layer_name,
|
||||
native_layer_name = self.config["primary"],
|
||||
offset = offset)
|
||||
for result in self.process_file_object(self.context, self.config["primary"], self.open, file_obj):
|
||||
file_obj = self.context.object(
|
||||
kernel.symbol_table_name + constants.BANG + "_FILE_OBJECT",
|
||||
layer_name = layer_name,
|
||||
native_layer_name = kernel.layer_name,
|
||||
offset = offset)
|
||||
for result in self.process_file_object(self.context, kernel.layer_name, self.open, file_obj):
|
||||
yield (0, result)
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.log(constants.LOGLEVEL_VVV, f"Cannot extract file at {offset:#x}")
|
||||
@@ -250,6 +251,8 @@ class DumpFiles(interfaces.plugins.PluginInterface):
|
||||
# a list of processes matching the pid filter. all files for these process(es) will be dumped.
|
||||
procs = []
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
if self.config.get("virtaddr", None) is not None:
|
||||
offsets.append((self.config["virtaddr"], True))
|
||||
elif self.config.get("physaddr", None) is not None:
|
||||
@@ -257,8 +260,8 @@ class DumpFiles(interfaces.plugins.PluginInterface):
|
||||
else:
|
||||
filter_func = pslist.PsList.create_pid_filter([self.config.get("pid", None)])
|
||||
procs = pslist.PsList.list_processes(self.context,
|
||||
self.config["primary"],
|
||||
self.config["nt_symbols"],
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
filter_func = filter_func)
|
||||
|
||||
return renderers.TreeGrid([("Cache", str), ("FileObject", format_hints.Hex), ("FileName", str),
|
||||
|
||||
@@ -15,17 +15,15 @@ vollog = logging.getLogger(__name__)
|
||||
class Envars(interfaces.plugins.PluginInterface):
|
||||
"Display process environment variables"
|
||||
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.ListRequirement(name = 'pid',
|
||||
description = 'Filter on specific process IDs',
|
||||
element_type = int,
|
||||
@@ -48,11 +46,12 @@ class Envars(interfaces.plugins.PluginInterface):
|
||||
"""
|
||||
|
||||
values = []
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for hive in hivelist.HiveList.list_hives(context = self.context,
|
||||
base_config_path = self.config_path,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
hive_offsets = None):
|
||||
sys = False
|
||||
ntuser = False
|
||||
@@ -192,10 +191,11 @@ class Envars(interfaces.plugins.PluginInterface):
|
||||
def run(self):
|
||||
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
return renderers.TreeGrid([("PID", int), ("Process", str), ("Block", str), ("Variable", str), ("Value", str)],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_func = filter_func)))
|
||||
|
||||
@@ -13,15 +13,13 @@ from volatility3.plugins.windows import poolscanner
|
||||
class FileScan(interfaces.plugins.PluginInterface):
|
||||
"""Scans for file objects present in a particular windows memory image."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'poolscanner', plugin = poolscanner.PoolScanner, version = (1, 0, 0)),
|
||||
]
|
||||
|
||||
@@ -50,7 +48,9 @@ class FileScan(interfaces.plugins.PluginInterface):
|
||||
yield mem_object
|
||||
|
||||
def _generator(self):
|
||||
for fileobj in self.scan_files(self.context, self.config['primary'], self.config['nt_symbols']):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for fileobj in self.scan_files(self.context, kernel.layer_name, kernel.symbol_table_name):
|
||||
|
||||
try:
|
||||
file_name = fileobj.FileName.String
|
||||
|
||||
@@ -30,8 +30,8 @@ def createservicesid(svc) -> str:
|
||||
class GetServiceSIDs(interfaces.plugins.PluginInterface):
|
||||
"""Lists process token sids."""
|
||||
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 0, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -53,20 +53,18 @@ class GetServiceSIDs(interfaces.plugins.PluginInterface):
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0))
|
||||
]
|
||||
|
||||
def _generator(self):
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
# Get the system hive
|
||||
for hive in hivelist.HiveList.list_hives(context = self.context,
|
||||
base_config_path = self.config_path,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_string = 'machine\\system',
|
||||
hive_offsets = None):
|
||||
# Get ControlSet\Services.
|
||||
|
||||
@@ -28,8 +28,8 @@ def find_sid_re(sid_string, sid_re_list) -> Union[str, interfaces.renderers.Base
|
||||
class GetSIDs(interfaces.plugins.PluginInterface):
|
||||
"""Print the SIDs owning each process"""
|
||||
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 0, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -53,10 +53,8 @@ class GetSIDs(interfaces.plugins.PluginInterface):
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.ListRequirement(name = 'pid',
|
||||
description = 'Filter on specific process IDs',
|
||||
element_type = int,
|
||||
@@ -75,12 +73,13 @@ class GetSIDs(interfaces.plugins.PluginInterface):
|
||||
|
||||
key = "Microsoft\\Windows NT\\CurrentVersion\\ProfileList"
|
||||
val = "ProfileImagePath"
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
sids = {}
|
||||
for hive in hivelist.HiveList.list_hives(context = self.context,
|
||||
base_config_path = self.config_path,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_string = 'config\\software',
|
||||
hive_offsets = None):
|
||||
|
||||
@@ -154,10 +153,11 @@ class GetSIDs(interfaces.plugins.PluginInterface):
|
||||
def run(self):
|
||||
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
return renderers.TreeGrid([("PID", int), ("Process", str), ("SID", str), ("Name", str)],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_func = filter_func)))
|
||||
|
||||
@@ -24,7 +24,7 @@ except ImportError:
|
||||
class Handles(interfaces.plugins.PluginInterface):
|
||||
"""Lists process open handles."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -38,10 +38,8 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.ListRequirement(name = 'pid',
|
||||
element_type = int,
|
||||
description = "Process IDs to include (all other processes are excluded)",
|
||||
@@ -69,7 +67,9 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
process' handle table, determine where the corresponding object's
|
||||
_OBJECT_HEADER can be found."""
|
||||
|
||||
virtual = self.config["primary"]
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
virtual = kernel.layer_name
|
||||
|
||||
try:
|
||||
# before windows 7
|
||||
@@ -80,7 +80,7 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
object_header.GrantedAccess = handle_table_entry.GrantedAccess
|
||||
except AttributeError:
|
||||
# starting with windows 8
|
||||
is_64bit = symbols.symbol_table_is_64bit(self.context, self.config["nt_symbols"])
|
||||
is_64bit = symbols.symbol_table_is_64bit(self.context, kernel.symbol_table_name)
|
||||
|
||||
if is_64bit:
|
||||
if handle_table_entry.LowValue == 0:
|
||||
@@ -104,8 +104,7 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
offset = handle_table_entry.InfoTable & ~7
|
||||
|
||||
# print("LowValue: {0:#x} Magic: {1:#x} Offset: {2:#x}".format(handle_table_entry.InfoTable, magic, offset))
|
||||
object_header = self.context.object(self.config["nt_symbols"] + constants.BANG + "_OBJECT_HEADER",
|
||||
virtual,
|
||||
object_header = self.context.object(kernel.symbol_table_name + constants.BANG + "_OBJECT_HEADER", virtual,
|
||||
offset = offset)
|
||||
object_header.GrantedAccess = handle_table_entry.GrantedAccessBits
|
||||
|
||||
@@ -124,10 +123,11 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
|
||||
if not has_capstone:
|
||||
return None
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
virtual_layer_name = self.config['primary']
|
||||
virtual_layer_name = kernel.layer_name
|
||||
kvo = self.context.layers[virtual_layer_name].config['kernel_virtual_offset']
|
||||
ntkrnlmp = self.context.module(self.config["nt_symbols"], layer_name = virtual_layer_name, offset = kvo)
|
||||
ntkrnlmp = self.context.module(kernel.symbol_table_name, layer_name = virtual_layer_name, offset = kvo)
|
||||
|
||||
try:
|
||||
func_addr = ntkrnlmp.get_symbol("ObpCaptureHandleInformationEx").address
|
||||
@@ -227,10 +227,12 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
"""Parse a process' handle table and yield valid handle table entries,
|
||||
going as deep into the table "levels" as necessary."""
|
||||
|
||||
virtual = self.config["primary"]
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
virtual = kernel.layer_name
|
||||
kvo = self.context.layers[virtual].config['kernel_virtual_offset']
|
||||
|
||||
ntkrnlmp = self.context.module(self.config["nt_symbols"], layer_name = virtual, offset = kvo)
|
||||
ntkrnlmp = self.context.module(kernel.symbol_table_name, layer_name = virtual, offset = kvo)
|
||||
|
||||
if level > 0:
|
||||
subtype = ntkrnlmp.get_type("pointer")
|
||||
@@ -292,13 +294,15 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
|
||||
def _generator(self, procs):
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
type_map = self.get_type_map(context = self.context,
|
||||
layer_name = self.config["primary"],
|
||||
symbol_table = self.config["nt_symbols"])
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name)
|
||||
|
||||
cookie = self.find_cookie(context = self.context,
|
||||
layer_name = self.config["primary"],
|
||||
symbol_table = self.config["nt_symbols"])
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name)
|
||||
|
||||
for proc in procs:
|
||||
try:
|
||||
@@ -345,12 +349,13 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
def run(self):
|
||||
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
return renderers.TreeGrid([("PID", int), ("Process", str), ("Offset", format_hints.Hex),
|
||||
("HandleValue", format_hints.Hex), ("Type", str),
|
||||
("GrantedAccess", format_hints.Hex), ("Name", str)],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(self.context,
|
||||
self.config['primary'],
|
||||
self.config['nt_symbols'],
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
filter_func = filter_func)))
|
||||
|
||||
@@ -21,16 +21,14 @@ vollog = logging.getLogger(__name__)
|
||||
class Hashdump(interfaces.plugins.PluginInterface):
|
||||
"""Dumps user hashes from memory"""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 1, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0))
|
||||
]
|
||||
|
||||
@@ -134,7 +132,7 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
rc4_key = md5.digest()
|
||||
|
||||
rc4 = ARC4.new(rc4_key)
|
||||
hbootkey = rc4.encrypt(sam_data[0x80:0xA0]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
hbootkey = rc4.encrypt(sam_data[0x80:0xA0]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
return hbootkey
|
||||
elif revision == 3:
|
||||
# AES encrypted
|
||||
@@ -153,7 +151,7 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
des2 = DES.new(des_k2, DES.MODE_ECB)
|
||||
cipher = AES.new(hbootkey[:16], AES.MODE_CBC, salt)
|
||||
obfkey = cipher.decrypt(enc_hash)
|
||||
return des1.decrypt(obfkey[:8]) + des2.decrypt(obfkey[8:16]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
return des1.decrypt(obfkey[:8]) + des2.decrypt(obfkey[8:16]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
|
||||
@classmethod
|
||||
def get_user_hashes(cls, user: registry.CM_KEY_NODE, samhive: registry.RegistryHive,
|
||||
@@ -231,9 +229,9 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
md5.update(hbootkey[:0x10] + pack("<L", rid) + lmntstr)
|
||||
rc4_key = md5.digest()
|
||||
rc4 = ARC4.new(rc4_key)
|
||||
obfkey = rc4.encrypt(enc_hash) # lgtm [py/weak-cryptographic-algorithm]
|
||||
obfkey = rc4.encrypt(enc_hash) # lgtm [py/weak-cryptographic-algorithm]
|
||||
|
||||
return des1.decrypt(obfkey[:8]) + des2.decrypt(obfkey[8:]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
return des1.decrypt(obfkey[:8]) + des2.decrypt(obfkey[8:]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
|
||||
@classmethod
|
||||
def get_user_name(cls, user: registry.CM_KEY_NODE, samhive: registry.RegistryHive) -> Optional[bytes]:
|
||||
@@ -289,10 +287,12 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
offset = self.config.get('offset', None)
|
||||
syshive = None
|
||||
samhive = None
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for hive in hivelist.HiveList.list_hives(self.context,
|
||||
self.config_path,
|
||||
self.config['primary'],
|
||||
self.config['nt_symbols'],
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
hive_offsets = None if offset is None else [offset]):
|
||||
|
||||
if hive.get_name().split('\\')[-1].upper() == 'SYSTEM':
|
||||
|
||||
@@ -16,16 +16,14 @@ from volatility3.framework.symbols.windows import extensions
|
||||
class Info(plugins.PluginInterface):
|
||||
"""Show OS & kernel details of the memory sample being analyzed."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols")
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
@@ -150,18 +148,22 @@ class Info(plugins.PluginInterface):
|
||||
|
||||
def _generator(self):
|
||||
|
||||
layer_name = self.config['primary']
|
||||
symbol_table = self.config['nt_symbols']
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
layer_name = kernel.layer_name
|
||||
symbol_table = kernel.symbol_table_name
|
||||
layer = self.context.layers[layer_name]
|
||||
table = self.context.symbol_space[symbol_table]
|
||||
|
||||
kdbg = self.get_kdbg_structure(self.context, self.config_path, layer_name, symbol_table)
|
||||
|
||||
yield (0, ("Kernel Base", hex(self.config["primary.kernel_virtual_offset"])))
|
||||
yield (0, ("DTB", hex(self.config["primary.page_map_offset"])))
|
||||
yield (0, ("Symbols", self.config["nt_symbols.isf_url"]))
|
||||
yield (0, ("Kernel Base", hex(layer.config["kernel_virtual_offset"])))
|
||||
yield (0, ("DTB", hex(layer.config["page_map_offset"])))
|
||||
yield (0, ("Symbols", table.config["isf_url"]))
|
||||
yield (0, ("Is64Bit", str(symbols.symbol_table_is_64bit(self.context, symbol_table))))
|
||||
yield (0, ("IsPAE", str(self.context.layers[layer_name].metadata.get("pae", False))))
|
||||
|
||||
for i, layer in self.get_depends(self.context, "primary"):
|
||||
for i, layer in self.get_depends(self.context, layer_name):
|
||||
yield (0, (layer.name, f"{i} {layer.__class__.__name__}"))
|
||||
|
||||
if kdbg.Header.OwnerTag == 0x4742444B:
|
||||
|
||||
@@ -21,16 +21,14 @@ vollog = logging.getLogger(__name__)
|
||||
class Lsadump(interfaces.plugins.PluginInterface):
|
||||
"""Dumps lsa secrets from memory"""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.VersionRequirement(name = 'hashdump', component = hashdump.Hashdump, version = (1, 1, 0)),
|
||||
requirements.VersionRequirement(name = 'hivelist', component = hivelist.HiveList, version = (1, 0, 0))
|
||||
]
|
||||
@@ -86,7 +84,7 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
rc4key = md5.digest()
|
||||
|
||||
rc4 = ARC4.new(rc4key)
|
||||
lsa_key = rc4.decrypt(obf_lsa_key[12:60]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
lsa_key = rc4.decrypt(obf_lsa_key[12:60]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
lsa_key = lsa_key[0x10:0x20]
|
||||
else:
|
||||
lsa_key = cls.decrypt_aes(obf_lsa_key, bootkey)
|
||||
@@ -127,7 +125,7 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
des_key = hashdump.Hashdump.sidbytes_to_key(block_key)
|
||||
des = DES.new(des_key, DES.MODE_ECB)
|
||||
enc_block = enc_block + b"\x00" * int(abs(8 - len(enc_block)) % 8)
|
||||
decrypted_data += des.decrypt(enc_block) # lgtm [py/weak-cryptographic-algorithm]
|
||||
decrypted_data += des.decrypt(enc_block) # lgtm [py/weak-cryptographic-algorithm]
|
||||
j += 7
|
||||
if len(key[j:j + 7]) < 7:
|
||||
j = len(key[j:j + 7])
|
||||
@@ -138,7 +136,10 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
|
||||
def _generator(self, syshive: registry.RegistryHive, sechive: registry.RegistryHive):
|
||||
|
||||
vista_or_later = versions.is_vista_or_later(context = self.context, symbol_table = self.config['nt_symbols'])
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
vista_or_later = versions.is_vista_or_later(context = self.context,
|
||||
symbol_table = kernel.symbol_table_name)
|
||||
|
||||
bootkey = hashdump.Hashdump.get_bootkey(syshive)
|
||||
lsakey = self.get_lsa_key(sechive, bootkey, vista_or_later)
|
||||
@@ -181,11 +182,12 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
|
||||
offset = self.config.get('offset', None)
|
||||
syshive = sechive = None
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for hive in hivelist.HiveList.list_hives(self.context,
|
||||
self.config_path,
|
||||
self.config['primary'],
|
||||
self.config['nt_symbols'],
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
hive_offsets = None if offset is None else [offset]):
|
||||
|
||||
if hive.get_name().split('\\')[-1].upper() == 'SYSTEM':
|
||||
|
||||
@@ -17,16 +17,14 @@ vollog = logging.getLogger(__name__)
|
||||
class Malfind(interfaces.plugins.PluginInterface):
|
||||
"""Lists process memory ranges that potentially contain injected code."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.ListRequirement(name = 'pid',
|
||||
element_type = int,
|
||||
description = "Process IDs to include (all other processes are excluded)",
|
||||
@@ -105,8 +103,8 @@ class Malfind(interfaces.plugins.PluginInterface):
|
||||
continue
|
||||
|
||||
if (vad.get_private_memory() == 1
|
||||
and vad.get_tag() == "VadS") or (vad.get_private_memory() == 0
|
||||
and protection_string != "PAGE_EXECUTE_WRITECOPY"):
|
||||
and vad.get_tag() == "VadS") or (vad.get_private_memory() == 0
|
||||
and protection_string != "PAGE_EXECUTE_WRITECOPY"):
|
||||
if cls.is_vad_empty(proc_layer, vad):
|
||||
continue
|
||||
|
||||
@@ -115,13 +113,14 @@ class Malfind(interfaces.plugins.PluginInterface):
|
||||
|
||||
def _generator(self, procs):
|
||||
# determine if we're on a 32 or 64 bit kernel
|
||||
is_32bit_arch = not symbols.symbol_table_is_64bit(self.context, self.config["nt_symbols"])
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
is_32bit_arch = not symbols.symbol_table_is_64bit(self.context, kernel.symbol_table_name)
|
||||
|
||||
for proc in procs:
|
||||
process_name = utility.array_to_string(proc.ImageFileName)
|
||||
|
||||
for vad, data in self.list_injections(self.context, self.config["primary"], self.config["nt_symbols"],
|
||||
proc):
|
||||
for vad, data in self.list_injections(self.context, kernel.layer_name, kernel.symbol_table_name, proc):
|
||||
|
||||
# if we're on a 64 bit kernel, we may still need 32 bit disasm due to wow64
|
||||
if is_32bit_arch or proc.get_is_wow64():
|
||||
@@ -145,13 +144,14 @@ class Malfind(interfaces.plugins.PluginInterface):
|
||||
yield (0, (proc.UniqueProcessId, process_name, format_hints.Hex(vad.get_start()),
|
||||
format_hints.Hex(vad.get_end()), vad.get_tag(),
|
||||
vad.get_protection(
|
||||
vadinfo.VadInfo.protect_values(self.context, self.config["primary"],
|
||||
self.config["nt_symbols"]),
|
||||
vadinfo.VadInfo.protect_values(self.context, kernel.layer_name,
|
||||
kernel.symbol_table_name),
|
||||
vadinfo.winnt_protections), vad.get_commit_charge(), vad.get_private_memory(),
|
||||
file_output, format_hints.HexBytes(data), disasm))
|
||||
|
||||
def run(self):
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
return renderers.TreeGrid([("PID", int), ("Process", str), ("Start VPN", format_hints.Hex),
|
||||
("End VPN", format_hints.Hex), ("Tag", str), ("Protection", str),
|
||||
@@ -159,6 +159,6 @@ class Malfind(interfaces.plugins.PluginInterface):
|
||||
("Hexdump", format_hints.HexBytes), ("Disasm", interfaces.renderers.Disassembly)],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_func = filter_func)))
|
||||
|
||||
@@ -16,16 +16,14 @@ vollog = logging.getLogger(__name__)
|
||||
class Memmap(interfaces.plugins.PluginInterface):
|
||||
"""Prints the memory map"""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0)),
|
||||
requirements.BooleanRequirement(name = 'coalesce', description = 'Clump output where possible',
|
||||
default = False, optional = True),
|
||||
@@ -108,12 +106,13 @@ class Memmap(interfaces.plugins.PluginInterface):
|
||||
|
||||
def run(self):
|
||||
filter_func = pslist.PsList.create_pid_filter([self.config.get('pid', None)])
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
return renderers.TreeGrid([("Virtual", format_hints.Hex), ("Physical", format_hints.Hex),
|
||||
("Size", format_hints.Hex), ("Offset in File", format_hints.Hex),
|
||||
("File output", str)],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_func = filter_func)))
|
||||
|
||||
@@ -17,16 +17,14 @@ vollog = logging.getLogger(__name__)
|
||||
class ModScan(interfaces.plugins.PluginInterface):
|
||||
"""Scans for modules present in a particular windows memory image."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.VersionRequirement(name = 'poolerscanner',
|
||||
component = poolscanner.PoolScanner,
|
||||
version = (1, 0, 0)),
|
||||
@@ -137,14 +135,16 @@ class ModScan(interfaces.plugins.PluginInterface):
|
||||
return None
|
||||
|
||||
def _generator(self):
|
||||
session_layers = list(self.get_session_layers(self.context, self.config['primary'], self.config['nt_symbols']))
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
session_layers = list(self.get_session_layers(self.context, kernel.layer_name, kernel.symbol_table_name))
|
||||
pe_table_name = intermed.IntermediateSymbolTable.create(self.context,
|
||||
self.config_path,
|
||||
"windows",
|
||||
"pe",
|
||||
class_types = pe.class_types)
|
||||
|
||||
for mod in self.scan_modules(self.context, self.config['primary'], self.config['nt_symbols']):
|
||||
for mod in self.scan_modules(self.context, kernel.layer_name, kernel.symbol_table_name):
|
||||
|
||||
try:
|
||||
BaseDllName = mod.BaseDllName.get_string()
|
||||
|
||||
@@ -19,16 +19,14 @@ vollog = logging.getLogger(__name__)
|
||||
class Modules(interfaces.plugins.PluginInterface):
|
||||
"""Lists the loaded kernel modules."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 1, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.VersionRequirement(name = 'pslist', component = pslist.PsList, version = (2, 0, 0)),
|
||||
requirements.VersionRequirement(name = 'dlllist', component = dlllist.DllList, version = (2, 0, 0)),
|
||||
requirements.BooleanRequirement(name = 'dump',
|
||||
@@ -38,13 +36,14 @@ class Modules(interfaces.plugins.PluginInterface):
|
||||
]
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
pe_table_name = intermed.IntermediateSymbolTable.create(self.context,
|
||||
self.config_path,
|
||||
"windows",
|
||||
"pe",
|
||||
class_types = pe.class_types)
|
||||
|
||||
for mod in self.list_modules(self.context, self.config['primary'], self.config['nt_symbols']):
|
||||
for mod in self.list_modules(self.context, kernel.layer_name, kernel.symbol_table_name):
|
||||
|
||||
try:
|
||||
BaseDllName = mod.BaseDllName.get_string()
|
||||
|
||||
@@ -13,15 +13,13 @@ from volatility3.plugins.windows import poolscanner
|
||||
class MutantScan(interfaces.plugins.PluginInterface):
|
||||
"""Scans for mutexes present in a particular windows memory image."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'poolscanner', plugin = poolscanner.PoolScanner, version = (1, 0, 0)),
|
||||
]
|
||||
|
||||
@@ -50,7 +48,9 @@ class MutantScan(interfaces.plugins.PluginInterface):
|
||||
yield mem_object
|
||||
|
||||
def _generator(self):
|
||||
for mutant in self.scan_mutants(self.context, self.config['primary'], self.config['nt_symbols']):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for mutant in self.scan_mutants(self.context, kernel.layer_name, kernel.symbol_table_name):
|
||||
|
||||
try:
|
||||
name = mutant.get_name()
|
||||
|
||||
@@ -22,16 +22,14 @@ vollog = logging.getLogger(__name__)
|
||||
class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Scans for network objects present in a particular windows memory image."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.VersionRequirement(name = 'poolscanner',
|
||||
component = poolscanner.PoolScanner,
|
||||
version = (1, 0, 0)),
|
||||
@@ -279,11 +277,13 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
def _generator(self, show_corrupt_results: Optional[bool] = None):
|
||||
""" Generates the network objects for use in rendering. """
|
||||
|
||||
netscan_symbol_table = self.create_netscan_symbol_table(self.context, self.config["primary"],
|
||||
self.config["nt_symbols"], self.config_path)
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for netw_obj in self.scan(self.context, self.config['primary'], self.config['nt_symbols'],
|
||||
netscan_symbol_table):
|
||||
netscan_symbol_table = self.create_netscan_symbol_table(self.context, kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
self.config_path)
|
||||
|
||||
for netw_obj in self.scan(self.context, kernel.layer_name, kernel.symbol_table_name, netscan_symbol_table):
|
||||
|
||||
vollog.debug(f"Found netw obj @ 0x{netw_obj.vol.offset:2x} of assumed type {type(netw_obj)}")
|
||||
# objects passed pool header constraints. check for additional constraints if strict flag is set.
|
||||
|
||||
@@ -20,16 +20,14 @@ vollog = logging.getLogger(__name__)
|
||||
class NetStat(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Traverses network tracking structures present in a particular windows memory image."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.VersionRequirement(name = 'netscan', component = netscan.NetScan, version = (1, 0, 0)),
|
||||
requirements.VersionRequirement(name = 'modules', component = modules.Modules, version = (1, 0, 0)),
|
||||
requirements.VersionRequirement(name = 'pdbutil', component = pdbutil.PDBUtility, version = (1, 0, 0)),
|
||||
@@ -419,19 +417,23 @@ class NetStat(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
def _generator(self, show_corrupt_results: Optional[bool] = None):
|
||||
""" Generates the network objects for use in rendering. """
|
||||
|
||||
netscan_symbol_table = netscan.NetScan.create_netscan_symbol_table(self.context, self.config["primary"],
|
||||
self.config["nt_symbols"], self.config_path)
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
tcpip_module = self.get_tcpip_module(self.context, self.config["primary"], self.config["nt_symbols"])
|
||||
netscan_symbol_table = netscan.NetScan.create_netscan_symbol_table(self.context,
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
self.config_path)
|
||||
|
||||
tcpip_module = self.get_tcpip_module(self.context, kernel.layer_name, kernel.symbol_table_name)
|
||||
|
||||
try:
|
||||
tcpip_symbol_table = pdbutil.PDBUtility.symbol_table_from_pdb(
|
||||
self.context, interfaces.configuration.path_join(self.config_path, 'tcpip'), self.config["primary"],
|
||||
"tcpip.pdb", tcpip_module.DllBase, tcpip_module.SizeOfImage)
|
||||
self.context, interfaces.configuration.path_join(self.config_path, 'tcpip'),
|
||||
kernel.layer_name, "tcpip.pdb", tcpip_module.DllBase, tcpip_module.SizeOfImage)
|
||||
except exceptions.VolatilityException:
|
||||
vollog.warning("Unable to locate symbols for the memory image's tcpip module")
|
||||
|
||||
for netw_obj in self.list_sockets(self.context, self.config['primary'], self.config['nt_symbols'],
|
||||
for netw_obj in self.list_sockets(self.context, kernel.layer_name, kernel.symbol_table_name,
|
||||
netscan_symbol_table, tcpip_module.DllBase, tcpip_symbol_table):
|
||||
|
||||
# objects passed pool header constraints. check for additional constraints if strict flag is set.
|
||||
|
||||
@@ -112,25 +112,25 @@ class PoolHeaderScanner(interfaces.layers.ScannerInterface):
|
||||
class PoolScanner(plugins.PluginInterface):
|
||||
"""A generic pool scanner plugin."""
|
||||
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'handles', plugin = handles.Handles, version = (1, 0, 0)),
|
||||
]
|
||||
|
||||
def _generator(self):
|
||||
|
||||
symbol_table = self.config["nt_symbols"]
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
symbol_table = kernel.symbol_table_name
|
||||
constraints = self.builtin_constraints(symbol_table)
|
||||
|
||||
for constraint, mem_object, header in self.generate_pool_scan(self.context, self.config["primary"],
|
||||
for constraint, mem_object, header in self.generate_pool_scan(self.context, kernel.layer_name,
|
||||
symbol_table, constraints):
|
||||
# generate some type-specific info for sanity checking
|
||||
if constraint.object_type == "Process":
|
||||
|
||||
@@ -16,7 +16,7 @@ vollog = logging.getLogger(__name__)
|
||||
class Privs(interfaces.plugins.PluginInterface):
|
||||
"""Lists process token privileges"""
|
||||
|
||||
_version = (1, 0, 0)
|
||||
_version = (1, 2, 0)
|
||||
_required_framework_version = (1, 0, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -40,10 +40,8 @@ class Privs(interfaces.plugins.PluginInterface):
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.ListRequirement(name = 'pid',
|
||||
description = 'Filter on specific process IDs',
|
||||
element_type = int,
|
||||
@@ -89,11 +87,12 @@ class Privs(interfaces.plugins.PluginInterface):
|
||||
def run(self):
|
||||
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
return renderers.TreeGrid([("PID", int), ("Process", str), ("Value", int), ("Privilege", str),
|
||||
("Attributes", str), ("Description", str)],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_func = filter_func)))
|
||||
|
||||
@@ -80,7 +80,8 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
return file_handle
|
||||
|
||||
@classmethod
|
||||
def create_pid_filter(cls, pid_list: List[int] = None, exclude: bool = False) -> Callable[[interfaces.objects.ObjectInterface], bool]:
|
||||
def create_pid_filter(cls, pid_list: List[int] = None, exclude: bool = False) -> Callable[
|
||||
[interfaces.objects.ObjectInterface], bool]:
|
||||
"""A factory for producing filter functions that filter based on a list
|
||||
of process IDs.
|
||||
|
||||
@@ -103,7 +104,8 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
return filter_func
|
||||
|
||||
@classmethod
|
||||
def create_name_filter(cls, name_list: List[str] = None, exclude: bool = False) -> Callable[[interfaces.objects.ObjectInterface], bool]:
|
||||
def create_name_filter(cls, name_list: List[str] = None, exclude: bool = False) -> Callable[
|
||||
[interfaces.objects.ObjectInterface], bool]:
|
||||
"""A factory for producing filter functions that filter based on a list
|
||||
of process names.
|
||||
|
||||
@@ -170,19 +172,21 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
yield proc
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
pe_table_name = intermed.IntermediateSymbolTable.create(self.context,
|
||||
self.config_path,
|
||||
"windows",
|
||||
"pe",
|
||||
class_types = pe.class_types)
|
||||
|
||||
memory = self.context.layers[self.config['kernel.layer_name']]
|
||||
memory = self.context.layers[kernel.layer_name]
|
||||
if not isinstance(memory, layers.intel.Intel):
|
||||
raise TypeError("Primary layer is not an intel layer")
|
||||
|
||||
for proc in self.list_processes(self.context,
|
||||
self.config['kernel.layer_name'],
|
||||
self.config['kernel.symbol_table_name'],
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
filter_func = self.create_pid_filter(self.config.get('pid', None))):
|
||||
|
||||
if not self.config.get('physical', self.PHYSICAL_DEFAULT):
|
||||
@@ -194,7 +198,7 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
|
||||
try:
|
||||
if self.config['dump']:
|
||||
file_handle = self.process_dump(self.context, self.config['kernel.symbol_table_name'],
|
||||
file_handle = self.process_dump(self.context, kernel.symbol_table_name,
|
||||
pe_table_name, proc, self.open)
|
||||
file_output = "Error outputting file"
|
||||
if file_handle:
|
||||
@@ -202,12 +206,13 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
file_output = str(file_handle.preferred_filename)
|
||||
|
||||
yield (0, (proc.UniqueProcessId, proc.InheritedFromUniqueProcessId,
|
||||
proc.ImageFileName.cast("string", max_length = proc.ImageFileName.vol.count, errors = 'replace'),
|
||||
format_hints.Hex(offset), proc.ActiveThreads, proc.get_handle_count(), proc.get_session_id(),
|
||||
proc.get_is_wow64(), proc.get_create_time(), proc.get_exit_time(), file_output))
|
||||
proc.ImageFileName.cast("string", max_length = proc.ImageFileName.vol.count,
|
||||
errors = 'replace'),
|
||||
format_hints.Hex(offset), proc.ActiveThreads, proc.get_handle_count(), proc.get_session_id(),
|
||||
proc.get_is_wow64(), proc.get_create_time(), proc.get_exit_time(), file_output))
|
||||
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.info(f"Invalid process found at address: {proc.vol.offset:x}. Skipping")
|
||||
vollog.info(f"Invalid process found at address: {proc.vol.offset:x}. Skipping")
|
||||
|
||||
def generate_timeline(self):
|
||||
for row in self._generator():
|
||||
|
||||
@@ -22,16 +22,14 @@ vollog = logging.getLogger(__name__)
|
||||
class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Scans for processes present in a particular windows memory image."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 1, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0)),
|
||||
requirements.VersionRequirement(name = 'info', component = info.Info, version = (1, 0, 0)),
|
||||
requirements.ListRequirement(name = 'pid',
|
||||
@@ -144,26 +142,29 @@ class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
return (nt_major_version, nt_minor_version, build)
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
pe_table_name = intermed.IntermediateSymbolTable.create(self.context,
|
||||
self.config_path,
|
||||
"windows",
|
||||
"pe",
|
||||
class_types = pe.class_types)
|
||||
for proc in self.scan_processes(self.context,
|
||||
self.config['primary'],
|
||||
self.config['nt_symbols'],
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))):
|
||||
|
||||
file_output = "Disabled"
|
||||
if self.config['dump']:
|
||||
# windows 10 objects (maybe others in the future) are already in virtual memory
|
||||
if proc.vol.layer_name == self.config['primary']:
|
||||
if proc.vol.layer_name == kernel.layer_name:
|
||||
vproc = proc
|
||||
else:
|
||||
vproc = self.virtual_process_from_physical(self.context, self.config['primary'],
|
||||
self.config['nt_symbols'], proc)
|
||||
vproc = self.virtual_process_from_physical(self.context, kernel.layer_name,
|
||||
kernel.symbol_table_name, proc)
|
||||
|
||||
file_handle = pslist.PsList.process_dump(self.context, self.config['nt_symbols'], pe_table_name, vproc,
|
||||
file_handle = pslist.PsList.process_dump(self.context, kernel.symbol_table_name,
|
||||
pe_table_name, vproc,
|
||||
self.open)
|
||||
file_output = "Error outputting file"
|
||||
if file_handle:
|
||||
|
||||
@@ -14,7 +14,7 @@ class PsTree(interfaces.plugins.PluginInterface):
|
||||
"""Plugin for listing processes in a tree based on their parent process
|
||||
ID."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -25,10 +25,8 @@ class PsTree(interfaces.plugins.PluginInterface):
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.BooleanRequirement(name = 'physical',
|
||||
description = 'Display physical offsets instead of virtual',
|
||||
default = pslist.PsList.PHYSICAL_DEFAULT,
|
||||
@@ -56,12 +54,15 @@ class PsTree(interfaces.plugins.PluginInterface):
|
||||
|
||||
def _generator(self):
|
||||
"""Generates the Tree of processes."""
|
||||
for proc in pslist.PsList.list_processes(self.context, self.config['primary'], self.config['nt_symbols']):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for proc in pslist.PsList.list_processes(self.context, kernel.layer_name,
|
||||
kernel.symbol_table_name):
|
||||
|
||||
if not self.config.get('physical', pslist.PsList.PHYSICAL_DEFAULT):
|
||||
offset = proc.vol.offset
|
||||
else:
|
||||
layer_name = self.config['primary']
|
||||
layer_name = kernel.layer_name
|
||||
memory = self.context.layers[layer_name]
|
||||
(_, _, offset, _, _) = list(memory.mapping(offset = proc.vol.offset, length = 0))[0]
|
||||
|
||||
|
||||
@@ -39,16 +39,14 @@ class HiveGenerator:
|
||||
class HiveList(interfaces.plugins.PluginInterface):
|
||||
"""Lists the registry hives present in a particular memory image."""
|
||||
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.StringRequirement(name = 'filter',
|
||||
description = "String to filter hive names returned",
|
||||
optional = True,
|
||||
@@ -66,9 +64,11 @@ class HiveList(interfaces.plugins.PluginInterface):
|
||||
def _generator(self) -> Iterator[Tuple[int, Tuple[int, str]]]:
|
||||
chunk_size = 0x500000
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for hive_object in self.list_hive_objects(context = self.context,
|
||||
layer_name = self.config["primary"],
|
||||
symbol_table = self.config["nt_symbols"],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_string = self.config.get('filter', None)):
|
||||
|
||||
file_output = "Disabled"
|
||||
@@ -77,8 +77,8 @@ class HiveList(interfaces.plugins.PluginInterface):
|
||||
hive = next(
|
||||
self.list_hives(self.context,
|
||||
self.config_path,
|
||||
layer_name = self.config["primary"],
|
||||
symbol_table = self.config["nt_symbols"],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
hive_offsets = [hive_object.vol.offset]))
|
||||
maxaddr = hive.hive.Storage[0].Length
|
||||
hive_name = self._sanitize_hive_name(hive.get_name())
|
||||
|
||||
@@ -15,16 +15,14 @@ class HiveScan(interfaces.plugins.PluginInterface):
|
||||
"""Scans for registry hives present in a particular windows memory
|
||||
image."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'poolscanner', plugin = poolscanner.PoolScanner, version = (1, 0, 0)),
|
||||
requirements.PluginRequirement(name = 'bigpools', plugin = bigpools.BigPools, version = (1, 0, 0)),
|
||||
]
|
||||
@@ -68,9 +66,12 @@ class HiveScan(interfaces.plugins.PluginInterface):
|
||||
yield mem_object
|
||||
|
||||
def _generator(self):
|
||||
for hive in self.scan_hives(self.context, self.config['primary'], self.config['nt_symbols']):
|
||||
|
||||
yield (0, (format_hints.Hex(hive.vol.offset), ))
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for hive in self.scan_hives(self.context, kernel.layer_name, kernel.symbol_table_name):
|
||||
|
||||
yield (0, (format_hints.Hex(hive.vol.offset),))
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid([("Offset", format_hints.Hex)], self._generator())
|
||||
|
||||
@@ -19,16 +19,14 @@ vollog = logging.getLogger(__name__)
|
||||
class PrintKey(interfaces.plugins.PluginInterface):
|
||||
"""Lists the registry keys under a hive or specific key value."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0)),
|
||||
requirements.IntRequirement(name = 'offset', description = "Hive Offset", default = None, optional = True),
|
||||
requirements.StringRequirement(name = 'key',
|
||||
@@ -43,10 +41,10 @@ class PrintKey(interfaces.plugins.PluginInterface):
|
||||
|
||||
@classmethod
|
||||
def key_iterator(
|
||||
cls,
|
||||
hive: RegistryHive,
|
||||
node_path: Sequence[objects.StructType] = None,
|
||||
recurse: bool = False
|
||||
cls,
|
||||
hive: RegistryHive,
|
||||
node_path: Sequence[objects.StructType] = None,
|
||||
recurse: bool = False
|
||||
) -> Iterable[Tuple[int, bool, datetime.datetime, str, bool, interfaces.objects.ObjectInterface]]:
|
||||
"""Walks through a set of nodes from a given node (last one in
|
||||
node_path). Avoids loops by not traversing into nodes already present
|
||||
@@ -188,12 +186,13 @@ class PrintKey(interfaces.plugins.PluginInterface):
|
||||
|
||||
def run(self):
|
||||
offset = self.config.get('offset', None)
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
return TreeGrid(columns = [('Last Write Time', datetime.datetime), ('Hive Offset', format_hints.Hex),
|
||||
('Type', str), ('Key', str), ('Name', str), ('Data', format_hints.MultiTypeData),
|
||||
('Volatile', bool)],
|
||||
generator = self._registry_walker(self.config['primary'],
|
||||
self.config['nt_symbols'],
|
||||
generator = self._registry_walker(kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
hive_offsets = None if offset is None else [offset],
|
||||
key = self.config.get('key', None),
|
||||
recurse = self.config.get('recurse', None)))
|
||||
|
||||
@@ -23,7 +23,7 @@ vollog = logging.getLogger(__name__)
|
||||
class UserAssist(interfaces.plugins.PluginInterface):
|
||||
"""Print userassist registry keys and information."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -37,10 +37,8 @@ class UserAssist(interfaces.plugins.PluginInterface):
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.IntRequirement(name = 'offset', description = "Hive Offset", default = None, optional = True),
|
||||
requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0))
|
||||
]
|
||||
@@ -115,13 +113,17 @@ class UserAssist(interfaces.plugins.PluginInterface):
|
||||
def _win7_or_later(self) -> bool:
|
||||
# TODO: change this if there is a better way of determining the OS version
|
||||
# _KUSER_SHARED_DATA.CookiePad is in Windows 6.1 (Win7) and later
|
||||
return self.context.symbol_space.get_type(self.config['nt_symbols'] + constants.BANG +
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
return self.context.symbol_space.get_type(kernel.symbol_table_name + constants.BANG +
|
||||
"_KUSER_SHARED_DATA").has_member('CookiePad')
|
||||
|
||||
def list_userassist(self, hive: RegistryHive) -> Generator[Tuple[int, Tuple], None, None]:
|
||||
"""Generate userassist data for a registry hive."""
|
||||
|
||||
hive_name = hive.hive.cast(self.config["nt_symbols"] + constants.BANG + "_CMHIVE").get_name()
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
hive_name = hive.hive.cast(kernel.symbol_table_name + constants.BANG + "_CMHIVE").get_name()
|
||||
|
||||
if self._win7 is None:
|
||||
try:
|
||||
@@ -216,11 +218,13 @@ class UserAssist(interfaces.plugins.PluginInterface):
|
||||
if self.config.get('offset', None) is not None:
|
||||
hive_offsets = [self.config.get('offset', None)]
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
# get all the user hive offsets or use the one specified
|
||||
for hive in hivelist.HiveList.list_hives(context = self.context,
|
||||
base_config_path = self.config_path,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_string = 'ntuser.dat',
|
||||
hive_offsets = hive_offsets):
|
||||
try:
|
||||
|
||||
@@ -6,50 +6,49 @@
|
||||
# It does this by locating the CSystems array through a variety of methods,
|
||||
# and then validating the entry for RC4 HMAC (0x17 / 23)
|
||||
#
|
||||
# For a thorough walkthrough on how the R&D was performed to develop this plugin,
|
||||
# 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>
|
||||
|
||||
import logging, io
|
||||
|
||||
import io
|
||||
import logging
|
||||
from typing import Iterable, Tuple, List, Optional
|
||||
|
||||
from volatility3.framework.symbols.windows import pdbutil
|
||||
from volatility3.framework import interfaces, symbols, exceptions
|
||||
from volatility3.framework import renderers, constants
|
||||
from volatility3.framework.layers import scanners
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.plugins.windows import pslist, vadinfo
|
||||
|
||||
from volatility3.framework.symbols.windows.extensions import pe
|
||||
|
||||
import pefile
|
||||
|
||||
from volatility3.framework import interfaces, symbols, exceptions
|
||||
from volatility3.framework import renderers, constants
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.layers import scanners
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.framework.symbols.windows import pdbutil
|
||||
from volatility3.framework.symbols.windows.extensions import pe
|
||||
from volatility3.plugins.windows import pslist, vadinfo
|
||||
|
||||
try:
|
||||
import capstone
|
||||
|
||||
has_capstone = True
|
||||
except ImportError:
|
||||
has_capstone = False
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
""" Looks for signs of Skeleton Key malware """
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.VersionRequirement(name = 'pslist', component = pslist.PsList, version = (2, 0, 0)),
|
||||
requirements.VersionRequirement(name = 'vadinfo', component = vadinfo.VadInfo, version = (2, 0, 0)),
|
||||
requirements.VersionRequirement(name = 'pdbutil', component = pdbutil.PDBUtility, version = (1, 0, 0)),
|
||||
@@ -71,26 +70,26 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
|
||||
try:
|
||||
dos_header = self.context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER",
|
||||
offset = base_address,
|
||||
layer_name = layer_name)
|
||||
offset = base_address,
|
||||
layer_name = layer_name)
|
||||
|
||||
for offset, data in dos_header.reconstruct():
|
||||
pe_data.seek(offset)
|
||||
pe_data.write(data)
|
||||
|
||||
|
||||
pe_ret = pefile.PE(data = pe_data.getvalue(), fast_load = True)
|
||||
|
||||
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.debug("Unable to reconstruct cryptdll.dll in memory")
|
||||
pe_ret = None
|
||||
|
||||
return pe_ret
|
||||
|
||||
def _check_for_skeleton_key_vad(self, csystem: interfaces.objects.ObjectInterface,
|
||||
cryptdll_base: int,
|
||||
cryptdll_size: int) -> bool:
|
||||
def _check_for_skeleton_key_vad(self, csystem: interfaces.objects.ObjectInterface,
|
||||
cryptdll_base: int,
|
||||
cryptdll_size: int) -> bool:
|
||||
"""
|
||||
Checks if Initialize and/or Decrypt is hooked by determining if
|
||||
Checks if Initialize and/or Decrypt is hooked by determining if
|
||||
these function pointers reference addresses inside of the cryptdll VAD
|
||||
|
||||
Args:
|
||||
@@ -101,11 +100,11 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
bool: if a skeleton key hook is present
|
||||
"""
|
||||
return not ((cryptdll_base <= csystem.Initialize <= cryptdll_base + cryptdll_size) and \
|
||||
(cryptdll_base <= csystem.Decrypt <= cryptdll_base + cryptdll_size))
|
||||
(cryptdll_base <= csystem.Decrypt <= cryptdll_base + cryptdll_size))
|
||||
|
||||
def _check_for_skeleton_key_symbols(self, csystem: interfaces.objects.ObjectInterface,
|
||||
rc4HmacInitialize: int,
|
||||
rc4HmacDecrypt: int) -> bool:
|
||||
def _check_for_skeleton_key_symbols(self, csystem: interfaces.objects.ObjectInterface,
|
||||
rc4HmacInitialize: int,
|
||||
rc4HmacDecrypt: int) -> bool:
|
||||
"""
|
||||
Uses the PDB information to specifically check if the csystem for RC4HMAC
|
||||
has an initialization pointer to rc4HmacInitialize and a decryption pointer
|
||||
@@ -113,12 +112,12 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
|
||||
Args:
|
||||
csystem: The RC4HMAC KERB_ECRYPT instance
|
||||
rc4HmacInitialize: The expected address of csystem Initialization function
|
||||
rc4HmacInitialize: The expected address of csystem Initialization function
|
||||
rc4HmacDecrypt: The expected address of the csystem Decryption function
|
||||
|
||||
|
||||
Returns:
|
||||
bool: if a skeleton key hook was found
|
||||
"""
|
||||
"""
|
||||
return csystem.Initialize != rc4HmacInitialize or csystem.Decrypt != rc4HmacDecrypt
|
||||
|
||||
def _construct_ecrypt_array(self, array_start: int, count: int, \
|
||||
@@ -137,21 +136,21 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
|
||||
try:
|
||||
array = cryptdll_types.object(object_type = "array",
|
||||
offset = array_start,
|
||||
subtype = cryptdll_types.get_type("_KERB_ECRYPT"),
|
||||
count = count,
|
||||
absolute = True)
|
||||
offset = array_start,
|
||||
subtype = cryptdll_types.get_type("_KERB_ECRYPT"),
|
||||
count = count,
|
||||
absolute = True)
|
||||
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.debug("Unable to construct cSystems array at given offset: {:x}".format(array_start))
|
||||
array = None
|
||||
|
||||
|
||||
return array
|
||||
|
||||
def _find_array_with_pdb_symbols(self, cryptdll_symbols: str,
|
||||
cryptdll_types: interfaces.context.ModuleInterface,
|
||||
proc_layer_name: str,
|
||||
cryptdll_base: int) -> Tuple[interfaces.objects.ObjectInterface, int, int, int]:
|
||||
def _find_array_with_pdb_symbols(self, cryptdll_symbols: str,
|
||||
cryptdll_types: interfaces.context.ModuleInterface,
|
||||
proc_layer_name: str,
|
||||
cryptdll_base: int) -> Tuple[interfaces.objects.ObjectInterface, int, int, int]:
|
||||
|
||||
"""
|
||||
Finds the CSystems array through use of PDB symbols
|
||||
@@ -177,7 +176,7 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
count_address = cryptdll_module.get_symbol("cCSystems").address
|
||||
|
||||
# we do not want to fail just because the count is not in memory
|
||||
# 16 was the size on samples I tested, so I chose it as the default
|
||||
# 16 was the size on samples I tested, so I chose it as the default
|
||||
try:
|
||||
count = cryptdll_types.object(object_type = "unsigned long", offset = count_address)
|
||||
except exceptions.InvalidAddressException:
|
||||
@@ -186,30 +185,31 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
array_start = cryptdll_module.get_absolute_symbol_address("CSystems")
|
||||
|
||||
array = self._construct_ecrypt_array(array_start, count, cryptdll_types)
|
||||
|
||||
|
||||
if array is None:
|
||||
vollog.debug("The CSystem array is not present in memory. Stopping PDB based analysis.")
|
||||
|
||||
return array, rc4HmacInitialize, rc4HmacDecrypt
|
||||
|
||||
def _get_cryptdll_types(self, context: interfaces.context.ContextInterface,
|
||||
config,
|
||||
config_path: str,
|
||||
proc_layer_name: str,
|
||||
cryptdll_base: int):
|
||||
def _get_cryptdll_types(self, context: interfaces.context.ContextInterface,
|
||||
config,
|
||||
config_path: str,
|
||||
proc_layer_name: str,
|
||||
cryptdll_base: int):
|
||||
"""
|
||||
Builds a symbol table from the cryptdll types generated after binary analysis
|
||||
|
||||
Args:
|
||||
context: the context to operate upon
|
||||
config:
|
||||
config:
|
||||
config_path:
|
||||
proc_layer_name: name of the lsass.exe process layer
|
||||
cryptdll_base: base address of cryptdll.dll inside of lsass.exe
|
||||
"""
|
||||
table_mapping = {"nt_symbols": config["nt_symbols"]}
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
table_mapping = {"nt_symbols": kernel.symbol_table_name}
|
||||
|
||||
cryptdll_symbol_table = intermed.IntermediateSymbolTable.create(context = context,
|
||||
cryptdll_symbol_table = intermed.IntermediateSymbolTable.create(context = context,
|
||||
config_path = config_path,
|
||||
sub_path = "windows",
|
||||
filename = "kerb_ecrypt",
|
||||
@@ -218,7 +218,7 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
return context.module(cryptdll_symbol_table, proc_layer_name, offset = cryptdll_base)
|
||||
|
||||
def _find_lsass_proc(self, proc_list: Iterable) -> \
|
||||
Tuple[interfaces.context.ContextInterface, str]:
|
||||
Tuple[interfaces.context.ContextInterface, str]:
|
||||
"""
|
||||
Walks the process list and returns the first valid lsass instances.
|
||||
There should be only one lsass process, but malware will often use the
|
||||
@@ -242,11 +242,10 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
vollog.debug("Process {}: invalid address {} in layer {}".format(proc_id, excp.invalid_address,
|
||||
excp.layer_name))
|
||||
|
||||
|
||||
return None, None
|
||||
|
||||
def _find_cryptdll(self, lsass_proc: interfaces.context.ContextInterface) -> \
|
||||
Tuple[int, int]:
|
||||
Tuple[int, int]:
|
||||
"""
|
||||
Finds the base address of cryptdll.dll inside of lsass.exe
|
||||
|
||||
@@ -260,18 +259,18 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
"""
|
||||
for vad in lsass_proc.get_vad_root().traverse():
|
||||
filename = vad.get_file_name()
|
||||
|
||||
|
||||
if isinstance(filename, str) and filename.lower().endswith("cryptdll.dll"):
|
||||
base = vad.get_start()
|
||||
return base, vad.get_end() - base
|
||||
|
||||
return None, None
|
||||
|
||||
def _find_csystems_with_symbols(self, proc_layer_name: str,
|
||||
cryptdll_types: interfaces.context.ModuleInterface,
|
||||
cryptdll_base: int,
|
||||
cryptdll_size: int) -> \
|
||||
Tuple[interfaces.objects.ObjectInterface, int, int]:
|
||||
def _find_csystems_with_symbols(self, proc_layer_name: str,
|
||||
cryptdll_types: interfaces.context.ModuleInterface,
|
||||
cryptdll_base: int,
|
||||
cryptdll_size: int) -> \
|
||||
Tuple[interfaces.objects.ObjectInterface, int, int]:
|
||||
"""
|
||||
Attempts to find CSystems and the expected address of the handlers.
|
||||
Relies on downloading and parsing of the cryptdll PDB file.
|
||||
@@ -281,27 +280,28 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
cryptdll_types: The types from cryptdll binary analysis
|
||||
cryptdll_base: the base address of cryptdll.dll
|
||||
crytpdll_size: the size of the VAD for cryptdll.dll
|
||||
|
||||
|
||||
Returns:
|
||||
A tuple of:
|
||||
array: An initialized Volatility array of _KERB_ECRYPT structures
|
||||
rc4HmacInitialize: The expected address of csystem Initialization function
|
||||
rc4HmacInitialize: The expected address of csystem Initialization function
|
||||
rc4HmacDecrypt: The expected address of the csystem Decryption function
|
||||
"""
|
||||
try:
|
||||
cryptdll_symbols = pdbutil.PDBUtility.symbol_table_from_pdb(self.context,
|
||||
interfaces.configuration.path_join(self.config_path, 'cryptdll'),
|
||||
proc_layer_name,
|
||||
"cryptdll.pdb",
|
||||
cryptdll_base,
|
||||
cryptdll_size)
|
||||
cryptdll_symbols = pdbutil.PDBUtility.symbol_table_from_pdb(self.context,
|
||||
interfaces.configuration.path_join(
|
||||
self.config_path, 'cryptdll'),
|
||||
proc_layer_name,
|
||||
"cryptdll.pdb",
|
||||
cryptdll_base,
|
||||
cryptdll_size)
|
||||
except exceptions.VolatilityException:
|
||||
vollog.debug("Unable to use the cryptdll PDB. Stopping PDB symbols based analysis.")
|
||||
return None, None, None
|
||||
|
||||
array, rc4HmacInitialize, rc4HmacDecrypt = \
|
||||
self._find_array_with_pdb_symbols(cryptdll_symbols, cryptdll_types, proc_layer_name, cryptdll_base)
|
||||
|
||||
self._find_array_with_pdb_symbols(cryptdll_symbols, cryptdll_types, proc_layer_name, cryptdll_base)
|
||||
|
||||
if array is None:
|
||||
vollog.debug("The CSystem array is not present in memory. Stopping PDB symbols based analysis.")
|
||||
|
||||
@@ -313,7 +313,7 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
|
||||
These instructions contain the offset of a target address
|
||||
relative to the current instruction pointer.
|
||||
|
||||
|
||||
Args:
|
||||
inst: A capstone instruction instance
|
||||
|
||||
@@ -322,7 +322,7 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
"""
|
||||
try:
|
||||
opnd = inst.operands[1]
|
||||
except capstone.CsError:
|
||||
except capstone.CsError:
|
||||
return None
|
||||
|
||||
if opnd.type != capstone.x86.X86_OP_MEM:
|
||||
@@ -334,9 +334,9 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
return inst.address + inst.size + opnd.mem.disp
|
||||
|
||||
def _analyze_cdlocatecsystem(self, function_bytes: bytes,
|
||||
function_start: int,
|
||||
cryptdll_types: interfaces.context.ModuleInterface,
|
||||
proc_layer_name: str) -> Optional[interfaces.objects.ObjectInterface]:
|
||||
function_start: int,
|
||||
cryptdll_types: interfaces.context.ModuleInterface,
|
||||
proc_layer_name: str) -> Optional[interfaces.objects.ObjectInterface]:
|
||||
"""
|
||||
Performs static analysis on CDLocateCSystem to find the instructions that
|
||||
reference CSystems as well as cCsystems
|
||||
@@ -380,7 +380,7 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
target_address = self._get_rip_relative_target(inst)
|
||||
|
||||
if target_address:
|
||||
array_start = target_address
|
||||
array_start = target_address
|
||||
|
||||
# we find the count before, so we can terminate the static analysis here
|
||||
break
|
||||
@@ -392,10 +392,10 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
|
||||
return array
|
||||
|
||||
def _find_csystems_with_export(self, proc_layer_name: str,
|
||||
cryptdll_types: interfaces.context.ModuleInterface,
|
||||
cryptdll_base: int,
|
||||
_) -> Optional[interfaces.objects.ObjectInterface]:
|
||||
def _find_csystems_with_export(self, proc_layer_name: str,
|
||||
cryptdll_types: interfaces.context.ModuleInterface,
|
||||
cryptdll_base: int,
|
||||
_) -> Optional[interfaces.objects.ObjectInterface]:
|
||||
"""
|
||||
Uses export table analysis to locate CDLocateCsystem
|
||||
This function references CSystems and cCsystems
|
||||
@@ -420,8 +420,7 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
"windows",
|
||||
"pe",
|
||||
class_types = pe.class_types)
|
||||
|
||||
|
||||
|
||||
cryptdll = self._get_pefile_obj(pe_table_name, proc_layer_name, cryptdll_base)
|
||||
if not cryptdll:
|
||||
return None
|
||||
@@ -440,7 +439,8 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
try:
|
||||
function_bytes = self.context.layers[proc_layer_name].read(function_start, 0x50)
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.debug("The CDLocateCSystem function is not present in the lsass address space. Stopping export based analysis.")
|
||||
vollog.debug(
|
||||
"The CDLocateCSystem function is not present in the lsass address space. Stopping export based analysis.")
|
||||
break
|
||||
|
||||
array = self._analyze_cdlocatecsystem(function_bytes, function_start, cryptdll_types, proc_layer_name)
|
||||
@@ -451,15 +451,15 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
|
||||
return None
|
||||
|
||||
def _find_csystems_with_scanning(self, proc_layer_name: str,
|
||||
cryptdll_types: interfaces.context.ModuleInterface,
|
||||
cryptdll_base: int,
|
||||
cryptdll_size: int) -> List[interfaces.context.ModuleInterface]:
|
||||
def _find_csystems_with_scanning(self, proc_layer_name: str,
|
||||
cryptdll_types: interfaces.context.ModuleInterface,
|
||||
cryptdll_base: int,
|
||||
cryptdll_size: int) -> List[interfaces.context.ModuleInterface]:
|
||||
"""
|
||||
Performs scanning to find potential RC4 HMAC csystem instances
|
||||
|
||||
This function may return several values as it cannot validate which is the active one
|
||||
|
||||
|
||||
Args:
|
||||
proc_layer_name: the lsass.exe process layer name
|
||||
cryptdll_types: the types from cryptdll binary analysis
|
||||
@@ -468,22 +468,22 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
Returns:
|
||||
A list of csystem instances
|
||||
"""
|
||||
|
||||
|
||||
csystems = []
|
||||
|
||||
|
||||
cryptdll_end = cryptdll_base + cryptdll_size
|
||||
|
||||
proc_layer = self.context.layers[proc_layer_name]
|
||||
|
||||
|
||||
ecrypt_size = cryptdll_types.get_type("_KERB_ECRYPT").size
|
||||
|
||||
# scan for potential instances of RC4 HMAC
|
||||
# the signature is based on the type being 0x17
|
||||
# and the block size member being 1 in all test samples
|
||||
# and the block size member being 1 in all test samples
|
||||
for address in proc_layer.scan(self.context,
|
||||
scanners.BytesScanner(b"\x17\x00\x00\x00\x01\x00\x00\x00"),
|
||||
sections = [(cryptdll_base, cryptdll_size)]):
|
||||
|
||||
|
||||
# this occurs across page boundaries
|
||||
if not proc_layer.is_valid(address, ecrypt_size):
|
||||
continue
|
||||
@@ -491,11 +491,11 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
kerb = cryptdll_types.object("_KERB_ECRYPT",
|
||||
offset = address,
|
||||
absolute = True)
|
||||
|
||||
|
||||
# ensure the Encrypt and Finish pointers are inside the VAD
|
||||
# these are not manipulated in the attack
|
||||
# these are not manipulated in the attack
|
||||
if (cryptdll_base < kerb.Encrypt < cryptdll_end) and \
|
||||
(cryptdll_base < kerb.Finish < cryptdll_end):
|
||||
(cryptdll_base < kerb.Finish < cryptdll_end):
|
||||
csystems.append(kerb)
|
||||
|
||||
return csystems
|
||||
@@ -509,35 +509,36 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
Args:
|
||||
procs: the process list filtered to lsass.exe instances
|
||||
"""
|
||||
|
||||
if not symbols.symbol_table_is_64bit(self.context, self.config["nt_symbols"]):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
if not symbols.symbol_table_is_64bit(self.context, kernel.symbol_table_name):
|
||||
vollog.info("This plugin only supports 64bit Windows memory samples")
|
||||
return
|
||||
|
||||
lsass_proc, proc_layer_name = self._find_lsass_proc(procs)
|
||||
if not lsass_proc:
|
||||
vollog.info("Unable to find a valid lsass.exe process in the process list. This should never happen. Analysis cannot proceed.")
|
||||
vollog.info(
|
||||
"Unable to find a valid lsass.exe process in the process list. This should never happen. Analysis cannot proceed.")
|
||||
return
|
||||
|
||||
cryptdll_base, cryptdll_size = self._find_cryptdll(lsass_proc)
|
||||
if not cryptdll_base:
|
||||
vollog.info("Unable to find the location of cryptdll.dll inside of lsass.exe. Analysis cannot proceed.")
|
||||
return
|
||||
|
||||
|
||||
# the custom type information from binary analysis
|
||||
cryptdll_types = self._get_cryptdll_types(self.context,
|
||||
self.config,
|
||||
cryptdll_types = self._get_cryptdll_types(self.context,
|
||||
self.config,
|
||||
self.config_path,
|
||||
proc_layer_name,
|
||||
cryptdll_base)
|
||||
|
||||
|
||||
# attempt to find the array and symbols directly from the PDB
|
||||
csystems, rc4HmacInitialize, rc4HmacDecrypt = \
|
||||
self._find_csystems_with_symbols(proc_layer_name,
|
||||
cryptdll_types,
|
||||
cryptdll_base,
|
||||
cryptdll_size)
|
||||
self._find_csystems_with_symbols(proc_layer_name,
|
||||
cryptdll_types,
|
||||
cryptdll_base,
|
||||
cryptdll_size)
|
||||
|
||||
csystems = None
|
||||
|
||||
@@ -550,7 +551,7 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
self._find_csystems_with_scanning]
|
||||
|
||||
for source in fallback_sources:
|
||||
csystems = source(proc_layer_name,
|
||||
csystems = source(proc_layer_name,
|
||||
cryptdll_types,
|
||||
cryptdll_base,
|
||||
cryptdll_size)
|
||||
@@ -587,13 +588,17 @@ class Skeleton_Key_Check(interfaces.plugins.PluginInterface):
|
||||
named processes to blend in or uses lsass.exe as a process hollowing target
|
||||
"""
|
||||
process_name = utility.array_to_string(proc.ImageFileName)
|
||||
|
||||
|
||||
return process_name != "lsass.exe"
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid([("PID", int), ("Process", str), ("Skeleton Key Found", bool), ("rc4HmacInitialize", format_hints.Hex), ("rc4HmacDecrypt", format_hints.Hex)],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
filter_func = self._lsass_proc_filter)))
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
return renderers.TreeGrid(
|
||||
[("PID", int), ("Process", str), ("Skeleton Key Found", bool), ("rc4HmacInitialize", format_hints.Hex),
|
||||
("rc4HmacDecrypt", format_hints.Hex)],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_func = self._lsass_proc_filter)))
|
||||
|
||||
@@ -18,16 +18,14 @@ from volatility3.plugins.windows import modules
|
||||
class SSDT(plugins.PluginInterface):
|
||||
"""Lists the system call table."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'modules', plugin = modules.Modules, version = (1, 0, 0)),
|
||||
]
|
||||
|
||||
@@ -75,11 +73,13 @@ class SSDT(plugins.PluginInterface):
|
||||
|
||||
def _generator(self) -> Iterator[Tuple[int, Tuple[int, int, Any, Any]]]:
|
||||
|
||||
layer_name = self.config['primary']
|
||||
collection = self.build_module_collection(self.context, self.config["primary"], self.config["nt_symbols"])
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
layer_name = kernel.layer_name
|
||||
collection = self.build_module_collection(self.context, layer_name, kernel.symbol_table_name)
|
||||
|
||||
kvo = self.context.layers[layer_name].config['kernel_virtual_offset']
|
||||
ntkrnlmp = self.context.module(self.config["nt_symbols"], layer_name = layer_name, offset = kvo)
|
||||
ntkrnlmp = self.context.module(kernel.symbol_table_name, layer_name = layer_name, offset = kvo)
|
||||
|
||||
# this is just one way to enumerate the native (NT) service table.
|
||||
# to do the same thing for the Win32K service table, we would need Win32K.sys symbol support
|
||||
@@ -91,7 +91,7 @@ class SSDT(plugins.PluginInterface):
|
||||
# on 32-bit systems the table indexes are 32-bits and contain pointers (unsigned)
|
||||
# on 64-bit systems the indexes are also 32-bits but they're offsets from the
|
||||
# base address of the table and can be negative, so we need a signed data type
|
||||
is_kernel_64 = symbols.symbol_table_is_64bit(self.context, self.config["nt_symbols"])
|
||||
is_kernel_64 = symbols.symbol_table_is_64bit(self.context, kernel.symbol_table_name)
|
||||
if is_kernel_64:
|
||||
array_subtype = "long"
|
||||
|
||||
|
||||
@@ -18,18 +18,16 @@ vollog = logging.getLogger(__name__)
|
||||
class Strings(interfaces.plugins.PluginInterface):
|
||||
"""Reads output from the strings command and indicates which process(es) each string belongs to."""
|
||||
|
||||
_version = (1, 0, 0)
|
||||
_version = (1, 2, 0)
|
||||
_required_framework_version = (1, 0, 0)
|
||||
strings_pattern = re.compile(rb"^(?:\W*)([0-9]+)(?:\W*)(\w[\w\W]+)\n?")
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0)),
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ListRequirement(name = 'pid',
|
||||
element_type = int,
|
||||
description = "Process ID to include (all other processes are excluded)",
|
||||
@@ -44,7 +42,7 @@ class Strings(interfaces.plugins.PluginInterface):
|
||||
|
||||
def _generator(self) -> Generator[Tuple, None, None]:
|
||||
"""Generates results from a strings file."""
|
||||
string_list: List[Tuple[int,bytes]] = []
|
||||
string_list: List[Tuple[int, bytes]] = []
|
||||
|
||||
# Test strings file format is accurate
|
||||
accessor = resources.ResourceAccessor()
|
||||
@@ -60,14 +58,16 @@ class Strings(interfaces.plugins.PluginInterface):
|
||||
vollog.error(f"Line in unrecognized format: line {count}")
|
||||
line = strings_fp.readline()
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
revmap = self.generate_mapping(self.context,
|
||||
self.config['primary'],
|
||||
self.config['nt_symbols'],
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
progress_callback = self._progress_callback,
|
||||
pid_list = self.config['pid'])
|
||||
|
||||
last_prog: float = 0
|
||||
line_count: float = 0
|
||||
line_count: float = 0
|
||||
num_strings = len(string_list)
|
||||
for offset, string in string_list:
|
||||
line_count += 1
|
||||
|
||||
@@ -21,17 +21,15 @@ vollog = logging.getLogger(__name__)
|
||||
class SvcScan(interfaces.plugins.PluginInterface):
|
||||
"""Scans for windows services."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0)),
|
||||
requirements.PluginRequirement(name = 'poolscanner', plugin = poolscanner.PoolScanner, version = (1, 0, 0)),
|
||||
requirements.PluginRequirement(name = 'vadyarascan', plugin = vadyarascan.VadYaraScan, version = (1, 0, 0))
|
||||
@@ -94,15 +92,18 @@ class SvcScan(interfaces.plugins.PluginInterface):
|
||||
native_types = native_types)
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
service_table_name = self.create_service_table(self.context, self.config["nt_symbols"], self.config_path)
|
||||
service_table_name = self.create_service_table(self.context, kernel.symbol_table_name,
|
||||
self.config_path)
|
||||
|
||||
relative_tag_offset = self.context.symbol_space.get_type(service_table_name + constants.BANG +
|
||||
"_SERVICE_RECORD").relative_child_offset("Tag")
|
||||
|
||||
filter_func = pslist.PsList.create_name_filter(["services.exe"])
|
||||
|
||||
is_vista_or_later = versions.is_vista_or_later(context = self.context, symbol_table = self.config["nt_symbols"])
|
||||
is_vista_or_later = versions.is_vista_or_later(context = self.context,
|
||||
symbol_table = kernel.symbol_table_name)
|
||||
|
||||
if is_vista_or_later:
|
||||
service_tag = b"serH"
|
||||
@@ -112,8 +113,8 @@ class SvcScan(interfaces.plugins.PluginInterface):
|
||||
seen = []
|
||||
|
||||
for task in pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_func = filter_func):
|
||||
|
||||
proc_id = "Unknown"
|
||||
|
||||
@@ -15,15 +15,13 @@ from volatility3.plugins.windows import poolscanner
|
||||
class SymlinkScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Scans for links present in a particular windows memory image."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
@@ -51,7 +49,9 @@ class SymlinkScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterfa
|
||||
yield mem_object
|
||||
|
||||
def _generator(self):
|
||||
for link in self.scan_symlinks(self.context, self.config['primary'], self.config['nt_symbols']):
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
for link in self.scan_symlinks(self.context, kernel.layer_name, kernel.symbol_table_name):
|
||||
|
||||
try:
|
||||
from_name = link.get_link_name()
|
||||
|
||||
@@ -33,7 +33,7 @@ winnt_protections = {
|
||||
class VadInfo(interfaces.plugins.PluginInterface):
|
||||
"""Lists process memory ranges."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (2, 0, 0)
|
||||
MAXSIZE_DEFAULT = 0
|
||||
|
||||
@@ -44,10 +44,8 @@ class VadInfo(interfaces.plugins.PluginInterface):
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
return [requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
# TODO: Convert this to a ListRequirement so that people can filter on sets of ranges
|
||||
requirements.IntRequirement(name = 'address',
|
||||
description = "Process virtual memory address to include " \
|
||||
@@ -169,6 +167,8 @@ class VadInfo(interfaces.plugins.PluginInterface):
|
||||
|
||||
def _generator(self, procs):
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
def passthrough(_: interfaces.objects.ObjectInterface) -> bool:
|
||||
return False
|
||||
|
||||
@@ -196,12 +196,14 @@ class VadInfo(interfaces.plugins.PluginInterface):
|
||||
yield (0, (proc.UniqueProcessId, process_name, format_hints.Hex(vad.vol.offset),
|
||||
format_hints.Hex(vad.get_start()), format_hints.Hex(vad.get_end()), vad.get_tag(),
|
||||
vad.get_protection(
|
||||
self.protect_values(self.context, self.config['primary'], self.config['nt_symbols']),
|
||||
self.protect_values(self.context, kernel.layer_name, kernel.symbol_table_name),
|
||||
winnt_protections), vad.get_commit_charge(), vad.get_private_memory(),
|
||||
format_hints.Hex(vad.get_parent()), vad.get_file_name(), file_output))
|
||||
|
||||
def run(self):
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
|
||||
|
||||
return renderers.TreeGrid([("PID", int), ("Process", str), ("Offset", format_hints.Hex),
|
||||
@@ -210,6 +212,6 @@ class VadInfo(interfaces.plugins.PluginInterface):
|
||||
("Parent", format_hints.Hex), ("File", str), ("File output", str)],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_func = filter_func)))
|
||||
|
||||
@@ -17,16 +17,14 @@ vollog = logging.getLogger(__name__)
|
||||
class VadYaraScan(interfaces.plugins.PluginInterface):
|
||||
"""Scans all the Virtual Address Descriptor memory maps using yara."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = "Memory layer for the kernel",
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.BooleanRequirement(name = "wide",
|
||||
description = "Match wide (unicode) strings",
|
||||
default = False,
|
||||
@@ -55,13 +53,15 @@ class VadYaraScan(interfaces.plugins.PluginInterface):
|
||||
|
||||
def _generator(self):
|
||||
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
rules = yarascan.YaraScan.process_yara_options(dict(self.config))
|
||||
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
|
||||
|
||||
for task in pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
layer_name = kernel.layer_name,
|
||||
symbol_table = kernel.symbol_table_name,
|
||||
filter_func = filter_func):
|
||||
layer_name = task.add_process_layer()
|
||||
layer = self.context.layers[layer_name]
|
||||
|
||||
@@ -27,21 +27,19 @@ except ImportError:
|
||||
class VerInfo(interfaces.plugins.PluginInterface):
|
||||
"""Lists version information from PE files."""
|
||||
|
||||
_required_framework_version = (1, 2, 0)
|
||||
_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
## TODO: we might add a regex option on the name later, but otherwise we're good
|
||||
## TODO: and we don't want any CLI options from pslist, modules, or moddump
|
||||
return [
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0)),
|
||||
requirements.PluginRequirement(name = 'modules', plugin = modules.Modules, version = (1, 0, 0)),
|
||||
requirements.VersionRequirement(name = 'dlllist', component = dlllist.DllList, version = (2, 0, 0)),
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.BooleanRequirement(name = "extensive",
|
||||
description = "Search physical layer for version information",
|
||||
optional = True,
|
||||
@@ -123,6 +121,7 @@ class VerInfo(interfaces.plugins.PluginInterface):
|
||||
mods: <generator> of modules
|
||||
session_layers: <generator> of layers in the session to be checked
|
||||
"""
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
pe_table_name = intermed.IntermediateSymbolTable.create(self.context,
|
||||
self.config_path,
|
||||
@@ -131,7 +130,7 @@ class VerInfo(interfaces.plugins.PluginInterface):
|
||||
class_types = pe.class_types)
|
||||
|
||||
# TODO: Fix this so it works with more than just intel layers
|
||||
physical_layer_name = self.context.layers[self.config['primary']].config.get('memory_layer', None)
|
||||
physical_layer_name = self.context.layers[kernel.layer_name].config.get('memory_layer', None)
|
||||
|
||||
for mod in mods:
|
||||
try:
|
||||
@@ -191,13 +190,14 @@ class VerInfo(interfaces.plugins.PluginInterface):
|
||||
build))
|
||||
|
||||
def run(self):
|
||||
procs = pslist.PsList.list_processes(self.context, self.config["primary"], self.config["nt_symbols"])
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
mods = modules.Modules.list_modules(self.context, self.config["primary"], self.config["nt_symbols"])
|
||||
procs = pslist.PsList.list_processes(self.context, kernel.layer_name, kernel.symbol_table_name)
|
||||
|
||||
mods = modules.Modules.list_modules(self.context, kernel.layer_name, kernel.symbol_table_name)
|
||||
|
||||
# populate the session layers for kernel modules
|
||||
session_layers = modules.Modules.get_session_layers(self.context, self.config['primary'],
|
||||
self.config['nt_symbols'])
|
||||
session_layers = modules.Modules.get_session_layers(self.context, kernel.layer_name, kernel.symbol_table_name)
|
||||
|
||||
return renderers.TreeGrid([("PID", int), ("Process", str), ("Base", format_hints.Hex), ("Name", str),
|
||||
("Major", int), ("Minor", int), ("Product", int), ("Build", int)],
|
||||
|
||||
@@ -16,16 +16,14 @@ vollog = logging.getLogger(__name__)
|
||||
class VirtMap(interfaces.plugins.PluginInterface):
|
||||
"""Lists virtual mapped sections."""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_required_framework_version = (1, 2, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
return [
|
||||
requirements.TranslationLayerRequirement(name = 'primary',
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols")
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"])
|
||||
]
|
||||
|
||||
def _generator(self, map):
|
||||
@@ -112,8 +110,10 @@ class VirtMap(interfaces.plugins.PluginInterface):
|
||||
yield value
|
||||
|
||||
def run(self):
|
||||
layer = self.context.layers[self.config['primary']]
|
||||
module = self.context.module(self.config['nt_symbols'],
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
|
||||
layer = self.context.layers[kernel.layer_name]
|
||||
module = self.context.module(kernel.symbol_table_name,
|
||||
layer_name = layer.name,
|
||||
offset = layer.config['kernel_virtual_offset'])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user