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

Source Code for Module rekall.plugins.windows.modscan

  1  # Rekall Memory Forensics 
  2  # Copyright (C) 2012 Michael Cohen <scudette@gmail.com> 
  3  # Copyright (C) 2008 Volatile Systems 
  4  # Copyright (c) 2008 Brendan Dolan-Gavitt <bdolangavitt@wesleyan.edu> 
  5  # Copyright 2013 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   
 22  """ 
 23  This module implements the fast module scanning 
 24   
 25  @author:       AAron Walters and Brendan Dolan-Gavitt 
 26  @license:      GNU General Public License 2.0 or later 
 27  @contact:      awalters@volatilesystems.com,bdolangavitt@wesleyan.edu 
 28  @organization: Volatile Systems 
 29  """ 
 30  # pylint: disable=protected-access 
 31  from rekall.plugins.windows import common 
 32  from rekall_lib import utils 
 33   
 34   
35 -class PoolScanModuleFast(common.PoolScanner):
36 - def __init__(self, **kwargs):
37 super(PoolScanModuleFast, self).__init__(**kwargs) 38 self.checks = [ 39 # Must have the right pool tag. 40 ('PoolTagCheck', dict( 41 tag=self.profile.get_constant("MODULE_POOLTAG"))), 42 43 # Must be large enough for an _LDR_DATA_TABLE_ENTRY. Windows 8 seems 44 # to not allocate the full structure here so this test does not 45 # always work. Disabled for now. 46 47 # ('CheckPoolSize', dict(min_size=self.profile.get_obj_size( 48 # "_LDR_DATA_TABLE_ENTRY"))), 49 50 ('CheckPoolType', dict( 51 paged=True, non_paged=True, free=True)), 52 53 ('CheckPoolIndex', dict(value=0)), 54 ]
55 56
57 -class ModScan(common.PoolScannerPlugin):
58 """Scan Physical memory for _LDR_DATA_TABLE_ENTRY objects.""" 59 60 __name = "modscan" 61 62 table_header = [ 63 dict(name="offset", style="address"), 64 dict(name="name", width=20), 65 dict(name="base", style="address"), 66 dict(name="size", style="address"), 67 dict(name="file") 68 ] 69 70 scanner_defaults = dict( 71 scan_kernel_nonpaged_pool=True 72 ) 73
74 - def collect(self):
75 for run in self.generate_memory_ranges(): 76 scanner = PoolScanModuleFast(profile=self.profile, 77 session=self.session, 78 address_space=run.address_space) 79 80 for pool_obj in scanner.scan(run.start, run.length): 81 if not pool_obj: 82 continue 83 84 ldr_entry = self.profile._LDR_DATA_TABLE_ENTRY( 85 vm=run.address_space, offset=pool_obj.obj_end) 86 87 # Must have a non zero size. 88 if ldr_entry.SizeOfImage == 0: 89 continue 90 91 # Must be page aligned. 92 if ldr_entry.DllBase & 0xFFF: 93 continue 94 95 yield (ldr_entry.obj_offset, 96 ldr_entry.BaseDllName.v(vm=self.kernel_address_space), 97 ldr_entry.DllBase, 98 ldr_entry.SizeOfImage, 99 ldr_entry.FullDllName.v(vm=self.kernel_address_space))
100 101
102 -class PoolScanThreadFast(common.PoolScanner):
103 """ Carve out threat objects using the pool tag """
104 - def __init__(self, **kwargs):
105 super(PoolScanThreadFast, self).__init__(**kwargs) 106 self.checks = [ 107 ('PoolTagCheck', dict( 108 tag=self.profile.get_constant("THREAD_POOLTAG"))), 109 110 ('CheckPoolSize', dict(min_size=self.profile.get_obj_size( 111 "_ETHREAD"))), 112 113 ('CheckPoolType', dict( 114 paged=True, non_paged=True, free=True)), 115 116 ('CheckPoolIndex', dict(value=0)), 117 ]
118 119
120 -class ThrdScan(common.PoolScannerPlugin):
121 """Scan physical memory for _ETHREAD objects""" 122 123 __name = "thrdscan" 124 125 table_header = [ 126 dict(name="offset", style="address"), 127 dict(name="pid", width=6, align="r"), 128 dict(name="tid", width=6, align="r"), 129 dict(name="start", style="address"), 130 dict(name="create_time", width=24), 131 dict(name="exit_time", width=24), 132 dict(name="name", width=16), 133 dict(name="symbol"), 134 ] 135 136 scanner_defaults = dict( 137 scan_kernel_nonpaged_pool=True 138 ) 139 140
141 - def collect(self):
142 with self.session.plugins.cc() as cc: 143 for run in self.generate_memory_ranges(): 144 scanner = PoolScanThreadFast( 145 profile=self.profile, session=self.session, 146 address_space=run.address_space) 147 148 for pool_obj in scanner.scan(run.start, run.length): 149 thread = pool_obj.GetObject("Thread").Body.cast("_ETHREAD") 150 if not thread: 151 continue 152 153 if (thread.Cid.UniqueProcess.v() != 0 and 154 thread.StartAddress == 0): 155 continue 156 157 try: 158 # Check the Semaphore Type. 159 if thread.Tcb.SuspendSemaphore.Header.Type != 0x05: 160 continue 161 162 if thread.KeyedWaitSemaphore.Header.Type != 0x05: 163 continue 164 except AttributeError: 165 pass 166 167 # Resolve the thread back to an owning process if possible. 168 task = thread.Tcb.ApcState.Process.dereference_as( 169 "_EPROCESS", vm=self.session.kernel_address_space) 170 171 # Try to switch to the tasks address space in order to 172 # resolve symbols. 173 start_address = thread.Win32StartAddress.v() 174 if start_address < self.session.GetParameter( 175 "highest_usermode_address"): 176 if task != self.session.GetParameter("process_context"): 177 cc.SwitchProcessContext(task) 178 179 else: 180 cc.SwitchProcessContext() 181 182 yield (thread.obj_offset, 183 thread.Cid.UniqueProcess, 184 thread.Cid.UniqueThread, 185 thread.Win32StartAddress.v(), 186 thread.CreateTime, 187 thread.ExitTime, 188 task.ImageFileName, 189 utils.FormattedAddress( 190 self.session.address_resolver, start_address))
191