def iterateList(self, mappings): ''' iterate forward, then backward, until null or duplicate ''' done = [0] obj = self #print 'going forward ' for fieldname in [forward, backward]: link = getattr(obj, fieldname) addr = utils.getaddress(link) log.debug('iterateList got a <%s>/0x%x'%(link.__class__.__name__,addr)) nb=0 while addr not in done: #print '%x %s'%(addr, addr in done) done.append(addr) memoryMap = utils.is_valid_address_value( addr, mappings, structType) if memoryMap == False: raise ValueError('the link of this linked list has a bad value') st = memoryMap.readStruct( addr, structType) model.keepRef(st, structType, addr) log.debug("keepRefx2 %s.%s @%x"%(structType, fieldname, addr )) yield addr # next link = getattr(st, fieldname) addr = utils.getaddress(link) #print 'going backward after %x'%(addr) raise StopIteration
def show_dumpname(structname, dumpname, address, rtype='python'): """ shows the values for klass at @address in memdump. :param structname the ctypes structure name (string) :type structName string :param dumpname the memdump filename :param address the address from where to read the structure :param rtype the return type format ( string, pickle, json ) :type rtype ['string', 'pickle', 'json', 'python'] :returns (instance, validated) instance the loaded ctypes and validated a boolean flag if validated is True, all constraints were OK in instance. """ from haystack import dump_loader log.debug('haystack show %s %s %x'%(dumpname, structname, address )) structType = getKlass(structname) mappings = dump_loader.load(dumpname) finder = StructFinder(mappings) # validate the input address. memoryMap = utils.is_valid_address_value(address, finder.mappings) if not memoryMap: log.error("the address is not accessible in the memoryMap") raise ValueError("the address is not accessible in the memoryMap") instance,validated = finder.loadAt( memoryMap, address, structType) out = _show_output(instance, validated, rtype) return out
def test_keepRef(self): self.assertNotEqual( self.mappings, None ) for fname, ftype in self.heap_obj.getFields(): attr = getattr(self.heap_obj, fname) if isCStringPointer(ftype): # ignore that - attr_addr = getaddress(attr.ptr) continue elif isPointerType(ftype): attr_addr = getaddress(attr) else: continue if attr_addr == 0: continue self.assertTrue( utils.is_valid_address_value(attr_addr, self.mappings), '%s: 0x%x is not valid'%(fname, attr_addr)) # the book should register struct type, not pointer to strut type attr_type = model.get_subtype(ftype) # look in the books saved = model.getRefByAddr( attr_addr ) _class, _addr, _obj = saved[0] self.assertEquals( attr_addr, _addr) self.assertEquals( attr_type, _class, '%s != %s' %(type(ftype), type(_class))) self.assertTrue( model.hasRef( model.get_subtype(ftype), attr_addr)) return
def iterateList(self, mappings): ''' iterate forward, then backward, until null or duplicate ''' done = [0] obj = self #print 'going forward ' for fieldname in [forward, backward]: link = getattr(obj, fieldname) addr = utils.getaddress(link) log.debug('iterateList got a <%s>/0x%x' % (link.__class__.__name__, addr)) nb = 0 while addr not in done: #print '%x %s'%(addr, addr in done) done.append(addr) memoryMap = utils.is_valid_address_value( addr, mappings, structType) if memoryMap == False: raise ValueError( 'the link of this linked list has a bad value') st = memoryMap.readStruct(addr, structType) model.keepRef(st, structType, addr) log.debug("keepRefx2 %s.%s @%x" % (structType, fieldname, addr)) yield addr # next link = getattr(st, fieldname) addr = utils.getaddress(link) #print 'going backward after %x'%(addr) raise StopIteration
def refresh(args): """ Default function for the refresh command line option. Try to map a Structure from a specific offset in memory. Returns it in pickled or text format. See the command line --help . """ log.debug(args) addr=int(args.addr,16) structType=getKlass(args.structName) mappings = MemoryMapper(pid=args.pid, memfile=args.memfile, dumpname=args.dumpname ).getMappings() finder = StructFinder(mappings) memoryMap = utils.is_valid_address_value(addr, finder.mappings) if not memoryMap: log.error("the address is not accessible in the memoryMap") raise ValueError("the address is not accessible in the memoryMap") instance,validated = finder.loadAt( memoryMap , addr, structType) ## if args.interactive: import code code.interact(local=locals()) if args.human: rtype = 'string' elif args.json: rtype = 'json' elif args.pickled: rtype = 'pickled' print _show_output(instance, validated, rtype) return
def test_keepRef(self): self.assertNotEqual(self.mappings, None) for fname, ftype in self.heap_obj.getFields(): attr = getattr(self.heap_obj, fname) if isCStringPointer(ftype): # ignore that - attr_addr = getaddress(attr.ptr) continue elif isPointerType(ftype): attr_addr = getaddress(attr) else: continue if attr_addr == 0: continue self.assertTrue( utils.is_valid_address_value(attr_addr, self.mappings), '%s: 0x%x is not valid' % (fname, attr_addr)) # the book should register struct type, not pointer to strut type attr_type = model.get_subtype(ftype) # look in the books saved = model.getRefByAddr(attr_addr) _class, _addr, _obj = saved[0] self.assertEquals(attr_addr, _addr) self.assertEquals(attr_type, _class, '%s != %s' % (type(ftype), type(_class))) self.assertTrue(model.hasRef(model.get_subtype(ftype), attr_addr)) return
def show_dumpname(structname, dumpname, address, rtype='python'): """ shows the values for klass at @address in memdump. :param structname the ctypes structure name (string) :type structName string :param dumpname the memdump filename :param address the address from where to read the structure :param rtype the return type format ( string, pickle, json ) :type rtype ['string', 'pickle', 'json', 'python'] :returns (instance, validated) instance the loaded ctypes and validated a boolean flag if validated is True, all constraints were OK in instance. """ from haystack import dump_loader log.debug('haystack show %s %s %x' % (dumpname, structname, address)) structType = getKlass(structname) mappings = dump_loader.load(dumpname) finder = StructFinder(mappings) # validate the input address. memoryMap = utils.is_valid_address_value(address, finder.mappings) if not memoryMap: log.error("the address is not accessible in the memoryMap") raise ValueError("the address is not accessible in the memoryMap") instance, validated = finder.loadAt(memoryMap, address, structType) out = _show_output(instance, validated, rtype) return out
def refresh(args): """ Default function for the refresh command line option. Try to map a Structure from a specific offset in memory. Returns it in pickled or text format. See the command line --help . """ log.debug(args) addr = int(args.addr, 16) structType = getKlass(args.structName) mappings = MemoryMapper(pid=args.pid, memfile=args.memfile, dumpname=args.dumpname).getMappings() finder = StructFinder(mappings) memoryMap = utils.is_valid_address_value(addr, finder.mappings) if not memoryMap: log.error("the address is not accessible in the memoryMap") raise ValueError("the address is not accessible in the memoryMap") instance, validated = finder.loadAt(memoryMap, addr, structType) ## if args.interactive: import code code.interact(local=locals()) if args.human: rtype = 'string' elif args.json: rtype = 'json' elif args.pickled: rtype = 'pickled' print _show_output(instance, validated, rtype) return
def _loadListEntries(self, fieldname, mappings, maxDepth): ''' we need to load the pointed entry as a valid struct at the right offset, and parse it. When does it stop following FLink/BLink ? sentinel is headAddr only ''' structType, offset = self._getListFieldInfo(fieldname) # DO NOT think HEAD is a valid entry. # if its a ListEntries, self has already been loaded anyway. headAddr = self._orig_address_ + utils.offsetof(type(self), fieldname) head = getattr(self, fieldname) for entry in head._iterateList(mappings): # DO NOT think HEAD is a valid entry if entry == headAddr: continue link = entry + offset log.debug('got a element of list at %s 0x%x/0x%x offset:%d' % (fieldname, entry, link, offset)) # use cache if possible, avoid loops. #XXX from haystack import model ref = model.getRef(structType, link) if ref: # struct has already been loaded, bail out log.debug("%s loading from references cache %s/0x%lx" % (fieldname, structType, link)) continue # do not reload else: # OFFSET read, specific to a LIST ENTRY model memoryMap = utils.is_valid_address_value( link, mappings, structType) if memoryMap is False: log.error( 'error while validating address 0x%x type:%s @end:0x%x' % (link, structType.__name__, link + ctypes.sizeof(structType))) log.error('self : %s , fieldname : %s' % (self.__class__.__name__, fieldname)) raise ValueError( 'error while validating address 0x%x type:%s @end:0x%x' % (link, structType.__name__, link + ctypes.sizeof(structType))) st = memoryMap.readStruct( link, structType) # point at the right offset st._orig_addr_ = link model.keepRef(st, structType, link) log.debug("keepRef %s.%s @%x" % (structType, fieldname, link)) # load the list entry structure members if not st.loadMembers(mappings, maxDepth - 1): log.error('Error while loading members on %s' % (self.__class__.__name__)) print st raise ValueError('error while loading members') return True
def _loadListEntries(self, fieldname, mappings, maxDepth): ''' we need to load the pointed entry as a valid struct at the right offset, and parse it. When does it stop following FLink/BLink ? sentinel is headAddr only ''' structType, offset = self._getListFieldInfo(fieldname) # DO NOT think HEAD is a valid entry. # if its a ListEntries, self has already been loaded anyway. headAddr = self._orig_address_ + utils.offsetof( type(self), fieldname) head = getattr(self, fieldname) for entry in head._iterateList(mappings): # DO NOT think HEAD is a valid entry if entry == headAddr: continue link = entry + offset log.debug('got a element of list at %s 0x%x/0x%x offset:%d'%(fieldname, entry, link, offset)) # use cache if possible, avoid loops. #XXX from haystack import model ref = model.getRef( structType, link) if ref: # struct has already been loaded, bail out log.debug("%s loading from references cache %s/0x%lx"%(fieldname, structType, link )) continue # do not reload else: # OFFSET read, specific to a LIST ENTRY model memoryMap = utils.is_valid_address_value( link, mappings, structType) if memoryMap is False: log.error('error while validating address 0x%x type:%s @end:0x%x'%(link, structType.__name__, link+ctypes.sizeof(structType)) ) log.error('self : %s , fieldname : %s'%(self.__class__.__name__, fieldname)) raise ValueError('error while validating address 0x%x type:%s @end:0x%x'%(link, structType.__name__, link+ctypes.sizeof(structType)) ) st = memoryMap.readStruct( link, structType) # point at the right offset st._orig_addr_ = link model.keepRef(st, structType, link) log.debug("keepRef %s.%s @%x"%(structType, fieldname, link )) # load the list entry structure members if not st.loadMembers(mappings, maxDepth-1): log.error('Error while loading members on %s'%(self.__class__.__name__)) print st raise ValueError('error while loading members') return True
def _HEAP_getFreeListsWinXP(self, mappings): """ Understanding_the_LFH.pdf page 17 """ freeList = [] # 128 blocks start = ctypes.addressof(self.FreeLists) # sentinel value logging.getLogger("listmodel").setLevel(level=logging.DEBUG) for freeBlock in self.FreeLists._iterateList(mappings): # try to get the size sizeaddr = freeBlock - Config.WORDSIZE memoryMap = utils.is_valid_address_value(sizeaddr, mappings) if memoryMap == False: raise ValueError("the link of this linked list has a bad value") val = memoryMap.readWord(sizeaddr) log.debug("\t - freeblock @%0.8x size:%d" % (freeBlock, val)) yield freeBlock # free_chain = [freeBlock for freeBlock in self.iterateListField( mappings, 'FreeLists')] logging.getLogger("listmodel").setLevel(level=logging.INFO) raise StopIteration
def _HEAP_getFreeListsWinXP(self, mappings): ''' Understanding_the_LFH.pdf page 17 ''' freeList = [] # 128 blocks start = ctypes.addressof(self.FreeLists) # sentinel value logging.getLogger('listmodel').setLevel(level=logging.DEBUG) for freeBlock in self.FreeLists._iterateList(mappings): # try to get the size sizeaddr = freeBlock - Config.WORDSIZE memoryMap = utils.is_valid_address_value(sizeaddr, mappings) if memoryMap == False: raise ValueError('the link of this linked list has a bad value') val = memoryMap.readWord(sizeaddr) log.debug('\t - freeblock @%0.8x size:%d' % (freeBlock, val)) yield freeBlock #free_chain = [freeBlock for freeBlock in self.iterateListField( mappings, 'FreeLists')] logging.getLogger('listmodel').setLevel(level=logging.INFO) raise StopIteration
def watch(opt): ''' structname watch vaddr [refreshrate] [varname]''' addr = opt.addr refresh = opt.refresh_rate varname = opt.varname # get structure class structType = abouchet.getKlass(opt.structName) # verify target compliance if varname is not None: varname = varname.split('.') if not check_varname_for_type(varname, structType): return False # load the struct mappings = memory_mapper.MemoryMapper(opt).getMappings() finder = abouchet.StructFinder(mappings) # get the target memory map memoryMap = utils.is_valid_address_value(addr, finder.mappings) if not memoryMap: log.error("the address is not accessible in the memoryMap") raise ValueError("the address is not accessible in the memoryMap") instance, validated = finder.loadAt(memoryMap, addr, structType) #instance.loadMembers(mappings) pyObj = instance.toPyObject() #print pyObj # print as asked every n secs. while True: clear() if varname is None: print pyObj else: print get_varname_value(varname, pyObj) if refresh == 0: break time.sleep(refresh) instance, validated = finder.loadAt(memoryMap, addr, structType) pyObj = instance.toPyObject()
def watch(opt): ''' structname watch vaddr [refreshrate] [varname]''' addr = opt.addr refresh = opt.refresh_rate varname = opt.varname # get structure class structType = abouchet.getKlass(opt.structName) # verify target compliance if varname is not None: varname = varname.split('.') if not check_varname_for_type(varname, structType): return False # load the struct mappings = memory_mapper.MemoryMapper(opt).getMappings() finder = abouchet.StructFinder(mappings) # get the target memory map memoryMap = utils.is_valid_address_value(addr, finder.mappings) if not memoryMap: log.error("the address is not accessible in the memoryMap") raise ValueError("the address is not accessible in the memoryMap") instance,validated = finder.loadAt( memoryMap , addr, structType) #instance.loadMembers(mappings) pyObj = instance.toPyObject() #print pyObj # print as asked every n secs. while True: clear() if varname is None: print pyObj else: print get_varname_value(varname, pyObj) if refresh == 0: break time.sleep(refresh) instance,validated = finder.loadAt( memoryMap , addr, structType) pyObj = instance.toPyObject()
def setUpClass(self): d = {'pickled': True, 'dumpname': 'test/dumps/ssh/ssh.1/', 'structName': 'sslsnoop.ctypes_openssh.session_state', 'addr': '0xb84ee318', 'pid': None, 'memfile': None, 'interactive': None, 'human': None, 'json': None, } args = type('args', ( object,), d) # setup haystack from haystack import config config.make_config_from_memdump(d['dumpname']) # addr = int(args.addr,16) structType = abouchet.getKlass(args.structName) self.mappings = memory_mapper.MemoryMapper(dumpname=args.dumpname).getMappings() self.finder = abouchet.StructFinder(self.mappings) memoryMap = utils.is_valid_address_value(addr, self.finder.mappings) # done self.session_state, self.found = self.finder.loadAt( memoryMap, addr, structType) self.pyobj = self.session_state.toPyObject()