Files
volatility3/volatility/framework/layers/__init__.py
T
Mike Auty 71d938d78b Add in support for looking for symbols in zip files.
We use the jar scheme because that's actually registered with the right
bodies, even if the syntax is a bit weird.  The contents is still
processed by the ResourceAccessor meaning it can be compressed with any
of the supported compression methods.
2017-11-05 22:29:46 +00:00

112 lines
4.1 KiB
Python

import bz2
import contextlib
import gzip
import hashlib
import logging
import lzma
import os
import urllib.parse
import urllib.request
import zipfile
from urllib import request
try:
import magic
IMPORTED_MAGIC = True
except ImportError:
IMPORTED_MAGIC = False
from volatility.framework import constants
from volatility.framework.interfaces.layers import IMPORTED_MAGIC
from volatility.framework.layers import intel, lime, physical, segmented, vmware
vollog = logging.getLogger(__name__)
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"""
urllib.request.install_opener(urllib.request.build_opener(JarHandler))
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, mode = "rb")
# 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
class JarHandler(request.BaseHandler):
"""Handles the jar scheme for URIs"""
def default_open(self, req):
"""Handles the request if it's the jar scheme"""
if req.type == 'jar':
subscheme, remainder = req.full_url.split(":")[1], ":".join(req.full_url.split(":")[2:])
if subscheme != 'file':
vollog.log(constants.LOGLEVEL_VVV, "Unsupported jar subscheme {}".format(subscheme))
return None
zipsplit = remainder.split("!")
if len(zipsplit) != 2:
vollog.log(constants.LOGLEVEL_VVV,
"Path did not contain exactly one fragment indicator: {}".format(remainder))
return None
zippath, filepath = zipsplit
return zipfile.ZipFile(zippath).open(filepath)