1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """Miscelaneous information gathering plugins."""
19
20 __author__ = "Michael Cohen <scudette@google.com>"
21 import hashlib
22
23
24 from rekall import obj
25 from rekall.plugins import core
26 from rekall.plugins.overlays import basic
27 from rekall.plugins.windows import common
28 from rekall_lib import utils
32 """Prints the boot physical memory map."""
33
34 __name = "phys_map"
35
36 table_header = [
37 dict(name="phys_start", style="address"),
38 dict(name="phys_end", style="address"),
39 dict(name="pages"),
40 ]
41
43 descriptor = self.profile.get_constant_object(
44 "MmPhysicalMemoryBlock",
45 target="Pointer",
46 target_args=dict(
47 target="_PHYSICAL_MEMORY_DESCRIPTOR",
48 ))
49
50 for memory_range in descriptor.Run:
51 yield (memory_range.BasePage * 0x1000,
52 (memory_range.BasePage + memory_range.PageCount) * 0x1000,
53 memory_range.PageCount)
54
55
56 -class WindowsSetProcessContext(core.SetProcessContextMixin,
57 common.WinProcessFilter):
58 """A cc plugin for windows."""
59
62 """Prints the Windows Kernel Virtual Address Map.
63
64 On 32 bit windows, the kernel virtual address space can be managed
65 dynamically. This plugin shows each region and what it is used for.
66
67 Note that on 64 bit windows the address space is large enough to not worry
68 about it. In that case, the offsets and regions are hard coded.
69
70 http://www.woodmann.com/forum/entry.php?219-Using-nt!_MiSystemVaType-to-navigate-dynamic-kernel-address-space-in-Windows7
71 """
72
73 __name = "virt_map"
74
75 table_header = [
76 dict(name="virt_start", style="address"),
77 dict(name="virt_end", style="address"),
78 dict(name="type", width=10),
79 ]
80
81 @classmethod
85
87 system_va_table = self.profile.get_constant_object(
88 "MiSystemVaType",
89 target="Array",
90 target_args=dict(
91 target="Enumeration",
92 target_args=dict(
93 target="byte",
94 enum_name="_MI_SYSTEM_VA_TYPE"
95 ),
96 )
97 )
98
99 system_range_start = self.profile.get_constant_object(
100 "MiSystemRangeStart", "unsigned int")
101
102
103 va_table_size = 0x1000 * 0x1000 / self.profile.get_obj_size("_MMPTE")
104
105
106 range_type = range_start = range_length = 0
107
108 for offset in range(system_range_start, 0xffffffff, va_table_size):
109 table_index = (offset - system_range_start) / va_table_size
110 page_type = system_va_table[table_index]
111 if page_type != range_type:
112 if range_type:
113 yield (range_start, range_start + range_length, range_type)
114
115 range_type = page_type
116 range_start = offset
117 range_length = va_table_size
118 else:
119 range_length += va_table_size
120
121
122 -class Objects(common.WindowsCommandPlugin):
123 """Displays all object Types on the system."""
124
125 name = "object_types"
126
127 table_header = [
128 dict(name="type", style="address"),
129 dict(name="index", align="r", width=5),
130 dict(name="NumberOfObjects", align="r", width=15),
131 dict(name="PoolType", width=20),
132 dict(name="name")
133 ]
134
136
137
138
139 type_table = self.profile.get_constant_object(
140 "ObpObjectTypes",
141 target="Array", target_args=dict(
142 target="Pointer",
143 count=0,
144 target_args=dict(
145 target="_OBJECT_TYPE")
146 )
147 )
148
149 type_type = type_table[0]
150 type_table.count = type_type.TotalNumberOfObjects
151
152 for t in type_table:
153 if t:
154 yield t
155
157 for obj_type in self.object_types():
158 yield dict(type=obj_type,
159 index=obj_type.Index,
160 NumberOfObjects=obj_type.TotalNumberOfObjects,
161 PoolType=obj_type.TypeInfo.PoolType,
162 name=obj_type.Name)
163
164
165 -class ImageInfo(common.WindowsCommandPlugin):
166 """List overview information about this image."""
167
168 name = "imageinfo"
169
170 table_header = [
171 dict(name="key", width=20),
172 dict(name="value")
173 ]
174
175 @staticmethod
177 """Return the time of each tick (float).
178
179 dis "nt!KeQueryTimeIncrement"
180 ------ nt!KeQueryTimeIncrement ------
181 MOV EAX, [RIP+0x24af66] 0x26161 nt!KeMaximumIncrement
182 RET
183 """
184 return profile.get_constant_object(
185 "KeMaximumIncrement", target="unsigned int") * 100e-9
186
188 """Returns the number of seconds since boot.
189 Ref:
190 KeQueryTickCount * KeQueryTimeIncrement
191
192 reactos/include/ddk/wdm.h:
193
194 #define SharedTickCount (KI_USER_SHARED_DATA + 0x320)
195
196 #define KeQueryTickCount(CurrentCount) \
197 *(ULONG64*)(CurrentCount) = *(volatile ULONG64*)SharedTickCount
198 """
199 current_tick_count = (
200 int(kuser_shared.TickCountQuad) or
201 int(kuser_shared.TickCountLow))
202
203 return current_tick_count * self.KeQueryTimeIncrement(self.profile)
204
206 yield ("Kernel DTB", "%#x" % self.kernel_address_space.dtb)
207
208 for desc, name, type in (
209 ("NT Build", "NtBuildLab", "String"),
210 ("NT Build Ex", "NtBuildLabEx", "String"),
211 ("Signed Drivers", "g_CiEnabled", "bool"),
212 ):
213
214 yield dict(
215 key=desc,
216 value=self.profile.get_constant_object(name, target=type))
217
218
219 kuser_shared = self.profile.get_constant_object(
220 "KI_USER_SHARED_DATA", "_KUSER_SHARED_DATA")
221
222 yield ("Time (UTC)", kuser_shared.SystemTime)
223
224
225 bias = kuser_shared.TimeZoneBias.cast("long long") / 1e7
226 yield ("Time (Local)", kuser_shared.SystemTime.display(
227 utc_shift=-bias))
228
229 yield ("Sec Since Boot", self.GetBootTime(kuser_shared))
230 yield ("NtSystemRoot", kuser_shared.NtSystemRoot)
231
234 """Fingerprint the current image.
235
236 This parameter tries to get something unique about the image quickly. The
237 idea is that two different images (even of the same system at different
238 points in time) will have very different fingerprints. The fingerprint is
239 used as a key to cache persistent information about the system.
240
241 Live systems can not have a stable fingerprint and so return a NoneObject()
242 here.
243
244 We return a list of tuples:
245 (physical_offset, expected_data)
246
247 The list uniquely identifies the image. If one were to read all physical
248 offsets and find the expected_data at these locations, then we have a very
249 high level of confidence that the image is unique and matches the
250 fingerprint.
251 """
252 name = "image_fingerprint"
253
255 if not self.session.physical_address_space:
256 return None
257
258 if self.session.physical_address_space.volatile:
259 return obj.NoneObject("No fingerprint for volatile image.")
260
261 result = []
262 profile = self.session.profile
263 phys_as = self.session.physical_address_space
264
265 address_space = self.session.GetParameter("default_address_space")
266
267 label = profile.get_constant_object("NtBuildLab", "String")
268 result.append((address_space.vtop(label.obj_offset), label.v()))
269
270 label = profile.get_constant_object("NtBuildLabEx", "String")
271 result.append((address_space.vtop(label.obj_offset), label.v()))
272
273 kuser_shared = profile.get_constant_object(
274 "KI_USER_SHARED_DATA", "_KUSER_SHARED_DATA")
275
276 system_time_offset = address_space.vtop(
277 kuser_shared.SystemTime.obj_offset)
278
279 result.append((system_time_offset, phys_as.read(system_time_offset, 8)))
280
281 tick_time_offset = address_space.vtop(
282 kuser_shared.multi_m("TickCountQuad", "TickCountLow").obj_offset)
283 result.append((tick_time_offset, phys_as.read(tick_time_offset, 8)))
284
285
286 for task in self.session.plugins.pslist().filter_processes():
287 name = task.name.cast("String", length=30)
288 task_name_offset = address_space.vtop(name.obj_offset)
289
290
291
292
293 result.append((task_name_offset, name.v()))
294
295 return dict(
296 hash=hashlib.sha1(unicode(result).encode("utf8")).hexdigest(),
297 tests=result)
298
299
300 -class ObjectTree(common.WindowsCommandPlugin):
301 """Visualize the kernel object tree.
302
303 Ref:
304 http://msdn.microsoft.com/en-us/library/windows/hardware/ff557762(v=vs.85).aspx
305 """
306
307 name = "object_tree"
308
309 __args = [
310 dict(name="type_regex", default=".", type="RegEx",
311 help="Filter the type of objects shown.")
312 ]
313
314 table_header = [
315 dict(name="_OBJECT_HEADER", style="address"),
316 dict(name="type", width=20),
317 dict(name="name", type="TreeNode"),
318 ]
319
327
329 """Tries to resolve the path back to something with a drive letter."""
330
331 try:
332 path = self.ResolveSymlinks(path)
333 for prefix, drive_letter in self.session.GetParameter(
334 "drive_letter_device_map").iteritems():
335 prefix = self.ResolveSymlinks(prefix)
336 if path.startswith(prefix):
337 return drive_letter + path[len(prefix):]
338
339
340
341 except KeyError:
342 return path
343
345 """Takes a path and resolves any intermediate symlinks in it.
346
347 Returns:
348 A direct path to the object.
349 """
350 components = path.split("\\")
351 return "\\".join(self._parse_path_components(components))
352
354 node = self.session.GetParameter("object_tree")
355 new_components = []
356
357 for i, component in enumerate(components):
358 if not component:
359 continue
360
361 if component == "??":
362 component = "GLOBAL??"
363
364 next_node = utils.CaseInsensitiveDictLookup(
365 component, node["Children"])
366
367
368
369 if next_node is None and i == 0 and component != "GLOBAL??":
370 return self._parse_path_components(["GLOBAL??"] + components)
371
372 if next_node is None:
373 raise KeyError(
374 "component %r not found at %s" % (
375 component, "\\".join(new_components)))
376
377 elif next_node["type"] == "SymbolicLink":
378 object_header = self.session.profile._OBJECT_HEADER(
379 next_node["offset"])
380
381 target = object_header.Object.LinkTarget.v()
382
383
384 return self._parse_path_components(
385 target.split("\\") + components[i+1:])
386
387 elif next_node["type"] != "Directory":
388 return new_components + components[i:]
389
390 new_components.append(component)
391 node = next_node
392
393 return new_components
394
396 for obj_header in directory.list():
397 if obj_header in seen:
398 continue
399 seen.add(obj_header)
400
401 name = unicode(obj_header.NameInfo.Name)
402 obj_type = str(obj_header.get_object_type())
403
404 if obj_type == "SymbolicLink":
405 name += u"-> %s (%s)" % (obj_header.Object.LinkTarget,
406 obj_header.Object.CreationTime)
407
408 if self.plugin_args.type_regex.search(obj_type):
409 yield dict(_OBJECT_HEADER=obj_header, type=obj_type,
410 name=name, depth=depth)
411
412 if obj_type == "Directory":
413 for x in self._collect_directory(
414 obj_header.Object, seen, depth=depth+1):
415 yield x
416
418
419 root = self.GetObjectByName("/")
420
421 seen = set()
422 for x in self._collect_directory(root, seen):
423 yield x
424
427 """Return current time, as known to the kernel."""
428
429 name = "times"
430
431 table_header = [
432 dict(name="Times"),
433 ]
434
449