Example #1
0
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
Example #2
0
    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
Example #3
0
    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
Example #4
0
    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
Example #5
0
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
Example #6
0
 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
Example #7
0
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))
Example #8
0
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_,
        }))
Example #9
0
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),
        )
Example #10
0
    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
Example #11
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
Example #12
0
 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
Example #13
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
Example #14
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)
Example #15
0
 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
Example #17
0
 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)
Example #18
0
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
Example #19
0
    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
Example #20
0
 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
Example #21
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
Example #22
0
 def get_name(self):
     return idc.get_func_name(self.ea)+"_"+ida_struct.get_member_name(self.mem.id)
Example #23
0
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()
Example #24
0
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
Example #25
0
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,
        )
Example #26
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))