From 9c4bd556f67db4ee3113751889db054fc6cda27b Mon Sep 17 00:00:00 2001 From: Analyst Date: Thu, 7 Mar 2019 09:00:19 -0600 Subject: [PATCH] add the symlinkscan plugin --- .../framework/plugins/windows/poolscanner.py | 14 ++++ .../framework/plugins/windows/symlinkscan.py | 83 +++++++++++++++++++ .../framework/symbols/windows/__init__.py | 1 + .../symbols/windows/extensions/__init__.py | 15 ++++ 4 files changed, 113 insertions(+) create mode 100644 volatility/framework/plugins/windows/symlinkscan.py diff --git a/volatility/framework/plugins/windows/poolscanner.py b/volatility/framework/plugins/windows/poolscanner.py index fa55743c5..8f32c6532 100644 --- a/volatility/framework/plugins/windows/poolscanner.py +++ b/volatility/framework/plugins/windows/poolscanner.py @@ -238,6 +238,20 @@ class PoolScanner(plugins.PluginInterface): type_name = symbol_table + constants.BANG + "_LDR_DATA_TABLE_ENTRY", size = (76, None), page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), + # symlinks on windows before windows 8 + PoolConstraint( + b'Sym\xe2', + type_name = symbol_table + constants.BANG + "_OBJECT_SYMBOLIC_LINK", + object_type = "SymbolicLink", + size = (72, None), + page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), + # symlinks on windows starting with windows 8 + PoolConstraint( + b'Symb', + type_name = symbol_table + constants.BANG + "_OBJECT_SYMBOLIC_LINK", + object_type = "SymbolicLink", + size = (72, None), + page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), ] if not tags_filter: diff --git a/volatility/framework/plugins/windows/symlinkscan.py b/volatility/framework/plugins/windows/symlinkscan.py new file mode 100644 index 000000000..979f099eb --- /dev/null +++ b/volatility/framework/plugins/windows/symlinkscan.py @@ -0,0 +1,83 @@ +# This file was contributed to the Volatility Framework Version 3. +# Copyright (C) 2018 Volatility Foundation. +# +# THE LICENSED WORK IS PROVIDED UNDER THE TERMS OF THE Volatility Contributors +# Public License V1.0("LICENSE") AS FIRST COMPLETED BY: Volatility Foundation, +# Inc. ANY USE, PUBLIC DISPLAY, PUBLIC PERFORMANCE, REPRODUCTION OR DISTRIBUTION +# OF, OR PREPARATION OF SUBSEQUENT WORKS, DERIVATIVE WORKS OR DERIVED WORKS BASED +# ON, THE LICENSED WORK CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS LICENSE AND ITS +# TERMS, WHETHER OR NOT SUCH RECIPIENT READS THE TERMS OF THE LICENSE. "LICENSED +# WORK,” “RECIPIENT" AND “DISTRIBUTOR" ARE DEFINED IN THE LICENSE. A COPY OF THE +# LICENSE IS LOCATED IN THE TEXT FILE ENTITLED "LICENSE.txt" ACCOMPANYING THE +# CONTENTS OF THIS FILE. IF A COPY OF THE LICENSE DOES NOT ACCOMPANY THIS FILE, A +# COPY OF THE LICENSE MAY ALSO BE OBTAINED AT THE FOLLOWING WEB SITE: +# https://www.volatilityfoundation.org/license/vcpl_v1.0 +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the +# specific language governing rights and limitations under the License. +# + +from typing import Iterable +import datetime +import volatility.framework.interfaces.plugins as plugins +from volatility.framework import renderers, interfaces, exceptions +from volatility.framework.configuration import requirements +from volatility.framework.renderers import format_hints +import volatility.plugins.windows.poolscanner as poolscanner +from volatility.plugins import timeliner + +class SymlinkScan(plugins.PluginInterface, timeliner.TimeLinerInterface): + """Scans for links present in a particular windows memory image""" + + @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"), + ] + + @classmethod + def scan_symlinks(cls, + context: interfaces.context.ContextInterface, + layer_name: str, + symbol_table: str) -> \ + Iterable[interfaces.objects.ObjectInterface]: + """Scans for links using the poolscanner module and constraints""" + + constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'Sym\xe2', b'Symb']) + + for result in poolscanner.PoolScanner.generate_pool_scan(context, layer_name, symbol_table, constraints): + + _constraint, mem_object, _header = result + yield mem_object + + def _generator(self): + for link in self.scan_symlinks(self.context, self.config['primary'], self.config['nt_symbols']): + + try: + from_name = link.get_link_name() + except exceptions.InvalidAddressException: + continue + + try: + to_name = link.LinkTarget.String + except exceptions.InvalidAddressException: + continue + + yield (0, (format_hints.Hex(link.vol.offset), link.get_create_time(), from_name, to_name)) + + def generate_timeline(self): + for row in self._generator(): + _depth, row_data = row + description = "Symlink: {} -> {}".format(row_data[2], row_data[3]) + yield (description, timeliner.TimeLinerType.CREATED, row_data[1]) + + def run(self): + return renderers.TreeGrid([ + ("Offset", format_hints.Hex), + ("CreateTime", datetime.datetime), + ("From Name", str), + ("To Name", str), + ], self._generator()) diff --git a/volatility/framework/symbols/windows/__init__.py b/volatility/framework/symbols/windows/__init__.py index 6b5fd312b..28cc33869 100644 --- a/volatility/framework/symbols/windows/__init__.py +++ b/volatility/framework/symbols/windows/__init__.py @@ -48,6 +48,7 @@ class WindowsKernelIntermedSymbols(intermed.IntermediateSymbolTable): self.set_type_class('_KSYSTEM_TIME', extensions._KSYSTEM_TIME) self.set_type_class('_KMUTANT', extensions._KMUTANT) self.set_type_class('_DRIVER_OBJECT', extensions._DRIVER_OBJECT) + self.set_type_class('_OBJECT_SYMBOLIC_LINK', extensions._OBJECT_SYMBOLIC_LINK) # This doesn't exist in very specific versions of windows try: diff --git a/volatility/framework/symbols/windows/extensions/__init__.py b/volatility/framework/symbols/windows/extensions/__init__.py index 03ed7d0a6..539a85585 100644 --- a/volatility/framework/symbols/windows/extensions/__init__.py +++ b/volatility/framework/symbols/windows/extensions/__init__.py @@ -449,6 +449,21 @@ class _DRIVER_OBJECT(objects.Struct, ExecutiveObject): return True +class _OBJECT_SYMBOLIC_LINK(objects.Struct, ExecutiveObject): + """A class for kernel link objects.""" + + def get_link_name(self) -> str: + header = self.object_header() + return header.NameInfo.Name.String # type: ignore + + def is_valid(self) -> bool: + """Determine if the object is valid""" + return True + + def get_create_time(self): + return conversion.wintime_to_datetime(self.CreationTime.QuadPart) + + class _FILE_OBJECT(objects.Struct, ExecutiveObject): """A class for windows file objects"""