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

Source Code for Module rekall.plugins.windows.modules

  1  # Rekall Memory Forensics 
  2  # 
  3  # Copyright 2013 Google Inc. All Rights Reserved. 
  4  # 
  5  # Authors: 
  6  # Michael Cohen <scudette@gmail.com> 
  7  # 
  8  # This program is free software; you can redistribute it and/or modify 
  9  # it under the terms of the GNU General Public License as published by 
 10  # the Free Software Foundation; either version 2 of the License, or (at 
 11  # your option) any later version. 
 12  # 
 13  # This program is distributed in the hope that it will be useful, but 
 14  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 16  # General Public License for more details. 
 17  # 
 18  # You should have received a copy of the GNU General Public License 
 19  # along with this program; if not, write to the Free Software 
 20  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 21  # 
 22   
 23  from rekall import plugin 
 24  from rekall import scan 
 25  from rekall.plugins.windows import common 
 26  from rekall_lib import utils 
 27   
 28   
29 -class Modules(common.WindowsCommandPlugin):
30 """Print list of loaded kernel modules.""" 31 32 __name = "modules" 33 34 __args = [ 35 dict(name="name_regex", type="RegEx", 36 help="Filter module names by this regex.") 37 ] 38 39 table_header = [ 40 dict(name="_LDR_DATA_TABLE_ENTRY", style="address"), 41 dict(name="name", width=20), 42 dict(name="base", style="address"), 43 dict(name="size", style="address"), 44 dict(name="path") 45 ] 46
47 - def lsmod(self):
48 """ A Generator for modules (uses _KPCR symbols) """ 49 for module in self.session.GetParameter( 50 "PsLoadedModuleList").list_of_type( 51 "_LDR_DATA_TABLE_ENTRY", "InLoadOrderLinks"): 52 53 # Skip modules which do not match. 54 if (self.plugin_args.name_regex and 55 not self.plugin_args.name_regex.search( 56 utils.SmartUnicode(module.FullDllName))): 57 continue 58 59 yield module
60
61 - def addresses(self):
62 """Returns a list of module addresses.""" 63 return sorted(self.mod_lookup.keys())
64
65 - def collect(self):
66 object_tree_plugin = self.session.plugins.object_tree() 67 68 for module in self.lsmod(): 69 yield dict(_LDR_DATA_TABLE_ENTRY=module, 70 name=module.BaseDllName, 71 base=module.DllBase, 72 size=module.SizeOfImage, 73 path=object_tree_plugin.FileNameWithDrive( 74 module.FullDllName.v()))
75 76
77 -class RSDSScanner(scan.BaseScanner):
78 """Scan for RSDS objects.""" 79 80 checks = [ 81 ("StringCheck", dict(needle="RSDS")) 82 ]
83 84
85 -class ModVersions(Modules):
86 """Try to determine the versions for all kernel drivers.""" 87 88 __name = "version_modules" 89 90 table_header = [ 91 dict(name="offset_v", style="address"), 92 dict(name="name", width=20), 93 dict(name="guid", width=33), 94 dict(name="pdb") 95 ] 96
97 - def ScanVersions(self):
98 pe_profile = self.session.LoadProfile("pe") 99 scanner = RSDSScanner(address_space=self.kernel_address_space, 100 session=self.session) 101 102 for module in self.lsmod(): 103 for hit in scanner.scan(offset=int(module.DllBase), 104 maxlen=int(module.SizeOfImage)): 105 106 rsds = pe_profile.CV_RSDS_HEADER(offset=hit, 107 vm=self.kernel_address_space) 108 guid = "%s%x" % (rsds.GUID.AsString, rsds.Age) 109 yield module, rsds, guid
110
111 - def collect(self):
112 for module, rsds, guid in self.ScanVersions(): 113 yield dict(offset_v=rsds, 114 name=module.BaseDllName, 115 guid=guid, 116 pdb=rsds.Filename)
117 118
119 -class VersionScan(plugin.PhysicalASMixin, plugin.TypedProfileCommand, 120 plugin.Command):
121 """Scan the physical address space for RSDS versions.""" 122 123 __name = "version_scan" 124 125 PHYSICAL_AS_REQUIRED = False 126 127 __args = [ 128 dict(name="name_regex", type="RegEx", default=".", 129 help="Filter module names by this regex."), 130 131 dict(name="scan_filename", required=False, positional=True, 132 help="Optional file to scan. If not specified " 133 "we scan the physical address space.") 134 ] 135 136 table_header = [ 137 dict(name="offset", style="address"), 138 dict(name="guid", width=33), 139 dict(name="pdb", width=30) 140 ] 141
142 - def __init__(self, *args, **kwargs):
143 """List kernel modules by walking the PsLoadedModuleList.""" 144 super(VersionScan, self).__init__(*args, **kwargs) 145 if self.plugin_args.scan_filename is not None: 146 load_as = self.session.plugins.load_as() 147 self.physical_address_space = load_as.GuessAddressSpace( 148 filename=self.plugin_args.scan_filename)
149
150 - def ScanVersions(self):
151 """Scans the physical AS for RSDS structures.""" 152 guids = set() 153 pe_profile = self.session.LoadProfile("pe") 154 scanner = RSDSScanner(address_space=self.physical_address_space, 155 session=self.session, profile=pe_profile) 156 157 for hit in scanner.scan(0, self.physical_address_space.end()): 158 rsds = pe_profile.CV_RSDS_HEADER( 159 offset=hit, vm=self.physical_address_space) 160 161 # The filename must end with pdb for valid pdb. 162 if not unicode(rsds.Filename).endswith("pdb"): 163 continue 164 165 guid = rsds.GUID_AGE 166 if guid not in guids: 167 guids.add(guid) 168 169 if self.plugin_args.name_regex.search(unicode(rsds.Filename)): 170 yield rsds, guid
171
172 - def collect(self):
173 for rsds, guid in self.ScanVersions(): 174 yield dict(offset=rsds, guid=guid, pdb=rsds.Filename)
175 176
177 -class UnloadedModules(common.WindowsCommandPlugin):
178 """Print a list of recently unloaded modules. 179 180 Ref: 181 http://volatility-labs.blogspot.de/2013/05/movp-ii-22-unloaded-windows-kernel_22.html 182 """ 183 184 name = "unloaded_modules" 185 186 table_header = [ 187 dict(name="name", width=20), 188 dict(name="start", style="address"), 189 dict(name="end", style="address"), 190 dict(name="time") 191 ] 192
193 - def collect(self):
194 unloaded_table = self.profile.get_constant_object( 195 "MmUnloadedDrivers", 196 target="Pointer", 197 target_args=dict( 198 target="Array", 199 target_args=dict( 200 target="_UNLOADED_DRIVER", 201 count=self.profile.get_constant_object( 202 "MmLastUnloadedDriver", "unsigned int").v(), 203 ) 204 ) 205 ) 206 207 # In Windows 10 this has moved to the MiState. 208 if unloaded_table == None: 209 mistate = self.profile.get_constant_object( 210 "MiState", target="_MI_SYSTEM_INFORMATION") 211 212 unloaded_table = mistate.multi_m( 213 "UnloadedDrivers", 214 "Vs.UnloadedDrivers" 215 ).dereference_as( 216 "Array", 217 target_args=dict( 218 target="_UNLOADED_DRIVERS", 219 count=mistate.LastUnloadedDriver) 220 ) 221 222 for driver in unloaded_table: 223 yield (driver.Name, 224 driver.StartAddress.v(), 225 driver.EndAddress.v(), 226 driver.CurrentTime)
227