Package rekall :: Package plugins :: Package windows :: Module kernel
[frames] | no frames]

Source Code for Module rekall.plugins.windows.kernel

  1  #!/usr/bin/python 
  2   
  3  # Rekall Memory Forensics 
  4  # Copyright (C) 2014 Michael Cohen <scudette@gmail.com> 
  5  # Copyright 2014 Google Inc. All Rights Reserved. 
  6  # 
  7  # This program is free software; you can redistribute it and/or modify 
  8  # it under the terms of the GNU General Public License as published by 
  9  # the Free Software Foundation; either version 2 of the License, or (at 
 10  # your option) any later version. 
 11  # 
 12  # This program is distributed in the hope that it will be useful, but 
 13  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 15  # General Public License for more details. 
 16  # 
 17  # You should have received a copy of the GNU General Public License 
 18  # along with this program; if not, write to the Free Software 
 19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 20  # 
 21  """This module discovers the kernel base address. 
 22   
 23  The profile provides kernel addresses relative to the kernel base address. This 
 24  varies each time, so we need a way to locate the kernel base address in the 
 25  kernel address space. 
 26  """ 
 27   
 28  __author__ = "Michael Cohen <scudette@google.com>" 
 29   
 30  from rekall import obj 
 31  from rekall import scan 
 32  from rekall.plugins import core 
 33  from rekall.plugins.windows import common 
 34  from rekall.plugins.overlays.windows import pe_vtypes 
35 36 37 -class ExportScanner(scan.BaseScanner):
38 # We search for the name of a section present in the PE header. 39 checks = [("MultiStringFinderCheck", dict(needles=[ 40 "INITKDBG", "MISYSPTE", "PAGEKD"]))]
41
42 43 -class ObjectTreeHook(common.AbstractWindowsParameterHook):
44 """Cache the object tree.""" 45 46 name = "object_tree" 47
48 - def BuildTree(self, result, root, seen):
49 for x in root: 50 # This prevents circular references to parent objects. They should 51 # never happen but some possibly corrupt images may contain links to 52 # parent objects. 53 if x.obj_offset in seen: 54 continue 55 56 seen.add(x.obj_offset) 57 58 name = x.NameInfo.Name.v() 59 if name == None: 60 continue 61 62 # We store the _OBJECT_HEADER offset and some metadata about the 63 # types. 64 object_type = x.get_object_type() 65 entry = result[name] = dict( 66 type=object_type, 67 type_name="_OBJECT_HEADER", 68 offset=x.obj_offset, 69 ) 70 71 if object_type == "Directory": 72 children = entry["Children"] = {} 73 self.BuildTree(children, x.Object, seen)
74 75 @core.MethodWithAddressSpace()
76 - def calculate(self):
77 seen = set() 78 79 root = self.session.profile.get_constant_object( 80 "ObpRootDirectoryObject", 81 target="Pointer", 82 target_args=dict( 83 target="_OBJECT_DIRECTORY" 84 ) 85 ) 86 87 result = dict( 88 type="Directory", 89 type_name="_OBJECT_DIRECTORY", 90 offset=root.deref().obj_offset, 91 Children={}) 92 93 self.BuildTree(result["Children"], root, seen) 94 return result
95
96 97 -class DriveLetterDeviceHook(common.AbstractWindowsParameterHook):
98 """Maps device names to drive letters.""" 99 100 name = "drive_letter_device_map" 101 102 @core.MethodWithAddressSpace()
103 - def calculate(self):
104 try: 105 result = {} 106 obj_tree_plugin = self.session.plugins.object_tree() 107 # The global path contains symlinks from the drive letter to the 108 # device name. 109 for global_obj in obj_tree_plugin.GetObjectByName( 110 r"\GLOBAL??").Object: 111 name = global_obj.NameInfo.Name.v() 112 if (global_obj.get_object_type() == "SymbolicLink" and 113 len(name) > 1 and name[1] == ":"): 114 target = global_obj.Object.LinkTarget.v() 115 116 result[target] = name 117 118 return result 119 120 # If we fail to traverse the object tree we just return None which will 121 # fail to resolve this drive letter but will try again next time. 122 except KeyError: 123 return None
124
125 126 -class KernelBaseHook(common.AbstractWindowsParameterHook):
127 """Finds the kernel base address.""" 128 129 name = "kernel_base" 130
131 - def calculate(self):
132 address_space = self.session.kernel_address_space 133 if not address_space: 134 return 135 136 scanner = ExportScanner(session=self.session, 137 address_space=address_space) 138 139 # The kernel image is always loaded in the same range called the 140 # "Initial Loader Mappings". Narrowing the possible range makes scanning 141 # much faster. (See http://www.codemachine.com/article_x64kvas.html) 142 if self.session.profile.metadata("arch") == "AMD64": 143 kernel_boundary = 0xFFFFF80000000000 144 else: 145 kernel_boundary = 0x80000000 146 147 maxlen = 0xFFFFF87FFFFFFFFF - kernel_boundary 148 kernel_boundary = obj.Pointer.integer_to_address(kernel_boundary) 149 for hit in scanner.scan(offset=kernel_boundary, maxlen=maxlen): 150 151 # Search backwards for an MZ signature on the page boundary. 152 page = hit & 0xFFFFFFFFFFFFF000 153 for _ in range(10): 154 if address_space.read(page, 2) == "MZ": 155 helper = pe_vtypes.PE( 156 address_space=address_space, 157 session=self.session, image_base=page) 158 159 if str(helper.RSDS.Filename) in common.KERNEL_NAMES: 160 self.session.logging.info( 161 "Detected kernel base at 0x%X", page) 162 return page 163 else: 164 page -= 0x1000
165
166 167 -class WindowsHighestUserAddress(common.AbstractWindowsParameterHook):
168 """The highest address for user mode/kernel mode division.""" 169 170 name = "highest_usermode_address" 171
172 - def calculate(self):
173 result = self.session.profile.get_constant_object( 174 "MmHighestUserAddress", "Pointer").v() 175 176 # Sometimes the pointer is not present, in that case we use hardcoded 177 # values. I dont think these values will ever change, maybe we should 178 # just hard code them anyway. 179 if result == 0: 180 if self.profile.metadata("arch") == "AMD64": 181 result = 0x7fffffeffff 182 result = 0x7ffeffff 183 184 return result
185
186 187 -class DTB2TaskMap(common.AbstractWindowsParameterHook):
188 """Maps the DTB to the _EPROCESS structs.""" 189 190 name = "dtb2task" 191
192 - def calculate(self):
193 result = {} 194 for task in self.session.plugins.pslist().filter_processes(): 195 result[int(task.dtb)] = task.obj_offset 196 197 return result
198