/usr/lib/python2.7/dist-packages/rekall/plugins/addrspaces/pmem.py is in python-rekall-core 1.6.0+dfsg-2.
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 | # Rekall Memory Forensics
#
# Copyright 2015 Google Inc. All Rights Reserved.
#
# This program 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.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""Address spaces specific to pmem live here."""
__author__ = "Adam Sindelar <adamsh@google.com>"
from os import path
from rekall import addrspace
from rekall import yaml_utils
from rekall.plugins.addrspaces import standard
class _StreamWrapper(object):
def __init__(self, stream):
self.stream = stream
def read(self, offset, length):
self.stream.seek(offset)
return self.stream.read(length)
def write(self, offset, length):
self.stream.seek(offset)
return self.stream.write(length)
class MacPmemAddressSpace(addrspace.RunBasedAddressSpace):
"""Implements an address space to overlay the new MacPmem device."""
name = "MacPmem"
order = standard.FileAddressSpace.order - 2
__image = True
volatile = True
fd = None
fname = None
_writable = True
def _ensure_fd_writable(self):
"""Reopen the device if necessary.
/dev/pmem is open read-only by default. This reopens it if writes are
requested.
"""
if self.session.GetParameter("writable_physical_memory"):
expected_mode = "r+"
else:
raise RuntimeError(
"writable_physical_memory is not set in the Session.")
if self.fd.mode != expected_mode:
self.fd.close()
self.fd = open(self.fname, expected_mode)
def __init__(self, base=None, filename=None, **kwargs):
super(MacPmemAddressSpace, self).__init__(**kwargs)
self.as_assert(base == None,
"Must be mapped directly over a raw device.")
self.fname = filename or (self.session and self.session.GetParameter(
"filename"))
self.as_assert(self.fname, "Filename must be specified.")
# Open as read-only even if writes are supported and allowed, because
# permissions may be set up such that opening for writing would be
# disallowed.
try:
self.fd = open(self.fname, "r")
except (OSError, IOError):
raise addrspace.ASAssertionError(
"Filename does not exist or can not be opened.")
self.fname_info = "%s_info" % self.fname
self.as_assert(path.exists(self.fname_info),
"MacPmem would declare a YML device at %s" %
self.fname_info)
self._load_yml(self.fname_info)
def _get_readable_runs(self, records):
"""Yields all the runs that are safe to read.
This just trusts the EFI bootmap at the moment.
"""
for record in records:
if record["type"] == "efi_range":
if efi_type_readable(record["efi_type"]):
yield (record["start"], record["start"], record["length"],
_StreamWrapper(self.fd))
def ConfigureSession(self, session_obj):
session_obj.SetCache("dtb", self.pmem_metadata["meta"]["dtb_off"],
volatile=False)
session_obj.SetCache("vm_kernel_slide",
self.pmem_metadata["meta"]["kaslr_slide"],
volatile=False)
def _load_yml(self, yml_path):
with open(yml_path) as fp:
data = self.pmem_metadata = yaml_utils.decode(fp.read())
for run in self._get_readable_runs(data["records"]):
self.add_run(*run)
def close(self):
self.fd.close()
# See http://wiki.phoenix.com/wiki/index.php/EFI_MEMORY_TYPE for list of
# segment types that become conventional memory after ExitBootServices()
# is sent to EFI.
EFI_SEGMENTS_SAFETY = {
"EfiReservedMemoryType": "",
"EfiLoaderCode": "rw", # General use.
"EfiLoaderData": "rw", # General use.
"EfiBootServicesCode": "rw", # General use.
"EfiBootServicesData": "rw", # General use.
"EfiRuntimeServicesCode": "r", # Memory to be preserved.
"EfiRuntimeServicesData": "r", # Memory to be preserved.
"EfiConventionalMemory": "r", # General use.
"EfiUnusableMemory": "", # (Hardware) errors - don't use.
"EfiACPIReclaimMemory": "rw", # General use after ACPI enabled.
"EfiACPIMemoryNVS": "r", # Memory to be preserved.
"EfiMemoryMappedIO": "", # ACPI tables.
"EfiMemoryMappedIOPortSpace": "", # ACPI tables.
"EfiPalCode": "r", # OS-dependent. Largely read-only.
"EfiMaxMemoryType": "rw", # No idea (adamsh). Looks like general use?
}
def efi_type_readable(efi_type):
return "r" in EFI_SEGMENTS_SAFETY[str(efi_type)]
|