mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-11 20:27:38 +02:00
Windows: Refactor names of FileInterfaces
This commit is contained in:
@@ -465,6 +465,7 @@ class CommandLine:
|
||||
return
|
||||
|
||||
self.seek(0)
|
||||
|
||||
if output_dir is None:
|
||||
raise TypeError("Output directory is not a string")
|
||||
os.makedirs(output_dir, exist_ok = True)
|
||||
@@ -473,13 +474,15 @@ class CommandLine:
|
||||
filename, extension = os.path.join(output_dir, '.'.join(pref_name_array[:-1])), pref_name_array[-1]
|
||||
output_filename = "{}.{}".format(filename, extension)
|
||||
|
||||
if not os.path.exists(output_filename):
|
||||
counter = 1
|
||||
while os.path.exists(output_filename):
|
||||
output_filename = "{}-{}.{}".format(filename, counter, extension)
|
||||
counter += 1
|
||||
with open(output_filename, "wb") as current_file:
|
||||
current_file.write(self.read())
|
||||
self._committed = True
|
||||
vollog.log(logging.INFO, "Saved stored plugin file: {}".format(output_filename))
|
||||
else:
|
||||
vollog.warning("Refusing to overwrite an existing file: {}".format(output_filename))
|
||||
|
||||
super().close()
|
||||
|
||||
return CLIFileHandler
|
||||
|
||||
@@ -20,11 +20,13 @@ vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FileHandlerInterface(IO[bytes]):
|
||||
"""Class for storing Files in the plugin as a means to output a file or
|
||||
files when necessary."""
|
||||
"""Class for storing Files in the plugin as a means to output a file when necessary.
|
||||
|
||||
This can be used as ContextManager that will close/produce the file automatically when exiting the context block
|
||||
"""
|
||||
|
||||
def __init__(self, filename: str) -> None:
|
||||
"""Creates a FileTemplate
|
||||
"""Creates a FileHandler
|
||||
|
||||
Args:
|
||||
filename: The requested name of the filename for the data
|
||||
@@ -35,19 +37,26 @@ class FileHandlerInterface(IO[bytes]):
|
||||
|
||||
@property
|
||||
def preferred_filename(self):
|
||||
"""The preferred filename to save the data to.
|
||||
Until this file has been written, this value may not be the final filename the data is written to.
|
||||
"""
|
||||
return self._preferred_filename
|
||||
|
||||
@preferred_filename.setter
|
||||
def preferred_filename(self, filename):
|
||||
"""Sets the preferred filename"""
|
||||
if self.closed:
|
||||
raise IOError("FileTemplate name cannot be changed once closed")
|
||||
raise IOError("FileHandler name cannot be changed once closed")
|
||||
if not isinstance(filename, str):
|
||||
raise TypeError("FileTemplateInterface preferred filenames must be strings")
|
||||
raise TypeError("FileHandler preferred filenames must be strings")
|
||||
if os.path.sep in filename:
|
||||
raise ValueError("FileTemplateInterface filenames cannot contain path separators")
|
||||
raise ValueError("FileHandler filenames cannot contain path separators")
|
||||
self._preferred_filename = filename
|
||||
|
||||
@abstractmethod
|
||||
def close(self):
|
||||
"""Method that commits the file and fixes the final filename for use"""
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
@@ -115,11 +124,10 @@ class PluginInterface(interfaces.configuration.ConfigurableInterface,
|
||||
|
||||
framework.require_interface_version(*self._required_framework_version)
|
||||
|
||||
def open(self, preferred_filename: str) -> FileHandlerInterface:
|
||||
"""Opens a file for output in bytes mode"""
|
||||
if self._file_handler is not None:
|
||||
return self._file_handler(preferred_filename)
|
||||
raise IOError("FileTemplate not specified for this plugin")
|
||||
@property
|
||||
def open(self):
|
||||
"""Returns a context manager and thus can be called like open"""
|
||||
return self._file_handler
|
||||
|
||||
def set_file_handler(self, handler: Type[FileHandlerInterface]) -> None:
|
||||
"""Sets the file handler to be used by this plugin."""
|
||||
|
||||
@@ -39,10 +39,10 @@ class ConfigWriter(plugins.PluginInterface):
|
||||
config = dict(self.context.config)
|
||||
filename = "config.extra"
|
||||
try:
|
||||
with self.open(filename) as filedata:
|
||||
filedata.write(bytes(json.dumps(config, sort_keys = True, indent = 2), 'raw_unicode_escape'))
|
||||
except Exception:
|
||||
vollog.warning("Unable to JSON encode configuration")
|
||||
with self.open(filename) as file_data:
|
||||
file_data.write(bytes(json.dumps(config, sort_keys = True, indent = 2), 'raw_unicode_escape'))
|
||||
except Exception as excp:
|
||||
vollog.warning("Unable to JSON encode configuration: {}".format(excp))
|
||||
|
||||
for k, v in config.items():
|
||||
yield (0, (k, json.dumps(v)))
|
||||
|
||||
@@ -47,7 +47,7 @@ class LayerWriter(plugins.PluginInterface):
|
||||
chunk_size: Optional[int] = None,
|
||||
progress_callback: Optional[constants.ProgressCallback] = None) -> Optional[
|
||||
plugins.FileHandlerInterface]:
|
||||
"""Produces a filedata from the named layer in the provided context
|
||||
"""Produces a FileHandler from the named layer in the provided context or None on failure
|
||||
|
||||
Args:
|
||||
context: the context from which to read the memory layer
|
||||
@@ -65,11 +65,11 @@ class LayerWriter(plugins.PluginInterface):
|
||||
chunk_size = cls.default_block_size
|
||||
|
||||
filehandler = file_handler(preferred_name)
|
||||
with filehandler as filedata:
|
||||
with filehandler as file_data:
|
||||
for i in range(0, layer.maximum_address, chunk_size):
|
||||
current_chunk_size = min(chunk_size, layer.maximum_address - i)
|
||||
data = layer.read(i, current_chunk_size, pad = True)
|
||||
filedata.write(data)
|
||||
file_data.write(data)
|
||||
if progress_callback:
|
||||
progress_callback((i / layer.maximum_address) * 100, 'Writing layer {}'.format(layer_name))
|
||||
return filehandler
|
||||
|
||||
@@ -138,8 +138,8 @@ class Timeliner(interfaces.plugins.PluginInterface):
|
||||
|
||||
# Write out a body file if necessary
|
||||
if self.config.get('create-bodyfile', True):
|
||||
with self.open("volatility.body") as filedata:
|
||||
with io.TextIOWrapper(filedata, write_through = True) as fp:
|
||||
with self.open("volatility.body") as file_data:
|
||||
with io.TextIOWrapper(file_data, write_through = True) as fp:
|
||||
for (plugin_name, item) in self.timeline:
|
||||
times = self.timeline[(plugin_name, item)]
|
||||
# Body format is: MD5|name|inode|mode_as_string|UID|GID|size|atime|mtime|ctime|crtime
|
||||
@@ -203,8 +203,8 @@ class Timeliner(interfaces.plugins.PluginInterface):
|
||||
for entry in old_dict:
|
||||
total_config[interfaces.configuration.path_join(plugin.__class__.__name__, entry)] = old_dict[entry]
|
||||
|
||||
with self.open("config.json") as filedata:
|
||||
with io.TextIOWrapper(filedata, write_through = True) as fp:
|
||||
with self.open("config.json") as file_data:
|
||||
with io.TextIOWrapper(file_data, write_through = True) as fp:
|
||||
json.dump(total_config, fp, sort_keys = True, indent = 2)
|
||||
|
||||
return renderers.TreeGrid(columns = [("Plugin", str), ("Description", str), ("Created Date", datetime.datetime),
|
||||
|
||||
@@ -71,23 +71,23 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
if layer_name is None:
|
||||
layer_name = dll_entry.vol.layer_name
|
||||
|
||||
filehandler = file_handler("{}{}.{:#x}.{:#x}.dmp".format(prefix,
|
||||
ntpath.basename(name),
|
||||
dll_entry.vol.offset,
|
||||
dll_entry.DllBase))
|
||||
file_handler = file_handler("{}{}.{:#x}.{:#x}.dmp".format(prefix,
|
||||
ntpath.basename(name),
|
||||
dll_entry.vol.offset,
|
||||
dll_entry.DllBase))
|
||||
|
||||
dos_header = context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER",
|
||||
offset = dll_entry.DllBase,
|
||||
layer_name = layer_name)
|
||||
|
||||
with filehandler as filedata:
|
||||
with file_handler as file_data:
|
||||
for offset, data in dos_header.reconstruct():
|
||||
filedata.seek(offset)
|
||||
filedata.write(data)
|
||||
except (IOError, exceptions.VolatilityException, OverflowError) as excp:
|
||||
file_data.seek(offset)
|
||||
file_data.write(data)
|
||||
except (IOError, exceptions.VolatilityException, OverflowError, ValueError) as excp:
|
||||
vollog.debug("Unable to dump dll at offset {}: {}".format(dll_entry.DllBase, excp))
|
||||
return None
|
||||
return filehandler
|
||||
return file_handler
|
||||
|
||||
def _generator(self, procs):
|
||||
pe_table_name = intermed.IntermediateSymbolTable.create(self.context,
|
||||
@@ -128,11 +128,11 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
|
||||
file_output = "Disabled"
|
||||
if self.config['dump']:
|
||||
filedata = self.dump_pe(self.context, pe_table_name, entry, self._file_handler,
|
||||
proc_layer_name, prefix = "pid.{}.".format(proc_id))
|
||||
file_handler = self.dump_pe(self.context, pe_table_name, entry, self._file_handler,
|
||||
proc_layer_name, prefix = "pid.{}.".format(proc_id))
|
||||
file_output = "Error outputting file"
|
||||
if filedata:
|
||||
file_output = filedata.preferred_filename
|
||||
if file_handler:
|
||||
file_output = file_handler.preferred_filename
|
||||
|
||||
yield (0, (proc.UniqueProcessId,
|
||||
proc.ImageFileName.cast("string",
|
||||
|
||||
@@ -36,7 +36,7 @@ class Malfind(interfaces.plugins.PluginInterface):
|
||||
default = False,
|
||||
optional = True),
|
||||
requirements.VersionRequirement(name = 'pslist', component = pslist.PsList, version = (2, 0, 0)),
|
||||
requirements.VersionRequirement(name = 'vadinfo', component = vadinfo.VadInfo, version = (1, 1, 0))
|
||||
requirements.VersionRequirement(name = 'vadinfo', component = vadinfo.VadInfo, version = (2, 0, 0))
|
||||
]
|
||||
|
||||
@classmethod
|
||||
@@ -135,8 +135,8 @@ class Malfind(interfaces.plugins.PluginInterface):
|
||||
if self.config['dump']:
|
||||
file_output = "Error outputting to file"
|
||||
try:
|
||||
filedata = vadinfo.VadInfo.vad_dump(self.context, proc, vad, self._file_handler)
|
||||
file_output = filedata.preferred_filename
|
||||
file_handler = vadinfo.VadInfo.vad_dump(self.context, proc, vad, self._file_handler)
|
||||
file_output = file_handler.preferred_filename
|
||||
except (exceptions.InvalidAddressException, OverflowError) as excp:
|
||||
vollog.debug("Unable to dump PE with pid {0}.{1:#x}: {2}".format(proc.UniqueProcessId,
|
||||
vad.get_start(), excp))
|
||||
|
||||
@@ -48,7 +48,8 @@ class Memmap(interfaces.plugins.PluginInterface):
|
||||
excp.layer_name))
|
||||
continue
|
||||
|
||||
with self.open("pid.{}.dmp".format(pid)) as filedata:
|
||||
file_handler = self.open("pid.{}.dmp".format(pid))
|
||||
with file_handler as file_data:
|
||||
|
||||
for mapval in proc_layer.mapping(0x0, proc_layer.maximum_address, ignore_errors = True):
|
||||
offset, size, mapped_offset, mapped_size, maplayer = mapval
|
||||
@@ -57,12 +58,12 @@ class Memmap(interfaces.plugins.PluginInterface):
|
||||
if self.config['dump']:
|
||||
try:
|
||||
data = proc_layer.read(offset, size, pad = True)
|
||||
filedata.write(data)
|
||||
file_output = filedata.preferred_filename
|
||||
file_data.write(data)
|
||||
file_output = file_handler.preferred_filename
|
||||
except exceptions.InvalidAddressException:
|
||||
file_output = "Error outputting to file"
|
||||
vollog.debug("Unable to write {}'s address {} to {}.dmp".format(proc_layer_name, offset,
|
||||
filedata.preferred_filename))
|
||||
vollog.debug("Unable to write {}'s address {} to {}".format(proc_layer_name, offset,
|
||||
file_handler.preferred_filename))
|
||||
|
||||
yield (0, (
|
||||
format_hints.Hex(offset),
|
||||
|
||||
@@ -79,10 +79,10 @@ class ModScan(interfaces.plugins.PluginInterface):
|
||||
|
||||
file_output = "Disabled"
|
||||
if self.config['dump']:
|
||||
filedata = dlllist.DllList.dump_pe(self.context, pe_table_name, mod, self._file_handler)
|
||||
file_handler = dlllist.DllList.dump_pe(self.context, pe_table_name, mod, self.open)
|
||||
file_output = "Error outputting file"
|
||||
if filedata:
|
||||
file_output = filedata.preferred_filename
|
||||
if file_handler:
|
||||
file_output = file_handler.preferred_filename
|
||||
|
||||
yield (0, (
|
||||
format_hints.Hex(mod.vol.offset),
|
||||
|
||||
@@ -58,10 +58,10 @@ class Modules(interfaces.plugins.PluginInterface):
|
||||
|
||||
file_output = "Disabled"
|
||||
if self.config['dump']:
|
||||
filedata = dlllist.DllList.dump_pe(self.context, pe_table_name, mod, self._file_handler)
|
||||
file_handler = dlllist.DllList.dump_pe(self.context, pe_table_name, mod, self._file_handler)
|
||||
file_output = "Error outputting file"
|
||||
if filedata:
|
||||
file_output = filedata.preferred_filename
|
||||
if file_handler:
|
||||
file_output = file_handler.preferred_filename
|
||||
|
||||
yield (0, (
|
||||
format_hints.Hex(mod.vol.offset),
|
||||
|
||||
@@ -74,15 +74,15 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
dos_header = context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER",
|
||||
offset = peb.ImageBaseAddress,
|
||||
layer_name = proc_layer_name)
|
||||
filehandler = file_handler("pid.{0}.{1:#x}.dmp".format(proc.UniqueProcessId, peb.ImageBaseAddress))
|
||||
with filehandler as filedata:
|
||||
file_handler = file_handler("pid.{0}.{1:#x}.dmp".format(proc.UniqueProcessId, peb.ImageBaseAddress))
|
||||
with file_handler as file_data:
|
||||
for offset, data in dos_header.reconstruct():
|
||||
filedata.seek(offset)
|
||||
filedata.write(data)
|
||||
file_data.seek(offset)
|
||||
file_data.write(data)
|
||||
except Exception as excp:
|
||||
vollog.debug("Unable to dump PE with pid {}: {}".format(proc.UniqueProcessId, excp))
|
||||
|
||||
return filehandler
|
||||
return file_handler
|
||||
|
||||
@classmethod
|
||||
def create_pid_filter(cls, pid_list: List[int] = None) -> Callable[[interfaces.objects.ObjectInterface], bool]:
|
||||
@@ -190,11 +190,11 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
|
||||
file_output = "Disabled"
|
||||
if self.config['dump']:
|
||||
filedata = self.process_dump(self.context, self.config['nt_symbols'], pe_table_name, proc,
|
||||
self._file_handler)
|
||||
file_handler = self.process_dump(self.context, self.config['nt_symbols'], pe_table_name, proc,
|
||||
self._file_handler)
|
||||
file_output = "Error outputting file"
|
||||
if filedata:
|
||||
file_output = filedata.preferred_filename
|
||||
if file_handler:
|
||||
file_output = file_handler.preferred_filename
|
||||
|
||||
yield (0, (proc.UniqueProcessId, proc.InheritedFromUniqueProcessId,
|
||||
proc.ImageFileName.cast("string", max_length = proc.ImageFileName.vol.count, errors = 'replace'),
|
||||
|
||||
@@ -82,20 +82,21 @@ class HiveList(interfaces.plugins.PluginInterface):
|
||||
maxaddr = hive.hive.Storage[0].Length
|
||||
hive_name = self._sanitize_hive_name(hive.get_name())
|
||||
|
||||
with self.open('registry.{}.{}.hive'.format(hive_name, hex(hive.hive_offset))) as filedata:
|
||||
file_handler = self.open('registry.{}.{}.hive'.format(hive_name, hex(hive.hive_offset)))
|
||||
with file_handler as file_data:
|
||||
if hive._base_block:
|
||||
hive_data = self.context.layers[hive.dependencies[0]].read(hive.hive.BaseBlock, 1 << 12)
|
||||
else:
|
||||
hive_data = '\x00' * (1 << 12)
|
||||
filedata.write(hive_data)
|
||||
file_data.write(hive_data)
|
||||
|
||||
for i in range(0, maxaddr, chunk_size):
|
||||
current_chunk_size = min(chunk_size, maxaddr - i)
|
||||
data = hive.read(i, current_chunk_size, pad = True)
|
||||
filedata.write(data)
|
||||
file_data.write(data)
|
||||
# if self._progress_callback:
|
||||
# self._progress_callback((i / maxaddr) * 100, 'Writing layer {}'.format(hive_name))
|
||||
file_output = filedata.preferred_filename
|
||||
file_output = file_handler.preferred_filename
|
||||
|
||||
yield (0, (format_hints.Hex(hive_object.vol.offset), hive_object.get_name() or "", file_output))
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class VadInfo(interfaces.plugins.PluginInterface):
|
||||
"""Lists process memory ranges."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (1, 1, 0)
|
||||
_version = (2, 0, 0)
|
||||
MAXSIZE_DEFAULT = 0
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -111,7 +111,7 @@ class VadInfo(interfaces.plugins.PluginInterface):
|
||||
def vad_dump(cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
proc: interfaces.objects.ObjectInterface,
|
||||
vad: interfaces.objects.ObjectInterface,
|
||||
vad: interfaces.objects.ObjectInterface,
|
||||
file_handler: Type[
|
||||
interfaces.plugins.FileHandlerInterface]) -> Optional[interfaces.plugins.FileHandlerInterface]:
|
||||
"""Extracts the complete data for Vad as a FileInterface.
|
||||
@@ -150,16 +150,16 @@ class VadInfo(interfaces.plugins.PluginInterface):
|
||||
file_name = "pid.{0}.vad.{1:#x}-{2:#x}.dmp".format(proc_id, vad_start, vad_end)
|
||||
try:
|
||||
file_handler = file_handler(file_name)
|
||||
with file_handler as filedata:
|
||||
chunk_size = 1024 * 1024 * 10
|
||||
offset = vad_start
|
||||
while offset < vad_end:
|
||||
to_read = min(chunk_size, vad_end - offset)
|
||||
data = proc_layer.read(offset, to_read, pad = True)
|
||||
if not data:
|
||||
break
|
||||
filedata.write(data)
|
||||
offset += to_read
|
||||
with file_handler as file_data:
|
||||
chunk_size = 1024 * 1024 * 10
|
||||
offset = vad_start
|
||||
while offset < vad_end:
|
||||
to_read = min(chunk_size, vad_end - offset)
|
||||
data = proc_layer.read(offset, to_read, pad = True)
|
||||
if not data:
|
||||
break
|
||||
file_data.write(data)
|
||||
offset += to_read
|
||||
|
||||
except Exception as excp:
|
||||
vollog.debug("Unable to dump VAD {}: {}".format(file_name, excp))
|
||||
@@ -188,10 +188,10 @@ class VadInfo(interfaces.plugins.PluginInterface):
|
||||
|
||||
file_output = "Disabled"
|
||||
if self.config['dump']:
|
||||
filedata = self.vad_dump(self.context, proc, vad, self._file_handler)
|
||||
file_handler = self.vad_dump(self.context, proc, vad, self._file_handler)
|
||||
file_output = "Error outputting file"
|
||||
if filedata:
|
||||
file_output = filedata.preferred_filename
|
||||
if file_handler:
|
||||
file_output = file_handler.preferred_filename
|
||||
|
||||
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(),
|
||||
|
||||
@@ -58,8 +58,8 @@ class Certificates(interfaces.plugins.PluginInterface):
|
||||
|
||||
if not isinstance(certificate_data, interfaces.renderers.BaseAbsentValue):
|
||||
with self.open("{} - {} - {}.crt".format(
|
||||
hex(hive.hive_offset), reg_section, key_hash)) as filedata:
|
||||
filedata.write(certificate_data)
|
||||
hex(hive.hive_offset), reg_section, key_hash)) as file_data:
|
||||
file_data.write(certificate_data)
|
||||
yield (0, (top_key, reg_section, key_hash, name))
|
||||
except KeyError:
|
||||
# Key wasn't found in this hive, carry on
|
||||
|
||||
Reference in New Issue
Block a user