diff --git a/volatility/framework/automagic/stacker.py b/volatility/framework/automagic/stacker.py index 87be48af3..bf763d6c7 100644 --- a/volatility/framework/automagic/stacker.py +++ b/volatility/framework/automagic/stacker.py @@ -18,6 +18,15 @@ from volatility.framework.layers import physical vollog = logging.getLogger(__name__) +IMPORTED_MAGIC = False +try: + import magic + + IMPORTED_MAGIC = True + vollog.debug("Imported python-magic, autodetecting compressed files based on content") +except ImportError: + pass + class LayerStacker(interfaces.automagic.AutomagicInterface): """Builds up layers in a single stack @@ -67,7 +76,24 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): current_config_path = interfaces.configuration.path_join(config_path, "stack", current_layer_name) # This must be specific to get us started, setup the config and run new_context.config[interfaces.configuration.path_join(current_config_path, "filename")] = self.local_store - new_context.add_layer(physical.FileLayer(new_context, current_config_path, current_layer_name)) + + # Determine compression + detected = None + if IMPORTED_MAGIC: + try: + detected = magic.detect_from_filename(self.local_store) + except: + pass + + if self.local_store.endswith('.xz') or (detected and detected.mime_type == 'application/x-xz'): + physical_layer = physical.XzFileLayer(new_context, current_config_path, current_layer_name) + elif self.local_store.endswith('.bz2') or (detected and detected.mime_type == 'application/x-bzip2'): + physical_layer = physical.Bz2FileLayer(new_context, current_config_path, current_layer_name) + elif self.local_store.endswith('.gz') or (detected and detected.mime_type == 'application/x-gzip'): + physical_layer = physical.GzFileLayer(new_context, current_config_path, current_layer_name) + else: + physical_layer = physical.FileLayer(new_context, current_config_path, current_layer_name) + new_context.add_layer(physical_layer) # Repeatedly apply "determine what this is" code and build as much up as possible stacked = True diff --git a/volatility/framework/layers/physical.py b/volatility/framework/layers/physical.py index e69a3d871..e9c7083a2 100644 --- a/volatility/framework/layers/physical.py +++ b/volatility/framework/layers/physical.py @@ -1,3 +1,6 @@ +import bz2 +import gzip +import lzma import os.path from volatility.framework import exceptions, interfaces @@ -144,3 +147,52 @@ class FileLayer(interfaces.layers.DataLayerInterface): @classmethod def get_requirements(cls): return [requirements.StringRequirement(name = 'filename', optional = False)] + + +class XzFileLayer(FileLayer): + def __init__(self, context, config_path, name): + super().__init__(context, config_path, name) + self._size = None + + @property + def _file(self): + """Property to prevent the initializer storing an unserializable open file (for context cloning)""" + # FIXME: Add "+" to the mode once we've determined whether write mode is enabled + mode = "rb" + if not self._file_: + self._file_ = lzma.open(self._filename, mode) + return self._file_ + + @property + def maximum_address(self): + """Returns the largest available address in the space""" + # Calculate the size by seeking to the end and telling + if self._size: + return self._size + orig = self._file.tell() + self._file.seek(0, 2) + self._size = self._file.tell() + self._file.seek(orig) + return self._size + + +class GzFileLayer(XzFileLayer): + @property + def _file(self): + """Property to prevent the initializer storing an unserializable open file (for context cloning)""" + # FIXME: Add "+" to the mode once we've determined whether write mode is enabled + mode = "rb" + if not self._file_: + self._file_ = gzip.open(self._filename, mode) + return self._file_ + + +class Bz2FileLayer(XzFileLayer): + @property + def _file(self): + """Property to prevent the initializer storing an unserializable open file (for context cloning)""" + # FIXME: Add "+" to the mode once we've determined whether write mode is enabled + mode = "rb" + if not self._file_: + self._file_ = bz2.open(self._filename, mode) + return self._file_