Package rekall :: Package plugins :: Package response :: Module windows_processes
[frames] | no frames]

Source Code for Module rekall.plugins.response.windows_processes

  1  import weakref 
  2  import win32con 
  3   
  4  import ctypes 
  5  from ctypes import wintypes 
  6  from rekall import addrspace 
  7  from rekall_lib import utils 
  8  from rekall.plugins.overlays import basic 
  9  from rekall.plugins.response import common 
 10  from rekall.plugins.response import processes 
 11   
 12   
 13  READ_ACCESS = (win32con.PROCESS_VM_READ | 
 14                 win32con.PROCESS_VM_OPERATION | 
 15                 win32con.PROCESS_QUERY_INFORMATION) 
 16   
 17  MEMORY_PROTECTIONS = { 
 18      0x10: "x---", 
 19      0x20: "xr--", 
 20      0x40: "xrw-", 
 21      0x80: "xrwc", 
 22      0x01: "----", 
 23      0x02: "-r--", 
 24      0x04: "-rw-", 
 25      0x08: "--wc" 
 26  } 
 27   
 28  MEMORY_TYPES = { 
 29      0x1000000: "MEM_IMAGE", 
 30      0x40000: "MEM_MAPPED", 
 31      0x20000: "MEM_PRIVATE" 
 32  } 
33 34 -class SYSTEM_INFO_32(ctypes.Structure):
35 _fields_ = [("wProcessorArchitecture", wintypes.WORD), 36 ("wReserved", wintypes.WORD), 37 ("dwPageSize", wintypes.DWORD), 38 ("lpMinimumApplicationAddress", wintypes.DWORD), 39 ("lpMaximumApplicationAddress", wintypes.DWORD), 40 ("dwActiveProcessorMask", wintypes.DWORD), 41 ("dwNumberOfProcessors", wintypes.DWORD), 42 ("dwProcessorType", wintypes.DWORD), 43 ("dwAllocationGranularity", wintypes.DWORD), 44 ("wProcessorLevel", wintypes.WORD), 45 ("wProcessorRevision", wintypes.WORD)]
46
47 -class SYSTEM_INFO_64(ctypes.Structure):
48 _fields_ = [("wProcessorArchitecture", wintypes.WORD), 49 ("wReserved", wintypes.WORD), 50 ("dwPageSize", wintypes.DWORD), 51 ("lpMinimumApplicationAddress", wintypes.LARGE_INTEGER), 52 ("lpMaximumApplicationAddress", wintypes.LARGE_INTEGER), 53 ("dwActiveProcessorMask", wintypes.LARGE_INTEGER), 54 ("dwNumberOfProcessors", wintypes.DWORD), 55 ("dwProcessorType", wintypes.DWORD), 56 ("dwAllocationGranularity", wintypes.DWORD), 57 ("wProcessorLevel", wintypes.WORD), 58 ("wProcessorRevision", wintypes.WORD)]
59
60 61 -class MEMORY_BASIC_INFORMATION_32(ctypes.Structure):
62 _fields_ = [ 63 ("BaseAddress", wintypes.DWORD), 64 ("AllocationBase", wintypes.DWORD), 65 ("AllocationProtect", wintypes.DWORD), 66 ("RegionSize", wintypes.UINT), 67 ("State", wintypes.DWORD), 68 ("Protect", wintypes.DWORD), 69 ("Type", wintypes.DWORD) 70 ]
71
72 73 -class MEMORY_BASIC_INFORMATION_64(ctypes.Structure):
74 _fields_ = [ 75 ("BaseAddress", wintypes.LARGE_INTEGER), 76 ("AllocationBase", wintypes.LARGE_INTEGER), 77 ("AllocationProtect", wintypes.DWORD), 78 ("RegionSize", wintypes.LARGE_INTEGER), 79 ("State", wintypes.DWORD), 80 ("Protect", wintypes.DWORD), 81 ("Type", wintypes.DWORD) 82 ]
83 84 OpenProcess = ctypes.windll.kernel32.OpenProcess 85 ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory 86 ReadProcessMemory.argtypes = [wintypes.HANDLE, 87 wintypes.LPCVOID, 88 wintypes.LPVOID, 89 ctypes.c_size_t, 90 ctypes.POINTER(ctypes.c_size_t)] 91 ReadProcessMemory.restype = wintypes.BOOL 92 93 CloseHandle = ctypes.windll.kernel32.CloseHandle 94 95 96 GetMappedFileNameA = ctypes.windll.psapi.GetMappedFileNameA 97 GetMappedFileNameA.argtypes = [wintypes.HANDLE, 98 wintypes.LPVOID, 99 wintypes.LPSTR, 100 wintypes.DWORD] 101 GetMappedFileNameA.restype = wintypes.DWORD 102 103 VirtualQueryEx = ctypes.windll.kernel32.VirtualQueryEx 104 VirtualQueryEx.argtypes = [wintypes.HANDLE, 105 wintypes.LPCVOID, 106 wintypes.LPVOID, 107 wintypes.DWORD] 108 VirtualQueryEx.restype = wintypes.DWORD 109 110 MAX_PATH = 1024
111 112 113 -class ProcessHandle(object):
114 - def __init__(self, pid):
115 handle = self.handle = ctypes.windll.kernel32.OpenProcess( 116 READ_ACCESS, # win32con.PROCESS_ALL_ACCESS, 117 False, 118 pid) 119 120 # Close the handle on GC so we do not leak handles. 121 self._closer = weakref.ref(self, lambda x: CloseHandle(handle))
122
123 124 -class LiveVad(utils.AttributeDict):
125 """Collect information about a VAD region. 126 127 This is the Live equivalent of _MMVAD. 128 """ 129 130 @utils.safe_property
131 - def length(self):
132 return self.end - self.start
133
134 135 -class APIVad(processes.APIProcessFilter):
136 """A VAD plugin using the APIs.""" 137 138 name = "vad" 139 140 __args = [ 141 dict(name="regex", type="RegEx", 142 help="A regular expression to filter VAD filenames."), 143 144 dict(name="offset", type="SymbolAddress", 145 help="Only print the vad corresponding to this offset."), 146 147 dict(name="verbosity", type="IntParser", default=1, 148 help="With high verbosity print more information on each region."), 149 ] 150 151 table_header = [ 152 dict(name='proc', type="proc", hidden=True), 153 dict(name="divider", type="Divider"), 154 dict(name='VAD', hidden=True), 155 dict(name='start', style="address"), 156 dict(name='end', style="address"), 157 dict(name='Protect', width=4), 158 dict(name='filename') 159 ] 160
161 - def generate_vads(self, pid):
162 process_handle = ProcessHandle(pid) 163 164 if not process_handle.handle: 165 return 166 167 SYSTEM_INFO = SYSTEM_INFO_64 168 MEMORY_BASIC_INFORMATION = MEMORY_BASIC_INFORMATION_64 169 170 system_info = SYSTEM_INFO() 171 psystem_info = ctypes.byref(system_info) 172 ctypes.windll.kernel32.GetSystemInfo(psystem_info) 173 174 base_address = system_info.lpMinimumApplicationAddress 175 max_address = system_info.lpMaximumApplicationAddress 176 page_address = base_address 177 178 while page_address < max_address: 179 mbi = MEMORY_BASIC_INFORMATION() 180 mbi_pointer = ctypes.byref(mbi) 181 size = ctypes.sizeof(mbi) 182 success = VirtualQueryEx( 183 process_handle.handle, 184 page_address, 185 mbi_pointer, 186 size) 187 188 if not success: 189 break 190 191 if mbi.AllocationProtect != 0: 192 # Try to resolve the filename if possible. 193 filename = ctypes.create_string_buffer("", MAX_PATH) 194 copied = GetMappedFileNameA( 195 process_handle.handle, page_address, filename, MAX_PATH) 196 if copied > 0: 197 filename = filename.value 198 else: 199 filename = None 200 201 yield LiveVad( 202 start=mbi.BaseAddress, 203 end=mbi.BaseAddress + mbi.RegionSize, 204 protection=mbi.AllocationProtect, 205 current_protection=mbi.Protect, 206 type=MEMORY_TYPES.get(mbi.Type, mbi.Type), 207 filename=filename, 208 pid=pid 209 ) 210 211 page_address = mbi.BaseAddress + mbi.RegionSize
212
213 - def merge_ranges(self, pid):
214 """Generate merged ranges.""" 215 old_vad = None 216 217 for vad in self.generate_vads(pid): 218 # Try to merge this range with the previous range. 219 if (old_vad and 220 old_vad.end == vad.start and 221 old_vad.protection == vad.protection and 222 old_vad.filename == vad.filename): 223 old_vad.end = vad.end 224 continue 225 226 # Yield the old range: 227 if old_vad: 228 yield old_vad 229 230 old_vad = vad 231 232 # Emit the last range. 233 if old_vad: 234 yield old_vad
235
236 - def collect(self):
237 generator = self.generate_vads 238 if self.plugin_args.verbosity <= 1: 239 generator = self.merge_ranges 240 241 for proc in self.filter_processes(): 242 divider = "{0} pid: {1:6}\n".format(proc.name, proc.pid) 243 yield dict(divider=divider) 244 245 for vad in generator(proc.pid): 246 if (self.plugin_args.regex and not 247 self.plugin_args.regex.search(vad.filename or "")): 248 continue 249 250 if (self.plugin_args.offset is not None and 251 not vad.start <= self.plugin_args.offset <= vad.end): 252 continue 253 254 yield dict(proc=proc, 255 VAD=vad, 256 start=vad.start, 257 end=vad.end, 258 Protect=MEMORY_PROTECTIONS.get( 259 vad.protection), 260 filename=vad.filename)
261
262 263 -class WinAPIProcessAddressSpace(addrspace.RunBasedAddressSpace):
264 """An address space which read processes using ReadProcessMemory().""" 265
266 - def __init__(self, pid=None, **kwargs):
267 super(WinAPIProcessAddressSpace, self).__init__(**kwargs) 268 269 self.process_handle = ProcessHandle(pid) 270 for vad in self.session.plugins.vad().merge_ranges(pid): 271 self.add_run(vad.start, vad.start, vad.length, 272 address_space=self, data=dict(pid=pid, vad=vad))
273
274 - def read(self, addr, length):
275 if length > self.session.GetParameter("buffer_size"): 276 raise IOError("Too much data to read.") 277 278 result = ctypes.create_string_buffer(length) 279 bytes_read = ctypes.c_size_t() 280 status = ReadProcessMemory( 281 self.process_handle.handle, 282 addr, result, length, ctypes.byref(bytes_read)) 283 284 # Failed ... return zeros. 285 if status == 0: 286 return addrspace.ZEROER.GetZeros(length) 287 288 return result.raw
289 290 # Register the process AS as a windows one. 291 common.IRProcessAddressSpace = WinAPIProcessAddressSpace
292 293 294 -def is_wow64(proc):
295 """Determine if the proc is Wow64.""" 296 # Not the most accurate method but very fast. 297 return (proc.environ.get("PROCESSOR_ARCHITECTURE") == 'x86' and 298 proc.environ.get("PROCESSOR_ARCHITEW6432") == 'AMD64')
299
300 301 -class WinAPIProfile(common.APIBaseProfile):
302 """Profile for Windows live analysis.""" 303
304 - def __init__(self, proc=None, **kwargs):
305 super(WinAPIProfile, self).__init__(**kwargs) 306 307 # This is a profile for a dll or module in the current process 308 # context. Depending if the current process is a Wow64 process we need 309 # to load the 32 or 64 bit profiles. 310 process_context = proc or self.session.GetParameter("process_context") 311 if process_context: 312 if is_wow64(process_context): 313 basic.Profile32Bits.Initialize(self) 314 else: 315 basic.ProfileLLP64.Initialize(self)
316 317 318 # Register the profile for windows. 319 common.IRProfile = WinAPIProfile 320