def get_overriden_func_names(union_name, offset, get_not_funcs_members=False): sptr = utils.get_sptr_by_name(union_name) res = [] if not sptr.is_union: return res for i in range(ida_struct.get_max_offset(sptr)): member = ida_struct.get_member(sptr, i) cls = ida_struct.get_member_name(member.id) tinfo = utils.get_member_tinfo(member) log.debug("Trying %s", cls) if cls == get_interface_empty_vtable_name() or not tinfo.is_ptr(): continue pointed_obj = tinfo.get_pointed_object() if not pointed_obj.is_struct(): continue vtable_sptr = utils.get_sptr_by_name(pointed_obj.get_final_type_name()) if ida_struct.get_max_offset(vtable_sptr) <= offset: continue funcptr_member = ida_struct.get_member(vtable_sptr, offset) funcptr_type = utils.get_member_tinfo(funcptr_member) func_name = ida_struct.get_member_name(funcptr_member.id) if not funcptr_type.is_funcptr() and not get_not_funcs_members: continue res.append((cls, func_name)) return res
def member_data(self, member): d = {} # TODO: variable size bool # TODO: retrieve_member_info - get operand type member info d['name'] = ida_struct.get_member_name(member.id) d['size'] = ida_struct.get_member_size(member) d['flag'] = member.flag d['offset'] = member.soff d['comment'] = ida_struct.get_member_cmt(member.id, False) d['repeatable_comment'] = ida_struct.get_member_cmt(member.id, True) if member.has_ti(): tinfo = ida_typeinf.tinfo_t() ida_struct.get_member_tinfo(tinfo, member) d['type_info_serialize'] = tinfo.serialize() d['type_info'] = str(tinfo) oi = ida_nalt.opinfo_t() ida_struct.retrieve_member_info(oi, member) # TODO: Do things with OI sptr = ida_struct.get_sptr(member) if sptr: struct_name = ida_struct.get_struc_name(sptr.id) d['struct_name'] = struct_name d['struct_uuid'] = StructureAnnotation.depend(self, struct_name) return d
def __process_struct_members(self, st_obj): members = [] for st_member in st_obj.members: mem_name = ida_struct.get_member_name( st_member.id) or ('unknown_%s' % st_member.id) mem_off_start = 0 if st_obj.is_union() else st_member.soff mem_off_end = st_member.eoff mem_tinfo = ida_typeinf.tinfo_t() ida_struct.get_member_tinfo(mem_tinfo, st_member) mem_typename = ida_typeinf.print_tinfo('', 0, 0, ida_typeinf.PRTYPE_1LINE, mem_tinfo, '', '') if not mem_typename: mem_typename = self.__describe_type_basetype( mem_tinfo.get_realtype()) members.append({ 'offset': mem_off_start, 'length': mem_off_end - mem_off_start, 'type': mem_typename, 'name': mem_name, }) return members
def _validate_ida_type(self): # Name m_name = ida_struct.get_member_name(self.mptr.id) if m_name != self.name: self.log.warn( "validate_ida_type: name mismatch. Expected '%s' but got '%s'", self.name, m_name) return False # Offset if self.mptr.soff != self.offset: self.log.warn( "validate_ida_type: offset mismatch. Expected %d but got %s", self.offset, str(self.mptr.soff)) return False # Size msize = self.mptr.eoff - self.mptr.soff if msize != self.size: self.log.warn( "validate_ida_type: size mismatch. Expected %d but got %d", self.size, msize) return False self.log.debug("validate_ida_type: found match for '%s'", self.hierarchy) return True
def is_member_vtable(member): member_type = utils.get_member_tinfo(member) member_name = ida_struct.get_member_name(member.id) if not is_valid_vtable_name(member_name): return False if not is_valid_vtable_type(member, member_type): return False return True
def name(self): if self.is_stack: name = ida_struct.get_member_name(self._member.id) else: name = idc.get_name(self.addr) if not name: return "" return name
def expand_struct(struct_id, new_size): struct = ida_struct.get_struc(struct_id) if struct is None: logging.warning("Struct id 0x%x wasn't found", struct_id) return logging.debug( "Expanding struc %s 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: member, full_name, x_struct = ida_struct.get_member_by_id(xref.frm) if x_struct is not None: old_name = ida_struct.get_member_name(member.id) offset = member.soff marker_name = "marker_%d" % random.randint(0, 0xFFFFFF) idc.add_struc_member( x_struct.id, marker_name, member.soff + new_size, idaapi.FF_DATA | idaapi.FF_BYTE, -1, 0, ) logging.debug( "Delete member (0x%x-0x%x)", member.soff, member.soff + new_size - 1 ) 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, ] ) else: logging.warning("Xref wasn't struct_member 0x%x", xref.frm) ret = push_ptr_member_to_struct( ida_struct.get_struc(struct_id), None, None, new_size - WORD_LEN ) logging.debug("Now fix args:") for fix_args in fix_list: ret = idc.add_struc_member(*fix_args) logging.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 main(): is_selected, sel_start, sel_end = ida_kernwin.read_selection() if not is_selected: logger.error('range must be selected') return -1 sel_end = ida_bytes.next_head(sel_end) buf = ida_bytes.get_bytes(sel_start, sel_end - sel_start) if buf is None: logger.error('failed to fetch instruction bytes') return -1 f = ida_funcs.get_func(sel_start) if f != ida_funcs.get_func(sel_end): logger.error('range must be within a single function') return -1 # find mappings from "$localN" to "custom_name" regvars = {} for i in range(0x1000): regvar = ida_frame.find_regvar(f, sel_start, '$local%d' % i) if regvar is None: continue regvars[regvar.canon] = regvar.user if len(regvars) >= f.regvarqty: break globals_ = {} for i, offset in netnode.Netnode('$ wasm.offsets').get('globals', {}).items(): globals_['$global' + i] = ida_name.get_name(offset) frame = {} if f.frame != ida_idaapi.BADADDR: names = set([]) for i in range(ida_struct.get_struc_size(f.frame)): s = ida_struct.get_struc(f.frame) if not s: continue m = ida_struct.get_member(s, i) if not m: continue name = ida_struct.get_member_name(m.id) if name in names: continue frame[i] = name names.add(name) emu = Emulator(buf) emu.run() print( emu.render(ctx={ 'regvars': regvars, 'frame': frame, 'globals': globals_, }))
def _update_member_type(struct_ptr, member_ptr, member_tif): assert struct_ptr assert member_ptr smt_code = set_member_tinfo(struct_ptr, member_ptr, member_tif) if smt_code != ida_struct.SMT_OK: log.warn( "Failed to %s type%s for member %s at offset 0x%X: %s", "set" if member_tif else "delete", " '%s'" % member_tif if member_tif else "", ida_struct.get_member_name(member_ptr.id), member_ptr.get_soff(), print_smt_error(smt_code), )
def ida_struct_changed(self, sid: int, old_name=None, new_name=None, deleted=False): """ A utility function to catch all changes that can happen to a struct: 1. Renames 2. Member Changes 3. Deletes Currently, any change to a struct will cause the main-thread to re-copy the entire struct from the local state into the remote state. This is done so we don't need to have multiple cases for single member changes. @param sid: Struct ID (IDA Thing) @param old_name: Old struct name (before rename) @param new_name: New struct name (after rename) @param deleted: True only when the entire struct has been deleted. @return: """ # parse the info of the current struct s_name = new_name if new_name else ida_struct.get_struc_name(sid) # back out if a stack variable snuck in if s_name.startswith("$"): return 0 sptr = ida_struct.get_struc(sid) s_size = ida_struct.get_struc_size(sptr) # if deleted, finish early if deleted: self.binsync_state_change(self.controller.push_artifact, Struct(s_name, None, {})) return 0 # convert the ida_struct into a binsync_struct binsync_struct = Struct(s_name, s_size, {}) for mptr in sptr.members: mid = mptr.id m_name = ida_struct.get_member_name(mid) m_off = mptr.soff m_type = ida_typeinf.idc_get_type(mptr.id) if mptr.has_ti() else "" m_size = ida_struct.get_member_size(mptr) binsync_struct.add_struct_member(m_name, m_off, m_type, m_size) # make the controller update the local state and push old_s_name = old_name if old_name else s_name self.binsync_state_change(self.controller.push_artifact, binsync_struct) return 0
def struct(name): sid = ida_struct.get_struc_id(name) if sid == 0xffffffffffffffff: return None sptr = ida_struct.get_struc(sid) size = ida_struct.get_struc_size(sptr) _struct = Struct(name, size, {}, last_change=int(time())) for mptr in sptr.members: mid = mptr.id m_name = ida_struct.get_member_name(mid) m_off = mptr.soff m_type = ida_typeinf.idc_get_type(mptr.id) if mptr.has_ti() else "" m_size = ida_struct.get_member_size(mptr) _struct.add_struct_member(m_name, m_off, m_type, m_size) return _struct
def struc_member_created(self, sptr, mptr): extra = {} sname = ida_struct.get_struc_name(sptr.id) fieldname = ida_struct.get_member_name(mptr.id) offset = 0 if mptr.unimem() else mptr.soff flag = mptr.flag nbytes = mptr.eoff if mptr.unimem() else mptr.eoff - mptr.soff mt = ida_nalt.opinfo_t() is_not_data = ida_struct.retrieve_member_info(mt, mptr) if is_not_data: if flag & ida_bytes.off_flag(): extra["target"] = mt.ri.target extra["base"] = mt.ri.base extra["tdelta"] = mt.ri.tdelta extra["flags"] = mt.ri.flags self._send_packet( evt.StrucMemberCreatedEvent( sname, fieldname, offset, flag, nbytes, extra ) ) # Is it really possible to create an enum? elif flag & ida_bytes.enum_flag(): extra["serial"] = mt.ec.serial self._send_packet( evt.StrucMemberCreatedEvent( sname, fieldname, offset, flag, nbytes, extra ) ) elif flag & ida_bytes.stru_flag(): extra["id"] = mt.tid if flag & ida_bytes.strlit_flag(): extra["strtype"] = mt.strtype self._send_packet( evt.StrucMemberCreatedEvent( sname, fieldname, offset, flag, nbytes, extra ) ) else: self._send_packet( evt.StrucMemberCreatedEvent( sname, fieldname, offset, flag, nbytes, extra ) ) return 0
def struc_member_renamed(self, sptr, mptr): #print(f"struc member renamed: {sptr.id}: {mptr.id}") """ Handles renaming of two things: 1. Global Structs 2. Stack Variables :param sptr: Struct Pointer :param mptr: Member Pointer :return: """ # struct pointer is actually a stack frame if sptr.is_frame(): stack_frame = sptr func_addr = idaapi.get_func_by_frame(stack_frame.id) try: stack_var_info = compat.get_func_stack_var_info(func_addr)[ compat.ida_to_angr_stack_offset(func_addr, mptr.soff)] except KeyError: l.debug( f"Failed to track an internal changing stack var: {mptr.id}." ) return 0 # find the properties of the changed stack var angr_offset = compat.ida_to_angr_stack_offset( func_addr, stack_var_info.stack_offset) size = stack_var_info.size type_str = stack_var_info.type # TODO: correct this fix in the get_func_stack_var_info new_name = ida_struct.get_member_name(mptr.id) # do the change on a new thread sv = StackVariable(angr_offset, StackOffsetType.IDA, new_name, type_str, size, func_addr) self.binsync_state_change(self.controller.push_artifact, sv) # an actual struct else: self.ida_struct_changed(sptr.id) return 0
def struc_member_renamed(self, sptr, mptr): if CONFIGURATION[DEBUG]: print 'DEBUG - Hooks - IDBHook.struc_member_renamed(sptr = %s, mptr = %s)' % ( pprint.pformat(sptr), pprint.pformat(mptr)) data = ida_struct.get_member_name(mptr.id) if sptr.props & 0x40: # Struct changed is a frame pointer update = idb_push_ops.StackVariableUpdate( update_type=idb_push_ops.UpdateTypes.StackVariableRenamed, address=ida_frame.get_func_by_frame(sptr.id), data=data, offset=mptr.soff, var_size=mptr.eoff - mptr.soff) else: return idaapi.IDB_Hooks.struc_member_created(self, sptr, mptr) if g_hooks_enabled and (data is not None) and (len(data) > 0): send_push_update(update) return idaapi.IDB_Hooks.struc_member_renamed(self, sptr, mptr)
def struc_member_created(self, sptr, mptr): if not shared.PAUSE_HOOK: tinfo = ida_typeinf.tinfo_t() ida_hexrays.get_member_type(mptr, tinfo) member_type = "unkown" if tinfo.get_size() == 1: member_type = 'db' elif tinfo.get_size() == 2: member_type = 'dw' elif tinfo.get_size() == 4: member_type = 'dd' elif tinfo.get_size() == 8: member_type = 'dq' else: pass pass_to_manager( CreateStructVariableEvent(ida_struct.get_struc_name(sptr.id), mptr.get_soff(), member_type, ida_struct.get_member_name(mptr.id))) return ida_idp.IDB_Hooks.struc_member_created(self, sptr, mptr)
def get_stkvar_name(inst_t, op_n): operand = inst_t.ops[op_n] if operand.addr > 2**31: addr = -(2**32 - operand.addr) else: addr = operand.addr var = ida_frame.get_stkvar(inst_t, operand, addr) if not var: log_file.write("<get_stkvar_name><get_stkvar> error: " + hex(inst_t.ea) + "\n") return None var = var[0] var_name = ida_struct.get_member_name(var.id) if var_name: return var_name else: # log_file.write("<get_stkvar_name><get_member_name> error: " + hex(inst_t.ea) + "\n") # return "STKVAR" return None
def view_dblclick(self, viewer, point): widget_type = ida_kernwin.get_widget_type(viewer) if not (widget_type == 48 or widget_type == 28): return # Decompiler or Structures window func_cand_name = None place, x, y = ida_kernwin.get_custom_viewer_place(viewer, False) if place.name() == "structplace_t": # Structure window: structplace = ida_kernwin.place_t_as_structplace_t(place) if structplace is not None: s = ida_struct.get_struc(ida_struct.get_struc_by_idx(structplace.idx)) if s: member = ida_struct.get_member(s, structplace.offset) if member: func_cand_name = ida_struct.get_member_name(member.id) if func_cand_name is None: line = utils.get_curline_striped_from_viewer(viewer) func_cand_name = cpp_utils.find_valid_cppname_in_line(line, x) if func_cand_name is not None: func_cand_ea = ida_name.get_name_ea(BADADDR, func_cand_name) if func_cand_ea is not None and utils.is_func_start(func_cand_ea): idc.jumpto(func_cand_ea)
def _update_member_name(member_ptr, new_member_name, overwrite): assert member_ptr assert new_member_name old_member_name = _remove_member_index(ida_struct.get_member_name(member_ptr.id)) if old_member_name == new_member_name: return True if not overwrite: log.error("There is already a member at offset 0x%X", member_ptr.get_soff()) return False log.debug("Overwriting member at offset 0x%X!", member_ptr.get_soff()) if not set_member_name_retry(member_ptr, new_member_name): log.error( "Failed to overwrite member name with '%s' at offset 0x%X", new_member_name, member_ptr.get_soff(), ) return False return True
def _get_frame(self): result = False sp = get_sp_val() ip = get_ip_val() if ip and sp: f = get_func(ip) if f: frame = get_frame(f) if frame: self.framesize = get_struc_size(frame) n = frame.memqty frame_offs = f.frregs + f.frsize self.ea = sp - get_spd(f, ip) - frame_offs for i in xrange(n): m = frame.get_member(i) if m: lvar_name = get_member_name(m.id) lvar_ea = self.ea + m.soff lvar_size = m.eoff - m.soff self.members[lvar_ea] = (lvar_name, m.soff, lvar_size, frame_offs) result = True return result
def struc_member_created(self, sptr, mptr): print("struc member created") extra = {} sname = ida_struct.get_struc_name(sptr.id) fieldname = ida_struct.get_member_name(mptr.id) offset = 0 if mptr.unimem() else mptr.soff flag = mptr.flag nbytes = mptr.eoff if mptr.unimem() else mptr.eoff - mptr.soff mt = ida_nalt.opinfo_t() is_not_data = ida_struct.retrieve_member_info(mt, mptr) if is_not_data: if flag & ida_bytes.off_flag(): extra["target"] = mt.ri.target extra["base"] = mt.ri.base extra["tdelta"] = mt.ri.tdelta extra["flags"] = mt.ri.flags # Is it really possible to create an enum? elif flag & ida_bytes.enum_flag(): extra["serial"] = mt.ec.serial elif flag & ida_bytes.stru_flag(): extra["struc_name"] = ida_struct.get_struc_name(mt.tid) if flag & ida_bytes.strlit_flag(): extra["strtype"] = mt.strtype return 0
def _validate_ida_type(self): # type ID if self.tid is None or self.tid is BADADDR: self.log.warn("validate_ida_type: tid=%s is invalid", str(self.tid)) return False # struc_t pointer ida_sptr = ida_struct.get_struc(self.tid) if ida_sptr.id != self.sptr.id: self.log.warn( "validate_ida_type: sptr.id mismatch. Got %s but expected %s", str(ida_sptr.id), str(self.sptr.id)) return False # Size ida_size = ida_struct.get_struc_size(ida_sptr) if ida_size != self.size: self.log.warn( "validate_ida_type: size mismatch. Got %s but expected %s", str(ida_size), str(self.size)) return False # members count = 0 ida_memb = self.sptr.members # first member while True: found = False ida_name = ida_struct.get_member_name(ida_memb.id) for memb in self.members_array: if memb.name != ida_name: continue found = True memb._set_mptr(ida_memb) if not memb._validate_ida_type(): self.log.warn( "validate_ida_type: field '%s' failed validation", memb.name) return False if not found: self.log.warn( "validate_ida_type: found unexpected member '%s'", str(ida_name)) return False count += 1 next_idx = ida_struct.get_next_member_idx( self.sptr, ida_memb.soff) # next member index if next_idx == -1: break ida_memb = self.sptr.get_member(next_idx) # next member # member count if count != len(self.members_array): self.log.warn( "validate_ida_type: incorrect number of members. Got %d, expected %d", count, len(self.members_array)) return False self.log.debug("validate_ida_type: found match for '%s'", self.hierarchy) return True
def get_name(self): return idc.get_func_name(self.ea)+"_"+ida_struct.get_member_name(self.mem.id)
def update_form(update): """ Processes an incoming update by adding it to the form. Args: update (IdbUpdate) - The message received from the ZMQ server, as a class that inherits IdbUpdate """ try: g_item_list_mutex.lock() message_type = update.update_type address = update.address current_data = None if message_type == idb_push_ops.UpdateTypes.Name: current_data = psida_common.get_non_default_name(address, update.is_local) if current_data == update.data: return elif message_type == idb_push_ops.UpdateTypes.Comment: current_data = psida_common.get_comment(address) if current_data == update.data: return elif message_type == idb_push_ops.UpdateTypes.RepeatableComment: current_data = psida_common.get_repeated_comment(address) if current_data == update.data: return elif message_type in [idb_push_ops.UpdateTypes.AnteriorLine, idb_push_ops.UpdateTypes.PosteriorLine]: current_data = idc.get_extra_cmt(address, update.line_index) if current_data == update.data: return elif message_type == idb_push_ops.UpdateTypes.LookHere: current_data = psida_common.get_non_default_name(address) elif message_type == idb_push_ops.UpdateTypes.StackVariableRenamed: func_frame = ida_frame.get_frame(address) update.func_frame_pointer = func_frame member = ida_struct.get_member(func_frame, update.offset) current_data = None if member is not None: current_data = ida_struct.get_member_name(member.id) if current_data == update.data: return if current_data is not None: update.new = False else: update.new = True elif message_type in [idb_push_ops.UpdateTypes.MakeData, idb_push_ops.UpdateTypes.MakeCode, idb_push_ops.UpdateTypes.MakeFunc]: current_data = update.get_conflict() if current_data == '': return else: if CONFIGURATION[DEBUG]: print 'DEBUG - UI - Unrecognized/Unimplemented type %d: in message %s' % (message_type, update.to_dict()) return update.data_at_address = current_data add_item(update) except: if CONFIGURATION['debug']: traceback.print_exc() print 'ERROR - UI - General error while updating form' finally: g_item_list_mutex.unlock()
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
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 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))