Windows: Add regex filtering to dumpfiles

In volatility2, the windows.dumpfiles plugin allows you to filter the dumped files
using a regular expression. This PR adds the same functionality to volatility3.

The regular expression is passed in using --regex=REGEX and all files matching
REGEX will be dumped. The --ignore-case flag can be passed to make the search
case-insensitive. The search is case-sensitive by default. The matching
volatility2 functionality can be found here:
https://github.com/volatilityfoundation/volatility/blob/a438e768194a9e05eb4d9ee
9338b881c0fa25937/volatility/plugins/dumpfiles.py#L844

Manual testing was performed on windows memory images across different windows
versions to verify the expected output.
This commit is contained in:
bbarnacle
2024-01-11 13:24:05 -05:00
committed by Brandon Barnacle
parent 66a4fc92bb
commit 52dcfb45f4
@@ -4,11 +4,12 @@
import logging
import ntpath
import re
from typing import List, Tuple, Type, Optional, Generator
from volatility3.framework import interfaces, renderers, exceptions, constants
from volatility3.framework.configuration import requirements
from volatility3.framework.renderers import format_hints
from volatility3.framework.renderers import format_hints, UnreadableValue
from volatility3.plugins.windows import handles
from volatility3.plugins.windows import pslist
@@ -53,6 +54,15 @@ class DumpFiles(interfaces.plugins.PluginInterface):
description="Dump a single _FILE_OBJECT at this physical address",
optional=True,
),
requirements.StringRequirement(
name="regex", description="Dump files matching REGEX", optional=True
),
requirements.BooleanRequirement(
name="ignore-case",
description="Ignore case in pattern match",
default=False,
optional=True,
),
requirements.VersionRequirement(
name="pslist", component=pslist.PsList, version=(2, 0, 0)
),
@@ -208,6 +218,11 @@ class DumpFiles(interfaces.plugins.PluginInterface):
def _generator(self, procs: List, offsets: List):
kernel = self.context.modules[self.config["kernel"]]
if self.config["regex"]:
if self.config["ignore-case"]:
file_re = re.compile(self.config["regex"], re.I)
else:
file_re = re.compile(self.config["regex"])
if procs:
# The handles plugin doesn't expose any staticmethod/classmethod, and it also requires stashing
@@ -243,6 +258,14 @@ 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")
if self.config["regex"]:
name = file_obj.file_name_with_device()
if isinstance(name, UnreadableValue):
continue
if not file_re.search(name):
continue
for result in self.process_file_object(
self.context, kernel.layer_name, self.open, file_obj
):
@@ -272,6 +295,13 @@ class DumpFiles(interfaces.plugins.PluginInterface):
if not file_obj.is_valid():
continue
if self.config["regex"]:
name = file_obj.file_name_with_device()
if isinstance(name, UnreadableValue):
continue
if not file_re.search(name):
continue
for result in self.process_file_object(
self.context, kernel.layer_name, self.open, file_obj
):