Package rekall :: Package plugins :: Package darwin :: Module processes
[frames] | no frames]

Source Code for Module rekall.plugins.darwin.processes

  1  # Rekall Memory Forensics 
  2  # 
  3  # Copyright 2013 Google Inc. All Rights Reserved. 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or (at 
  8  # your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, but 
 11  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 13  # General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License 
 16  # along with this program; if not, write to the Free Software 
 17  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 18   
 19  """ 
 20  Darwin Process collectors. 
 21  """ 
 22   
 23  __author__ = "Adam Sindelar <adamsh@google.com>" 
 24   
 25  from rekall import plugin 
 26  from rekall_lib import registry 
 27   
 28  from rekall.plugins import core 
 29  from rekall.plugins.darwin import common 
 30  from rekall.plugins.common import memmap 
31 32 33 -class DarwinPslist(common.ProcessFilterMixin, 34 common.AbstractDarwinCommand):
35 name = "pslist" 36 37 table_header = [ 38 dict(width=40, name="proc", type="proc"), 39 dict(width=8, name="alive"), 40 dict(name="ppid", width=6), 41 dict(name="uid", width=6), 42 dict(name="is64bit", width=6), 43 dict(name="start_time", width=30, style="short"), 44 dict(name="cr3", width=15, style="address") 45 ] 46
47 - def collect(self):
48 for proc in self.filter_processes(): 49 yield dict( 50 proc=proc, 51 alive=proc.obj_producers != {"dead_procs"}, 52 ppid=proc.p_ppid, 53 uid=proc.p_uid, 54 is64bit=proc.task.map.pmap.pm_task_map == "TASK_MAP_64BIT", 55 start_time=proc.p_start.as_datetime(), 56 cr3=proc.task.map.pmap.pm_cr3 57 )
58
59 60 -class DarwinPsxView(common.ProcessFilterMixin, 61 common.AbstractDarwinCommand):
62 name = "psxview" 63 64 # pylint: disable=no-self-argument 65 @registry.classproperty 66 @registry.memoize
67 - def table_header(cls):
68 header = [dict(width=40, name="proc", type="proc")] 69 70 for method in cls.methods(): 71 header.append(dict(name=method, width=8)) 72 73 return plugin.PluginHeader(*header)
74
75 - def collect(self):
76 methods = self.methods() 77 for proc in self.filter_processes(): 78 row = [proc] 79 for method in methods: 80 row.append(method in proc.obj_producers) 81 82 yield row
83
84 85 -class DarwinPsTree(common.AbstractDarwinCommand):
86 name = "pstree" 87 88 table_header = [ 89 dict(name="depth", type="DepthIndicator", width=10), 90 dict(name="pid", width=6), 91 dict(name="ppid", width=6), 92 dict(name="uid", width=6), 93 dict(name="name", width=30) 94 ] 95
96 - def collect(self):
97 # Get the first process from pslist. 98 first_proc = self.session.plugins.search( 99 "(select * from pslist() where proc.pid == 0).proc").first_result 100 for proc, depth in self.recurse_proc(first_proc, 0): 101 yield [depth, proc.pid, proc.p_ppid, proc.p_uid, proc.command]
102
103 - def recurse_proc(self, proc, depth):
104 if proc.validate(): 105 yield proc, depth 106 for child in proc.p_children.lh_first.p_sibling: 107 for subproc, subdepth in self.recurse_proc(child, depth + 1): 108 yield subproc, subdepth
109
110 111 -class DarwinMaps(common.ProcessFilterMixin, common.AbstractDarwinCommand):
112 """Display the process maps.""" 113 114 __name = "maps" 115
116 - def render(self, renderer):
117 renderer.table_header([ 118 dict(name="vm_map_entry", style="address"), 119 dict(name="Proc", width=40), 120 ("Start", "start", "[addrpad]"), 121 ("End", "end", "[addrpad]"), 122 ("Protection", "protection", "6"), 123 dict(name="Map Name", wrap=False), 124 ]) 125 126 for proc in self.filter_processes(): 127 for map in proc.task.map.hdr.walk_list( 128 "links.next", include_current=False): 129 130 # Format the map permissions nicesly. 131 protection = ( 132 ("r" if map.protection.VM_PROT_READ else "-") + 133 ("w" if map.protection.VM_PROT_WRITE else "-") + 134 ("x" if map.protection.VM_PROT_EXECUTE else "-")) 135 136 # Find the vnode this mapping is attached to. 137 vnode = map.find_vnode_object() 138 139 renderer.table_row( 140 map, 141 proc, 142 map.links.start, 143 map.links.end, 144 protection, 145 "sub_map" if map.is_sub_map else vnode.path, 146 )
147
148 149 -class DarwinVadDump(core.DirectoryDumperMixin, common.ProcessFilterMixin, 150 common.AbstractDarwinCommand):
151 """Dump the VMA memory for a process.""" 152 153 __name = "vaddump" 154
155 - def render(self, renderer):
156 for proc in self.filter_processes(): 157 if not proc.task.map.pmap: 158 continue 159 160 renderer.format("Pid: {0:6}\n", proc.p_pid) 161 162 # Get the task and all process specific information 163 task_space = proc.get_process_address_space() 164 name = proc.p_comm 165 166 for vma in proc.task.map.hdr.walk_list( 167 "links.next", include_current=False): 168 filename = "{0}.{1}.{2:08x}-{3:08x}.dmp".format( 169 name, proc.p_pid, vma.links.start, vma.links.end) 170 171 renderer.format(u"Writing {0}, pid {1} to {2}\n", 172 proc.p_comm, proc.p_pid, filename) 173 174 with renderer.open(directory=self.dump_dir, 175 filename=filename, 176 mode='wb') as fd: 177 self.CopyToFile(task_space, vma.links.start, 178 vma.links.end, fd)
179
180 181 -class DarwinPSAUX(common.ProcessFilterMixin, common.AbstractDarwinCommand):
182 """List processes with their commandline.""" 183 184 __name = "psaux" 185
186 - def render(self, renderer):
187 renderer.table_header([ 188 ("Pid", "pid", "8"), 189 ("Name", "name", "20"), 190 ("Stack", "stack", "[addrpad]"), 191 ("Length", "length", "8"), 192 ("Argc", "argc", "8"), 193 ("Arguments", "argv", "[wrap:80]")]) 194 195 for proc in self.filter_processes(): 196 renderer.table_row( 197 proc.p_pid, 198 proc.p_comm, 199 proc.user_stack, 200 proc.p_argslen, 201 proc.p_argc, 202 " ".join(proc.argv))
203
204 205 -class DarwinMemMap(memmap.MemmapMixIn, common.ProcessFilterMixin, 206 common.AbstractDarwinCommand):
207 """Prints the memory map for darwin tasks.""" 208 __name = "memmap" 209
211 return 0x800000000000
212
213 214 -class DarwinMemDump(memmap.MemDumpMixin, common.ProcessFilterMixin, 215 common.AbstractDarwinCommand):
216 """Dumps the memory map for darwin tasks."""
217
218 219 # Plugins below represent different enumeration methods for process filter: 220 221 222 -class PsListAllProcHook(common.AbstractDarwinParameterHook):
223 """List all processes by following the _allproc list head.""" 224 225 name = "allproc" 226
227 - def calculate(self):
228 first = self.session.profile.get_constant_object( 229 "_allproc", target="proclist").lh_first 230 231 result = set(first.p_list) 232 return [x.obj_offset for x in result]
233
234 235 -class PsListTasksHook(common.AbstractDarwinParameterHook):
236 """List all processes by following the _allproc list head.""" 237 238 name = "tasks" 239
240 - def calculate(self):
241 """List processes using the processor tasks queue. 242 243 See 244 /osfmk/kern/processor.c (processor_set_things) 245 """ 246 seen = set() 247 248 tasks = self.session.profile.get_constant_object( 249 "_tasks", 250 target="queue_entry", 251 vm=self.session.kernel_address_space) 252 253 for task in tasks.list_of_type("task", "tasks"): 254 proc = task.bsd_info.deref() 255 if proc: 256 seen.add(proc.obj_offset) 257 258 return seen
259
260 261 -class PsListPgrpHashHook(common.AbstractDarwinParameterHook):
262 """List all processes by following the _allproc list head.""" 263 264 name = "pgrphash" 265
266 - def calculate(self):
267 """Process groups are organized in a hash chain. 268 269 xnu-1699.26.8/bsd/sys/proc_internal.h 270 """ 271 seen = set() 272 273 # Note that _pgrphash is initialized through: 274 275 # xnu-1699.26.8/bsd/kern/kern_proc.c:195 276 # hashinit(int elements, int type, u_long *hashmask) 277 278 # /xnu-1699.26.8/bsd/kern/kern_subr.c: 327 279 # hashinit(int elements, int type, u_long *hashmask) { 280 # ... 281 # *hashmask = hashsize - 1; 282 283 # Hence the value in _pgrphash is one less than the size of the hash 284 # table. 285 pgr_hash_table = self.session.profile.get_constant_object( 286 "_pgrphashtbl", 287 target="Pointer", 288 target_args=dict( 289 target="Array", 290 target_args=dict( 291 target="pgrphashhead", 292 count=self.session.profile.get_constant_object( 293 "_pgrphash", "unsigned long") + 1 294 ) 295 ) 296 ) 297 298 for slot in pgr_hash_table.deref(): 299 for pgrp in slot.lh_first.walk_list("pg_hash.le_next"): 300 for proc in pgrp.pg_members.lh_first.walk_list( 301 "p_pglist.le_next"): 302 seen.add(proc.obj_offset) 303 304 return seen
305
306 307 -class PsListPidHashHook(common.AbstractDarwinParameterHook):
308 """List all processes by following the _allproc list head.""" 309 310 name = "pidhash" 311
312 - def calculate(self):
313 """Lists processes using pid hash tables. 314 315 xnu-1699.26.8/bsd/kern/kern_proc.c:834: 316 pfind_locked(pid_t pid) 317 """ 318 seen = set() 319 320 # Note that _pidhash is initialized through: 321 322 # xnu-1699.26.8/bsd/kern/kern_proc.c:194 323 # pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash); 324 325 # /xnu-1699.26.8/bsd/kern/kern_subr.c: 327 326 # hashinit(int elements, int type, u_long *hashmask) { 327 # ... 328 # *hashmask = hashsize - 1; 329 330 # Hence the value in pidhash is one less than the size of the hash 331 # table. 332 pid_hash_table = self.session.profile.get_constant_object( 333 "_pidhashtbl", 334 target="Pointer", 335 target_args=dict( 336 target="Array", 337 target_args=dict( 338 target="pidhashhead", 339 count=self.session.profile.get_constant_object( 340 "_pidhash", "unsigned long") + 1 341 ) 342 ) 343 ) 344 345 for plist in pid_hash_table.deref(): 346 for proc in plist.lh_first.walk_list("p_hash.le_next"): 347 if proc: 348 seen.add(proc.obj_offset) 349 350 return seen
351
352 353 -class DarwinPgrpHashCollector(common.AbstractDarwinCachedProducer):
354 name = "pgrphash" 355 type_name = "proc"
356
357 358 -class DarwinTaskProcessCollector(common.AbstractDarwinCachedProducer):
359 name = "tasks" 360 type_name = "proc"
361
362 363 -class DarwinAllProcCollector(common.AbstractDarwinCachedProducer):
364 name = "allproc" 365 type_name = "proc"
366
367 368 -class DarwinPidHashProcessCollector(common.AbstractDarwinCachedProducer):
369 name = "pidhash" 370 type_name = "proc"
371