def add(self, name, type, offset): """Add a member at ``offset`` with the given ``name`` and ``type``. To specify a particular size, ``type`` can be a tuple with the second element referring to the size. """ flag, typeid, nbytes = interface.typemap.resolve(type) # FIXME: handle .strtype (strings), .ec (enums), .cd (custom) opinfo = idaapi.opinfo_t() opinfo.tid = typeid realoffset = offset - self.baseoffset if name is None: logging.warn( "{:s}.instance({:s}).members.add : name is undefined, defaulting to offset {:+#x}" .format(__name__, self.owner.name, realoffset)) name = 'v', realoffset if isinstance(name, tuple): name = interface.tuplename(*name) res = idaapi.add_struc_member(self.owner.ptr, name, realoffset, flag, opinfo, nbytes) if res == idaapi.STRUC_ERROR_MEMBER_OK: logging.info( "{:s}.instance({:s}).members.add : idaapi.add_struc_member(sptr={!r}, fieldname={:s}, offset={:+#x}, flag={:#x}, mt={:#x}, nbytes={:#x}) : Success" .format(__name__, self.owner.name, self.owner.name, name, realoffset, flag, typeid, nbytes)) else: error = { idaapi.STRUC_ERROR_MEMBER_NAME: 'Duplicate field name', idaapi.STRUC_ERROR_MEMBER_OFFSET: 'Invalid offset', idaapi.STRUC_ERROR_MEMBER_SIZE: 'Invalid size', } callee = "idaapi.add_struc_member(sptr={!r}, fieldname={:s}, offset={:+#x}, flag={:#x}, mt={:#x}, nbytes={:#x})".format( self.owner.name, name, realoffset, flag, typeid, nbytes) logging.fatal(' : '.join( ('members_t.add', callee, error.get(res, "Error code {:#x}".format(res))))) return None res = idaapi.get_member(self.owner.ptr, realoffset) if res is None: logging.fatal( "{:s}.instance({:s}.members.add : Failed creating member {!r} {:s}:{:+#x}" .format(__name__, self.owner.name, name, realoffset, nbytes)) # sloppily figure out what the correct index is idx = self.index(idaapi.get_member(self.owner.ptr, realoffset)) return member_t(self.owner, idx)
def make_stack_variable(func_start, offset, name, size): func = idaapi.get_func(func_start) frame = idaapi.get_frame(func) if frame is None: if idaapi.add_frame(func, 0, 0, 0) == -1: raise ValueError("couldn't create frame for function @ 0x%x" % func_start) frame = idaapi.get_frame(func) offset += func.frsize member = idaapi.get_member(frame, offset) if member: return 0 else: # No member at the offset, create a new one if idaapi.add_struc_member( frame, name, offset, idaapi.wordflag() if size == 2 else idaapi.byteflag(), None, size) == 0: return 1 else: raise ValueError( "failed to create stack frame member %s @ +0x%x in function @ 0x%x" % (name, offset, func_start))
def near_offset(self, offset): '''Return the member near to the specified ``offset``.''' min, max = map(lambda sz: sz + self.baseoffset, (idaapi.get_struc_first_offset(self.owner.ptr), idaapi.get_struc_last_offset(self.owner.ptr))) if (offset < min) or (offset >= max): logging.warn( "{:s}.instance({:s}).members.near_offset : Requested offset {:+#x} not within bounds ({:#x},{:#x}). Trying anyways.." .format(__name__, self.owner.name, offset, min, max)) res = offset - self.baseoffset mem = idaapi.get_member(self.owner.ptr, res) if mem is None: logging.info( "{:s}.instance({:s}).members.near_offset : Unable to locate member at offset {:+#x}. Trying get_best_fit_member instead." .format(__name__, self.owner.name, res)) mem = idaapi.get_best_fit_member(self.owner.ptr, res) if mem is None: raise LookupError( "{:s}.instance({:s}).members.near_offset : Unable to find member near offset : {:+#x}" .format(__name__, self.owner.name, offset)) index = self.index(mem) return self[index]
def dt_type(self): m = idaapi.get_member(self.__owner.ptr, self.offset) if m is None: return 0 flag = m.flag & idaapi.DT_TYPE # idaapi(swig) and python have different definitions of what constant values are max = (sys.maxint + 1) * 2 return flag if flag < sys.maxint else flag - max
def is_gap(structure_name,field_offset): sid = idaapi.get_struc_id(structure_name) if sid != idaapi.BADADDR: sptr = idaapi.get_struc(sid) mptr = idaapi.get_member(sptr, field_offset) if mptr: return False else: return True
def dt_type(self): m = idaapi.get_member(self.__owner.ptr, self.offset) if m is None: return 0 flag = m.flag & idaapi.DT_TYPE # idaapi(swig) and python have different definitions of what constant values are max = (sys.maxint+1)*2 return flag if flag < sys.maxint else flag - max
def add(self, name, offset, type): """Add a member at ``offset`` with the given ``name`` and ``type``. To specify a particular size, ``type`` can be a tuple with the second element referring to the size. """ flag, typeid, nbytes = typemap.resolve(type) # FIXME: handle .strtype (strings), .ec (enums), .cd (custom) opinfo = idaapi.opinfo_t() opinfo.tid = typeid realoffset = offset - self.baseoffset if name is None: logging.warn( 'members_t.add : name is undefined, defaulting to offset %x' % (realoffset)) name = 'v_%x' % realoffset res = idaapi.add_struc_member(self.owner.ptr, name, realoffset, flag, opinfo, nbytes) if res == idaapi.STRUC_ERROR_MEMBER_OK: logging.info( 'members_t.add : idaapi.add_struc_member(sptr=%s, fieldname=%s, offset=%x, flag=%x, mt=%x, nbytes=%x) : Success' % (self.owner.name, name, realoffset, flag, typeid, nbytes)) else: error = { idaapi.STRUC_ERROR_MEMBER_NAME: 'Duplicate field name', idaapi.STRUC_ERROR_MEMBER_OFFSET: 'Invalid offset', idaapi.STRUC_ERROR_MEMBER_SIZE: 'Invalid size', } callee = 'idaapi.add_struc_member(sptr=%s, fieldname=%s, offset=%x, flag=%x, mt=%x, nbytes=%x)' % ( self.owner.name, name, realoffset, flag, typeid, nbytes) logging.fatal(' : '.join( ('members_t.add', callee, error.get(res, 'Error code %x' % res)))) return None res = idaapi.get_member(self.owner.ptr, realoffset) if res is None: logging.fatal("member_t.create : Failed creating member %s %x:+%x", name, realoffset, nbytes) # sloppily figure out what the correct index is idx = self.index(idaapi.get_member(self.owner.ptr, realoffset)) return member_t(self.owner, idx)
def get_struct_member_type(structure_name, field_offset): sid = idaapi.get_struc_id(structure_name) if sid != idaapi.BADADDR: sptr = idaapi.get_struc(sid) mptr = idaapi.get_member(sptr, field_offset) if mptr: tif = idaapi.tinfo_t() idaapi.get_member_tinfo2(mptr, tif) return tif return None
def get_stack_variable_name(func_start, offset): func = idaapi.get_func(func_start) frame = idaapi.get_frame(func) if frame is None: raise ValueError("couldn't get frame for function @ 0x%x" % func_start) offset += func.frsize member = idaapi.get_member(frame, offset) return idaapi.get_member_name(member.id)
def get_stkvar_map(ea): '''ea_t -> {int : (str, tinfo_t)}''' # NOTE mutates d frame = idaapi.get_frame(ea) def make_map(d, (off, name, _)): mem = idaapi.get_member(frame, off) ti = idaapi.tinfo_t() idaapi.get_or_guess_member_tinfo2(mem, ti) d[off] = (name, ti) return d
def get_stkvar_map(ea): '''ea_t -> {int : (str, tinfo_t)}''' # NOTE mutates d frame = idaapi.get_frame(ea) def make_map(d, (off, name, _)): mem = idaapi.get_member(frame, off) ti = idaapi.tinfo_t() idaapi.get_or_guess_member_tinfo2(mem, ti) d[off] = (name, ti) return d
def by_offset(self, offset): '''Return the member at the specified ``offset``.''' min, max = map(lambda sz: sz + self.baseoffset, (idaapi.get_struc_first_offset(self.owner.ptr), idaapi.get_struc_last_offset(self.owner.ptr))) mptr = idaapi.get_member(self.owner.ptr, max - self.baseoffset) msize = idaapi.get_member_size(mptr) if (offset < min) or (offset >= max + msize): raise LookupError( "{:s}.instance({:s}).members.by_offset : Requested offset {:+#x} not within bounds ({:#x},{:#x})" .format(__name__, self.owner.name, offset, min, max + msize)) mem = idaapi.get_member(self.owner.ptr, offset - self.baseoffset) if mem is None: raise LookupError( "{:s}.instance({:s}).members.by_offset : Unable to find member at offset : {:+#x}" .format(__name__, self.owner.name, offset)) index = self.index(mem) return self[index]
def dt_type(self): '''Return the member's `.dt_type` attribute.''' m = idaapi.get_member(self.__owner.ptr, self.offset - self.__owner.members.baseoffset) if m is None: return 0 flag = m.flag & idaapi.DT_TYPE # idaapi(swig) and python have different definitions of what constant values are max = (sys.maxint + 1) * 2 return (max + flag) if flag < 0 else (flag - max) if flag > max else flag
def loadMembersIDA7(struc, sid): '''Returns list of tuples of (offset, memberName, member)''' #mixing idc & idaapi, kinda annoying but need low-level idaapi for a # type access, but cant dig into structs... members = [] off = idaapi.get_struc_first_offset(struc) while off != idc.BADADDR: logger.debug('struc offset: 0x%x (%d)', off, off) member = idaapi.get_member(struc, off) if (member == 0) or (member is None): pass #not really an error, i guess else: members.append((off, idc.get_member_name(sid, off), member)) off = idaapi.get_struc_next_offset(struc, off) members.sort(key=lambda mem: mem[0]) return members
def loadMembersIDA7(struc, sid): '''Returns list of tuples of (offset, memberName, member)''' #mixing idc & idaapi, kinda annoying but need low-level idaapi for a # type access, but cant dig into structs... members = [] off = idaapi.get_struc_first_offset(struc) while off != idc.BADADDR: logger.debug('struc offset: 0x%x (%d)', off, off) member = idaapi.get_member(struc, off) if (member == 0) or (member is None): pass #not really an error, i guess else: members.append( (off, idc.get_member_name(sid, off), member) ) off = idaapi.get_struc_next_offset(struc, off ) members.sort(key = lambda mem: mem[0]) return members
def byOffset(self, offset): min, max = map(lambda sz: sz - self.baseoffset, (idaapi.get_struc_first_offset(self.owner.ptr), idaapi.get_struc_last_offset(self.owner.ptr))) if (offset < min) or (offset >= max): logging.warn( 'structure_t(%s).members.byoffset : Requested offset %x not within bounds (%x,%x). Trying anyways..' % (self.owner.name, offset, min, max)) mem = idaapi.get_member(self.owner.ptr, offset - self.baseoffset) if mem is None: logging.warn( 'structure_t(%s).members.byoffset : Unable to locate member at offset %x. Trying get_best_fit_member instead.' % (self.owner.name, offset - self.baseoffset)) mem = idaapi.get_best_fit_member(self.owner.ptr, offset - self.baseoffset) if mem is None: raise IndexError, offset index = self.index(mem) return self[index]
def xrefs_to(self): """ Retrieves the xrefs to the stack variable. NOTE: This code is very SWIGGY because IDA did not properly expose this functionality. :raises ValueError: if frame_id, stack_offset, or string_reference was not provided. This is needed to determine what function to use. """ if self._xrefs_to is None: if not self.string_reference: raise ValueError('Unable to get xrefs without string_reference.') if not (self.frame_id and self.stack_offset): raise ValueError('Unable to get xrefs without frame_id and stack_offset') xrefs = idaapi.xreflist_t() frame = idaapi.get_frame(self.frame_id) func = idaapi.get_func(self.string_reference) member = idaapi.get_member(frame, self.stack_offset) idaapi.build_stkvar_xrefs(xrefs, func, member) self._xrefs_to = [ref.ea for ref in xrefs] return self._xrefs_to
def check_field(self, sid, ftype, strid, offset, size, name): if ftype is None: for i in range(offset, offset + size): self.assertIsNone(idc.GetMemberName(sid, i)) self.assertEqual(idc.GetMemberFlag(sid, i), -1) return try: self.assertNotEqual(idc.GetMemberName(sid, offset - 1), name) except: pass for k in range(offset, offset + size): self.assertEqual(idc.GetMemberName(sid, k), name) self.assertEqual(idc.GetMemberSize(sid, k), size) self.assertEqual(idc.GetMemberFlag(sid, k) & idaapi.DT_TYPE, ftype & 0xFFFFFFFF) if strid != -1: st = idaapi.get_struc(sid) mb = idaapi.get_member(st, offset) op = idaapi.opinfo_t() idaapi.retrieve_member_info(op, mb) self.assertEqual(op.tid, strid) self.assertNotEqual(idc.GetMemberName(sid, offset + size), name)
def save_strucs(self, memory_exporter): """ Structures : export modified structures and delete those who have been deleted """ for struc_id in self.structures_to_process: self.ida_model.clear_exported_struc_enum_id(struc_id) sidx = idc.GetStrucIdx(struc_id) if sidx is None or sidx == idc.BADADDR: # it is a deleted structure or a stackframe # in this last case we need to export the parent (function) eaFunc = idaapi.get_func_by_frame(struc_id) if eaFunc != idc.BADADDR: # OK, it is a stackframe self.ida_model.accept_struc( memory_exporter, 0, struc_id, ya.OBJECT_TYPE_STACKFRAME, ya.OBJECT_TYPE_STACKFRAME_MEMBER, stackframe_func_addr=eaFunc) self.ida_model.accept_ea(memory_exporter, 0, eaFunc) else: # it is a deleted structure self.ida_model.accept_deleted_struc(memory_exporter, struc_id) else: self.ida_model.accept_struc(memory_exporter, 0, struc_id) logger.debug("Walking members") """ Structure members : update modified ones, and remove deleted ones We iterate over members : -if the parent struc has been deleted, delete the member -otherwise, detect if the member has been updated or removed -updated : accept struc_member + accept_struc if not already exported! -removed : accept struc_member_deleted """ for (struc_id, member_set) in self.strucmember_to_process.iteritems(): ida_struc = idaapi.get_struc(struc_id) logger.debug("Walking struc 0x%08X" % struc_id) sidx = idc.GetStrucIdx(struc_id) is_stackframe = False struc_deleted = False if sidx is None or sidx == idc.BADADDR: f = idaapi.get_func_by_frame(struc_id) if f is not None and f != idc.BADADDR: is_stackframe = True else: struc_deleted = True if is_stackframe: strucmember_type = ya.OBJECT_TYPE_STACKFRAME_MEMBER struc_name = None struc_type = ya.OBJECT_TYPE_STACKFRAME eaFunc = idaapi.get_func_by_frame(struc_id) stackframe_func_addr = eaFunc func = idaapi.get_func(eaFunc) self.ida_model.accept_function(memory_exporter, 0, eaFunc, func) else: strucmember_type = ya.OBJECT_TYPE_STRUCT_MEMBER struc_type = ya.OBJECT_TYPE_STRUCT stackframe_func_addr = None if not struc_deleted: struc_name = idc.GetStrucName(struc_id) if struc_deleted: # The structure has been deleted : we need to delete the members # Note: at first sight, it is not a stackframe # TODO: handle function->stackframe deletion here for (member_id, offset) in member_set: self.ida_model.accept_deleted_strucmember(memory_exporter, struc_id, None, offset) else: # The structure or stackframe has been modified is_union = ida_struc.is_union() for (member_id, offset) in member_set: ida_member = idaapi.get_member(ida_struc, offset) if ida_member is None: new_member_id = -1 else: new_member_id = ida_member.id logger.debug("exporting member %s at offset 0x%02X (mid=0x%016X)" % (strucmember_type, offset, member_id)) self.ida_model.clear_exported_struc_member_id(new_member_id) if new_member_id == -1: # the member has been deleted : delete it self.ida_model.accept_deleted_strucmember( memory_exporter, struc_id, struc_name, offset, struc_type, strucmember_type) elif offset > 0 and idc.GetMemberId(struc_id, offset - 1) == new_member_id: # the member was deleted, and replaced by a member starting above it self.ida_model.accept_deleted_strucmember( memory_exporter, struc_id, struc_name, offset, struc_type, strucmember_type) elif new_member_id != member_id: # the member has been deleted and later recreated name = idaapi.get_member_name(new_member_id) self.ida_model.accept_struc_member( memory_exporter, 0, ida_struc, struc_id, is_union, offset, struc_name, name, struc_type, strucmember_type, stackframe_func_addr=stackframe_func_addr) else: # the member has just been modified name = idaapi.get_member_name(new_member_id) logger.debug("exporting member %s (%s) at offset 0x%02X (mid=0x%016X)" % (strucmember_type, name, offset, member_id)) self.ida_model.accept_struc_member( memory_exporter, 0, ida_struc, struc_id, is_union, offset, struc_name, name, struc_type, strucmember_type, stackframe_func_addr=stackframe_func_addr)
def walk_struct_members(): for (idx, sid, name) in idautils.Structs(): s = idaapi.get_struc(sid) for (offset, name, size) in idautils.StructMembers(sid): m = idaapi.get_member(s, offset) yield m.id
def visit_expr(self, *args): e = args[0] dr = idaapi.dr_R | idaapi.XREF_USER ea = self.find_addr(e) # We wish to know what context a struct usage occurs in # so we can determine what kind of xref to create. Unfortunately, # a post-order traversal makes this difficult. # For assignments, we visit the left, instead # Note that immediate lvalues will be visited twice, # and will be eronneously marked with a read dref. # However, it is safer to overapproximate than underapproximate if is_assn(e.op) or is_incdec(e.op): e = e.x dr = idaapi.dr_W | idaapi.XREF_USER # &x if e.op == idaapi.cot_ref: e = e.x dr = idaapi.dr_O | idaapi.XREF_USER # x.m, x->m if e.op == idaapi.cot_memref or e.op == idaapi.cot_memptr: moff = e.m # The only way I could figure out how # to get the structure/member associated with its use typ = e.x.type if e.op == idaapi.cot_memptr: typ.remove_ptr_or_array() strname = typ.dstr() if strname.startswith("struct "): strname = strname[len("struct "):] stid = idaapi.get_struc_id(strname) struc = idaapi.get_struc(stid) mem = idaapi.get_member(struc, moff) if struc is not None: self.add_dref(ea, stid, dr) if mem is not None: self.add_dref(ea, stid, dr, mem.id) else: log.error( "failure from %08X " "on struct %s (id: 0x%X) %s", ea, strname, stid, flags_to_str(dr), ) elif idaapi.is_lvalue(e.op) and e.type.is_struct(): strname = e.type.dstr() if strname.startswith("struct "): strname = strname[len("struct "):] stid = idaapi.get_struc_id(strname) struc = idaapi.get_struc(stid) if struc is not None: self.add_dref(ea, stid, dr) return 0
def flag(self): '''Return the member's `.flag` attribute.''' m = idaapi.get_member(self.__owner.ptr, self.offset - self.__owner.members.baseoffset) return 0 if m is None else m.flag
def clear_struc_fields(self, struc_id, struc_size, xref_keys, is_union=False, member_type=ya.OBJECT_TYPE_STRUCT_MEMBER, name_offset=0): idc.BeginTypeUpdating(idc.UTP_STRUCT) last_offset = idc.GetLastMember(struc_id) # get existing member offsets field_offsets = set() for (xref_offset, xref_operand) in xref_keys: field_offsets.add(xref_offset) new_offsets = set() struc = idaapi.get_struc(struc_id) # create missing members first (prevent from deleting all members) for offset in field_offsets: member = idaapi.get_member(struc, offset) if member is not None and member.soff < offset: # we have a member above this member that is too big and contain this member # clear it! if DEBUG_EXPORTER: logger.debug( "reduce field : set_member_type(0x%08X, 0x%08X), overlapping 0x%08X", struc_id, member.soff, offset) idaapi.set_member_type(struc, member.soff, idc.FF_BYTE, None, 1) member = idaapi.get_member(struc, offset) if member is None or idaapi.get_member_name(member.id) is None: new_offsets.add(offset) member_name = YaToolIDATools.get_default_struc_member_name( member_type, offset, name_offset) if offset == last_offset and offset == struc_size: field_size = 0 else: field_size = 1 if DEBUG_EXPORTER: logger.debug( "AddStrucMember(0x%08X, '%s', 0x%08X, idc.FF_BYTE, -1, 0x%08X), name_offset=%d", struc_id, member_name, offset, field_size, name_offset) retval = idc.AddStrucMember(struc_id, member_name, offset, idc.FF_BYTE, -1, field_size) if retval != 0: logger.error( "Error %d with idc.AddStrucMember(0x%08X, '%s', 0x%08X," "idc.FF_BYTE, -1, 0x%08X), name_offset=%d", retval, struc_id, member_name, offset, field_size, name_offset) elif DEBUG_EXPORTER: logger.debug("Member exists : (0x%08X, '%s', 0x%08X, 0x%08X)", struc_id, idc.GetMemberName(struc_id, offset), offset, idc.GetMemberSize(struc_id, offset)) kept_offsets = field_offsets - new_offsets # clear kept members # split the loop since we will modify the structure while iterating offsets = set() for (offset, member_name) in YaToolIDATools.struc_member_list( struc_id, is_union): offsets.add(offset) for offset in offsets: if offset in kept_offsets: # This member already existed and is kept if offset == last_offset and offset == struc_size: # this is the last field, and it is a variable sized structure field_size = 0 else: field_size = 1 if member_type == ya.OBJECT_TYPE_STRUCT_MEMBER: strucmember_id = self.hash_provider.get_struc_member_id( struc_id, offset) elif member_type == ya.OBJECT_TYPE_STACKFRAME_MEMBER: strucmember_id = self.hash_provider.get_stackframe_member_object_id( struc_id, offset) else: logger.error("Bad member_type : %d" % member_type) if strucmember_id not in self.strucmember_ids: # It is not necessary to clear the member if it is presnet in the resolved_objects if DEBUG_EXPORTER: logger.debug( "SetStrucmember(0x%08X, None, 0x%08X, idc.FF_BYTE, -1, 0x%08X, name_offset=%s)", struc_id, offset, field_size, name_offset) YaToolIDATools.SetStrucmember(struc_id, None, offset, idc.FF_BYTE, -1, field_size, member_type=member_type, name_offset=name_offset) idc.SetMemberComment(struc_id, offset, "", 0) idc.SetMemberComment(struc_id, offset, "", 1) elif offset not in new_offsets: if (member_type != ya.OBJECT_TYPE_STACKFRAME_MEMBER or not idaapi.is_special_member( idc.GetMemberId(struc_id, offset))): if DEBUG_EXPORTER: logger.debug( "DelStrucMember(0x%08X, 0x%08X) (=%s:%s)", struc_id, offset, idc.GetStrucName(struc_id), idc.GetMemberName(struc_id, offset)) idc.DelStrucMember(struc_id, offset) else: # in new_offsets : just created pass idc.EndTypeUpdating(idc.UTP_STRUCT)
def save_strucs(self, ida_model, memory_exporter): """ Structures : export modified structures and delete those who have been deleted """ for struc_id in self.structures_to_process: sidx = idc.GetStrucIdx(struc_id) if sidx is None or sidx == idc.BADADDR: # it is a deleted structure or a stackframe # in this last case we need to export the parent (function) eaFunc = idaapi.get_func_by_frame(struc_id) if eaFunc != idc.BADADDR: # OK, it is a stackframe ida_model.accept_struct(memory_exporter, eaFunc, struc_id) ida_model.accept_ea(memory_exporter, eaFunc) else: # it is a deleted structure ida_model.delete_struct(memory_exporter, struc_id) else: ida_model.accept_struct(memory_exporter, idc.BADADDR, struc_id) logger.debug("Walking members") """ Structure members : update modified ones, and remove deleted ones We iterate over members : -if the parent struc has been deleted, delete the member -otherwise, detect if the member has been updated or removed -updated : accept struc_member + accept_struct if not already exported! -removed : accept struc_member_deleted """ for (struc_id, member_set) in self.strucmember_to_process.iteritems(): ida_struc = idaapi.get_struc(struc_id) logger.debug("Walking struc 0x%08X" % struc_id) sidx = idc.GetStrucIdx(struc_id) is_stackframe = False struc_deleted = False if sidx is None or sidx == idc.BADADDR: f = idaapi.get_func_by_frame(struc_id) if f is not None and f != idc.BADADDR: is_stackframe = True else: struc_deleted = True stackframe_func_addr = idc.BADADDR if is_stackframe: eaFunc = idaapi.get_func_by_frame(struc_id) stackframe_func_addr = eaFunc ida_model.accept_function(memory_exporter, eaFunc) if struc_deleted: # The structure has been deleted : we need to delete the members # Note: at first sight, it is not a stackframe # TODO: handle function->stackframe deletion here for (member_id, offset) in member_set: ida_model.delete_struct_member(memory_exporter, idc.BADADDR, struc_id, offset) else: # The structure or stackframe has been modified for (member_id, offset) in member_set: ida_member = idaapi.get_member(ida_struc, offset) if ida_member is None: new_member_id = -1 else: new_member_id = ida_member.id if new_member_id == -1: # the member has been deleted : delete it ida_model.delete_struct_member(memory_exporter, stackframe_func_addr, struc_id, offset) elif offset > 0 and idc.GetMemberId( struc_id, offset - 1) == new_member_id: # the member was deleted, and replaced by a member starting above it ida_model.delete_struct_member(memory_exporter, stackframe_func_addr, struc_id, offset) else: # the member has just been modified ida_model.accept_struct_member(memory_exporter, stackframe_func_addr, ida_member.id)
def flag(self): m = idaapi.get_member(self.__owner.ptr, self.offset - self.__owner.members.baseoffset) return 0 if m is None else m.flag