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

Source Code for Module rekall.plugins.response.processes

  1  """Rekall plugins for displaying processes in live triaging.""" 
  2   
  3  import psutil 
  4  from efilter.protocols import structured 
  5   
  6  from rekall_lib import utils 
  7   
  8  from rekall.plugins import core 
  9  from rekall.plugins.response import common 
 10  from rekall.plugins.overlays import basic 
 11   
 12  from rekall.plugins import yarascanner 
13 14 15 -class _LiveProcess(utils.SlottedObject):
16 """An object to represent a live process. 17 18 This is the live equivalent of _EPROCESS. 19 """ 20 __slots__ = ("_proc", "_obj_profile", "session", 21 "start_time", "obj_offset", "pid") 22 23 obj_offset = 0 24
25 - def __init__(self, proc, session=None):
26 """Construct a representation of the live process. 27 28 Args: 29 proc: The psutil.Process instance. 30 """ 31 # Hold on to the original psutil object. 32 self._proc = proc 33 self._obj_profile = None 34 self.session = session 35 super(_LiveProcess, self).__init__() 36 37 self.start_time = basic.UnixTimeStamp( 38 name="create_time", value=self.create_time, session=self.session)
39 40 @utils.safe_property
41 - def obj_profile(self):
42 # Delay creation of the profile because it needs to look in the 43 # environment which is slow. 44 if self._obj_profile is None: 45 self._obj_profile = common.IRProfile( 46 session=self.session, proc=self) 47 48 return self._obj_profile
49
50 - def __int__(self):
51 return self.pid
52
53 - def _get_field(self, field_name):
54 try: 55 result = getattr(self._proc, field_name) 56 if callable(result): 57 result = result() 58 59 return result 60 except psutil.Error: 61 # Some processes do not have environ defined. 62 if field_name == "environ": 63 return {} 64 65 return None 66 except AttributeError: 67 return None
68
69 - def __format__(self, formatspec):
70 """Support the format() protocol.""" 71 if not formatspec: 72 formatspec = "s" 73 74 if formatspec[-1] in "xdXD": 75 return format(int(self), formatspec) 76 77 return object.__format__(self, formatspec)
78
79 - def __repr__(self):
80 return "<Live Process pid=%s>" % self.pid
81
83 return common.IRProcessAddressSpace(self.pid, session=self.session)
84
85 - def as_dict(self):
86 try: 87 return self._proc.as_dict() 88 except Exception: 89 # This can happen if the process no longer exists. 90 return {}
91 92 # Automatically add accessors for psutil fields. 93 psutil_fields = ['cmdline', 'connections', 'cpu_affinity', 94 'cpu_percent', 'cpu_times', 'create_time', 95 'cwd', 'environ', 'exe', 'gids', 'io_counters', 96 'ionice', 'memory_full_info', 'memory_info', 97 'memory_info_ex', 'memory_maps', 'memory_percent', 98 'name', 'nice', 'num_ctx_switches', 'num_fds', 99 'num_threads', 'open_files', 'pid', 'ppid', 100 'status', 'terminal', 'threads', 'uids', 'username', 101 'num_handles'] 102 103 # Generate accessors for psutil derived properties. 104 properties = dict(__slots__=()) 105 for field in psutil_fields: 106 properties[field] = property( 107 lambda self, field=field: self._get_field(field)) 108 109 LiveProcess = type("LiveProcess", (_LiveProcess, ), properties) 110 111 112 structured.IStructured.implement( 113 for_type=LiveProcess, 114 implementations={ 115 structured.resolve: lambda d, m: getattr(d, m, None), 116 structured.getmembers_runtime: lambda d: set(psutil_fields + d.keys()), 117 } 118 )
119 120 121 -class APIProcessFilter(common.AbstractAPICommandPlugin):
122 """A live process filter using the system APIs.""" 123 124 __abstract = True 125 126 __args = [ 127 dict(name="pids", positional=True, type="ArrayIntParser", default=[], 128 help="One or more pids of processes to select."), 129 130 dict(name="proc_regex", default=None, type="RegEx", 131 help="A regex to select a process by name."), 132 ] 133 134 @utils.safe_property
135 - def filtering_requested(self):
136 return (self.plugin_args.pids or self.plugin_args.proc_regex)
137
138 - def filter_processes(self):
139 """Filters eprocess list using pids lists.""" 140 for proc in self.list_process(): 141 if not self.filtering_requested: 142 yield proc 143 144 else: 145 if int(proc.pid) in self.plugin_args.pids: 146 yield proc 147 148 elif (self.plugin_args.proc_regex and 149 self.plugin_args.proc_regex.match( 150 utils.SmartUnicode(proc.name))): 151 yield proc
152
153 - def list_process(self):
154 result = [LiveProcess(x, session=self.session) 155 for x in psutil.process_iter()] 156 157 return result
158
159 -class APILsof(APIProcessFilter):
160 """A plugin which lists all open files.""" 161 name = "lsof" 162 163 table_header = [ 164 dict(name="divider", type="Divider"), 165 dict(name="proc", hidden=True), 166 dict(name="file", hidden=True), 167 dict(name="name", width=30), 168 dict(name="pid", width=6, align="r"), 169 dict(name="user", width=8), 170 dict(name="fd", width=4), 171 dict(name="mode", width=4), 172 dict(name="offset", width=12), 173 dict(name="node", width=8), 174 dict(name="path"), 175 ] 176
177 - def collect(self):
178 for proc in self.filter_processes(): 179 yield dict(divider=proc) 180 181 for fd in (proc.open_files or []): 182 yield dict(file=fd, proc=proc, 183 name=proc.name, 184 pid=proc.pid, 185 user=proc.username, 186 fd=fd.fd, 187 offset=fd.position, 188 path=fd.path, 189 mode=fd.mode)
190
191 192 193 -class APIPslist(APIProcessFilter):
194 """A live pslist plugin using the APIs.""" 195 196 name = "pslist" 197 198 table_header = [ 199 dict(name="proc", hidden=True), 200 dict(name="Name", width=30), 201 dict(name="pid", width=6, align="r"), 202 dict(name="ppid", width=6, align="r"), 203 dict(name="Thds", width=6, align="r"), 204 dict(name="Hnds", width=8, align="r"), 205 dict(name="wow64", width=6), 206 dict(name="start", width=24), 207 dict(name="binary"), 208 ] 209
210 - def column_types(self):
211 return self._row(LiveProcess(psutil.Process(), session=self.session))
212
213 - def is_wow64(self, proc):
214 """Determine if the proc is Wow64.""" 215 # Not the most accurate method but very fast. 216 return (proc.environ.get("PROCESSOR_ARCHITECTURE") == 'x86' and 217 proc.environ.get("PROCESSOR_ARCHITEW6432") == 'AMD64')
218
219 - def _row(self, proc):
220 return dict(proc=proc, 221 Name=proc.name, 222 pid=proc.pid, 223 ppid=proc.ppid, 224 Thds=proc.num_threads, 225 Hnds=proc.num_handles, 226 wow64=self.is_wow64(proc), 227 start=proc.start_time, 228 binary=proc.exe)
229
230 - def collect(self):
231 for proc in self.filter_processes(): 232 yield self._row(proc)
233
234 235 -class APISetProcessContext(core.SetProcessContextMixin, 236 APIProcessFilter):
237 """A cc plugin for setting process context to live mode.""" 238 name = "cc"
239
240 241 -class APIProcessScanner(APIProcessFilter):
242 """Scanner for scanning processes using the ReadProcessMemory() API.""" 243 244 __abstract = True 245
246 - def generate_memory_ranges(self):
247 with self.session.plugins.cc() as cc: 248 for task in self.filter_processes(): 249 comment = "%s (%s)" % (task.name, task.pid) 250 251 cc.SwitchProcessContext(task) 252 253 process_address_space = self.session.GetParameter( 254 "default_address_space") 255 256 for _, _, run in process_address_space.runs: 257 vad = run.data["vad"] 258 self.session.logging.info( 259 "Scanning %s (%s) in: %s [%#x-%#x]", 260 task.name, task.pid, vad.filename or "", 261 vad.start, vad.end) 262 263 run.data["comment"] = comment 264 run.data["task"] = task 265 yield run
266
267 268 -class ProcessYaraScanner(yarascanner.YaraScanMixin, APIProcessScanner):
269 """Yara scan process memory using the ReadProcessMemory() API.""" 270 name = "yarascan"
271