class Metasm::WindowsHeap
Attributes
heaps[RW]
Public Instance Methods
each_heap() { |ar| ... }
click to toggle source
yields the _HEAP structure for all heaps
# File samples/dbg-plugins/heapscan/heapscan.rb, line 573 def each_heap heaps.each { |a, l| ar = @cp.decode_c_struct('_HEAP', @dbg.memory, a) yield ar } end
each_heap_segment(ar) { |ptr, sa-ptr| ... }
click to toggle source
yields all [ptr, len] for allocated segments of a _HEAP this maps to the _HEAP_SEGMENT further subdivised to skip the _HEAP_UNCOMMMTTED_RANGE areas for the last chunk of the _HEAP_SEGMENT, only yield up to chunk_header
# File samples/dbg-plugins/heapscan/heapscan.rb, line 584 def each_heap_segment(ar) ar.segments.to_array.compact.each { |a| sg = @cp.decode_c_struct('_HEAP_SEGMENT', @dbg.memory, a) skiplist = [] ptr = sg.uncommittedranges while ptr ucr = @cp.decode_c_struct('_HEAP_UNCOMMMTTED_RANGE', @dbg.memory, ptr) skiplist << [ucr.Address, ucr.Size] ptr = ucr.Next end ptr = sg.firstentry # XXX lastentryinsegment == firstentry ??? # lastvalidentry = address of the end of the segment (may point to unmapped space) ptrend = sg.lastvalidentry skiplist.delete_if { |sa, sl| sa < ptr or sa + sl > ptrend } skiplist << [ptrend, 1] skiplist.sort.each { |sa, sl| yield(ptr, sa-ptr) ptr = sa + sl } } end
each_listentry(le, st, off=0) { |decode_c_struct(st, memory, ptr-off)| ... }
click to toggle source
call with a LIST_ENTRY allocstruct, the target structure and LE offset in this structure
# File samples/dbg-plugins/heapscan/heapscan.rb, line 608 def each_listentry(le, st, off=0) ptr0 = le.stroff ptr = le.flink while ptr != ptr0 yield @cp.decode_c_struct(st, @dbg.memory, ptr-off) ptr = @cp.decode_c_struct('_LIST_ENTRY', @dbg.memory, ptr).flink end end
scan_chunks()
click to toggle source
# File samples/dbg-plugins/heapscan/heapscan.rb, line 489 def scan_chunks @hsz = @cp.sizeof(@cp.find_c_struct('_HEAP_ENTRY')) @chunks = {} each_heap { |ar| scan_heap(ar) } end
scan_chunks_xr()
click to toggle source
scan all chunks for cross-references (one chunk containing a pointer to some other chunk)
# File samples/dbg-plugins/heapscan/heapscan.rb, line 496 def scan_chunks_xr @xrchunksto = {} @xrchunksfrom = {} each_heap { |ar| scan_heap_xr(ar) } end
scan_frontend(ar)
click to toggle source
# File samples/dbg-plugins/heapscan/heapscan.rb, line 511 def scan_frontend(ar) if ar.frontendheaptype == 1 laptr = ar.frontendheap @chunks.delete laptr # not a real (user) chunk 128.times { la = @cp.decode_c_struct('_HEAP_LOOKASIDE', @dbg.memory, laptr) free = la.listhead.flink while free @chunks.delete free free = @cp.decode_c_struct('_LIST_ENTRY', @dbg.memory, free).flink end laptr += la.sizeof } end end
scan_heap(ar)
click to toggle source
scan chunks from a heap
# File samples/dbg-plugins/heapscan/heapscan.rb, line 503 def scan_heap(ar) each_heap_segment(ar) { |p, l| scan_heap_segment(p, l) } scan_frontend(ar) scan_valloc(ar) end
scan_heap_segment(first, len)
click to toggle source
# File samples/dbg-plugins/heapscan/heapscan.rb, line 534 def scan_heap_segment(first, len) off = 0 heapcpy = pagecache(first, len) while off < len he = @cp.decode_c_struct('_HEAP_ENTRY', heapcpy, off) sz = he.Size*8 if he.Flags & 1 == 1 @chunks[first+off+@hsz] = sz - he.UnusedBytes end off += sz end end
scan_heap_segment_xr(first, len)
click to toggle source
# File samples/dbg-plugins/heapscan/heapscan.rb, line 553 def scan_heap_segment_xr(first, len) off = 0 heapcpy = pagecache(first, len) while off < len he = @cp.decode_c_struct('_HEAP_ENTRY', heapcpy, off) sz = he.Size*8 ptr = first + off + @hsz if he.Flags & 1 == 1 and csz = @chunks[ptr] and csz > 0 heapcpy[off + @hsz, csz].unpack('L*').each { |p| if @chunks[p] (@xrchunksto[ptr] ||= []) << p (@xrchunksfrom[p] ||= []) << ptr end } end off += sz end end
scan_heap_xr(ar)
click to toggle source
# File samples/dbg-plugins/heapscan/heapscan.rb, line 547 def scan_heap_xr(ar) each_heap_segment(ar) { |p, l| scan_heap_segment_xr(p, l) } end
scan_valloc(ar)
click to toggle source
# File samples/dbg-plugins/heapscan/heapscan.rb, line 527 def scan_valloc(ar) each_listentry(ar.virtualallocdblocks, '_HEAP_VIRTUAL_ALLOC_ENTRY') { |va| # Unusedbyte count stored in the BusyBlock.Size field @chunks[va.stroff + va.sizeof] = va.CommitSize - va.Size } end