Package rekall :: Package plugins :: Package overlays :: Package windows :: Module heap
[frames] | no frames]

Source Code for Module rekall.plugins.overlays.windows.heap

  1  # Rekall Memory Forensics 
  2  # Copyright 2014 Google Inc. All Rights Reserved. 
  3  # 
  4  # This program is free software; you can redistribute it and/or modify 
  5  # it under the terms of the GNU General Public License as published by 
  6  # the Free Software Foundation; either version 2 of the License, or (at 
  7  # your option) any later version. 
  8  # 
  9  # This program is distributed in the hope that it will be useful, but 
 10  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 12  # General Public License for more details. 
 13  # 
 14  # You should have received a copy of the GNU General Public License 
 15  # along with this program; if not, write to the Free Software 
 16  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 17  # 
 18   
 19  """The module implements user mode heap overlays. 
 20   
 21  Recent versions of windows use the Low Fragmentation Heap (LFH). 
 22   
 23  http://illmatics.com/Understanding_the_LFH.pdf 
 24   
 25  """ 
 26   
 27  __author__ = "Michael Cohen <scudette@google.com>" 
 28   
 29  from rekall import addrspace 
 30  from rekall import obj 
 31  from rekall.plugins.overlays.windows import common 
 32  from rekall.plugins.overlays.windows import pe_vtypes 
 33  from rekall_lib import utils 
 34   
 35   
 36  _HEAP_Flags = dict( 
 37      NO_SERIALIZE=0x00000001L, 
 38      GROWABLE=0x00000002L, 
 39      GENERATE_EXCEPTIONS=0x00000004L, 
 40      ZERO_MEMORY=0x00000008L, 
 41      REALLOC_IN_PLACE_ONLY=0x00000010L, 
 42      TAIL_CHECKING_ENABLED=0x00000020L, 
 43      FREE_CHECKING_ENABLED=0x00000040L, 
 44      DISABLE_COALESCE_ON_FREE=0x00000080L, 
 45      CREATE_ALIGN_16=0x00010000L, 
 46      CREATE_ENABLE_TRACING=0x00020000L, 
 47      CREATE_ENABLE_EXECUTE=0x00040000L, 
 48  ) 
 49   
 50  _HEAP_ENTRY_Flags = dict( 
 51      BUSY=0x01, 
 52      EXTRA_PRESENT=0x02, 
 53      FILL_PATTERN=0x04, 
 54      VIRTUAL_ALLOC=0x08, 
 55      LAST_ENTRY=0x10, 
 56      SETTABLE_FLAG1=0x20, 
 57      SETTABLE_FLAG2=0x40, 
 58      SETTABLE_FLAG3=0x80, 
 59  ) 
 60   
 61  overlays = { 
 62      '_PEB': [None, { 
 63          'ProcessHeaps': [None, ['Pointer', dict( 
 64              target='Array', 
 65              target_args=dict( 
 66                  count=lambda x: x.NumberOfHeaps, 
 67                  target='Pointer', 
 68                  target_args=dict( 
 69                      target='_HEAP' 
 70                      ) 
 71                  ) 
 72              )]], 
 73      }], 
 74   
 75      '_HEAP': [None, { 
 76          'BlocksIndex': [None, ['Pointer', dict( 
 77              target='_HEAP_LIST_LOOKUP' 
 78              )]], 
 79   
 80          'Flags': [None, ['Flags', dict( 
 81              maskmap=_HEAP_Flags, 
 82              target="unsigned long" 
 83              )]], 
 84   
 85          'FrontEndHeapType': lambda x: x.cast( 
 86              "Enumeration", 
 87              # LOOK_ASIDE is not available on Win7+. 
 88              choices={ 
 89                  0: "BACKEND",    # Only using backend allocator. 
 90                  1: "LOOK_ASIDE", 
 91                  2: "LOW_FRAG", 
 92                  }, 
 93              value=x.m("FrontEndHeapType") 
 94          ), 
 95   
 96          'FrontEndHeap': [None, ["Pointer", dict( 
 97              target="_LFH_HEAP" 
 98              )]], 
 99   
100          }], 
101   
102      '_HEAP_ENTRY': [None, { 
103          'Flags': [None, ['Flags', dict( 
104              maskmap=_HEAP_ENTRY_Flags, 
105              target="unsigned char" 
106              )]], 
107   
108          }], 
109   
110      '_HEAP_FREE_ENTRY': [None, { 
111          'Flags': [None, ['Flags', dict( 
112              maskmap=_HEAP_ENTRY_Flags, 
113              target="unsigned char" 
114              )]], 
115   
116          }], 
117   
118      '_HEAP_LIST_LOOKUP': [None, { 
119          'ListHints': [None, ["Array", dict( 
120              target="_LIST_ENTRY", 
121              count=lambda x: x.ArraySize 
122          )]], 
123      }], 
124   
125      '_HEAP_USERDATA_HEADER': [None, { 
126          'Entries': [lambda x: x.obj_end, ["Array", dict( 
127              target="_HEAP_ENTRY", 
128              count=lambda x: x.obj_parent.BlockCount, 
129              target_size=lambda x: x.obj_parent.BlockSize * 16, 
130              )]], 
131      }], 
132  } 
133 134 135 -class _HEAP_ENTRY(obj.Struct):
136 """A heap entry. 137 138 Note that heap entries for a given heap are encoded by using a random field 139 XORed with the heap entry. This object automatically decodes the heap entry 140 if the heap is encoded. 141 """ 142
143 - def __init__(self, **kwargs):
144 super(_HEAP_ENTRY, self).__init__(**kwargs) 145 146 encoding = self.obj_context.get("Encoding") 147 if encoding: 148 heap_as = self.obj_context["HeapAS"] 149 self.obj_vm = addrspace.BufferAddressSpace( 150 session=self.obj_session, 151 base_offset=self.obj_offset, 152 data=utils.XOR( 153 heap_as.read(self.obj_offset, self.obj_size), 154 encoding) 155 )
156 157 @utils.safe_property
158 - def PrevEntry(self):
159 if self.PreviousSize == 0: 160 return obj.NoneObject("First Entry") 161 162 return self.cast( 163 "Pointer", 164 target="_HEAP_ENTRY", 165 value=(self.obj_offset + 166 self.PreviousSize * self.obj_size))
167 168 @utils.safe_property
169 - def NextEntry(self):
170 if self.Flags.LAST_ENTRY or self.Size == 0: 171 return obj.NoneObject("Last Entry") 172 173 return self.cast( 174 "Pointer", 175 target="_HEAP_ENTRY", 176 value=(self.obj_offset + 177 self.Size * self.obj_profile.get_obj_size("_HEAP_ENTRY")))
178 179 @utils.safe_property
180 - def Allocation(self):
181 allocation_size = self.Size * self.obj_size 182 183 # On 64 bit platforms allocations are allowed to overflow into the first 184 # 8 bytes of the next allocation. 185 if self.obj_profile.metadata("arch") == "AMD64": 186 allocation_size -= 8 187 188 return self.obj_profile.String(offset=self.obj_end, 189 term=None, 190 length=allocation_size)
191
192 193 -class _HEAP(obj.Struct):
194 """ 195 Ref: 196 http://www.informit.com/articles/article.aspx?p=1081496 197 """ 198
199 - def __init__(self, **kwargs):
200 super(_HEAP, self).__init__(**kwargs) 201 202 # This passes the heap's encoding to all members of this heap. 203 if self.m("Encoding"): 204 self.obj_context["Encoding"] = self.obj_vm.read( 205 self.Encoding.obj_offset, self.Encoding.obj_size) 206 207 self.obj_context["HeapAS"] = self.obj_vm
208 209 @utils.safe_property
210 - def Segments(self):
211 """Returns an iterator over the segments.""" 212 # Windows XP has an array of segments. 213 segment_array = self.m("Segments") 214 if segment_array: 215 for segment in segment_array: 216 segment = segment.dereference() 217 218 # Since we operate in the process address space address 0 may be 219 # valid. 220 if not segment: 221 break 222 223 yield segment 224 225 return 226 227 # Windows 7 has a linked list of segments. 228 for segment in self.SegmentList.list_of_type( 229 "_HEAP_SEGMENT", "SegmentListEntry"): 230 yield segment
231 232 233 @utils.safe_property
234 - def Entries(self):
235 """Iterates over all the entries in all the segments.""" 236 for segment in self.Segments: 237 for entry in segment.FirstEntry.walk_list("NextEntry", True): 238 yield entry
239
240 241 242 -class Ntdll(pe_vtypes.BasicPEProfile):
243 """A profile for the ntdll user mode DLL.""" 244 245 @classmethod
246 - def Initialize(cls, profile):
251
252 253 -def InitializeHeapProfile(profile):
254 profile.add_overlay(overlays) 255 profile.add_classes( 256 _HEAP=_HEAP, 257 _HEAP_ENTRY=_HEAP_ENTRY, 258 _HEAP_FREE_ENTRY=_HEAP_ENTRY, 259 )
260