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