#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import print_function import argparse import logging import struct import sys from haystack import cli from haystack import argparse_utils from haystack.outputters import text from haystack.mappings import folder # from haystack.outputters import python """ Search for HEAP. """ log = logging.getLogger('cliwin') def find_heap(): argv = sys.argv[1:] parser = cli.base_argparser('haystack-find-heap', "Find heaps in a dumpfile") parser.add_argument('--verbose', '-v', action='store_true', help='Verbose') parser.add_argument('--mappings', '-m', action='store_true', help='Show mappings') # only if address is present group = parser.add_argument_group('For a specific HEAP') group.add_argument('address', nargs='?', type=argparse_utils.int16, default=None, help='Load Heap from address (hex)') group.add_argument('--heap', '-p', action='store_true', help='Show the heap content') group.add_argument('--frontend', '-f', action='store_true', help='Show the frontend heap content') opts = parser.parse_args(argv) cli.set_logging_level(opts) memory_handler = cli.make_memory_handler(opts) finder = memory_handler.get_heap_finder() # Show Target information if opts.bits or opts.osname: print('Forced target resolution:', memory_handler.get_target_platform()) else: print('Automatic target resolution:', memory_handler.get_target_platform()) if opts.mappings: # show all memory mappings print('Process mappings:') print('@start @stop File Offset M:m ') for m in memory_handler.get_mappings(): print(m) if opts.address is not None: one_heap(opts, finder) return print('Probable Process HEAPS:') for m in memory_handler.get_mappings(): for addr in range(m.start, m.end, 0x1000): special = '' for os, bits, offset in [('winxp', 32, 8), ('winxp', 64, 16), ('win7', 32, 100), ('win7', 64, 160)]: signature = struct.unpack('I', m.read_bytes(addr+offset, 4))[0] if signature == 0xeeffeeff: if addr != m.start: special = ' (!) ' print('[+] %s %dbits %s 0x%0.8x' % (os, bits, special, addr), m) # Then show heap analysis print('Found Heaps:') for walker in finder.list_heap_walkers(): validator = walker.get_heap_validator() validator.print_heap_analysis(walker.get_heap(), opts.verbose) return def one_heap(opts, finder): address = opts.address memory_handler = finder._memory_handler # just return the heap ctypes_heap, valid = finder.search_heap_direct(address) out = text.RecursiveTextOutputter(finder._memory_handler) # out = python.PythonOutputter(finder._memory_handler) if opts.heap: print(out.parse(ctypes_heap, depth=2)) print('Valid =', valid) if opts.frontend: heap_addr = ctypes_heap._orig_address_ heap_m = memory_handler.get_mapping_for_address(heap_addr) walker = finder.get_heap_walker(heap_m) win_heap = walker._heap_module _utils = memory_handler.get_target_platform().get_target_ctypes_utils() if ctypes_heap.FrontEndHeapType == 0: log.error('BACKEND HEAP Type') elif ctypes_heap.FrontEndHeapType == 1: lal_start_addr = _utils.get_pointee_address(ctypes_heap.FrontEndHeap) m = memory_handler.is_valid_address(lal_start_addr, win_heap.HEAP_LOOKASIDE * 128) if not m: log.error('HEAP.FrontEndHeap has a bad address %x', lal_start_addr) return set() lal_list = m.read_struct(lal_start_addr, win_heap.HEAP_LOOKASIDE * 128) for i, st in enumerate(lal_list): out.parse(st, depth=2) elif ctypes_heap.FrontEndHeapType == 2 and memory_handler.get_target_platform().get_os_name() != 'winxp': lfh_start_addr = _utils.get_pointee_address(ctypes_heap.FrontEndHeap) m = memory_handler.is_valid_address(lfh_start_addr, win_heap.LFH_HEAP) if not m: log.error('HEAP.FrontEndHeap has a bad address %x', lfh_start_addr) return set() lfh_heap = m.read_struct(lfh_start_addr, win_heap.LFH_HEAP) out.parse(lfh_heap, depth=2) pass # fake it if valid: m = memory_handler.get_mapping_for_address(address) # we force the mapping to be a heap container because we where asked to validator = finder.get_heap_walker(m).get_heap_validator() validator.print_heap_analysis(ctypes_heap, opts.verbose) else: print("Could not load Heap for target", memory_handler.get_target_platform()) return if __name__ == '__main__': find_heap()