def make(opts): log.info('[+] Loading context of %s'%(opts.dump1)) context = context.get_context(opts.dump1) #'../../outputs/skype.1.a') # TODO # refresh if len(context.structures) != len(context.structures_addresses): log.info('[+] Refreshing from %d structures cached'%( len(context.structures) )) mallocRev = MallocReverser() context = mallocRev.reverse(context) mallocRev.check_inuse(context) log.info('[+] Final %d structures from malloc blocs'%( len(context.structures) )) heap1 = context.mappings.getHeap() log.info('[+] Loading mappings of %s'%(opts.dump2)) newmappings = dump_loader.load( opts.dump2) heap2 = newmappings.getHeap() log.info('[+] finding diff values with %s'%(opts.dump2)) addrs = cmd_cmp(heap1, heap2, heap1.start) # now compare with structures addresses structures = [] realloc=0 log.info('[+] Looking at %d differences'%( len(addrs) )) st = [] # joined iteration, found structure affected # use info from malloc : structures.start + .size addr_iter = iter(addrs) structs_addr_iter = iter(context.malloc_addresses) structs_size_iter = iter(context.malloc_sizes) try: addr = addr_iter.next() st_addr = structs_addr_iter.next() st_size = structs_size_iter.next() cnt=1 while True: while (addr - st_addr) >= st_size : # find st containing offset st_addr = structs_addr_iter.next() st_size = structs_size_iter.next() # check for gaps if (addr - st_addr) < 0: # went to far - no struct overlapping while (addr - st_addr) < 0: # addr is in between two struct - dump all addr stuck out of malloc_chunks addr = addr_iter.next() pass continue # if 0 <= (addr - st_addr) < st_size: # check if offset is really in st ( should be always if your not dumb/there no holes ) structures.append( context.structures[ st_addr ]) # tag the structure as different cnt+=1 else: ## (addr - st_addr) < 0 # impossible by previous while ## (addr - st_addr) >= st_size # then continur continue while (addr - st_addr) < st_size : # enumerate offsets in st range addr = addr_iter.next() cnt+=1 except StopIteration,e: pass
def setUpClass(self): # self.context3 = context.get_context('test/src/test-ctypes3.dump') self.context6 = context.get_context("test/src/test-ctypes6.32.dump") from haystack.reverse.heuristics import dsa self.dsa = dsa.DSASimple(self.context6.mappings) self.st = self.context6.listStructures()[0]
def test_string_overlap(self): context6 = context.get_context('test/src/test-ctypes6.dump') for s in context6.listStructures(): #s.resolvePointers() self.dsa.analyze_fields(s) log.debug(s.toString()) self.assertTrue(True) # test no error
def test_string_overlap(self): context6 = context.get_context('test/src/test-ctypes6.32.dump') for s in context6.listStructures(): # s.resolvePointers() self.dsa.analyze_fields(s) log.debug(s.toString()) self.assertTrue(True) # test no error
def test_closestFloorValue(self): lst = numpy.asarray(range(0,100,10)) self.assertEquals(utils.closestFloorValue(41, lst), (40,4)) self.assertEquals(utils.closestFloorValue(40, lst), (40,4)) with self.assertRaises(ValueError): utils.closestFloorValue(-1, lst) ctx = context.get_context('test/src/test-ctypes3.dump') lst = ctx._structures_addresses
def test4(): dumpname = '/home/jal/outputs/dumps/ssh/ssh.1' # 23418' #dumpname = '/home/jal/outputs/dumps/skype/skype.1/skype.1.a' print('[+] load context', dumpname) ctx = context.get_context(dumpname) mappings = ctx.mappings for ptr, name in ctx._function_names.items(): print('@%x -> %s::%s' % (ptr, mappings.get_mapping_for_address(ptr).pathname, name))
def test_closestFloorValue(self): lst = numpy.asarray(range(0, 100, 10)) self.assertEquals(utils.closestFloorValue(41, lst), (40, 4)) self.assertEquals(utils.closestFloorValue(40, lst), (40, 4)) with self.assertRaises(ValueError): utils.closestFloorValue(-1, lst) ctx = context.get_context('test/src/test-ctypes3.dump') lst = ctx._structures_addresses
def makeSignatures(dumpname): from haystack.reverse import context log.debug('\t[-] Loading the context for a dumpname.') ctx = context.get_context(dumpname) heap = ctx.heap log.info('[+] Make the signatures.') sigMaker = SignatureMaker(heap) sig = sigMaker.search() return ctx, sig
def makeSizeCaches(dumpname): ''' gets all allocators instances from the dump, order them by size.''' from haystack.reverse import context log.debug('\t[-] Loading the context for a dumpname.') ctx = context.get_context(dumpname) log.debug('\t[-] Make the size dictionnaries.') sizeCache = StructureSizeCache(ctx) sizeCache.cacheSizes() return ctx, sizeCache
def reverseLookup(opt): from haystack.reverse import context log.info('[+] Load context') ctx = context.get_context(opt.dumpname) addr = opt.struct_addr log.info('[+] find offsets of struct_addr:%x'%(addr)) i = -1 structs = set() try: structs = ctx.listStructuresForPointerValue(addr) except ValueError,e: log.info('[+] Found no structures.') return
def reverseInstances(dumpname): from haystack.reverse import context log.debug ('[+] Loading the memory dump ') ctx = context.get_context(dumpname) try: if not os.access(Config.getStructsCacheDir(ctx.dumpname), os.F_OK): os.mkdir(Config.getStructsCacheDir(ctx.dumpname)) # we use common allocators to find structures. #log.debug('Reversing malloc') #mallocRev = MallocReverser() #ctx = mallocRev.reverse(ctx) #mallocRev.check_inuse(ctx) # try to find some logical constructs. log.debug('Reversing DoubleLinkedListReverser') doublelink = DoubleLinkedListReverser() ctx = doublelink.reverse(ctx) # decode bytes contents to find basic types. log.debug('Reversing Fields') fr = FieldReverser() ctx = fr.reverse(ctx) # identify pointer relation between structures log.debug('Reversing PointerFields') pfr = PointerFieldReverser() ctx = pfr.reverse(ctx) # graph pointer relations between structures log.debug('Reversing PointerGraph') ptrgraph = PointerGraphReverser() ctx = ptrgraph.reverse(ctx) ptrgraph._saveStructures(ctx) #save to file save_headers(ctx) #fr._saveStructures(ctx) ##libRev = KnowStructReverser('libQt') ##ctx = libRev.reverse(ctx) # we have more enriched context # etc except KeyboardInterrupt,e: #except IOError,e: log.warning(e) log.info('[+] %d structs extracted'%( context.structuresCount()) ) raise e pass
def reverseInstances(dumpname): from haystack.reverse import context log.debug('[+] Loading the memory dump ') ctx = context.get_context(dumpname) try: if not os.access(Config.getStructsCacheDir(ctx.dumpname), os.F_OK): os.mkdir(Config.getStructsCacheDir(ctx.dumpname)) # we use common allocators to find structures. #log.debug('Reversing malloc') #mallocRev = MallocReverser() #ctx = mallocRev.reverse(ctx) #mallocRev.check_inuse(ctx) # try to find some logical constructs. log.debug('Reversing DoubleLinkedListReverser') doublelink = DoubleLinkedListReverser() ctx = doublelink.reverse(ctx) # decode bytes contents to find basic types. log.debug('Reversing Fields') fr = FieldReverser() ctx = fr.reverse(ctx) # identify pointer relation between structures log.debug('Reversing PointerFields') pfr = PointerFieldReverser() ctx = pfr.reverse(ctx) # graph pointer relations between structures log.debug('Reversing PointerGraph') ptrgraph = PointerGraphReverser() ctx = ptrgraph.reverse(ctx) ptrgraph._saveStructures(ctx) #save to file save_headers(ctx) #fr._saveStructures(ctx) ##libRev = KnowStructReverser('libQt') ##ctx = libRev.reverse(ctx) # we have more enriched context # etc except KeyboardInterrupt, e: #except IOError,e: log.warning(e) log.info('[+] %d structs extracted' % (context.structuresCount())) raise e pass
def make(opts): fname = opts.gexf # if __name__ == '__main__': # if False: # ctx = context.get_context('../../outputs/skype.1.a') ctx = context.get_context(opts.dumpname) # digraph=networkx.readwrite.gexf.read_gexf( '../../outputs/skype.1.a.gexf') digraph = networkx.readwrite.gexf.read_gexf(opts.gexf.name) heap = ctx.mappings.get_heap() # only add heap structure with links edges = [(x, y) for x, y in digraph.edges() if int(x, 16) in heap and int(y, 16) in heap] graph = networkx.DiGraph() graph.add_edges_from(edges) printGraph(graph, os.path.basename(opts.dumpname))
def make(opts): fname = opts.gexf #if __name__ == '__main__': #if False: #ctx = context.get_context('../../outputs/skype.1.a') ctx = context.get_context(opts.dumpname) #digraph=networkx.readwrite.gexf.read_gexf( '../../outputs/skype.1.a.gexf') digraph = networkx.readwrite.gexf.read_gexf(opts.gexf.name) heap = ctx.mappings.getHeap() # only add heap structure with links edges = [(x, y) for x, y in digraph.edges() if int(x, 16) in heap and int(y, 16) in heap] graph = networkx.DiGraph() graph.add_edges_from(edges) printGraph(graph, os.path.basename(opts.dumpname))
def test_get_context(self): '''FIXME: maybe not the best idea to use a reverser in a haystack.base test unit''' from haystack.reverse import context self.putty = context.get_context('test/dumps/putty/putty.1.dump') mappings = self.putty.mappings # print ''.join(['%s\n'%(m) for m in mappings]) with self.assertRaises(ValueError): mappings.get_context(0x0) with self.assertRaises(ValueError): mappings.get_context(0xb76e12d3) #[heap] children self.assertEquals( mappings.get_context(0x0062d000).heap, mappings.get_mapping_for_address(0x005c0000)) self.assertEquals( mappings.get_context(0x0063e123).heap, mappings.get_mapping_for_address(0x005c0000)) self.putty.reset() self.putty = None
def setUpClass(self): self.ssh = context.get_context('test/dumps/ssh/ssh.1') self.putty = context.get_context('test/dumps/putty/putty.1.dump') pass
def _listStructures(self): from haystack.reverse import context self.context = context.get_context(self.mappings.name) self.show_structures_allocated(self.context) return
def make(opts): log.info('[+] Loading context of %s' % (opts.dump1)) # '../../outputs/skype.1.a') # TODO ctx = context.get_context(opts.dump1) # refresh if len(ctx.structures) != len(ctx.structures_addresses): log.info( '[+] Refreshing from %d allocators cached' % (len( ctx.structures))) # FIXME, I think its now an heapwalker, not a reverser mallocRev = reversers.MallocReverser() ctx = mallocRev.reverse(ctx) mallocRev.check_inuse(ctx) log.info( '[+] Final %d allocators from malloc blocs' % (len( ctx.structures))) finder = ctx.get_memory_handler().get_heap_finder() heap1 = finder.list_heap_walkers()[0] log.info('[+] Loading _memory_handler of %s' % (opts.dump2)) newmappings = dump_loader.load(opts.dump2) finder2 = newmappings.get_heap_finder() heap2 = finder2.list_heap_walkers()[0] log.info('[+] finding diff values with %s' % (opts.dump2)) addrs = cmd_cmp(heap1, heap2, heap1.start) # now compare with allocators addresses structures = [] realloc = 0 log.info('[+] Looking at %d differences' % (len(addrs))) st = [] # joined iteration, found structure affected # use info from malloc : allocators.start + .size addr_iter = iter(addrs) structs_addr_iter = iter(ctx.malloc_addresses) structs_size_iter = iter(ctx.malloc_sizes) try: addr = addr_iter.next() st_addr = structs_addr_iter.next() st_size = structs_size_iter.next() cnt = 1 while True: while (addr - st_addr) >= st_size: # find st containing offset st_addr = structs_addr_iter.next() st_size = structs_size_iter.next() # check for gaps if (addr - st_addr) < 0: # went to far - no struct overlapping # addr is in between two struct - dump all addr stuck out of # malloc_chunks while (addr - st_addr) < 0: addr = addr_iter.next() pass continue # # check if offset is really in st ( should be always if your not # dumb/there no holes ) if 0 <= (addr - st_addr) < st_size: # tag the structure as different structures.append(ctx.structures[st_addr]) cnt += 1 else: # (addr - st_addr) < 0 # impossible by previous while # (addr - st_addr) >= st_size # then continur continue while (addr - st_addr) < st_size: # enumerate offsets in st range addr = addr_iter.next() cnt += 1 except StopIteration as e: pass addrs_found = cnt log.info( '[+] On %d diffs, found %d structs with different values. realloc: %d' % (addrs_found, len(structures), realloc)) log.info('[+] Outputing to file (will be long-ish)') print_diff_files(opts, context, newmappings, structures)
def setUpClass(self): self.ssh1 = context.get_context('test/dumps/ssh/ssh.1')
def setUpClass(self): self.context6 = context.get_context('test/src/test-ctypes6.dump')
def setUpClass(self): self.ssh1 = context.get_context("test/dumps/ssh/ssh.1")
def setUp(self): model.reset() # os.chdir() self.context = context.get_context('test/src/test-ctypes3.32.dump') self.dsa = dsa.DSASimple(self.context.config)
def test_reverseInstances(self): log.info('START test test_reverseInstances') ctx = context.get_context('test/dumps/ssh/ssh.1') dumpname = 'test/dumps/ssh/ssh.1' ctx = ctx.config.cleanCache(dumpname) ctx = reversers.reverseInstances(dumpname)
def setUpClass(self): self.context6 = context.get_context("test/src/test-ctypes6.dump")
def make(opts): log.info('[+] Loading context of %s' % (opts.dump1)) context = context.get_context( opts.dump1) #'../../outputs/skype.1.a') # TODO # refresh if len(context.structures) != len(context.structures_addresses): log.info('[+] Refreshing from %d structures cached' % (len(context.structures))) mallocRev = MallocReverser() context = mallocRev.reverse(context) mallocRev.check_inuse(context) log.info('[+] Final %d structures from malloc blocs' % (len(context.structures))) heap1 = context.mappings.getHeap() log.info('[+] Loading mappings of %s' % (opts.dump2)) newmappings = dump_loader.load(opts.dump2) heap2 = newmappings.getHeap() log.info('[+] finding diff values with %s' % (opts.dump2)) addrs = cmd_cmp(heap1, heap2, heap1.start) # now compare with structures addresses structures = [] realloc = 0 log.info('[+] Looking at %d differences' % (len(addrs))) st = [] # joined iteration, found structure affected # use info from malloc : structures.start + .size addr_iter = iter(addrs) structs_addr_iter = iter(context.malloc_addresses) structs_size_iter = iter(context.malloc_sizes) try: addr = addr_iter.next() st_addr = structs_addr_iter.next() st_size = structs_size_iter.next() cnt = 1 while True: while (addr - st_addr) >= st_size: # find st containing offset st_addr = structs_addr_iter.next() st_size = structs_size_iter.next() # check for gaps if (addr - st_addr) < 0: # went to far - no struct overlapping while ( addr - st_addr ) < 0: # addr is in between two struct - dump all addr stuck out of malloc_chunks addr = addr_iter.next() pass continue # if 0 <= ( addr - st_addr ) < st_size: # check if offset is really in st ( should be always if your not dumb/there no holes ) structures.append(context.structures[st_addr] ) # tag the structure as different cnt += 1 else: ## (addr - st_addr) < 0 # impossible by previous while ## (addr - st_addr) >= st_size # then continur continue while (addr - st_addr) < st_size: # enumerate offsets in st range addr = addr_iter.next() cnt += 1 except StopIteration, e: pass
def setUpClass(self): #self.context3 = context.get_context('test/src/test-ctypes3.dump') self.context6 = context.get_context('test/src/test-ctypes6.dump') from haystack.reverse.heuristics import dsa self.dsa = dsa.DSASimple() self.st = self.context6.listStructures()[0]
def setUp(self): #os.chdir() self.context = context.get_context('test/src/test-ctypes3.dump')
def test_reverseInstances(self): ctx = context.get_context('test/dumps/ssh/ssh.1') dumpname = 'test/dumps/ssh/ssh.1' ctx = Config.cleanCache(dumpname) ctx = reversers.reverseInstances(dumpname)
def setUpClass(self): from haystack.reverse.heuristics import dsa self.context = context.get_context('test/src/test-ctypes3.32.dump') self.dsa = dsa.DSASimple(self.context.config) self.pta = dsa.EnrichedPointerFields(self.context.config) pass
def setUpClass(self): self.context = None #context.get_context('test/src/test-ctypes3.dump') self.putty7124 = context.get_context('test/dumps/putty/putty.7124.dump') self.dsa = DSASimple()
def test3(): ''' reverse fn pointer names by trying to rebase the ptr value to a local ld_open ''' # load local memdump # map all librairies # go through all pointers in librairies # try to dl_addr the pointers by rebasing. #from haystack import dump_loader #dump = memory_loader.load('/home/jal/outputs/dumps/ssh/ssh.1') IGNORES = ['None', '[heap]', '[stack]', '[vdso]'] dumpname = '/home/jal/outputs/dumps/ssh/ssh.1' # 23418' #dumpname = '/home/jal/outputs/dumps/skype/skype.1/skype.1.a' print('[+] load context', dumpname) ctx = context.get_context(dumpname) mappings = ctx.mappings ldso = dict() for m in mappings: if m.pathname not in IGNORES and m.pathname not in ldso: try: ldso[m.pathname] = ctypes.CDLL(m.pathname) except OSError as e: IGNORES.append(m.pathname) print('[+] context loaded') # mmap_libdl = [ m for m in _memory_handler if 'ld-2.13' in m.pathname ] #and 'x' in m.permissions] #hptrs = ctx._pointers_values_heap # print '[+] %d pointers in heap to heap '%( len(hptrs) ) # looking in [heap] pointing to elsewhere all_ptrs = ctx.listPointerValueInHeap() print('[+] %d pointers in heap to elsewhere ' % (len(all_ptrs))) localmappings = getMappings() #crypto = _memory_handler.get_mapping('/lib/i386-linux-gnu/libcrypto.so.1.0.0') # for lm in crypto: # print lm # print '---' #crypto = localmappings.get_mapping('/lib/i386-linux-gnu/libcrypto.so.1.0.0') # for lm in crypto: # print lm # return for ptr in set(all_ptrs): # get dump mmap m = mappings.get_mapping_for_address(ptr) if m.pathname not in IGNORES: # find the right localmmap localmaps = localmappings._get_mapping(m.pathname) found = False for localm in localmaps: if localm.offset == m.offset and localm.permissions == m.permissions: # found it found = True caddr = ptr - m.start + localm.start # rebase dl_name, fnaddr = getname(caddr) if dl_name is not None: #sym = libdl.dlsym( ldso[m.pathname]._handle, dl_name, 'xxx') #fnaddr = struct.unpack('L',struct.pack('l', sym) )[0] if fnaddr == caddr: # reverse check print('[+] REBASE 0x%x -> 0x%x p:%s|%s|=%s off:%x|%x|=%s %s fn: %s @%x' % ( ptr, caddr, m.permissions, localm.permissions, localm.permissions == m.permissions, m.offset, localm.offset, m.offset == localm.offset, m.pathname, dl_name, fnaddr)) # yield (ptr, m, dl_name) else: # continue print('[-] MIDDLE 0x%x -> 0x%x p:%s|%s|=%s off:%x|%x|=%s %s fn: %s @%x' % ( ptr, caddr, m.permissions, localm.permissions, localm.permissions == m.permissions, m.offset, localm.offset, m.offset == localm.offset, m.pathname, dl_name, fnaddr)) else: continue print('FAIL REBASE (not public ?) 0x%x -> 0x%x p:%s|%s|=%s off:%x|%x|=%s %s fn: %s ' % ( ptr, caddr, m.permissions, localm.permissions, localm.permissions == m.permissions, m.offset, localm.offset, m.offset == localm.offset, m.pathname, dl_name)) pass break if not found: continue print('[+] not a fn pointer %x\n' % (ptr), m, '\n ---dump Vs local ---- \n', '\n'.join(map(str, localmaps))) # pass for name, lib in ldso.items(): ret = libdl.dlclose(lib._handle) return
def main(): from haystack.reverse import context ctx = context.get_context('test/dumps/skype/skype.1/skype.1.f') from haystack.reverse import structure it = structure.cacheLoadAllLazy(ctx) structs = [] for i in range(10000): structs.append(it.next()) [s.toString() for addr, s in structs] #51 Mo structure.CacheWrapper.refs.size = 5 for i in range(5): structure.CacheWrapper.refs[i] = i #51 Mo from meliae import scanner scanner.dump_all_objects('filename.json') from meliae import loader om = loader.load('filename.json') s = om.summarize() s ''' Total 206750 objects, 150 types, Total size = 27.2MiB (28495037 bytes) Index Count % Size % Cum Max Kind 0 75801 36 7529074 26 26 27683 str 1 11507 5 6351864 22 48 552 Field 2 16 0 5926913 20 69 2653328 numpy.ndarray 3 10000 4 1680000 5 75 168 CacheWrapper 4 2099 1 1158648 4 79 552 AnonymousStructInstance 5 1182 0 857136 3 82 98440 dict 6 18630 9 745200 2 85 40 weakref 7 14136 6 633148 2 87 43812 list ''' # clearly Field instances keep some place.... # most 10000 Anonymous intances are not int memory now om.compute_referrers() # om[ addr].parents # om[ addr].children # get the biggest Field f_addr = s.summaries[1].max_address om[f_addr] #Field(179830860 552B 21refs 1par) om[f_addr].parents # [179834316] # >>> om[ 179834316 ] # list(179834316 132B 19refs 1par) <- list of fields in Struct l_addr = om[f_addr].parents[0] om[l_addr].parents # [179849516] # >>> om[ 179849516 ] # AnonymousStructInstance(179849516 552B 23refs 19par) anon_addr = om[l_addr].parents[0] om[anon_addr] #179849516 is a anon struct import networkx import matplotlib.pyplot as plt graphme()
def main(): from haystack.reverse import context ctx = context.get_context('test/dumps/skype/skype.1/skype.1.f') from haystack.reverse import structure it = structure.cacheLoadAllLazy(ctx) structs = [] for i in range(10000): structs.append(it.next()) [s.toString() for addr, s in structs] # 51 Mo structure.CacheWrapper.refs.size = 5 for i in range(5): structure.CacheWrapper.refs[i] = i # 51 Mo from meliae import scanner scanner.dump_all_objects('filename.json') from meliae import loader om = loader.load('filename.json') s = om.summarize() s ''' Total 206750 objects, 150 types, Total size = 27.2MiB (28495037 bytes) Index Count % Size % Cum Max Kind 0 75801 36 7529074 26 26 27683 str 1 11507 5 6351864 22 48 552 Field 2 16 0 5926913 20 69 2653328 numpy.ndarray 3 10000 4 1680000 5 75 168 CacheWrapper 4 2099 1 1158648 4 79 552 AnonymousStructInstance 5 1182 0 857136 3 82 98440 dict 6 18630 9 745200 2 85 40 weakref 7 14136 6 633148 2 87 43812 list ''' # clearly Field instances keep some place.... # most 10000 Anonymous intances are not int memory now om.compute_referrers() # om[ addr].parents # om[ addr].children # get the biggest Field f_addr = s.summaries[1].max_address om[f_addr] # Field(179830860 552B 21refs 1par) om[f_addr].parents # [179834316] # >>> om[ 179834316 ] # list(179834316 132B 19refs 1par) <- list of fields in Struct l_addr = om[f_addr].parents[0] om[l_addr].parents # [179849516] # >>> om[ 179849516 ] # AnonymousStructInstance(179849516 552B 23refs 19par) anon_addr = om[l_addr].parents[0] om[anon_addr] # 179849516 is a anon struct import networkx import matplotlib.pyplot as plt graphme()
def make(opts): log.info('[+] Loading context of %s' % (opts.dump1)) # '../../outputs/skype.1.a') # TODO ctx = context.get_context(opts.dump1) # refresh if len(ctx.structures) != len(ctx.structures_addresses): log.info('[+] Refreshing from %d allocators cached' % (len(ctx.structures))) # FIXME, I think its now an heapwalker, not a reverser mallocRev = reversers.MallocReverser() ctx = mallocRev.reverse(ctx) mallocRev.check_inuse(ctx) log.info('[+] Final %d allocators from malloc blocs' % (len(ctx.structures))) finder = ctx.get_memory_handler().get_heap_finder() heap1 = finder.get_heap_mappings()[0] log.info('[+] Loading _memory_handler of %s' % (opts.dump2)) newmappings = dump_loader.load(opts.dump2) finder2 = newmappings.get_heap_finder() heap2 = finder2.get_heap_mappings()[0] log.info('[+] finding diff values with %s' % (opts.dump2)) addrs = cmd_cmp(heap1, heap2, heap1.start) # now compare with allocators addresses structures = [] realloc = 0 log.info('[+] Looking at %d differences' % (len(addrs))) st = [] # joined iteration, found structure affected # use info from malloc : allocators.start + .size addr_iter = iter(addrs) structs_addr_iter = iter(ctx.malloc_addresses) structs_size_iter = iter(ctx.malloc_sizes) try: addr = addr_iter.next() st_addr = structs_addr_iter.next() st_size = structs_size_iter.next() cnt = 1 while True: while (addr - st_addr) >= st_size: # find st containing offset st_addr = structs_addr_iter.next() st_size = structs_size_iter.next() # check for gaps if (addr - st_addr) < 0: # went to far - no struct overlapping # addr is in between two struct - dump all addr stuck out of # malloc_chunks while (addr - st_addr) < 0: addr = addr_iter.next() pass continue # # check if offset is really in st ( should be always if your not # dumb/there no holes ) if 0 <= (addr - st_addr) < st_size: # tag the structure as different structures.append(ctx.structures[st_addr]) cnt += 1 else: # (addr - st_addr) < 0 # impossible by previous while # (addr - st_addr) >= st_size # then continur continue while (addr - st_addr) < st_size: # enumerate offsets in st range addr = addr_iter.next() cnt += 1 except StopIteration as e: pass addrs_found = cnt log.info( '[+] On %d diffs, found %d structs with different values. realloc: %d' % (addrs_found, len(structures), realloc)) log.info('[+] Outputing to file (will be long-ish)') print_diff_files(opts, context, newmappings, structures)
def setUpClass(self): from haystack.reverse.heuristics import dsa self.context = context.get_context('test/src/test-ctypes3.dump') self.dsa = dsa.DSASimple() self.pta = dsa.EnrichedPointerFields() pass