1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 import re
29 import StringIO
30
31 from rekall import kb
32 from rekall import testlib
33 from rekall import plugin
34 from rekall.ui import text
35 from rekall.plugins import core
36 from rekall.plugins.addrspaces import intel
37 from rekall.plugins.windows import common
38 from rekall.plugins.windows import pagefile
39 from rekall_lib import utils
40
41
42 -class VtoP(core.VtoPMixin, common.WinProcessFilter):
43 """Prints information about the virtual to physical translation."""
44
45
46 -class PFNInfo(common.WindowsCommandPlugin):
47 """Prints information about an address from the PFN database."""
48
49 __name = "pfn"
50
51
52 PAGE_SIZE = 0x1000
53 PAGE_BITS = 12
54
55 __args = [
56 dict(name="pfn", type="IntParser", positional=True, required=True,
57 help="The PFN to examine.")
58 ]
59
60 table_header = [
61 dict(name="fact", width=25),
62 dict(name="Address", style="address"),
63 dict(name="Value"),
64 ]
65
66
68 pfn_obj = self.profile.get_constant_object("MmPfnDatabase")[
69 self.plugin_args.pfn]
70
71 yield "PFN", self.plugin_args.pfn
72 yield "PFN Record VA", pfn_obj.obj_offset
73
74 yield "Type", None, pfn_obj.Type
75
76
77 if pfn_obj.Type in ("Zeroed", "Freed", "Bad"):
78 yield "Flink", pfn_obj.u1.Flink
79 yield "Blink", pfn_obj.u2.Blink
80
81 return
82
83
84 flags = ["Modified",
85 "ParityError",
86 "ReadInProgress",
87 "WriteInProgress"]
88
89 long_flags_string = " ".join(
90 [v for v in flags if pfn_obj.u3.e1.m(v) == 0])
91
92 yield "Flags", None, long_flags_string
93
94 containing_page = int(pfn_obj.u4.PteFrame)
95 pte_physical_address = ((containing_page << self.PAGE_BITS) |
96 (int(pfn_obj.PteAddress) & 0xFFF))
97
98 yield "Reference", None, pfn_obj.u3.e2.ReferenceCount
99 yield "ShareCount", None, pfn_obj.u2.ShareCount
100 yield "Color", None, pfn_obj.multi_m("u3.e1.PageColor", "u4.PageColor")
101
102 yield "Controlling PTE (VA)", pfn_obj.PteAddress
103 yield "Controlling PTE (PA)", pte_physical_address
104 yield ("Controlling PTE Type", None,
105 "Prototype" if pfn_obj.IsPrototype else "Hardware")
106
107
108 if containing_page == self.plugin_args.pfn:
109 owning_process = pfn_obj.u1.Flink.cast(
110 "Pointer", target="_EPROCESS")
111
112 yield "Owning process", owning_process
113
114
115 collection = intel.DescriptorCollection(self.session)
116 self.session.kernel_address_space.describe_pte(
117 collection, pfn_obj.PteAddress,
118 pfn_obj.PteAddress.Long, 0)
119
120 yield "Controlling PTE", None, collection
121
122 if pfn_obj.OriginalPte:
123 collection = intel.DescriptorCollection(self.session)
124 self.session.kernel_address_space.describe_proto_pte(
125 collection, pfn_obj.OriginalPte.v(),
126 pfn_obj.OriginalPte.Long, 0)
127
128 yield "Original PTE", None, collection
129
130
131 -class PtoV(common.WinProcessFilter):
132 """Converts a physical address to a virtual address."""
133
134 __name = "ptov"
135
136 PAGE_SIZE = 0x1000
137 PAGE_BITS = 12
138
139 __args = [
140 dict(name="physical_address", type="IntParser", positional=True,
141 help="The Virtual Address to examine.")
142 ]
143
145 super(PtoV, self).__init__(*args, **kwargs)
146
147 if self.profile.metadata("arch") == "I386":
148 if self.profile.metadata("pae"):
149 self.table_names = ["Phys", "PTE", "PDE", "DTB"]
150 self.bit_divisions = [12, 9, 9, 2]
151
152 else:
153 self.table_names = ["Phys", "PTE", "PDE", "DTB"]
154 self.bit_divisions = [12, 10, 10]
155
156 elif self.profile.metadata("arch") == "AMD64":
157 self.table_names = ["Phys", "PTE", "PDE", "PDPTE", "PML4E", "DTB"]
158 self.bit_divisions = [12, 9, 9, 9, 9, 4]
159
160 else:
161 raise plugin.PluginError("Memory model not supported.")
162
163 - def ptov(self, collection, physical_address):
177
179 """An implementation of ptov for x64."""
180 pfn_database = self.session.profile.get_constant_object("MmPfnDatabase")
181
182
183 physical_addresses = dict(Phys=physical_address)
184
185
186
187 phys_addresses_of_pte = {}
188 ptes = {}
189 p_addr = physical_address
190 pfns = {}
191
192
193
194
195
196 for i, name in enumerate(self.table_names):
197 pfn = p_addr >> self.PAGE_BITS
198 pfns[name] = pfn_obj = pfn_database[pfn]
199
200
201 pte = pfn_obj.PteAddress
202
203
204
205
206
207
208 if i > 0:
209 physical_addresses[name] = ptes[
210 self.table_names[i-1]].obj_offset
211
212
213 p_addr = ((pfn_obj.u4.PteFrame << self.PAGE_BITS) |
214 (pte.v() & 0xFFF))
215
216 phys_addresses_of_pte[name] = p_addr
217
218
219
220
221 ptes[name] = self.session.profile._MMPTE(
222 p_addr, vm=self.session.physical_address_space)
223
224 self.session.logging.getChild("PageTranslation").debug(
225 "%s %#x is controlled by pte %#x (PFN %#x)",
226 name, physical_addresses[name], ptes[name], pfns[name])
227
228
229 dtb = p_addr & ~0xFFF
230
231
232
233
234 virtual_address = 0
235 start_of_page_table = dtb
236 size_of_pte = self.session.profile._MMPTE().obj_size
237
238 for name, bit_division in reversed(zip(
239 self.table_names, self.bit_divisions)):
240 pte = ptes[name]
241 virtual_address += (
242 ptes[name].obj_offset - start_of_page_table) / size_of_pte
243
244 virtual_address <<= bit_division
245
246
247
248
249 start_of_page_table = pte.u.Hard.PageFrameNumber << self.PAGE_BITS
250
251 if name == "Phys":
252 collection.add(intel.PhysicalAddressDescriptor,
253 address=physical_address)
254
255 elif name == "DTB":
256
257 collection.add(pagefile.WindowsDTBDescriptor,
258 dtb=physical_addresses["DTB"] & ~0xFFF)
259
260 else:
261 collection.add(pagefile.WindowsPTEDescriptor,
262 object_name=name, pte_value=pte.Long,
263 pte_addr=pte.obj_offset, session=self.session)
264
265 virtual_address = self.session.profile.integer_to_address(
266 virtual_address)
267 virtual_address += physical_address & 0xFFF
268
269 collection.add(intel.VirtualAddressDescriptor, dtb=dtb,
270 address=virtual_address)
271
281
282
283 -class WinRammap(common.WindowsCommandPlugin):
284 """Scan all physical memory and report page owners."""
285
286 name = "rammap"
287
288 __args = [
289 dict(name="start", type="IntParser", default=0, positional=True,
290 help="Physical memory address to start displaying."),
291 dict(name="end", type="IntParser",
292 help="Physical memory address to end displaying."),
293 ]
294
295 table_header = [
296 dict(name="phys_offset", max_depth=1,
297 type="TreeNode", child=dict(style="address", align="l"),
298 width=16),
299 dict(name="List", width=10),
300 dict(name="Use", width=15),
301 dict(name="Pr", width=2),
302 dict(name="Process", type="_EPROCESS"),
303 dict(name="VA", style="address"),
304 dict(name="Offset", style="address"),
305 dict(name="Filename"),
306 ]
307
315
317 pfn_obj = self.pfn_database[phys_off >> 12]
318
319 collection = intel.DescriptorCollection(self.session)
320 self.ptov_plugin.ptov(collection, phys_off)
321 result = dict(phys_offset=phys_off,
322 List=pfn_obj.Type,
323 Pr=pfn_obj.Priority)
324
325
326 descriptor = collection["VirtualAddressDescriptor"]
327 if descriptor:
328 dtb_descriptor = collection["WindowsDTBDescriptor"]
329
330 if descriptor.address > self.session.GetParameter(
331 "highest_usermode_address"):
332 _, _, pool = self.pools.is_address_in_pool(descriptor.address)
333 if pool:
334 yield dict(Use=pool.PoolType,
335 VA=descriptor.address, **result)
336 else:
337 yield dict(Use="Kernel",
338 VA=descriptor.address, **result)
339 else:
340 yield dict(Use="Private",
341 Process=dtb_descriptor.owner(),
342 VA=descriptor.address, **result)
343
344 return
345
346 descriptor = collection["WindowsFileMappingDescriptor"]
347 if descriptor:
348 subsection = descriptor.get_subsection()
349 filename, file_offset = descriptor.filename_and_offset(
350 subsection=subsection)
351
352
353 virtual_address = None
354
355 depth = 0
356
357 for process, virtual_address in descriptor.get_owners(
358 subsection=subsection):
359
360 yield dict(Use="Mapped File",
361 Filename=filename,
362 Offset=file_offset,
363 depth=depth,
364 Process=process,
365 VA=virtual_address, **result)
366
367 if self.plugin_args.verbosity <= 1:
368 return
369
370
371
372 depth = 1
373
374
375 if depth == 0:
376 yield dict(Use="Mapped File",
377 Filename=filename,
378 Offset=file_offset,
379 **result)
380 return
381
382 if pfn_obj.u3.e2.ReferenceCount == 0:
383 result["Use"] = "Unused"
384 yield result
385 return
386
387 yield result
388
402
412
413
419
420
421 -class DTBScan(common.WinProcessFilter):
422 """Scans the physical memory for DTB values.
423
424 This plugin can compare the DTBs found against the list of known processes
425 to find hidden processes.
426 """
427
428 __name = "dtbscan"
429
430 __args = [
431 dict(name="limit", type="IntParser", default=2**64,
432 help="Stop scanning after this many mb.")
433 ]
434
435 table_header = [
436 dict(name="DTB", style="address"),
437 dict(name="VA", style="address"),
438 dict(name="Owner", type="_EPROCESS"),
439 dict(name="Known", type="Bool"),
440 ]
441
482
483
488
489
491 """Produce all the subsection objects we know about.
492
493 Returns a dict keyed with subsection offsets with values being a details
494 dict. The details include the vad and the _EPROCESS address for this
495 process.
496 """
497 name = "subsections"
498
500 result = {}
501 for task in self.session.plugins.pslist().filter_processes():
502 self.session.report_progress("Inspecting VAD for %s", task.name)
503 for vad in task.RealVadRoot.traverse():
504 subsection_list = vad.multi_m(
505 "Subsection", "ControlArea.FirstSubsection")
506 for subsection in subsection_list.walk_list(
507 "NextSubsection", include_current=True):
508 record = result.setdefault(subsection.obj_offset, [])
509 record.append(dict(task=task.obj_offset,
510 vad=vad.obj_offset,
511 type=vad.obj_type))
512 return result
513
514
516 """A ranged collection for Prototype PTE arrays."""
517
518 name = "prototype_pte_array_subsection_lookup"
519
521 result = utils.RangedCollection()
522 for subsection_offset in self.session.GetParameter("subsections"):
523 subsection = self.session.profile._SUBSECTION(subsection_offset)
524 start = subsection.SubsectionBase.v()
525
526
527 if start < self.session.GetParameter("highest_usermode_address"):
528 continue
529
530 end = start + (subsection.PtesInSubsection *
531 subsection.SubsectionBase[0].obj_size)
532 result.insert(start, end, subsection_offset)
533
534 return result
535