From 7cc54ba23aef6d20abb65ac04cc7584c92e6a618 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Sat, 2 Mar 2019 23:09:12 +0000 Subject: [PATCH] Add in LayerWriter plugin. --- volatility/framework/plugins/layerwriter.py | 86 +++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 volatility/framework/plugins/layerwriter.py diff --git a/volatility/framework/plugins/layerwriter.py b/volatility/framework/plugins/layerwriter.py new file mode 100644 index 000000000..a137e8834 --- /dev/null +++ b/volatility/framework/plugins/layerwriter.py @@ -0,0 +1,86 @@ +# 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. +# + +import logging +import os +from typing import List + +from volatility.framework import renderers, interfaces +from volatility.framework.configuration import requirements +from volatility.framework.interfaces import plugins + +vollog = logging.getLogger(__name__) + + +class LayerWriter(plugins.PluginInterface): + """Runs the automagics and lists out the generated layers if no layer name is specified, otherwise writes out the named layer""" + + default_output_name = "output.raw" + default_block_size = 0x500000 + + @classmethod + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Memory layer for the kernel', architectures = ["Intel32", "Intel64"]), + requirements.StringRequirement( + name = 'layer_name', description = 'Name of the layer to write out', default = None, optional = True), + requirements.StringRequirement( + name = 'output', + description = 'Filename to output the chosen layer', + optional = True, + default = cls.default_output_name), + requirements.IntRequirement( + name = 'block_size', + description = "Size of blocks to copy over", + default = cls.default_block_size, + optional = True) + ] + + def _generator(self): + if self.config.get('layer_name', None) is None: + for layer_name in self.context.memory: + yield 0, ("Layer '{}' available as '{}'".format(layer_name, + self.context.memory[layer_name].__class__.__name__), ) + elif self.config['layer_name'] not in self.context.memory: + yield 0, ('Layer Name does not exist', ) + elif os.path.exists(self.config.get('output', self.default_output_name)): + yield 0, ('Refusing to overwrite existing output file', ) + else: + chunk_size = self.config.get('block_size', self.default_block_size) + layer = self.context.memory[self.config['layer_name']] + + try: + filedata = plugins.FileInterface(self.config.get('output', self.default_output_name)) + 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.data.write(data) + self.produce_file(filedata) + except Exception as excp: + import pdb + pdb.set_trace() + vollog.warning("Unable to write out output file") + + yield 0, ('Layer {} has been written to {}'.format(self.config['layer_name'], + self.config.get('output', self.default_output_name)), ) + + def run(self): + return renderers.TreeGrid([("Status", str)], self._generator())