def expanding_struc(self, sptr, offset, delta): sname = ida_struct.get_struc_name(sptr.id) self._send_packet(evt.ExpandingStrucEvent(sname, offset, delta)) return 0
def is_struct_vtable(struct): if struct is None: return False struct_name = ida_struct.get_struc_name(struct.id) return VTABLE_POSTFIX in struct_name
def frame(self): frame_id = get_func_attr(self.__start, FUNCATTR_FRAME) if frame_id is not None: return FunctionFrame(get_struc_name(frame_id), create_new=False)
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
def update_vtable_struct( functions_ea, vtable_struct, class_name, this_type=None, get_next_func_callback=get_vtable_line, vtable_head=None, ignore_list=None, add_dummy_member=False, pure_virtual_name=None, parent_name=None, add_func_this=True, force_rename_vtable_head=False, # rename vtable head even if it is already named by IDA # if it's not named, then it will be renamed anyway ): # pylint: disable=too-many-arguments,too-many-locals,too-many-branches # TODO: refactor if this_type is None: this_type = utils.get_typeinf_ptr(class_name) if not add_func_this: this_type = None func_ea, next_func = get_next_func_callback( functions_ea, ignore_list=ignore_list, pure_virtual_name=pure_virtual_name, ) dummy_i = 1 offset = 0 while func_ea is not None: new_func_name, _ = update_func_name_with_class(func_ea, class_name) func_ptr = None if ida_hexrays.init_hexrays_plugin(): fix_userpurge(func_ea, idc.TINFO_DEFINITE) update_func_this(func_ea, this_type, idc.TINFO_DEFINITE) func_ptr = utils.get_typeinf_ptr(utils.get_func_tinfo(func_ea)) else: func_ptr = make_funcptr_pt(func_ea, this_type) # TODO: maybe try to get or guess type? if add_dummy_member: utils.add_to_struct(vtable_struct, "dummy_%d" % dummy_i, func_ptr) dummy_i += 1 offset += utils.WORD_LEN ptr_member = utils.add_to_struct( vtable_struct, new_func_name, func_ptr, offset, overwrite=True, is_offs=True ) if ptr_member is None: log.error( "Couldn't add %s(%s) to vtable struct 0x%X at offset 0x%X", new_func_name, str(func_ptr), vtable_struct.id, offset, ) offset += utils.WORD_LEN if not ida_xref.add_dref(ptr_member.id, func_ea, ida_xref.XREF_USER | ida_xref.dr_I): log.warn( "Couldn't create xref between member %s and func %s", ida_struct.get_member_name(ptr_member.id), idc.get_name(func_ea), ) func_ea, next_func = get_next_func_callback( next_func, ignore_list=ignore_list, pure_virtual_name=pure_virtual_name, ) vtable_size = ida_struct.get_struc_size(vtable_struct) if vtable_head is None: vtable_head = functions_ea # ida_bytes.del_items(vtable_head, ida_bytes.DELIT_SIMPLE, vtable_size) ida_bytes.create_struct(vtable_head, vtable_size, vtable_struct.id) if not idc.hasUserName(idc.get_full_flags(vtable_head)) or force_rename_vtable_head: if parent_name is None and this_type: parent = utils.deref_struct_from_tinfo(this_type) parent_name = ida_struct.get_struc_name(parent.id) if parent_name == class_name: parent_name = None idc.set_name( vtable_head, get_vtable_instance_name(class_name, parent_name), ida_name.SN_CHECK | ida_name.SN_FORCE, )
def struc_member_deleted(self, sptr, off1, off2): sname = ida_struct.get_struc_name(sptr.id) self._send_packet(evt.StrucMemberDeletedEvent(sname, off2)) return 0
def get_operand_struct_name(inst, op_no): path_len = 1 path = ida_pro.tid_array(path_len) if ida_bytes.get_stroff_path(path.cast(), None, inst.ea, op_no): return ida_struct.get_struc_name(path[0]) return ''
def __str__(self): return "%s.%s @ 0x%X" % (get_struc_name( self._sid), self.name, self.offset)
def __repr__(self): return "StructureMember(%s, 0x%X)" % (get_struc_name( self._sid), self._offset)
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 update_vtable_struct( functions_ea, vtable_struct, class_name, this_type=None, get_next_func_callback=get_vtable_line, vtable_head=None, ignore_list=None, add_dummy_member=False, pure_virtual_name=None, parent_name=None, add_func_this=True, ): is_first_member = True if this_type is None: this_type = utils.get_typeinf_ptr(class_name) if not add_func_this: this_type = None func, next_func = get_next_func_callback( functions_ea, ignore_list=ignore_list, pure_virtual_name=pure_virtual_name ) dummy_i = 1 while func is not None: new_func_name, is_name_changed = update_func_name_with_class(func, class_name) func_ptr = None if ida_hexrays.init_hexrays_plugin(): if is_name_changed: func_type = update_func_this(func, this_type) else: func_type = update_func_this(func, None) if func_type is not None: func_ptr = utils.get_typeinf_ptr(func_type) else: func_ptr = make_funcptr_pt(func, this_type) if add_dummy_member: utils.add_to_struct(vtable_struct, f"dummy_{dummy_i}", func_ptr) dummy_i += 1 if is_first_member: # We did an hack for vtables contained in union vtable with one dummy member ptr_member = utils.add_to_struct( vtable_struct, new_func_name, func_ptr, 0, overwrite=True ) is_first_member = False else: ptr_member = utils.add_to_struct( vtable_struct, new_func_name, func_ptr, is_offset=True ) if ptr_member is None: logging.exception( "Couldn't add %s(%s) to %d", new_func_name, str(func_ptr), vtable_struct.id, ) ida_xref.add_dref(ptr_member.id, func, ida_xref.XREF_USER | ida_xref.dr_I) func, next_func = get_next_func_callback( next_func, ignore_list=ignore_list, pure_virtual_name=pure_virtual_name ) vtable_size = ida_struct.get_struc_size(vtable_struct) if vtable_head is None: vtable_head = functions_ea ida_bytes.del_items(vtable_head, ida_bytes.DELIT_SIMPLE, vtable_size) ida_bytes.create_struct(vtable_head, vtable_size, vtable_struct.id) if parent_name is None and this_type: parent = utils.deref_struct_from_tinfo(this_type) parent_name = ida_struct.get_struc_name(parent.id) if parent_name == class_name: parent_name = None utils.set_name_retry(vtable_head, get_vtable_instance_name(class_name, parent_name))
def struc_member_deleted(self, sptr, off1, off2): sname = ida_struct.get_struc_name(sptr.id) return 0
def expanding_struc(self, sptr, offset, delta): sname = ida_struct.get_struc_name(sptr.id) return 0
def expand_struct(struct_id, new_size): struct = ida_struct.get_struc(struct_id) if struct is None: log.warning("Struct id 0x%X wasn't found", struct_id) return log.debug( "Expanding struc %s, size: 0x%X -> 0x%X", ida_struct.get_struc_name(struct_id), ida_struct.get_struc_size(struct_id), new_size, ) if ida_struct.get_struc_size(struct_id) > new_size - WORD_LEN: return fix_list = [] xrefs = idautils.XrefsTo(struct.id) for xref in xrefs: if xref.type == ida_xref.dr_R and xref.user == 0 and xref.iscode == 0: res = ida_struct.get_member_by_id(xref.frm) if not res or not res[0]: log.warning("Xref from %08X wasn't struct_member", xref.frm) continue member = res[0] x_struct = ida_struct.get_member_struc(ida_struct.get_member_fullname(member.id)) assert x_struct old_name = ida_struct.get_member_name(member.id) offset = member.soff # FIXME: why use random here? marker_name = "marker_%d" % random.randint(0, 0xFFFFFF) # FIXME: check if add_struc_member actually added a member idc.add_struc_member( x_struct.id, marker_name, member.soff + new_size, idaapi.FF_DATA | idaapi.FF_BYTE, -1, 0, ) log.debug( "Delete member (0x%X-0x%X)", member.soff, member.soff + new_size - 1, ) # FIXME: check if struc member actually deleted ida_struct.del_struc_members(x_struct, member.soff, member.soff + new_size - 1) fix_list.append( [ x_struct.id, old_name, offset, idaapi.FF_STRUCT | idaapi.FF_DATA, struct_id, new_size, ] ) ret = add_to_struct(ida_struct.get_struc(struct_id), None, None, new_size - WORD_LEN) log.debug("Now fix args:") for fix_args in fix_list: ret = idc.add_struc_member(*fix_args) log.debug("%s = %d", fix_args, ret) x_struct_id = fix_args[0] idc.del_struc_member(x_struct_id, ida_struct.get_struc_size(x_struct_id))
def struc_created(self, tid): name = ida_struct.get_struc_name(tid) is_union = ida_struct.is_union(tid) self._send_packet(evt.StrucCreatedEvent(tid, name, is_union)) return 0
def name(self): return get_struc_name(self._sid)
def deleting_struc(self, sptr): sname = ida_struct.get_struc_name(sptr.id) self._send_packet(evt.StrucDeletedEvent(sname)) return 0
def dependency_name(self): struc_id = ida_struct.get_struc_by_idx(self.idx) return ida_struct.get_struc_name(struc_id)
def renaming_struc_member(self, sptr, mptr, newname): sname = ida_struct.get_struc_name(sptr.id) offset = mptr.soff self._send_packet(evt.StrucMemberRenamedEvent(sname, offset, newname)) return 0
# https://github.com/csnover/ida-misc # # Sorts all the structs in a database in case-insensitive alphabetical order. import ida_struct from idaapi import BADADDR structs = [] idx = ida_struct.get_first_struc_idx() while idx != BADADDR: id = ida_struct.get_struc_by_idx(idx) name = ida_struct.get_struc_name(id) structs.append((name, ida_struct.get_struc(id))) idx = ida_struct.get_next_struc_idx(idx) structs.sort(key=lambda t: t[0].lower()) for i, t in enumerate(structs): ida_struct.set_struc_idx(t[1], i)