mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-09 11:17:38 +02:00
Added dlllist and netscan to timline
This commit is contained in:
@@ -3,19 +3,21 @@
|
||||
#
|
||||
import logging
|
||||
import ntpath
|
||||
import datetime
|
||||
from typing import List
|
||||
|
||||
from volatility.framework import exceptions, renderers, interfaces, constants
|
||||
from volatility.framework.configuration import requirements
|
||||
from volatility.framework.renderers import format_hints
|
||||
from volatility.framework.renderers import format_hints, conversion
|
||||
from volatility.framework.symbols import intermed
|
||||
from volatility.framework.symbols.windows.extensions import pe
|
||||
from volatility.plugins.windows import pslist
|
||||
from volatility.plugins import timeliner
|
||||
from volatility.plugins.windows import pslist, info
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DllList(interfaces.plugins.PluginInterface):
|
||||
class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Lists the loaded modules in a particular windows memory image."""
|
||||
|
||||
_version = (1, 0, 0)
|
||||
@@ -28,7 +30,8 @@ class DllList(interfaces.plugins.PluginInterface):
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (1, 0, 0)),
|
||||
requirements.VersionRequirement(name = 'pslist', component = pslist.PsList, version = (1, 0, 0)),
|
||||
requirements.VersionRequirement(name = 'info', component = info.Info, version = (1, 0, 0)),
|
||||
requirements.ListRequirement(name = 'pid',
|
||||
element_type = int,
|
||||
description = "Process IDs to include (all other processes are excluded)",
|
||||
@@ -86,6 +89,12 @@ class DllList(interfaces.plugins.PluginInterface):
|
||||
"pe",
|
||||
class_types = pe.class_types)
|
||||
|
||||
kuser = info.Info.get_kuser_structure(self.context, self.config['primary'], self.config['nt_symbols'])
|
||||
nt_major_version = int(kuser.NtMajorVersion)
|
||||
nt_minor_version = int(kuser.NtMinorVersion)
|
||||
# this only applies to versions higher or equal to Window 7 (6.1 and higher)
|
||||
dll_load_time_field = (nt_major_version > 6) or (nt_major_version == 6 and nt_minor_version >= 1)
|
||||
time_delta_1600 = datetime.timedelta(days=(1970 - 1601) * 365 + 89)
|
||||
for proc in procs:
|
||||
|
||||
proc_id = proc.UniqueProcessId
|
||||
@@ -93,7 +102,7 @@ class DllList(interfaces.plugins.PluginInterface):
|
||||
|
||||
for entry in proc.load_order_modules():
|
||||
|
||||
BaseDllName = FullDllName = renderers.UnreadableValue()
|
||||
BaseDllName = FullDllName = DllLoadTime = renderers.UnreadableValue()
|
||||
try:
|
||||
BaseDllName = entry.BaseDllName.get_string()
|
||||
# We assume that if the BaseDllName points to an invalid buffer, so will FullDllName
|
||||
@@ -101,8 +110,14 @@ class DllList(interfaces.plugins.PluginInterface):
|
||||
except exceptions.InvalidAddressException:
|
||||
pass
|
||||
|
||||
if dll_load_time_field:
|
||||
try:
|
||||
DllLoadTime = conversion.wintime_to_datetime(entry.LoadTime.QuadPart)
|
||||
except:
|
||||
pass
|
||||
|
||||
dumped = False
|
||||
if self.config['dump']:
|
||||
if self.config.get('dump'):
|
||||
filedata = self.dump_pe(self.context, pe_table_name, entry, proc_layer_name)
|
||||
if filedata:
|
||||
filedata.preferred_filename = "pid.{0}.".format(proc_id) + filedata.preferred_filename
|
||||
@@ -113,13 +128,27 @@ class DllList(interfaces.plugins.PluginInterface):
|
||||
proc.ImageFileName.cast("string",
|
||||
max_length = proc.ImageFileName.vol.count,
|
||||
errors = 'replace'), format_hints.Hex(entry.DllBase),
|
||||
format_hints.Hex(entry.SizeOfImage), BaseDllName, FullDllName, dumped))
|
||||
format_hints.Hex(entry.SizeOfImage), BaseDllName, FullDllName, DllLoadTime, dumped))
|
||||
|
||||
def generate_timeline(self):
|
||||
for row in self._generator(pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
symbol_table = self.config['nt_symbols'],
|
||||
filter_func = pslist.PsList.create_pid_filter(None))):
|
||||
_depth, row_data = row
|
||||
if not isinstance(row_data[6], datetime.datetime):
|
||||
continue
|
||||
description = "DLL Load: Process {} {} Loaded {} ({}) Size {} Offset {}".format(row_data[0], row_data[1],
|
||||
row_data[4], row_data[5],
|
||||
row_data[3], row_data[2])
|
||||
yield (description, timeliner.TimeLinerType.CREATED, row_data[6])
|
||||
|
||||
def run(self):
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
|
||||
|
||||
return renderers.TreeGrid([("PID", int), ("Process", str), ("Base", format_hints.Hex),
|
||||
("Size", format_hints.Hex), ("Name", str), ("Path", str), ("Dumped", bool)],
|
||||
("Size", format_hints.Hex), ("Name", str), ("Path", str),
|
||||
("LoadTime", datetime.datetime), ("Dumped", bool)],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(context = self.context,
|
||||
layer_name = self.config['primary'],
|
||||
|
||||
@@ -55,10 +55,11 @@ class FileScan(interfaces.plugins.PluginInterface):
|
||||
except exceptions.InvalidAddressException:
|
||||
continue
|
||||
|
||||
yield (0, (format_hints.Hex(fileobj.vol.offset), file_name))
|
||||
yield (0, (format_hints.Hex(fileobj.vol.offset), file_name, fileobj.Size))
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid([
|
||||
("Offset", format_hints.Hex),
|
||||
("Name", str),
|
||||
("Size", int)
|
||||
], self._generator())
|
||||
|
||||
@@ -16,7 +16,7 @@ from volatility.plugins.windows import info, poolscanner
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
class NetScan(interfaces.plugins.PluginInterface):
|
||||
class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Scans for network objects present in a particular windows memory image."""
|
||||
|
||||
_version = (1, 0, 0)
|
||||
@@ -28,8 +28,8 @@ class NetScan(interfaces.plugins.PluginInterface):
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.PluginRequirement(name = 'poolscanner', plugin = poolscanner.PoolScanner, version = (1, 0, 0)),
|
||||
requirements.PluginRequirement(name = 'info', plugin = info.Info, version= (1, 0, 0)),
|
||||
requirements.VersionRequirement(name='poolscanner', component=poolscanner.PoolScanner, version=(1, 0, 0)),
|
||||
requirements.VersionRequirement(name='info', component=info.Info, version=(1, 0, 0)),
|
||||
requirements.BooleanRequirement(name = 'include-corrupt',
|
||||
description = "Radically eases result validation. This will show partially overwritten data. WARNING: the results are likely to include garbage and/or corrupt data. Be cautious!",
|
||||
default = False,
|
||||
@@ -332,6 +332,21 @@ class NetScan(interfaces.plugins.PluginInterface):
|
||||
# this should not happen therefore we log it.
|
||||
vollog.debug("Found network object unsure of its type: {} of type {}".format(netw_obj, type(netw_obj)))
|
||||
|
||||
def generate_timeline(self):
|
||||
for row in self._generator():
|
||||
_depth, row_data = row
|
||||
# Skip network connections without creation time
|
||||
if not isinstance(row_data[9], datetime.datetime):
|
||||
continue
|
||||
row_data = ["N/A" if isinstance(i, renderers.UnreadableValue) or isinstance(i, renderers.UnparsableValue)
|
||||
else i for i in row_data]
|
||||
description = "Network connection: Process {} {} Local Address {}:{} " \
|
||||
"Remote Address {}:{} State {} Protocol {} ".format(row_data[7], row_data[8],
|
||||
row_data[2], row_data[3],
|
||||
row_data[4], row_data[5],
|
||||
row_data[6], row_data[1])
|
||||
yield (description, timeliner.TimeLinerType.CREATED, row_data[9])
|
||||
|
||||
def run(self):
|
||||
show_corrupt_results = self.config.get('include-corrupt', None)
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
def generate_timeline(self):
|
||||
for row in self._generator():
|
||||
_depth, row_data = row
|
||||
description = "Process: {} ({})".format(row_data[2], row_data[3])
|
||||
description = "Process: {} {} ({})".format(row_data[0], row_data[2], row_data[3])
|
||||
yield (description, timeliner.TimeLinerType.CREATED, row_data[8])
|
||||
yield (description, timeliner.TimeLinerType.MODIFIED, row_data[9])
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
def generate_timeline(self):
|
||||
for row in self._generator():
|
||||
_depth, row_data = row
|
||||
description = "Process: {} ({})".format(row_data[2], row_data[3])
|
||||
description = "Process: {} {} ({})".format(row_data[0], row_data[2], row_data[3])
|
||||
yield (description, timeliner.TimeLinerType.CREATED, row_data[8])
|
||||
yield (description, timeliner.TimeLinerType.MODIFIED, row_data[9])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user