/usr/lib/python2.7/dist-packages/volatility/plugins/addrspaces/ieee1394.py is in volatility 2.3.1-7.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | # Volatility
#
# Authors:
# 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 Version 2 as
# published by the Free Software Foundation. You may not use, modify or
# distribute this program under any other version of the GNU General
# Public License.
#
# 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/>.
#
import time
import urlparse
import volatility.addrspace as addrspace
# TODO: Remove this once we no longer support old/broken versions of urlparse (2.6.2)
check = urlparse.urlsplit("firewire://method/0")
urlparse_broken = False
if check[1] != 'method':
urlparse_broken = True
def FirewireRW(netloc, location):
if netloc in fw_implementations:
return fw_implementations[netloc](location)
return None
class FWRaw1394(object):
def __init__(self, location):
locarr = location.split('/')
self.bus = locarr[0]
self.node = locarr[1]
self._node = None
def is_valid(self):
"""Initializes the firewire implementation"""
self._node = None
try:
h = firewire.Host()
self._node = h[self.bus][self.node]
return True, "Valid"
except IndexError:
return False, "Firewire node " + str(self.node) + " on bus " + str(self.bus) + " was not accessible"
except IOError, e:
return False, "Firewire device IO error - " + str(e)
return False, "Unknown Error occurred"
def read(self, addr, length):
"""Reads bytes from the specified address"""
return self._node.read(addr, length)
def write(self, addr, buf):
"""Writes buf bytes at addr"""
return self._node.write(addr, buf)
class FWForensic1394(object):
def __init__(self, location):
"""Initializes the firewire implementation"""
self.location = location.strip('/')
self._bus = forensic1394.Bus()
self._bus.enable_sbp2()
self._device = None
def is_valid(self):
try:
time.sleep(2)
devices = self._bus.devices()
# FIXME: Base the device off the location rather than hardcoded first remote device
self._device = devices[int(self.location)]
# Cetain Firewire cards misreport their maximum request size, notably Ricoh onboard chipsets
# Uncomment the line below for such broken hardware
# self._device._request_size = 1024
if not self._device.isopen():
self._device.open()
# The device requires time to settle before it can be used
return True, "Valid"
except IOError, e:
print repr(e)
return False, "Forensic1394 returned an exception: " + str(e)
return False, "Unknown Error occurred"
def read(self, addr, length):
"""Reads bytes from the specified address"""
return self._device.read(addr, length)
def write(self, addr, buf):
"""Writes buf bytes at addr"""
return self._device.write(addr, buf)
class FirewireAddressSpace(addrspace.BaseAddressSpace):
"""A physical layer address space that provides access via firewire"""
## We should be *almost* the AS of last resort
order = 99
def __init__(self, base, config, **kargs):
self.as_assert(base == None, 'Must be first Address Space')
try:
(scheme, netloc, path, _, _, _) = urlparse.urlparse(config.LOCATION)
self.as_assert(scheme == 'firewire', 'Not a firewire URN')
if urlparse_broken:
if path.startswith('//') and path[2:].find('/') > 0:
firstslash = path[2:].find('/')
netloc = path[2:firstslash + 2]
path = path[firstslash + 3:]
self._fwimpl = FirewireRW(netloc, path)
except (AttributeError, ValueError):
self.as_assert(False, "Unable to parse {0} as a URL".format(config.LOCATION))
addrspace.BaseAddressSpace.__init__(self, base, config, **kargs)
self.as_assert(self._fwimpl is not None, "Unable to locate {0} implementation.".format(netloc))
valid, reason = self._fwimpl.is_valid()
self.as_assert(valid, reason)
# We have a list of exclusions because we know that trying to read anything in these sections
# will cause the target machine to bluescreen
# Exceptions are in the form (start, length, "Reason")
self._exclusions = sorted([(0xa0000, 0xfffff - 0xa0000, "Upper Memory Area")])
self.name = "Firewire using " + str(netloc) + " at " + str(path)
# We have no way of knowing how big a firewire space is...
# Set it to the maximum for the moment
# TODO: Find a way of determining the size safely and reliably from the space itself
self.size = 0xFFFFFFFF
def intervals(self, start, size):
"""Returns a list of intervals, from start of length size, that do not include the exclusions"""
return self._intervals(sorted(self._exclusions), start, size + start, [])
def _intervals(self, exclusions, start, end, accumulator):
"""Accepts a sorted list of intervals and a start and end
This will return a list of intervals between start and end
that does not contain any of the intervals in the list of exclusions.
"""
if not len(exclusions):
# We're done
return accumulator + [(start, end - start)]
e = exclusions[0]
estart = e[0]
eend = e[1] + estart
# e and range overlap
if (eend < start or estart > end):
# Ignore this exclusion
return self._intervals(exclusions[1:], start, end, accumulator)
if estart < start:
if eend < end:
# Covers the start of the remaining length
return self._intervals(exclusions[1:], eend, end, accumulator)
else:
# Covers the entire remaining area
return accumulator
else:
if eend < end:
# Covers a section of the remaining length
return self._intervals(exclusions[1:], eend, end, accumulator + [(start, estart - start)])
else:
# Covers the end of the remaining length
return accumulator + [(start, estart - start)]
def read(self, offset, length):
"""Reads a specified size in bytes from the current offset
Fills any excluded holes with zeros (so in that sense, similar to zread)
"""
ints = self.intervals(offset, length)
output = "\x00" * length
try:
for i in ints:
datstart, datlen = i[0], i[1]
if datlen > 0:
# node.read won't work on 0 byte
readdata = self._fwimpl.read(datstart, datlen)
# I'm not sure why, but sometimes readdata comes out longer than the requested size
# We just truncate it to the right length
output = output[:datstart - offset] + readdata[:datlen] + output[(datstart - offset) + datlen:]
except IOError, e:
print repr(e)
raise RuntimeError("Failed to read from firewire device")
self.as_assert(len(output) == length, "Firewire read lengths failed to match")
return output
def zread(self, offset, length):
""" Delegate padded reads to normal read, since errors reading
the physical address should probably be reported back to the user
"""
return self.read(offset, length)
def write(self, offset, data):
"""Writes a specified size in bytes"""
if not self._config.WRITE:
return False
ints = self.intervals(offset, len(data))
try:
for i in ints:
datstart, datlen = i[0], i[1]
if datlen > 0:
self._fwimpl.write(datstart, data[(datstart - offset):(datstart - offset) + datlen])
except IOError:
raise RuntimeError("Failed to write to the firewire device")
return True
def get_address_range(self):
"""Returns the size of the address range"""
return [0, self.size - 1]
def get_available_addresses(self):
"""Returns a list of available addresses"""
for i in self.intervals(0, self.size):
yield i
fw_implementations = {}
try:
import firewire #pylint: disable-msg=F0401
fw_implementations['raw1394'] = FWRaw1394
except ImportError:
pass
try:
import forensic1394 #pylint: disable-msg=F0401
fw_implementations['forensic1394'] = FWForensic1394
except ImportError:
pass
if not len(fw_implementations):
FirewireAddressSpace = None
|