def add_struc_member_retry(struct_ptr, member_name, offset, flag, mt, member_size): """ @return: tuple(error_code, member_ptr) @note: use print_struc_error(error_code) to get error message """ assert struct_ptr, offset assert member_name, offset assert member_size, offset error_code = ida_struct.add_struc_member(struct_ptr, member_name, offset, flag, mt, member_size) i = 0 member_base_name = member_name while error_code == ida_struct.STRUC_ERROR_MEMBER_NAME: member_name = "%s%s%d" % (member_base_name, MEMBER_INDEX_SPLITTER, i) i += 1 if i > MAX_MEMBER_INDEX: return None error_code = ida_struct.add_struc_member( struct_ptr, member_name, offset, flag, mt, member_size ) if error_code == ida_struct.STRUC_ERROR_MEMBER_OK: member_ptr = ida_struct.get_member_by_name(struct_ptr, member_name) assert member_ptr, offset else: member_ptr = None return error_code, member_ptr
def set_ida_struct(struct: Struct, controller) -> bool: # first, delete any struct by the same name if it exists sid = ida_struct.get_struc_id(struct.name) if sid != 0xffffffffffffffff: sptr = ida_struct.get_struc(sid) ida_struct.del_struc(sptr) # now make a struct header ida_struct.add_struc(ida_idaapi.BADADDR, struct.name, False) sid = ida_struct.get_struc_id(struct.name) sptr = ida_struct.get_struc(sid) # expand the struct to the desired size # XXX: do not increment API here, why? Not sure, but you cant do it here. ida_struct.expand_struc(sptr, 0, struct.size) # add every member of the struct for off, member in struct.struct_members.items(): # convert to ida's flag system mflag = convert_size_to_flag(member.size) # create the new member ida_struct.add_struc_member( sptr, member.member_name, member.offset, mflag, None, member.size, ) return True
def apply(self): func_frame = self.func_frame_pointer if self.new: ida_struct.add_struc_member(func_frame, self.data, self.offset, 0, ida_nalt.opinfo_t(), self.var_size) else: ida_struct.set_member_name(func_frame, self.offset, self.data) return True
def apply_member(cls, struct, data): ida_struct.add_struc_member(struct, data['name'], data['offset'], data['flag'], data['opinfo'], data['size']) member = ida_struct.get_member(struct, data['offset']) if 'comment' in data and data['comment']: ida_struct.set_member_cmt(member, data['comment'], False) if 'repeatable_comment' in data and data['repeatable_comment']: ida_struct.set_member_cmt(member, data['repeatable_comment'], True)
def push_ptr_member_to_struct( struct, member_name, member_type, offset=BADADDR, overwrite=False ): mt = None flag = idaapi.FF_DWORD member_size = WORD_LEN if member_type is not None and (member_type.is_struct() or member_type.is_union()): logging.debug("Is struct!") substruct = extract_struct_from_tinfo(member_type) if substruct is not None: flag = idaapi.FF_STRUCT mt = ida_nalt.opinfo_t() mt.tid = substruct.id logging.debug( f"Is struct: {ida_struct.get_struc_name(substruct.id)}/{substruct.id}" ) member_size = ida_struct.get_struc_size(substruct.id) member_type = None elif WORD_LEN == 4: flag = idaapi.FF_DWORD elif WORD_LEN == 8: flag = idaapi.FF_QWORD new_member_name = member_name if overwrite and ida_struct.get_member(struct, offset): logging.debug("Overwriting!") ret_val = ida_struct.set_member_name(struct, offset, member_name) i = 0 while ret_val == ida_struct.STRUC_ERROR_MEMBER_NAME: new_member_name = "%s_%d" % (member_name, i) i += 1 if i > 250: return ret_val = ida_struct.set_member_name(struct, offset, new_member_name) else: ret_val = ida_struct.add_struc_member( struct, new_member_name, offset, flag, mt, member_size ) i = 0 while ret_val == ida_struct.STRUC_ERROR_MEMBER_NAME: new_member_name = "%s_%d" % (member_name, i) i += 1 if i > 250: return ret_val = ida_struct.add_struc_member( struct, new_member_name, offset, flag, mt, member_size ) if ret_val != 0: logging.debug(f"ret_val: {ret_val}") member_ptr = ida_struct.get_member_by_name(struct, new_member_name) if member_ptr is None: logging.debug("member is None") if member_type is not None and member_ptr is not None: ida_struct.set_member_tinfo( struct, member_ptr, 0, member_type, idaapi.TINFO_DEFINITE ) return member_ptr
def defENTENT(): sid = ida_struct.get_struc_id("ENTENT") if sid != ida_idaapi.BADADDR: struc = ida_struct.get_struc(sid) ida_struct.del_struc(struc) sid = ida_struct.add_struc(ida_idaapi.BADADDR, "ENTENT", 0) struc = ida_struct.get_struc(sid) ida_struct.add_struc_member(struc, "flags", ida_idaapi.BADADDR, FF_BYTE, None, 1) ida_struct.add_struc_member(struc, "addr", ida_idaapi.BADADDR, FF_WORD, None, 2) return sid
def __call__(self): mt = ida_nalt.opinfo_t() if ida_bytes.is_struct(self.flag): mt.tid = self.extra['id'] if ida_bytes.is_off0(self.flag) or ida_bytes.is_off1(self.flag): mt.ri = ida_nalt.refinfo_t(self.extra['flags'], self.extra['base'], self.extra['target'], self.extra['tdelta']) if ida_bytes.is_strlit(self.flag): mt.strtype = self.extra['strtype'] struc = ida_struct.get_struc_id(Event.encode(self.sname)) sptr = ida_struct.get_struc(struc) ida_struct.add_struc_member(sptr, Event.encode(self.fieldname), self.offset, self.flag, mt, self.nbytes)
def create_struct(name, fields, size): struct_id = idaapi.get_struc_id(name) # print struct_id if struct_id != idaapi.BADADDR: i = ida_kernwin.ask_yn( 0, "A class structure for %s already exists. Are you sure you want to remake it?" % name) if i == idaapi.BADADDR: return if i == 1: idaapi.del_struc_members(idaapi.get_struc(struct_id), 0, idaapi.get_struc_size(struct_id)) # struct_id = idc.AddStrucEx(idaapi.BADADDR, name + "_vtbl", 0) else: struct_id = idaapi.add_struc(idaapi.BADADDR, name, 0) if struct_id == idaapi.BADADDR: Warning( "Could not create the class structure!.\nPlease check something.") return sptr = idaapi.get_struc(struct_id) for off in fields: off, type_name, type_kind, field_name = fields[off] print( "Process field. Off = 0x%04X, type_name = %s (%d: %s), field_name = %s" % (off, type_name, type_kind, type_sizes[type_kind][0], field_name)) type_size = type_sizes[type_kind][1] ret = ida_struct.add_struc_member(sptr, field_name.decode(), off, flags_dict[type_size], None, type_size) if ret != 0: ida_kernwin.warning("Unknown error! Err = %d" % ret) return mptr = ida_struct.get_member(sptr, off) ida_struct.set_member_cmt( mptr, " --> %s (%d: %s)" % (type_name.decode(), type_kind, type_sizes[type_kind][0]), False) struct_size = ida_struct.get_struc_size(sptr) if size < struct_size: ida_kernwin.warning( "Struct create error! final size (%d) > instanse size (%d)" % (struct_size, size)) elif size > struct_size: for i in range(size - struct_size): ida_struct.add_struc_member(sptr, "dummy%d" % i, idaapi.BADADDR, idaapi.FF_BYTE, None, 1)
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"
def update_idb(self): sid = ida_struct.get_struc_id(self._name) if sid != -1: sptr = ida_struct.get_struc(sid) ida_struct.del_struc(sptr) sid = ida_struct.add_struc(idc.BADADDR, self._name, 0) sptr = ida_struct.get_struc(sid) for f in self._fields: ida_struct.add_struc_member(sptr, f.name, idc.BADADDR, (idc.FF_BYTE | idc.FF_DATA) & 0xFFFFFFFF, None, 1) member_name = "{}.{}".format(self._name, f.name) idc.SetType( idaapi.get_member_by_fullname(member_name)[0].id, f.type) ida_auto.auto_wait()
def get_guid_tid(): tid = ida_struct.get_struc_id('GUID') if tid == idaapi.BADADDR: print("[*] create GUID struct") tid = ida_struct.add_struc(0xffffffff, 'GUID', 0) sptr = ida_struct.get_struc(tid) ida_struct.add_struc_member(sptr, 'Data1', 0x0, 0x20000000, None, 4) ida_struct.add_struc_member(sptr, 'Data2', 0x4, 0x10000000, None, 2) ida_struct.add_struc_member(sptr, 'Data3', 0x6, 0x10000000, None, 2) ida_struct.add_struc_member(sptr, 'Data4', 0x8, 0x00000000, None, 8) return tid
def load(infos): insn = ida_ua.insn_t() for info in infos: # Find or create struct. struct_id = ida_struct.get_struc_id(info['name']) if struct_id == BADADDR: print('[IDA-Sync] Creating new struct %s.' % info['name']) struct_id = ida_struct.add_struc(info['idx'], info['name']) struct = ida_struct.get_struc(struct_id) ida_struct.set_struc_idx(struct, info['idx']) # Create struct members. for member in info['members']: ida_struct.add_struc_member( struct, member['name'], member['offset'], # flag 0, # opinfo_t instance... maybe it should sometimes be # something? None, member['size'], ) # Create xrefs to members of the struct as offsets. for xref in info['xrefs']: typ = xref['type'] # Offset xref. if typ == 1: # TODO figure out what second argument does. idc.op_plain_offset(xref['from'], 1, xref['offset']) # Read/write xrefs. elif typ in [2, 3]: ida_ua.create_insn(xref['from'], insn) idc.op_stroff(insn, 1, struct.id, 0) # TODO do the other cases come up? else: pass
class RTTIClassHierarchyDescriptor(RTTIStruc): bases = None msid = get_struc_id("RTTIClassHierarchyDescriptor") if msid != BADADDR: del_struc(get_struc(msid)) msid = add_struc(0xFFFFFFFF, "RTTIClassHierarchyDescriptor", False) add_struc_member(get_struc(msid), "signature", BADADDR, FF_DWRD | FF_DATA, None, 4) add_struc_member(get_struc(msid), "attribute", BADADDR, FF_DWRD | FF_DATA, None, 4) add_struc_member(get_struc(msid), "numBaseClasses", BADADDR, FF_DWRD | FF_DATA, None, 4) add_struc_member(get_struc(msid), "pBaseClassArray", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva(), 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 update_idb(self, delete_existing_members=True): sid = ida_struct.get_struc_id(self._name) sptr = ida_struct.get_struc(sid) if sid == idc.BADADDR: sid = ida_struct.add_struc(idc.BADADDR, self._name, 0) sptr = ida_struct.get_struc(sid) else: if delete_existing_members: ida_struct.del_struc_members(sptr, 0, 0xffffffff) for f in self._fields: ida_struct.add_struc_member(sptr, f.name, f.offset, (idc.FF_BYTE | idc.FF_DATA) & 0xFFFFFFFF, None, 1) member_name = "{}.{}".format(self._name, f.name) idc.SetType( idaapi.get_member_by_fullname(member_name)[0].id, f.type) ida_auto.auto_wait()
class RTTITypeDescriptor(RTTIStruc): class_name = None msid = get_struc_id("RTTITypeDescriptor") if msid != BADADDR: del_struc(get_struc(msid)) msid = add_struc(0xFFFFFFFF, "RTTITypeDescriptor", False) add_struc_member(get_struc(msid), "pVFTable", BADADDR, FF_DATA | u.PTR_TYPE | FF_0OFF, u.mt_address(), u.PTR_SIZE) add_struc_member(get_struc(msid), "spare", BADADDR, FF_DATA | u.PTR_TYPE, None, u.PTR_SIZE) add_struc_member(get_struc(msid), "name", BADADDR, FF_DATA | FF_ASCI, u.mt_ascii(), 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_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 import_structures(structures): """ Import structures :param structures: Dict containing structure information """ curr_idx = ida_struct.get_last_struc_idx() + 1 for struct_name, struct_info in structures.items(): # Create structure tid = ida_struct.add_struc(curr_idx, struct_name) # Get struct object and add members struct = ida_struct.get_struc(tid) for member_name, member_info in struct_info['members'].items(): flag = get_flag_from_type(member_info['type']) ida_struct.add_struc_member( struct, member_name, member_info['offset'], flag, None, member_info['size'] ) curr_idx += 1
def implement(self): id_of_struct = ida_struct.get_struc_id(self._id) sturct_obj = ida_struct.get_struc(long(id_of_struct)) val_type = "" size = 0 if self._variable_type == "db": val_type = ida_bytes.FF_BYTE size = 1 elif self._variable_type == "dw": val_type = ida_bytes.FF_WORD size = 2 elif self._variable_type == "dd": val_type = ida_bytes.FF_DWORD size = 4 elif self._variable_type == "dq": val_type = ida_bytes.FF_QWORD size = 8 else: val_type = ida_bytes.FF_STRUCT size = 0 ida_struct.add_struc_member(sturct_obj, self._value, int(self._offset), val_type, None, size)
def __call__(self): mt = ida_nalt.opinfo_t() if ida_bytes.is_struct(self.flag): mt.tid = self.extra["id"] if ida_bytes.is_off0(self.flag) or ida_bytes.is_off1(self.flag): mt.ri = ida_nalt.refinfo_t( self.extra["flags"], self.extra["base"], self.extra["target"], self.extra["tdelta"], ) if ida_bytes.is_strlit(self.flag): mt.strtype = self.extra["strtype"] struc = ida_struct.get_struc_id(Event.encode(self.sname)) sptr = ida_struct.get_struc(struc) ida_struct.add_struc_member( sptr, Event.encode(self.fieldname), self.offset, self.flag, mt, self.nbytes, )
def _prepare_ida_type(self): sptr = self.struct.sptr # Create structure member if ida_struct.add_struc_member( sptr, self.name, self.offset, 0, None, self.size) != ida_struct.STRUC_ERROR_MEMBER_OK: raise RuntimeError("Could not create struct member '{}'".format( self.name)) # Get member pointer self.mptr = ida_struct.get_member_by_name(sptr, self.name) # set type ida_struct.set_member_tinfo(sptr, self.mptr, self.offset, self.tif, 0) self.log.info("Created struct member '%s' of size %d at offset %d", self.hierarchy, self.size, self.offset)
class RTTICompleteObjectLocator(RTTIStruc): # Init class statics msid = get_struc_id("RTTICompleteObjectLocator") if msid != BADADDR: del_struc(get_struc(msid)) msid = add_struc(0xFFFFFFFF, "RTTICompleteObjectLocator", False) add_struc_member(get_struc(msid), "signature", BADADDR, FF_DATA | FF_DWRD, None, 4) add_struc_member(get_struc(msid), "offset", BADADDR, FF_DATA | FF_DWRD, None, 4) add_struc_member(get_struc(msid), "cdOffset", BADADDR, FF_DATA | FF_DWRD, None, 4) add_struc_member(get_struc(msid), "pTypeDescriptor", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva(), 4) add_struc_member(get_struc(msid), "pClassDescriptor", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva(), 4) if u.x64: add_struc_member(get_struc(msid), "pSelf", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva(), 4) tid = msid struc = get_struc(tid) size = get_struc_size(tid) print "Completed Registering RTTICompleteObjectLocator" def __init__(self, ea, vtable): do_unknown_range(ea, self.size, DOUNK_DELNAMES) if doStruct(ea, self.size, self.tid): # Get adress of type descriptor from CompleteLocator print "Complete Object Locator at: 0x%x" % ea offset = get_member_by_name(self.struc, "pTypeDescriptor").soff typeDescriptor = get_32bit(ea + offset) + u.x64_imagebase() print "Looking for type Descriptor at: 0x%x" % typeDescriptor rtd = RTTITypeDescriptor(typeDescriptor) if rtd.class_name: print "Type Descriptor at: 0x%x" % typeDescriptor offset = get_member_by_name(self.struc, "pClassDescriptor").soff classHierarchyDes = get_32bit(ea + offset) + u.x64_imagebase() rchd = RTTIClassHierarchyDescriptor(classHierarchyDes) # filter out None entries rchd.bases = filter(lambda x: x, rchd.bases) className = strip(rtd.class_name) classes[className] = [strip(b) for b in rchd.bases] vtables[className] = vtable MakeNameEx(vtable, "vtable__" + className, SN_NOWARN) else: # if the RTTITypeDescriptor doesn't have a valid name for us to # read, then this wasn't a valid RTTICompleteObjectLocator MakeUnknown(ea, self.size, DOUNK_SIMPLE)
def defSEGENT(): sid = ida_struct.get_struc_id("SEGENT") if sid != ida_idaapi.BADADDR: struc = ida_struct.get_struc(sid) ida_struct.del_struc(struc) sid = ida_struct.add_struc(ida_idaapi.BADADDR, "SEGENT", 0) struc = ida_struct.get_struc(sid) ida_struct.add_struc_member(struc, "flags", ida_idaapi.BADADDR, ida_bytes.FF_WORD, None, 2) ida_struct.add_struc_member(struc, "oSegment", ida_idaapi.BADADDR, ida_bytes.FF_WORD, None, 2) ida_struct.add_struc_member(struc, "nParagraphs", ida_idaapi.BADADDR, ida_bytes.FF_WORD, None, 2) ida_struct.add_struc_member(struc, "nReloc", ida_idaapi.BADADDR, ida_bytes.FF_WORD, None, 2) ida_struct.add_struc_member(struc, "minAlloc", ida_idaapi.BADADDR, ida_bytes.FF_WORD, None, 2) ida_struct.add_struc_member(struc, "unused", ida_idaapi.BADADDR, ida_bytes.FF_WORD, None, 2) return sid
def install_vtables_union( class_name, class_vtable_member=None, vtable_member_tinfo=None, offset=0 ): logging.debug( "install_vtables_union(%s, %s, %s)", class_name, class_vtable_member, str(vtable_member_tinfo), ) if class_vtable_member and vtable_member_tinfo: old_vtable_sptr = utils.extract_struct_from_tinfo(vtable_member_tinfo) old_vtable_class_name = ida_struct.get_struc_name(old_vtable_sptr.id) else: old_vtable_class_name = get_class_vtable_struct_name(class_name, offset) old_vtable_sptr = utils.get_sptr_by_name(old_vtable_class_name) vtables_union_name = old_vtable_class_name if old_vtable_sptr and not ida_struct.set_struc_name( old_vtable_sptr.id, old_vtable_class_name + "_orig" ): logging.exception( f"Failed changing {old_vtable_class_name}->" f"{old_vtable_class_name+'orig'}" ) return -1 vtables_union_id = utils.get_or_create_struct_id(vtables_union_name, True) vtable_member_tinfo = utils.get_typeinf(old_vtable_class_name + "_orig") if vtables_union_id == BADADDR: logging.exception( f"Cannot create union vtable for {class_name}(){vtables_union_name}" ) return -1 vtables_union = ida_struct.get_struc(vtables_union_id) if not vtables_union: logging.exception(f"Could retrieve vtables union for {class_name}") if vtable_member_tinfo is not None: vtables_union_vtable_field_name = get_class_vtables_field_name(class_name) else: vtables_union_vtable_field_name = get_interface_empty_vtable_name() utils.add_to_struct( vtables_union, vtables_union_vtable_field_name, vtable_member_tinfo ) parent_struct = utils.get_sptr_by_name(class_name) flag = idaapi.FF_STRUCT mt = idaapi.opinfo_t() mt.tid = vtables_union_id struct_size = ida_struct.get_struc_size(vtables_union_id) vtables_union_ptr_type = utils.get_typeinf_ptr(vtables_union_name) if class_vtable_member: member_ptr = class_vtable_member else: member_id = ida_struct.add_struc_member( parent_struct, get_class_vtable_field_name(class_name), offset, flag, mt, struct_size, ) member_ptr = ida_struct.get_member_by_id(member_id) ida_struct.set_member_tinfo( parent_struct, member_ptr, 0, vtables_union_ptr_type, idaapi.TINFO_DEFINITE ) return vtables_union
def add_to_struct( struct, member_name, member_type=None, offset=BADADDR, is_offset=False, overwrite=False, ): mt = None flag = idaapi.FF_DWORD member_size = WORD_LEN if member_type is not None and (member_type.is_struct() or member_type.is_union()): logging.debug("Is struct!") substruct = extract_struct_from_tinfo(member_type) if substruct is not None: flag = idaapi.FF_STRUCT mt = ida_nalt.opinfo_t() mt.tid = substruct.id logging.debug( f"Is struct: {ida_struct.get_struc_name(substruct.id)}/{substruct.id}" ) member_size = ida_struct.get_struc_size(substruct.id) elif WORD_LEN == 4: flag = idaapi.FF_DWORD elif WORD_LEN == 8: flag = idaapi.FF_QWORD if is_offset: flag |= idaapi.FF_0OFF mt = ida_nalt.opinfo_t() r = ida_nalt.refinfo_t() r.init( ida_nalt.get_reftype_by_size(WORD_LEN) | ida_nalt.REFINFO_NOBASE) mt.ri = r new_member_name = member_name member_ptr = ida_struct.get_member(struct, offset) if overwrite and member_ptr: if ida_struct.get_member_name(member_ptr.id) != member_name: logging.debug("Overwriting!") ret_val = ida_struct.set_member_name(struct, offset, member_name) i = 0 while ret_val == ida_struct.STRUC_ERROR_MEMBER_NAME: new_member_name = "%s_%d" % (member_name, i) i += 1 if i > 250: logging.debug("failed change name") return ret_val = ida_struct.set_member_name(struct, offset, new_member_name) else: ret_val = ida_struct.add_struc_member(struct, new_member_name, offset, flag, mt, member_size) i = 0 while ret_val == ida_struct.STRUC_ERROR_MEMBER_NAME: new_member_name = "%s_%d" % (member_name, i) i += 1 if i > 250: return ret_val = ida_struct.add_struc_member(struct, new_member_name, offset, flag, mt, member_size) if ret_val != 0: logging.debug(f"ret_val: {ret_val}") member_ptr = ida_struct.get_member_by_name(struct, new_member_name) if member_type is not None and member_ptr is not None: ida_struct.set_member_tinfo(struct, member_ptr, 0, member_type, idaapi.TINFO_DEFINITE) return member_ptr
""" This file is part of Polichombr (c) ANSSI-FR 2018 Description: Semi automated test that add some data in the IDA database, that should be reflected in the second database """ import ida_name, ida_bytes, ida_struct import idc ida_name.set_name(0x401000, "TESTFUNCTION") ida_bytes.set_cmt(0x40100A, "TEST COMMENT", 0) ida_bytes.set_cmt(0x40100F, "TEST RPT COMMENT", 1) struct_1 = ida_struct.add_struc(0, "TESTSTRUCT1") struct_pointer = ida_struct.get_struc(struct_1) ida_struct.add_struc_member(struct_pointer, "TESTMEMBER", 0, 0, None, 0) idc.SetType(0x401000, "int __cdecl start(char *lpszTestArg);")
def analyze_function_frame(self, function: Function) -> None: """ inspect the given function to determine the frame layout and set references appropriately. args: function (Function): function instance. """ # given a function prologue like the following: # # 23 80 80 80 80 00 get_global $global0 # 21 04 set_local $local4 # 41 20 i32.const 0x20 # 21 05 set_local $local5 # 20 04 get_local $local4 # 20 05 get_local $local5 # 6B i32.sub # 21 06 set_local $local6 # # recognize that the function frame is 0x20 bytes. if not self.has_llvm_prologue(function): return bc = self.get_prologue_bc(function['offset']) if len(bc) == 0: return global_frame_pointer = bc[0].imm.global_index frame_size = bc[2].imm.value local_frame_pointer = bc[7].imm.local_index # add a frame structure to the function f = ida_funcs.get_func(function['offset']) ida_frame.add_frame(f, 0x0, 0x0, frame_size) ida_struct.set_struc_name(f.frame, 'frame%d' % function['index']) # ensure global variable $frame_stack is named appropriately ida_name.set_name(self.proc.globals[global_frame_pointer]['offset'], '$frame_stack') # re-map local variable to $frame_pointer ida_frame.add_regvar(f, function['offset'], function['offset'] + function['size'], '$local%d' % local_frame_pointer, '$frame_pointer', '') # define the frame structure layout by scanning for references within this function frame_references = self.find_function_frame_references( function, local_frame_pointer) for frame_offset, refs in frame_references.items(): member_name = 'field_%x' % frame_offset for ref in refs: if 'parameter' in ref: member_name = 'param%d' % (ref['parameter']) # pick largest element size for the element type flags = 0 size = 0 for ref in refs: fl = { 'i8': ida_bytes.FF_BYTE | ida_bytes.FF_DATA, 'i16': ida_bytes.FF_WORD | ida_bytes.FF_DATA, 'i32': ida_bytes.FF_DWORD | ida_bytes.FF_DATA, 'i64': ida_bytes.FF_QWORD | ida_bytes.FF_DATA, 'f32': ida_bytes.FF_FLOAT | ida_bytes.FF_DATA, 'f64': ida_bytes.FF_DOUBLE | ida_bytes.FF_DATA, }[ref['element_size']] s = { 'i8': 1, 'i16': 2, 'i32': 4, 'i64': 8, 'f32': 4, 'f64': 8, }[ref['element_size']] # by luck, FF_BYTE < FF_WORD < FF_DWORD < FF_QWORD, # so we can order flag values. if fl > flags: flags = fl size = s logger.debug('adding frame member %s to function %d', member_name, function['index']) ida_struct.add_struc_member(ida_struct.get_struc(f.frame), member_name, frame_offset, flags & 0xFFFFFFFF, None, size) # mark struct references for refs in frame_references.values(): for ref in refs: # set type of operand 0 to function frame structure offset # ref: https://github.com/idapython/src/blob/a3855ab969fd16758b3de007525feeba3a920344/tools/inject_pydoc/bytes.py#L5 insn = ida_ua.insn_t() if not ida_ua.decode_insn(insn, ref['offset']): continue path = ida_pro.tid_array(1) path[0] = f.frame ida_bytes.op_stroff(insn, 0, path.cast(), 1, 0)
def install_vtables_union(class_name, class_vtable_member=None, vtable_member_tinfo=None, offset=0): # pylint: disable=too-many-locals # TODO: this function is too big and must be refactored log.debug( "install_vtables_union(%s, %s, %s)", class_name, class_vtable_member, str(vtable_member_tinfo), ) if class_vtable_member and vtable_member_tinfo: old_vtable_sptr = utils.extract_struct_from_tinfo(vtable_member_tinfo) old_vtable_class_name = ida_struct.get_struc_name(old_vtable_sptr.id) else: old_vtable_class_name = get_class_vtable_struct_name(class_name, offset) old_vtable_sptr = utils.get_sptr_by_name(old_vtable_class_name) vtables_union_name = old_vtable_class_name if old_vtable_sptr and not ida_struct.set_struc_name( old_vtable_sptr.id, old_vtable_class_name + "_orig" ): # FIXME: why log exception? log.exception( "Failed changing %s->%s_orig", old_vtable_class_name, old_vtable_class_name, ) # FIXME: why -1 and not None? return -1 vtables_union_id = utils.get_or_create_struct_id(vtables_union_name, True) vtable_member_tinfo = utils.get_typeinf(old_vtable_class_name + "_orig") if vtables_union_id == BADADDR: log.exception( "Cannot create union vtable for %s()%s", class_name, vtables_union_name, ) # FIXME: why -1 and not None? return -1 vtables_union = ida_struct.get_struc(vtables_union_id) if not vtables_union: log.exception("Could retrieve vtables union for %s", class_name) # FIXME: return -1? if vtable_member_tinfo is not None: vtables_union_vtable_field_name = get_class_vtables_field_name(class_name) else: vtables_union_vtable_field_name = get_interface_empty_vtable_name() utils.add_to_struct(vtables_union, vtables_union_vtable_field_name, vtable_member_tinfo) parent_struct = utils.get_sptr_by_name(class_name) flag = idaapi.FF_STRUCT mt = idaapi.opinfo_t() mt.tid = vtables_union_id struct_size = ida_struct.get_struc_size(vtables_union_id) vtables_union_ptr_type = utils.get_typeinf_ptr(vtables_union_name) if class_vtable_member: member_ptr = class_vtable_member else: # FIXME: add_struc_member returns error code, not member id member_id = ida_struct.add_struc_member( parent_struct, get_class_vtable_field_name(class_name), offset, flag, mt, struct_size, ) # FIXME: get_member_by_id returns tuple, not member ptr member_ptr = ida_struct.get_member_by_id(member_id) ida_struct.set_member_tinfo( parent_struct, member_ptr, 0, vtables_union_ptr_type, idaapi.TINFO_DEFINITE, ) # FIXME: might be None! Is this OK, considering we return -1 everywhere else? return vtables_union