| Trees | Indices | Help |
|
|---|
|
|
1 # Rekall Memory Forensics
2 # Copyright (c) 2010, 2011, 2012 Michael Ligh <michael.ligh@mnin.org>
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 # pylint: disable=protected-access
21
22 from rekall import plugin
23 from rekall import obj
24 from rekall.plugins.windows import common
25 from rekall.plugins.windows import vadinfo
26 from rekall_lib import utils
27
28
29 SERVICE_TYPE_FLAGS = {
30 'SERVICE_KERNEL_DRIVER': 0,
31 'SERVICE_FILE_SYSTEM_DRIVER': 1,
32 'SERVICE_WIN32_OWN_PROCESS': 4,
33 'SERVICE_WIN32_SHARE_PROCESS': 5,
34 'SERVICE_INTERACTIVE_PROCESS': 8
35 }
36
37 SERVICE_STATE_ENUM = {
38 1: 'SERVICE_STOPPED',
39 2: 'SERVICE_START_PENDING',
40 3: 'SERVICE_STOP_PENDING',
41 4: 'SERVICE_RUNNING',
42 5: 'SERVICE_CONTINUE_PENDING',
43 6: 'SERVICE_PAUSE_PENDING',
44 7: 'SERVICE_PAUSED'
45 }
46
47 svcscan_base_x86 = {
48 '_SERVICE_HEADER': [None, {
49 'Tag': [0x0, ['array', 4, ['unsigned char']]],
50 'ServiceRecord': [0xC, ['pointer', ['_SERVICE_RECORD']]],
51 }],
52
53 '_SERVICE_RECORD': [None, {
54 'NextService': [0x0, ['_SERVICE_HEADER']],
55 'ServiceName': [0x8, ['pointer', ['UnicodeString', dict(length=512)]]],
56 'DisplayName': [0xc, ['pointer', ['UnicodeString', dict(length=512)]]],
57 'Order': [0x10, ['unsigned int']],
58 'Tag': [0x18, ['array', 4, ['unsigned char']]],
59 'DriverName': [0x24, ['pointer', ['UnicodeString', dict(
60 length=256)]]],
61 'ServiceProcess': [0x24, ['pointer', ['_SERVICE_PROCESS']]],
62 'Type': [0x28, ['Flags', {'bitmap': SERVICE_TYPE_FLAGS}]],
63 'State': [0x2c, ['Enumeration', dict(target='long',
64 choices=SERVICE_STATE_ENUM)]],
65 }],
66
67 '_SERVICE_PROCESS': [None, {
68 'BinaryPath': [0x8, ['pointer', ['UnicodeString', dict(
69 encoding='utf16', length=256)]]],
70 'ProcessId': [0xc, ['unsigned int']],
71 }],
72 }
73
74 svcscan_base_x64 = {
75 '_SERVICE_HEADER': [None, {
76 'Tag': [0x0, ['Array', dict(
77 count=4,
78 target='unsigned char'
79 )]],
80 'ServiceRecord': [0x10, ['Pointer', dict(
81 target='_SERVICE_RECORD'
82 )]],
83 }],
84
85 '_SERVICE_RECORD': [None, {
86 'NextService': [0x0, ['Pointer', dict(
87 target="_SERVICE_RECORD"
88 )]],
89 'ServiceName': [0x8, ['pointer', ['UnicodeString', dict(
90 encoding='utf16', length=512)]]],
91
92 'DisplayName': [0x10, ['Pointer', dict(
93 target='UnicodeString',
94 target_args=dict(length=512)
95 )]],
96 'Order': [0x18, ['unsigned int']],
97 'Tag' : [0x20, ['Array', dict(
98 count=4,
99 target='unsigned char'
100 )]],
101 'DriverName': [0x30, ['Pointer', dict(
102 target='UnicodeString',
103 target_args=dict(
104 length=256
105 )
106 )]],
107 'ServiceProcess': [0x30, ['Pointer', dict(
108 target='_SERVICE_PROCESS'
109 )]],
110 'Type': [0x38, ['Flags', {'bitmap': SERVICE_TYPE_FLAGS}]],
111 'State': [0x3C, ['Enumeration', dict(
112 target='long', choices=SERVICE_STATE_ENUM)]],
113 }],
114
115 '_SERVICE_PROCESS': [None, {
116 'BinaryPath': [0x10, ['Pointer', dict(
117 target='UnicodeString',
118 target_args=dict(
119 length=256
120 )
121 )]],
122 'ProcessId': [0x18, ['unsigned int']],
123 }],
124 }
128 "Service records for XP/2003 x86 and x64"
129
130 @utils.safe_property
132 "Return the binary path for a service"
133
134 # No path in memory for services that aren't running
135 # (if needed, query the registry key)
136 if str(self.State) != 'SERVICE_RUNNING':
137 return obj.NoneObject("No path, service isn't running")
138
139 # Depending on whether the service is for a process
140 # or kernel driver, the binary path is stored differently
141 if 'PROCESS' in str(self.Type):
142 return self.ServiceProcess.BinaryPath.dereference()
143 else:
144 return self.DriverName.dereference()
145
146 @utils.safe_property
148 "Return the process ID for a service"
149
150 if str(self.State) == 'SERVICE_RUNNING':
151 if 'PROCESS' in str(self.Type):
152 return self.ServiceProcess.ProcessId
153
154 return obj.NoneObject("Cannot get process ID")
155
157 "Check some fields for validity"
158 return (super(_SERVICE_RECORD_LEGACY, self).is_valid() and
159 self.Order > 0 and self.Order < 0xFFFF)
160
164
173
174
175 _SERVICE_RECORD_VISTA_X86 = {
176 '_SERVICE_RECORD': [None, {
177 'NextService': [0x0, ['pointer', ['_SERVICE_RECORD']]],
178 'ServiceName': [0x4, ['pointer', ['UnicodeString', dict(length=512)]]],
179 'DisplayName': [0x8, ['pointer', ['UnicodeString', dict(length=512)]]],
180 'Order': [0xC, ['unsigned int']],
181 'ServiceProcess': [0x1C, ['pointer', ['_SERVICE_PROCESS']]],
182 'DriverName': [0x1C, ['pointer', ['UnicodeString', dict(
183 length=256)]]],
184 'Type' : [0x20, ['Flags', {'bitmap': SERVICE_TYPE_FLAGS}]],
185 'State': [0x24, ['Enumeration', dict(
186 target='unsigned int', choices=SERVICE_STATE_ENUM)]],
187 }],
188 }
189
190
191 _SERVICE_RECORD_VISTA_X64 = {
192 '_SERVICE_RECORD': [None, {
193 'NextService': [0x00, ['Pointer', dict(
194 target='_SERVICE_RECORD'
195 )]],
196
197 'ServiceName': [0x08, ['pointer', ['UnicodeString', dict(
198 length=512
199 )]]],
200 'DisplayName': [0x10, ['pointer', ['UnicodeString', dict(
201 length=512
202 )]]],
203 'Order': [0x18, ['unsigned int']],
204 'ServiceProcess': [0x28, ['pointer', ['_SERVICE_PROCESS']]],
205 'DriverName': [0x28, ['Pointer', dict(
206 target='UnicodeString',
207 target_args=dict(
208 length=256,
209 )
210 )]],
211
212 'Type' : [0x30, ['Flags', {'bitmap': SERVICE_TYPE_FLAGS}]],
213 'State': [0x34, ['Enumeration', dict(
214 target='unsigned int',
215 choices=SERVICE_STATE_ENUM
216 )]],
217 }],
218 }
219
220
221 _SERVICE_RECORD_WIN81_X64 = {
222 "_SERVICE_RECORD": [None, {
223 "Tag": [0, ["String", dict(length=4)]], # Signature sErv
224 'NextService': [0x8, ['Pointer', dict(
225 target='_SERVICE_RECORD'
226 )]],
227
228 'ServiceName': [0x10, ['pointer', ['UnicodeString', dict(
229 length=512
230 )]]],
231 'DisplayName': [0x18, ['pointer', ['UnicodeString', dict(
232 length=512
233 )]]],
234 'Order': [0x20, ['unsigned int']],
235 'ServiceProcess': [0x38, ['pointer', ['_SERVICE_PROCESS']]],
236 'DriverName': [0x38, ['Pointer', dict(
237 target='UnicodeString',
238 target_args=dict(
239 length=256,
240 )
241 )]],
242
243 'Type' : [0x40, ['Flags', {'bitmap': SERVICE_TYPE_FLAGS}]],
244 'State': [0x44, ['Enumeration', dict(
245 target='unsigned int',
246 choices=SERVICE_STATE_ENUM
247 )]],
248 }],
249
250 '_SERVICE_PROCESS': [None, {
251 'Tag': [0, ["String", dict(length=4)]], # Sc16
252 'BinaryPath': [0x18, ['Pointer', dict(
253 target='UnicodeString',
254 target_args=dict(
255 length=256
256 )
257 )]],
258 'ProcessId': [0x20, ['unsigned int']],
259 }],
260 }
264 """A modification for the service control manager."""
265
266 @classmethod
268 if profile.metadata("arch") == "I386":
269 profile.add_overlay(svcscan_base_x86)
270 else:
271 # 32bit Vista profiles
272 profile.add_overlay(svcscan_base_x64)
273
274 # Windows XP, 2003
275 version = profile.metadata("version")
276 if version < 6.0:
277 profile.add_classes({
278 '_SERVICE_RECORD': _SERVICE_RECORD_LEGACY,
279 '_SERVICE_HEADER': _SERVICE_HEADER,
280 })
281 profile.add_constants(dict(ServiceTag="sErv"))
282
283 # Vista 2008 and windows 7
284 elif 6.0 <= version <= 6.2:
285 profile.add_classes({
286 '_SERVICE_RECORD': _SERVICE_RECORD_RECENT,
287 '_SERVICE_HEADER': _SERVICE_HEADER,
288 })
289 profile.add_constants(dict(ServiceTag="serH"))
290
291 if profile.metadata("arch") == "I386":
292 profile.add_overlay(_SERVICE_RECORD_VISTA_X86)
293 else:
294 profile.add_overlay(_SERVICE_RECORD_VISTA_X64)
295
296 # Windows 8.1 and Windows 10
297 elif 6.2 <= version:
298 profile.add_classes({
299 '_SERVICE_RECORD': _SERVICE_RECORD_RECENT,
300 '_SERVICE_HEADER': _SERVICE_HEADER,
301 })
302 profile.add_constants(dict(ServiceTag="serH"))
303
304 if profile.metadata("arch") == "I386":
305 profile.add_overlay(_SERVICE_RECORD_VISTA_X86)
306 else:
307 profile.add_overlay(_SERVICE_RECORD_WIN81_X64)
308
309 else:
310 raise RuntimeError(
311 "Unsupported windows version. Please file a bug.")
312
316 """A scanner for the service tags."""
317
319 super(SvcRecordScanner, self).__init__(**kwargs)
320 self.checks = [
321 ('StringCheck', dict(
322 needle=self.profile.get_constant("ServiceTag"))),
323 ]
324 self.tag_offset = self.profile.get_obj_offset('_SERVICE_RECORD', 'Tag')
325
327 for hit in super(SvcRecordScanner, self).scan(**kwargs):
328 svc_record = self.profile._SERVICE_RECORD(
329 vm=self.address_space, offset=hit - self.tag_offset)
330
331 if svc_record.is_valid():
332 yield svc_record
333
336 """A scanner for the service tags."""
337
339 super(SvcHeaderScanner, self).__init__(**kwargs)
340 self.checks = [
341 ('StringCheck', dict(
342 needle=self.profile.get_constant("ServiceTag"))),
343 ]
344
345 # On systems more recent than XP/2003, the serH marker doesn't
346 # find *all* services, but the ones it does find have linked
347 # lists to the others. We use this variable to track which
348 # ones we've seen so as to not yield duplicates.
349 self.records = set()
350
352 for hit in super(SvcHeaderScanner, self).scan(**kwargs):
353 svc_header = self.profile._SERVICE_HEADER(
354 vm=self.address_space, offset=hit)
355
356 if svc_header.is_valid():
357 for record in svc_header.ServiceRecord.walk_list("NextService"):
358 if record.is_valid() and record not in self.records:
359 self.records.add(record)
360
361 yield record
362
365 "Scan for Windows services"
366
367 __name = "svcscan"
368
370 """Scan for callbacks.
371
372 Args:
373 scan_in_kernel_address_space: If False we will use the physical
374 address space for scanning, while if true we scan in the kernel
375 address space.
376 """
377 super(SvcScan, self).__init__(**kwargs)
378 self.scan_in_kernel_address_space = scan_in_kernel_address_space
379
380 # Update the profile.
381 self.profile = ServiceModification(self.profile)
382
384 # Get the version we're analyzing
385 version = self.profile.metadatas('major', 'minor')
386
387 pslist = self.session.plugins.pslist(proc_regex="services.exe")
388 for task in pslist.filter_processes():
389 # Process AS must be valid
390 process_space = task.get_process_address_space()
391 if process_space == None:
392 continue
393
394 # XP/2003 use the _SERVICE_RECORD object.
395 if version <= "5.2":
396 scanner = SvcRecordScanner(
397 task=task, process_profile=self.profile,
398 session=self.session)
399 else:
400 # Windows Vista, 2008, and 7 use the _SERVICE_HEADER
401 scanner = SvcHeaderScanner(
402 task=task, process_profile=self.profile,
403 session=self.session)
404
405 # Find all instances of the record tag
406 for record in scanner.scan():
407 yield record
408
410 renderer.table_header([
411 ("Offset", "offset", "[addrpad]"),
412 ("Order", "order", "5"),
413 ("PID", "pid", "4"),
414 ("Service Name", "service", "30"),
415 ("Display Name", "display_name", "40"),
416 ("Service Type", "type", "30"),
417 ("Service State", "state", "15"),
418 ("Binary Path", "binary_path", "")])
419
420 for rec in self.calculate():
421 renderer.table_row(
422 rec,
423 rec.Order,
424 rec.Pid,
425 rec.ServiceName.deref(),
426 rec.DisplayName.deref(),
427 rec.Type,
428 rec.State,
429 rec.Binary)
430
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Oct 9 03:29:43 2017 | http://epydoc.sourceforge.net |