def get_member_from_struct(ea, sname, mname): """ get_member_from_struct: ea, sname, mname Retrieves a DWORD member named 'mname' from struct 'sname' starting at address 'ea'. """ sid = idaapi.get_struc_id(sname) stru = idaapi.get_struc(sid) member = idaapi.get_member_by_name(stru, mname) # TODO check size return idc.Dword(ea + member.soff)
class RTTIClassHierarchyDescriptor(RTTIStruc): bases = None msid = get_struc_id("RTTIClassHierarchyDescriptor") if msid != BADADDR: del_struc(msid) msid = add_struc(0xFFFFFFFF, "RTTIClassHierarchyDescriptor", False) add_struc_member(msid, "signature", BADADDR, FF_DWRD | FF_DATA, -1, 4) add_struc_member(msid, "attribute", BADADDR, FF_DWRD | FF_DATA, -1, 4) add_struc_member(msid, "numBaseClasses", BADADDR, FF_DWRD | FF_DATA, -1, 4) add_struc_member(msid, "pBaseClassArray", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva().tid, 4) tid = msid struc = get_struc(tid) print("Completed Registering RTTIClassHierarchyDescriptor") def __init__(self, ea): print("Processing Class Hierarchy Descriptor at 0x%x" % ea) do_unknown_range(ea, get_struc_size(self.tid), DOUNK_DELNAMES) if doStruct(ea, get_struc_size(self.tid), self.tid): baseClasses = get_32bit( ea + get_member_by_name(get_struc( self.tid), "pBaseClassArray").soff) + u.x64_imagebase() nb_classes = get_32bit( ea + get_member_by_name(get_struc(self.tid), "numBaseClasses").soff) print("Baseclasses array at 0x%x" % baseClasses) # Skip the first base class as it is itself (could check) self.bases = [] for i in range(1, nb_classes): baseClass = get_32bit(baseClasses + i * 4) + u.x64_imagebase() print("base class 0x%x" % baseClass) doDwrd(baseClasses + i * 4, 4) op_offset(baseClasses + i * 4, -1, u.REF_OFF | REFINFO_RVA, -1, 0, 0) doStruct(baseClass, RTTIBaseClassDescriptor.size, RTTIBaseClassDescriptor.tid) typeDescriptor = get_32bit(baseClass) + u.x64_imagebase() self.bases.append( RTTITypeDescriptor(typeDescriptor).class_name)
def __init__(self, ea): name = ea + get_member_by_name(get_struc(self.tid), "name").soff strlen = u.get_strlen(name) if strlen is None: # not a real vtable return self.size = self.size + strlen mangled = get_ascii_contents(name, strlen, 0) if mangled is None: # not a real function name return print "Mangled: " + mangled demangled = demangle_name('??_R0' + mangled[1:], 0) if demangled: do_unknown_range(ea, self.size, DOUNK_DELNAMES) if doStruct(ea, self.size, self.tid): print " Made td at 0x%x: %s" % (ea, demangled) self.class_name = demangled return print " FAIL :(" return
def add_auto_comment(self, ea, text): if ea is not None: prefix = "" if idaapi.get_struc(ea) is not None: if idc.GetStrucIdx(ea) == idc.BADADDR: prefix = "stackframe '%s'" % idc.GetFunctionName( idaapi.get_func_by_frame(ea)) else: prefix = "structure '%s'" % idc.GetStrucName(ea) elif idc.GetEnumIdx(ea) != idc.BADADDR: prefix = "enum '%s'" % idc.GetEnumName(ea) else: foffset = idc.GetFuncOffset(ea) if foffset is None: prefix = self.yatools.address_to_hex_string(ea) else: prefix = "%s,%s" % (self.yatools.address_to_hex_string(ea), foffset) self.auto_comments.add((prefix, text)) else: self.auto_comments.add(("", text))
def __init__(self, ea): name = ea + get_member_by_name(get_struc(self.tid), "name").soff strlen = u.get_strlen(name) if strlen is None: # not a real vtable return self.size = self.size + strlen mangled = get_strlit_contents(name, strlen, 0) if mangled is None: # not a real function name return print("Mangled: " + mangled) demangled = demangle_name('??_R0' + mangled[1:], 0) if demangled: del_items(ea, self.size, DELIT_DELNAMES) if create_struct(ea, self.size, self.tid): print(" Made td at 0x%x: %s" % (ea, demangled)) self.class_name = demangled return print(" FAIL :(") return
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)
class RTTITypeDescriptor(RTTIStruc): class_name = None msid = get_struc_id("RTTITypeDescriptor") if msid != BADADDR: del_struc(msid) msid = add_struc(0xFFFFFFFF, "RTTITypeDescriptor", False) add_struc_member(msid, "pVFTable", BADADDR, FF_DATA | u.PTR_TYPE | FF_0OFF, u.mt_address().tid, u.PTR_SIZE) add_struc_member(msid, "spare", BADADDR, FF_DATA | u.PTR_TYPE, -1, u.PTR_SIZE) add_struc_member(msid, "name", BADADDR, FF_DATA | FF_STRLIT, u.mt_ascii().tid, 0) tid = msid struc = get_struc(tid) size = get_struc_size(tid) print("Completed Registering RTTITypeDescriptor") def __init__(self, ea): name = ea + get_member_by_name(get_struc(self.tid), "name").soff strlen = u.get_strlen(name) if strlen is None: # not a real vtable return self.size = self.size + strlen mangled = get_strlit_contents(name, strlen, 0) if mangled is None: # not a real function name return print("Mangled: " + mangled) demangled = demangle_name('??_R0' + mangled[1:], 0) if demangled: del_items(ea, self.size, DELIT_DELNAMES) if create_struct(ea, self.size, self.tid): print(" Made td at 0x%x: %s" % (ea, demangled)) self.class_name = demangled return print(" FAIL :(") return
def members(id): st = idaapi.get_struc(id) if not st: # empty structure return size = idaapi.get_struc_size(st) offset = 0 for i in range(st.memqty): m = st.get_member(i) ms = idaapi.get_member_size(m) left,right = m.soff,m.eoff if offset < left: yield (offset,left-offset), (None,None) offset = left yield (offset,ms),(idaapi.get_member_name(m.id), idaapi.get_member_cmt(m.id, 1)) offset += ms return
def ev_rename(self, ea, new_name): """ This function only records information about the element *before* it is renamed """ if idaapi.is_member_id(ea): name = idaapi.get_member_fullname(ea) elif idaapi.get_struc(ea) is not None: name = idaapi.get_struc_name(ea) elif idaapi.get_enum_idx(ea) != idc.BADADDR: name = idaapi.get_enum_name(ea) elif idaapi.get_enum_idx( idaapi.get_enum_member_enum(ea)) != idc.BADADDR: # this is an enum member id enum_id = idaapi.get_enum_member_enum(ea) name = idaapi.get_enum_name( enum_id) + "." + idaapi.get_enum_member_name(ea) else: name = idc.Name(ea) hooks.current_rename_infos[ea] = name return 0
class RTTIBaseClassDescriptor(RTTIStruc): msid = get_struc_id("RTTIBaseClassDescriptor") if msid != BADADDR: del_struc(get_struc(msid)) msid = add_struc(0xFFFFFFFF, "RTTIBaseClassDescriptor", False) add_struc_member(get_struc(msid), "pTypeDescriptor", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva(), 4) add_struc_member(get_struc(msid), "numContainerBases", BADADDR, FF_DWRD | FF_DATA, None, 4) add_struc_member(get_struc(msid), "PMD", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva(), 4) add_struc_member(get_struc(msid), "attributes", BADADDR, FF_DWRD | FF_DATA, None, 4) tid = msid struc = get_struc(tid) size = get_struc_size(tid) print "Completed Registering RTTIBaseClassDescriptor"
class RTTITypeDescriptor(RTTIStruc): class_name = None msid = get_struc_id("RTTITypeDescriptor") if msid != BADADDR: del_struc(msid) msid = add_struc(0xFFFFFFFF, "RTTITypeDescriptor", False) add_struc_member(msid, "pVFTable", BADADDR, FF_DATA | u.PTR_TYPE | FF_0OFF, -1, u.PTR_SIZE) add_struc_member(msid, "spare", BADADDR, FF_DATA | u.PTR_TYPE | FF_0OFF, -1, u.PTR_SIZE) add_struc_member(msid, "name", BADADDR, FF_DATA | FF_ASCI, STRTYPE_C, 0) tid = msid struc = get_struc(tid) size = get_struc_size(tid) print "Completed Registering RTTITypeDescriptor" def __init__(self, ea): name = ea + get_member_by_name(self.struc, "name").soff strlen = u.get_strlen(name) if strlen is None: # not a real vtable return self.size = self.size + strlen mangled = get_ascii_contents(name, strlen, 0) if mangled is None: # not a real function name return print "Mangled: " + mangled demangled = demangle_name('??_R0' + mangled[1:], 0) if demangled: do_unknown_range(ea, self.size, DOUNK_DELNAMES) if doStruct(ea, self.size, self.tid): print " Made td at 0x%x: %s" % (ea, demangled) self.class_name = demangled return print " FAIL :(" return
def members(id): """Return the ((offset,size),(name,comment)) of each member within the specified structure""" st = idaapi.get_struc(id) if not st: # empty structure return size = idaapi.get_struc_size(st) offset = 0 for i in range(st.memqty): m = st.get_member(i) ms = idaapi.get_member_size(m) left, right = m.soff, m.eoff if offset < left: yield (offset, left - offset), (None, None) offset = left yield (offset, ms), (idaapi.get_member_name(m.id), idaapi.get_member_cmt(m.id, 1)) offset += ms return
def __call__(self): sptr = idaapi.get_struc(idc.get_struc_id(self.sname.encode('utf-8'))) idaapi.del_struc_member(sptr, self.offset)
def get(id): return idaapi.get_struc(id)
def __call__(self): sptr = idaapi.get_struc(idc.get_struc_id(self.sname.encode('utf-8'))) idaapi.set_member_name(sptr, self.offset, self.newname.encode('utf-8'))
def __call__(self): sptr = idaapi.get_struc(idc.get_struc_id(self.sname.encode('utf-8'))) idaapi.expand_struc(sptr, self.offset, self.delta)
def run(self): try: logger.debug('Starting up') dlg = StructTyperWidget() dlg.setStructs(loadStructs()) oldTo = idaapi.set_script_timeout(0) res = dlg.exec_() idaapi.set_script_timeout(oldTo) if res == QtWidgets.QDialog.Accepted: regPrefix = dlg.getRegPrefix() sid = None struc = None if dlg.ui.rb_useStackFrame.isChecked(): ea = idc.here() if using_ida7api: sid = idc.get_frame_id(ea) else: sid = idc.GetFrame(ea) struc = idaapi.get_frame(ea) logger.debug('Dialog result: accepted stack frame') if (sid is None) or (sid == idc.BADADDR): #i should really figure out which is the correct error case raise RuntimeError( 'Failed to get sid for stack frame at 0x%x' % ea) if (struc is None) or (struc == 0) or (struc == idc.BADADDR): raise RuntimeError( 'Failed to get struc_t for stack frame at 0x%x' % ea) if using_ida7api: pass else: #need the actual pointer value, not the swig wrapped struc_t struc = long(struc.this) else: structName = dlg.getActiveStruct() if structName is None: print("No struct selected. Bailing out") return logger.debug('Dialog result: accepted %s "%s"', type(structName), structName) if using_ida7api: sid = idc.get_struc_id(structName) else: sid = idc.GetStrucIdByName(structName) if (sid is None) or (sid == idc.BADADDR): #i should really figure out which is the correct error case raise RuntimeError('Failed to get sid for %s' % structName) tid = idaapi.get_struc_id(structName) if (tid is None) or (tid == 0) or (tid == idc.BADADDR): #i should really figure out which is the correct error case raise RuntimeError('Failed to get tid_t for %s' % structName) if using_ida7api: struc = idaapi.get_struc(tid) else: struc = g_dll.get_struc(tid) if (struc is None) or (struc == 0) or (struc == idc.BADADDR): raise RuntimeError('Failed to get struc_t for %s' % structName) foundMembers = self.processStruct(regPrefix, struc, sid) if dlg.ui.rb_useStackFrame.isChecked() and (foundMembers != 0): #reanalyze current function if we're analyzing a stack frame & found some func pointers if using_ida7api: funcstart = idc.get_func_attr(idc.here(), idc.FUNCATTR_START) funcend = idc.get_func_attr(idc.here(), idc.FUNCATTR_END) else: funcstart = idc.GetFunctionAttr( idc.here(), idc.FUNCATTR_START) funcend = idc.GetFunctionAttr(idc.here(), idc.FUNCATTR_END) if (funcstart != idc.BADADDR) and (funcend != idc.BADADDR): if using_ida7api: idc.plan_and_wait(funcstart, funcend) else: idc.AnalyzeArea(funcstart, funcend) elif res == QtWidgets.QDialog.Rejected: logger.info('Dialog result: canceled by user') else: logger.debug('Unknown result') raise RuntimeError('Dialog unknown result') except Exception, err: logger.exception("Exception caught: %s", str(err))
def ptr(self): '''Return the structure's idaapi pointer.''' return idaapi.get_struc(self.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 __call__(self): sptr = idaapi.get_struc(self.sid) idaapi.del_struc_member(sptr, self.offset)
def get_struct(name): sid = idaapi.get_struc_id(name) return idaapi.get_struc(sid)
def get_node_for_member(mem, parent): if idaapi.isStruct(mem.flag): return unset_structure_node(idaapi.get_struc(util.member_str_id(mem, parent))) else: return unset_primitive_node()
def run(self): try: logger.debug('Starting up') dlg = StructTyperWidget() dlg.setStructs(loadStructs()) oldTo = idaapi.set_script_timeout(0) res = dlg.exec_() idaapi.set_script_timeout(oldTo) if res == QtWidgets.QDialog.Accepted: regPrefix = dlg.getRegPrefix() sid = None struc = None if dlg.ui.rb_useStackFrame.isChecked(): ea = idc.here() if using_ida7api: sid = idc.get_frame_id(ea) else: sid = idc.GetFrame(ea) struc = idaapi.get_frame(ea) logger.debug('Dialog result: accepted stack frame') if (sid is None) or (sid == idc.BADADDR): #i should really figure out which is the correct error case raise RuntimeError('Failed to get sid for stack frame at 0x%x' % ea) if (struc is None) or (struc == 0) or (struc == idc.BADADDR): raise RuntimeError('Failed to get struc_t for stack frame at 0x%x' % ea) if using_ida7api: pass else: #need the actual pointer value, not the swig wrapped struc_t struc= long(struc.this) else: structName = dlg.getActiveStruct() if structName is None: print("No struct selected. Bailing out") return logger.debug('Dialog result: accepted %s "%s"', type(structName), structName) if using_ida7api: sid = idc.get_struc_id(structName) else: sid = idc.GetStrucIdByName(structName) if (sid is None) or (sid == idc.BADADDR): #i should really figure out which is the correct error case raise RuntimeError('Failed to get sid for %s' % structName) tid = idaapi.get_struc_id(structName) if (tid is None) or (tid == 0) or (tid == idc.BADADDR): #i should really figure out which is the correct error case raise RuntimeError('Failed to get tid_t for %s' % structName) if using_ida7api: struc = idaapi.get_struc(tid) else: struc = g_dll.get_struc(tid) if (struc is None) or (struc == 0) or (struc == idc.BADADDR): raise RuntimeError('Failed to get struc_t for %s' % structName) foundMembers = self.processStruct(regPrefix, struc, sid) if dlg.ui.rb_useStackFrame.isChecked() and (foundMembers != 0): #reanalyze current function if we're analyzing a stack frame & found some func pointers if using_ida7api: funcstart = idc.get_func_attr(idc.here(), idc.FUNCATTR_START) funcend = idc.get_func_attr(idc.here(), idc.FUNCATTR_END) else: funcstart = idc.GetFunctionAttr(idc.here(), idc.FUNCATTR_START) funcend = idc.GetFunctionAttr(idc.here(), idc.FUNCATTR_END) if (funcstart != idc.BADADDR) and (funcend != idc.BADADDR): if using_ida7api: idc.plan_and_wait(funcstart, funcend) else: idc.AnalyzeArea(funcstart, funcend) elif res == QtWidgets.QDialog.Rejected: logger.info('Dialog result: canceled by user') else: logger.debug('Unknown result') raise RuntimeError('Dialog unknown result') except Exception, err: logger.exception("Exception caught: %s", str(err))
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 __init__(self): self.elts = [] for i in range(idaapi.get_struc_qty()): self.elts.append( struct_node(idaapi.get_struc(idaapi.get_struc_by_idx(i))))
def __init__(self): self.elts = [] for i in range(idaapi.get_struc_qty()): self.elts.append(struct_node(idaapi.get_struc(idaapi.get_struc_by_idx(i))))
def ptr(self): return idaapi.get_struc(self.id)
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 __call__(self): sptr = idaapi.get_struc(self.sid) idaapi.expand_struc(sptr, self.offset, self.delta)
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 f_ExpandStruc(sid, off, delta, recalc): s = idaapi.get_struc(sid) return idaapi.expand_struc(s, off, delta, recalc)
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)