diff --git a/volatility/framework/interfaces/layers.py b/volatility/framework/interfaces/layers.py index aa21b5913..01bfa3308 100644 --- a/volatility/framework/interfaces/layers.py +++ b/volatility/framework/interfaces/layers.py @@ -1,19 +1,11 @@ """Defines layers for containing data. One layer may combine other layers, map data based on the data itself, or map a procedure (such as decryption) across another layer of data.""" -import bz2 import collections import collections.abc -import contextlib import functools -import gzip -import hashlib import logging -import lzma import math import multiprocessing -import os -import urllib.parse -import urllib.request from abc import ABCMeta, abstractmethod from volatility.framework import constants, exceptions, validity @@ -408,65 +400,3 @@ class DummyProgress(object): self.value = 0 -class ResourceAccessor(object): - """Object for openning URLs as files (downloading locally first if necessary)""" - - def __init__(self, progress_callback = None, context = None): - self._progress_callback = progress_callback - self._context = context - - def open(self, url, mode = "rb"): - """Returns a file-like object for a particular URL opened in mode""" - with contextlib.closing(urllib.request.urlopen(url, context = self._context)) as fp: - # Cache the file locally - url_type, path = urllib.parse.splittype(url) - - if url_type == 'file': - curfile = urllib.request.urlopen(url, context = self._context) - else: - # TODO: find a way to check if we already have this file (look at http headers?) - block_size = 1028 * 8 - temp_filename = os.path.join(constants.CACHE_PATH, - "data_" + hashlib.sha512(bytes(url, 'latin-1')).hexdigest()) - cache_file = open(temp_filename, "wb") - while True: - block = fp.read(block_size) - if not block: - break - cache_file.write(block) - if self._progress_callback: - # TODO: Figure out the size and therefore percentage complete - self._progress_callback(0, "Reading file {}".format(url)) - cache_file.close() - # Re-open the cache with a different mode - curfile = open(temp_filename) - - # Determine whether the file is a particular type of file, and if so, open it as such - if IMPORTED_MAGIC: - while True: - try: - # Detect the content - detected = magic.detect_from_fobj(curfile) - except: - break - - if detected: - if detected.mime_type == 'application/x-xz': - curfile = lzma.LZMAFile(curfile, mode) - elif detected.mime_type == 'application/x-bzip2': - curfile = bz2.BZ2File(curfile, mode) - elif detected.mime_type == 'application/x-gzip': - curfile = gzip.GzipFile(fileobj = curfile, mode = mode) - else: - break - else: - break - - # Read and rewind to ensure we're inside any compressed file layers - curfile.read(1) - curfile.seek(0) - - # Fallback in case the file doesn't exist - if curfile is None: - raise ValueError("URL does not reference an openable file") - return curfile diff --git a/volatility/framework/layers/__init__.py b/volatility/framework/layers/__init__.py index c290d62b4..b1191f901 100644 --- a/volatility/framework/layers/__init__.py +++ b/volatility/framework/layers/__init__.py @@ -1 +1,78 @@ +import bz2 +import contextlib +import gzip +import hashlib +import lzma +import os +import urllib.parse +import urllib.request + +import magic + +from volatility.framework import constants +from volatility.framework.interfaces.layers import IMPORTED_MAGIC from volatility.framework.layers import intel, lime, physical, segmented, vmware + + +class ResourceAccessor(object): + """Object for openning URLs as files (downloading locally first if necessary)""" + + def __init__(self, progress_callback = None, context = None): + self._progress_callback = progress_callback + self._context = context + + def open(self, url, mode = "rb"): + """Returns a file-like object for a particular URL opened in mode""" + with contextlib.closing(urllib.request.urlopen(url, context = self._context)) as fp: + # Cache the file locally + url_type, path = urllib.parse.splittype(url) + + if url_type == 'file': + curfile = urllib.request.urlopen(url, context = self._context) + else: + # TODO: find a way to check if we already have this file (look at http headers?) + block_size = 1028 * 8 + temp_filename = os.path.join(constants.CACHE_PATH, + "data_" + hashlib.sha512(bytes(url, 'latin-1')).hexdigest()) + cache_file = open(temp_filename, "wb") + while True: + block = fp.read(block_size) + if not block: + break + cache_file.write(block) + if self._progress_callback: + # TODO: Figure out the size and therefore percentage complete + self._progress_callback(0, "Reading file {}".format(url)) + cache_file.close() + # Re-open the cache with a different mode + curfile = open(temp_filename) + + # Determine whether the file is a particular type of file, and if so, open it as such + if IMPORTED_MAGIC: + while True: + try: + # Detect the content + detected = magic.detect_from_fobj(curfile) + except: + break + + if detected: + if detected.mime_type == 'application/x-xz': + curfile = lzma.LZMAFile(curfile, mode) + elif detected.mime_type == 'application/x-bzip2': + curfile = bz2.BZ2File(curfile, mode) + elif detected.mime_type == 'application/x-gzip': + curfile = gzip.GzipFile(fileobj = curfile, mode = mode) + else: + break + else: + break + + # Read and rewind to ensure we're inside any compressed file layers + curfile.read(1) + curfile.seek(0) + + # Fallback in case the file doesn't exist + if curfile is None: + raise ValueError("URL does not reference an openable file") + return curfile diff --git a/volatility/framework/layers/physical.py b/volatility/framework/layers/physical.py index bf69b6afc..8f0db49e2 100644 --- a/volatility/framework/layers/physical.py +++ b/volatility/framework/layers/physical.py @@ -1,4 +1,4 @@ -from volatility.framework import exceptions, interfaces +from volatility.framework import exceptions, interfaces, layers from volatility.framework.configuration import requirements @@ -75,7 +75,7 @@ class FileLayer(interfaces.layers.DataLayerInterface): # FIXME: Add "+" to the mode once we've determined whether write mode is enabled mode = "rb" if not self._file_: - self._file_ = interfaces.layers.ResourceAccessor().open(self._location, mode) + self._file_ = layers.ResourceAccessor().open(self._location, mode) return self._file_ @property diff --git a/volatility/framework/symbols/intermed.py b/volatility/framework/symbols/intermed.py index 2527c8e0f..2541283ec 100644 --- a/volatility/framework/symbols/intermed.py +++ b/volatility/framework/symbols/intermed.py @@ -6,7 +6,7 @@ import os import pathlib from volatility import schemas -from volatility.framework import class_subclasses, constants, exceptions, interfaces, objects +from volatility.framework import class_subclasses, constants, exceptions, interfaces, objects, layers from volatility.framework.symbols import native vollog = logging.getLogger(__name__) @@ -69,7 +69,7 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface): # Check there are no obvious errors # Open the file and test the version self._versions = dict([(x.version, x) for x in class_subclasses(ISFormatTable)]) - fp = interfaces.layers.ResourceAccessor().open(isf_url) + fp = layers.ResourceAccessor().open(isf_url) json_object = json.load(fp) fp.close()