/usr/lib/python2.7/dist-packages/rekall/plugins/windows/index.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 | # Rekall Memory Forensics
# Copyright 2014 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
#
"""This module implements profile indexing.
Rekall relies on accurate profiles for reliable analysis of memory artifacts. We
depend on selecting the correct profile from the profile repository, but
sometimes its hard to determine the exact profile to use. For windows, the
profile must match exactly the GUID in the driver.
However, sometimes, the GUID is unavailable or it could be manipulated. In that
case we would like to determine the profile version by applying the index.
The profile repository has an index for each kernel module stored. We can use
this index to determine the exact version of the profile very quickly - even if
the RSDS GUID is not available or incorrect.
"""
__author__ = "Michael Cohen <scudette@google.com>"
from rekall import obj
from rekall import testlib
from rekall.plugins.windows import common
from rekall.plugins.overlays import basic
class GuessGUID(common.WindowsCommandPlugin):
"""Try to guess the exact version of a kernel module by using an index."""
name = "guess_guid"
__args = [
dict(name="module", positional=True,
help="The name of the module to guess."),
dict(name="minimal_match", default=1, type="IntParser",
help="The minimal number of comparison points to be considered. "
"Sometimes not all comparison points can be used since they may "
"not be mapped."),
]
table_header = [
dict(name="pid", width=20),
dict(name="session", width=20),
dict(name="profile"),
]
def ScanProfile(self):
"""Scan for module using version_scan for RSDS scanning."""
module_name = self.plugin_args.module.split(".")[0]
for _, guid in self.session.plugins.version_scan(
name_regex="^%s.pdb" % module_name).ScanVersions():
yield obj.NoneObject(), "%s/GUID/%s" % (module_name, guid)
def LookupIndex(self):
"""Loookup the profile from an index."""
try:
index = self.session.LoadProfile(
"%s/index" % self.plugin_args.module)
except ValueError:
return
cc = self.session.plugins.cc()
for session in self.session.plugins.sessions().session_spaces():
# Switch the process context to this session so the address
# resolver can find the correctly mapped driver.
with cc:
cc.SwitchProcessContext(iter(session.processes()).next())
# Get the image base of the win32k module.
image_base = self.session.address_resolver.get_address_by_name(
self.plugin_args.module)
for profile, _ in index.LookupIndex(
image_base, minimal_match=self.plugin_args.minimal_match):
yield self.session.GetParameter("process_context"), profile
def GuessProfiles(self):
"""Search for suitable profiles using a variety of methods."""
# Usually this plugin is invoked from ParameterHooks which will take the
# first hit. So we try to do the fast methods first, then fall back to
# the slower methods.
for x in self.LookupIndex():
yield x
# Looking up the index failed because it was not there, or the index did
# not contain the right profile - fall back to RSDS scanning.
for x in self.ScanProfile():
yield x
def collect(self):
for context, possibility in self.GuessProfiles():
yield (context.pid, context.SessionId, possibility)
class EProcessIndex(basic.ProfileLLP64):
"""A profile index for _EPROCESS structs."""
@classmethod
def Initialize(cls, profile):
super(EProcessIndex, cls).Initialize(profile)
profile.add_types({
'_KUSER_SHARED_DATA': [None, {
"NtMajorVersion": [620, ["unsigned long", {}]],
"NtMinorVersion": [624, ["unsigned long", {}]],
}]
})
def LoadIndex(self, index):
self.index = index
# Consolidate all the relative offsets from the ImageFileName to the
# DirectoryTableBase.
self.filename_to_dtb = set()
for metadata in index.values():
offsets = metadata["offsets"]
relative_offset = offsets["_EPROCESS.ImageFileName"] - (
offsets["_EPROCESS.Pcb"] +
offsets["_KPROCESS.DirectoryTableBase"])
arch = metadata.get("arch", "AMD64")
self.filename_to_dtb.add((relative_offset, arch))
class TestGuessGUID(testlib.SortedComparison):
PARAMETERS = dict(
commandline="guess_guid win32k"
)
|