def test_complex_text(self): # struct a - basic types offset = self.offsets['struct_d'][0] m = self.memory_handler.get_mapping_for_address(offset) # d = m.read_struct(offset, self.ctypes5_gen32.struct_d) results, validated = api.load_record(self.memory_handler, self.ctypes5_gen32.struct_d, offset) self.assertTrue(results) parser = text.RecursiveTextOutputter(self.memory_handler) out = parser.parse(results) # should not fail x = eval(out) self.assertEqual(len(x.keys()), 15) # 14 + padding # its an byte string, that is a hex value. self.assertEqual(self.values['struct_d.a'], hex(x['a']).encode()) self.assertEqual(len(x['b'].keys()), 9) self.assertEqual(len(x['b2'].keys()), 8) self.assertEqual(int(self.values['struct_d.b.e']), x['b']['e']) self.assertEqual(int(self.values['struct_d.b2.e']), x['b2']['e']) for i in range(9): self.assertEqual(int(self.values['struct_d.c[%d].a' % (i)]), x['c'][i]['a']) self.assertEqual(int(self.values['struct_d.f[%d]' % (i)]), x['f'][i]) self.assertEqual(int(self.values['struct_d.e']), x['e']) self.assertEqual(self.values['struct_d.i'], x['i']) return
def toPyObject(self): d = OpenSSHStruct.toPyObject(self) #log.info('self.send_context.evp.app_data: 0x%lx'%(self.send_context.evp.app_data)) # populate AppData. try: if d.receive_context.evp.cipher.nid == 0: d.receive_context.evp.app_data = self.receive_context.getEvpAppData( ).toPyObject() d.send_context.evp.app_data = self.send_context.getEvpAppData( ).toPyObject() #log.debug('self.send_context.evp.app_data: %s'%(self.send_context.getEvpAppData())) #log.debug('d.send_context.evp.app_data: %s'%(d.send_context.evp.app_data)) ## TODO find a better way to pass a void_p for that cipher data #d.receive_context.evp.cipher_data = self.receive_context.getEvpAppData().toPyObject() #d.send_context.evp.cipher_data = self.send_context.getEvpAppData().toPyObject() if (type(d.send_context.evp.cipher_data) == tuple and d.send_context.evp.cipher_data[0] is not None and d.send_context.evp.cipher_data[1] is not None): from haystack.outputters import text parser = text.RecursiveTextOutputter(mappings) log.debug("cipher_data has %s" % (parser.parse(d.send_context.evp.cipher_data))) except AttributeError as e: log.error('Error while populating receive/send context') return d
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
def EVP_CIPHER_CTX_loadMembers(self, mappings, maxDepth): if not super(EVP_CIPHER_CTX, self).loadMembers(mappings, maxDepth): return False log.debug('trying to load cipher_data Structs.') ''' if bool(cipher) and bool(self.cipher.nid) and mappings.is_valid_address(cipher_data): memcopy( self.cipher_data, cipher_data_addr, self.cipher.ctx_size) # cast possible on cipher.nid -> cipherType ''' cipher = mappings.getRef(evp_cipher_st, get_pointee_address(self.cipher)) if cipher.nid == 0: # NID_undef, not openssl doing log.info( 'The cipher is home made - the cipher context data should be application dependant (app_data)' ) return True struct = getCipherDataType(cipher.nid) log.debug('cipher type is %s - loading %s' % (getCipherName(cipher.nid), struct)) if (struct is None): log.warning("Unsupported cipher %s" % (cipher.nid)) return True # c_void_p is a basic type. attr_obj_address = self.cipher_data memoryMap = mappings.is_valid_address_value(attr_obj_address, struct) log.debug("cipher_data CAST into : %s " % (struct)) if not memoryMap: log.warning( 'in CTX On second toughts, cipher_data seems to be at an invalid address. That should not happen (often).' ) log.warning('%s addr:0x%lx size:0x%lx addr+size:0x%lx ' % (mappings.is_valid_address_value(attr_obj_address), attr_obj_address, ctypes.sizeof(struct), attr_obj_address + ctypes.sizeof(struct))) return True #ok st = memoryMap.readStruct(attr_obj_address, struct) mappings.keepRef(st, struct, attr_obj_address) self.cipher_data = ctypes.c_void_p(ctypes.addressof(st)) ###print 'self.cipher_data in loadmembers',self.cipher_data # check debug attr = getattr(self, 'cipher_data') log.debug('Copied 0x%lx into %s (0x%lx)' % (ctypes.addressof(st), 'cipher_data', attr)) log.debug( 'LOADED cipher_data as %s from 0x%lx (%s) into 0x%lx' % (struct, attr_obj_address, mappings.is_valid_address_value(attr_obj_address, struct), attr)) from haystack.outputters import text parser = text.RecursiveTextOutputter(mappings) log.debug('\t\t---------\n%s\t\t---------' % (parser.parse(st))) return True
def loadMembers(self, mappings, maxDepth): if not ctypes.Structure.loadMembers(self, mappings, maxDepth): return False #log.debug('evp app_data attr_obj_address=0x%lx'%(self.evp.app_data) ) #log.debug('evp cipher_data attr_obj_address=0x%lx'%(self.evp.cipher_data) ) ##none cipher = mappings.getRef(Cipher, get_pointee_address(self.cipher)) ciphername = mappings.getRef(ctypes.CString, get_pointee_address(cipher.name.ptr)) # cast evp.app_data into a valid struct if ciphername in self.cipherContexts: # evp.cipher.nid should be 0 struct = self.cipherContexts[ciphername] if (struct is None): log.warning("Unsupported cipher %s" % (ciphername)) return True attr_obj_address = get_pointee_address(self.evp.app_data) memoryMap = mappings.is_valid_address_value( attr_obj_address, struct) log.debug("CipherContext CAST app_data into : %s " % (struct)) if not memoryMap: log.warning( 'On second toughts, app_data seems to be at an invalid address. That should not happen (often).' ) log.warning('%s addr:0x%lx size:0x%lx addr+size:0x%lx ' % (mappings.is_valid_address_value(attr_obj_address), attr_obj_address, ctypes.sizeof(struct), attr_obj_address + ctypes.sizeof(struct))) return False # DEBUG kill it # read the void * and keep a ref st = memoryMap.readStruct(attr_obj_address, struct) mappings.keepRef(st, struct, attr_obj_address) # yeah... no. "self.evp.app_data = xx" means SEGFAULT. address_evp_app_data = ctypes.addressof(st) log.debug('Copied 0x%lx into app_data (0x%lx)' % (attr_obj_address, address_evp_app_data)) log.debug('LOADED app_data as %s from 0x%lx (%s) into 0x%lx' % (struct, attr_obj_address, mappings.is_valid_address_value( attr_obj_address, struct), address_evp_app_data)) from haystack.outputters import text parser = text.RecursiveTextOutputter(mappings) log.debug('\t\t---------\n%s\t\t---------' % (parser.parse(st))) else: log.debug( "Unknown cipher %s, can't load a data struct for the EVP_CIPHER_CTX->app_data" % (ciphername)) return True
def output_to_string(memory_handler, results): """ Transform ctypes results in a string format :param memory_handler: IMemoryHandler :param results: results from the search_record :return: """ if not isinstance(results, list): raise TypeError('Feed me a list of results') parser = text.RecursiveTextOutputter(memory_handler) ret = '[' for ss, addr in results: ret += "# --------------- 0x%lx \n%s" % (addr, parser.parse(ss)) pass ret += ']' return ret
def getEvpAppData(self, mappings): cipher = self.getCipher(mappings) ciphername = cipher.getName(mappings) if ciphername in self.cipherContexts: struct = self.cipherContexts[ciphername] from haystack.outputters import text parser = text.RecursiveTextOutputter(mappings) if (struct is None): log.warning("Unsupported cipher %s" % (ciphername)) log.warning("%s" % (parser.parse(cipher))) return None log.debug('CAST evp.app_data Into %s' % (struct)) attr_obj_address = get_pointee_address(self.evp.app_data) st = mappings.getRef(struct, attr_obj_address) #st = struct.from_address(attr) log.debug('app_data value is : 0x%lx' % (attr_obj_address)) log.debug(parser.parse(st)) return st return None
def main(argv): parser = argparse.ArgumentParser(prog='haystack-find-heap', description="Find heaps in a dumpfile") parser.add_argument('--host', action='store', default='winxp', help='winxp,win7') parser.add_argument('dumpname', type=argparse_utils.readable, help='process memory dump name') parser.add_argument('address', nargs='?', type=argparse_utils.int16, default=None, help='Load Heap from address (hex)') opts = parser.parse_args(argv) #if 'libc' == opts.host: # my_finder = LibcHeapFinder() #el if 'winxp' == opts.host: my_finder = WinXPHeapFinder() elif 'win7' == opts.host: my_finder = Win7HeapFinder() else: raise ValueError('not such heap finder for %s' % opts.host) memdumpname = opts.dumpname if opts.address is None: if my_finder.search_heap(memdumpname) is not None: return else: address = opts.address # just return the heap ret = my_finder.search_heap_direct(memdumpname, address) out = text.RecursiveTextOutputter(my_finder.memory_handler) #out = python.PythonOutputter(my_finder.memory_handler) print out.parse(ret[0], depth=4) print 'Valid=', ret[1] return
def setUp(self): self._heap_finder = self._memory_handler.get_heap_finder() self.parser = text.RecursiveTextOutputter(self._memory_handler) return
def p(self, ss): # FIXME DEBUG from haystack.outputters import text parser = text.RecursiveTextOutputter(self._memory_handler) return parser.parse(ss)