mirror of
https://github.com/volatilityfoundation/volatility
synced 2026-06-08 18:04:46 +00:00
148 lines
5.3 KiB
Python
148 lines
5.3 KiB
Python
# Volatility
|
|
# Copyright (C) 2007-2013 Volatility Foundation
|
|
# Copyright (C) 2004,2005,2006 4tphi Research
|
|
#
|
|
# Authors:
|
|
# {npetroni,awalters}@4tphi.net (Nick Petroni and AAron Walters)
|
|
# Michael Cohen <scudette@users.sourceforge.net>
|
|
# Mike Auty <mike.auty@gmail.com>
|
|
#
|
|
# This file is part of Volatility.
|
|
#
|
|
# Volatility is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Volatility is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Volatility. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
""" These are standard address spaces supported by Volatility """
|
|
import struct
|
|
import volatility.addrspace as addrspace
|
|
import volatility.debug as debug #pylint: disable-msg=W0611
|
|
import urllib
|
|
import os
|
|
|
|
#pylint: disable-msg=C0111
|
|
|
|
def write_callback(option, _opt_str, _value, parser, *_args, **_kwargs):
|
|
"""Callback function to ensure that write support is only enabled if user repeats a long string
|
|
|
|
This call back checks whether the user really wants write support and then either enables it
|
|
(for all future parses) by changing the option to store_true, or disables it permanently
|
|
by ensuring all future attempts to store the value store_false.
|
|
"""
|
|
if not hasattr(parser.values, 'write'):
|
|
# We don't want to use config.outfile, since this should always be seen by the user
|
|
option.dest = "write"
|
|
option.action = "store_false"
|
|
parser.values.write = False
|
|
for _ in range(3):
|
|
testphrase = "Yes, I want to enable write support"
|
|
response = raw_input("Write support requested. Please type \"" + testphrase +
|
|
"\" below precisely (case-sensitive):\n")
|
|
if response == testphrase:
|
|
option.action = "store_true"
|
|
parser.values.write = True
|
|
return
|
|
print "Write support disabled."
|
|
|
|
class FileAddressSpace(addrspace.BaseAddressSpace):
|
|
""" This is a direct file AS.
|
|
|
|
For this AS to be instantiated, we need
|
|
|
|
1) A valid config.LOCATION (starting with file://)
|
|
|
|
2) no one else has picked the AS before us
|
|
|
|
3) base == None (we dont operate on anyone else so we need to be
|
|
right at the bottom of the AS stack.)
|
|
"""
|
|
## We should be the AS of last resort
|
|
order = 100
|
|
def __init__(self, base, config, layered = False, **kwargs):
|
|
addrspace.BaseAddressSpace.__init__(self, base, config, **kwargs)
|
|
self.as_assert(base == None or layered, 'Must be first Address Space')
|
|
self.as_assert(config.LOCATION.startswith("file://"), 'Location is not of file scheme')
|
|
|
|
path = urllib.url2pathname(config.LOCATION[7:])
|
|
self.as_assert(os.path.exists(path), 'Filename must be specified and exist')
|
|
self.name = os.path.abspath(path)
|
|
self.fname = self.name
|
|
self.mode = 'rb'
|
|
if config.WRITE:
|
|
self.mode += '+'
|
|
self.fhandle = open(self.fname, self.mode)
|
|
self.fhandle.seek(0, 2)
|
|
self.fsize = self.fhandle.tell()
|
|
self._long_struct = struct.Struct("=I")
|
|
|
|
# Abstract Classes cannot register options, and since this checks config.WRITE in __init__, we define the option here
|
|
@staticmethod
|
|
def register_options(config):
|
|
config.add_option("WRITE", short_option = 'w', action = "callback", default = False,
|
|
help = "Enable write support", callback = write_callback)
|
|
|
|
def fread(self, length):
|
|
length = int(length)
|
|
return self.fhandle.read(length)
|
|
|
|
def read(self, addr, length):
|
|
addr, length = int(addr), int(length)
|
|
try:
|
|
self.fhandle.seek(addr)
|
|
except (IOError, OverflowError):
|
|
return None
|
|
data = self.fhandle.read(length)
|
|
if len(data) == 0:
|
|
return None
|
|
return data
|
|
|
|
def zread(self, addr, length):
|
|
data = self.read(addr, length)
|
|
if data is None:
|
|
data = "\x00" * length
|
|
elif len(data) != length:
|
|
data += "\x00" * (length - len(data))
|
|
return data
|
|
|
|
def read_long(self, addr):
|
|
string = self.read(addr, 4)
|
|
longval, = self._long_struct.unpack(string)
|
|
return longval
|
|
|
|
def get_available_addresses(self):
|
|
# Since the second parameter is the length of the run
|
|
# not the end location, it must be set to fsize, not fsize - 1
|
|
yield (0, self.fsize)
|
|
|
|
def is_valid_address(self, addr):
|
|
if addr == None:
|
|
return False
|
|
return 0 <= addr < self.fsize
|
|
|
|
def close(self):
|
|
self.fhandle.close()
|
|
|
|
def write(self, addr, data):
|
|
if not self._config.WRITE:
|
|
return False
|
|
try:
|
|
self.fhandle.seek(addr)
|
|
self.fhandle.write(data)
|
|
except IOError:
|
|
return False
|
|
return True
|
|
|
|
def __eq__(self, other):
|
|
return self.__class__ == other.__class__ and self.base == other.base and hasattr(other, "fname") and self.fname == other.fname
|
|
|