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