예제 #1
0
    def __process_function_typeinfo(self, info, func):

        tinfo = ida_typeinf.tinfo_t()
        ida_nalt.get_tinfo(tinfo,func.start_ea)
        
        func_type_data = ida_typeinf.func_type_data_t()
        tinfo.get_func_details(func_type_data)

        #calling convention
        info['calling_convention'] = self.__describe_callingconvention(func_type_data.cc)
        info['memory_model_code']  = self.__describe_memorymodel_code(func_type_data.cc)
        info['memory_model_data']  = self.__describe_memorymodel_data(func_type_data.cc)

        #return type
        info['return_type'] = ida_typeinf.print_tinfo('', 0, 0, ida_typeinf.PRTYPE_1LINE, func_type_data.rettype, '', '')

        #arguments
        arguments = list()
        
        for funcarg in func_type_data:
            arginfo = {
                'name'              : funcarg.name,
                'type'              : ida_typeinf.print_tinfo('', 0, 0, ida_typeinf.PRTYPE_1LINE, funcarg.type, '', ''),
                'argument_location' : self.__describe_argloc(funcarg.argloc.atype())
            }
            
            arguments.append(arginfo)

        info['arguments'] = arguments
예제 #2
0
    def __get_type_data(self, ea):
        tinfo = ida_typeinf.tinfo_t()
        ida_nalt.get_tinfo(tinfo, ea)
        func_type_data = ida_typeinf.func_type_data_t()
        tinfo.get_func_details(func_type_data)

        return func_type_data
예제 #3
0
 def __init__(self, cpu_context, start_ea):
     self._cpu_context = cpu_context
     self.start_ea = start_ea
     # TODO: Possibly move the get_function_data work into this class?
     self._func_type_data = utils.get_function_data(self.start_ea)
     tif = ida_typeinf.tinfo_t()
     ida_nalt.get_tinfo(tif, self.start_ea)
     self._tif = tif
예제 #4
0
def _is_func_type(ea):
    """Determines if data item at address is a function type."""
    try:
        idc.get_type(ea)
    except TypeError:
        return False
    tif = ida_typeinf.tinfo_t()
    ida_nalt.get_tinfo(tif, ea)
    func_type_data = ida_typeinf.func_type_data_t()
    return bool(tif.get_func_details(func_type_data))
예제 #5
0
 def ti_changed(self, ea, type, fnames):
     if not shared.PAUSE_HOOK:
         log("Ti changed: {0} {1} {2}".format(str(ea), str(type),
                                              str(fnames)))
         flags_of_address = idc.GetFlags(ea)
         if isFunc(flags_of_address):
             tinfo = tinfo_t()
             ida_nalt.get_tinfo(ea, tinfo)
             pass_to_manager(ChangeFunctionHeaderEvent(ea, str(tinfo)))
         else:
             pass_to_manager(ChangeTypeEvent(ea, type))
             if flags_of_address & ida_bytes.FF_STRUCT:
                 log(str(dir(type)))
     return ida_idp.IDB_Hooks.ti_changed(self, ea, type, fnames)
예제 #6
0
파일: utils.py 프로젝트: ddash-ct/kordesii
def _is_func_type(ea):
    """Determines if data item at address is a function type."""
    try:
        idc.get_type(ea)
    except TypeError:
        return False
    tif = ida_typeinf.tinfo_t()
    ida_nalt.get_tinfo(tif, ea)
    func_type_data = ida_typeinf.func_type_data_t()
    # In IDA 7.6, imported functions are now function pointers.
    # To handle this, check if we need to pull out a pointed object first
    if tif.is_funcptr():
        tif = tif.get_pointed_object()
    return bool(tif.get_func_details(func_type_data))
예제 #7
0
def get_type(addr):
    tif = idaapi.tinfo_t()
    ida_nalt.get_tinfo(tif, addr)
    funcdata = idaapi.func_type_data_t()
    tif.get_func_details(funcdata)
    func_type = idaapi.print_tinfo("", 0, 0, PRTYPE_1LINE, tif, "", "")
    ret_type = idaapi.print_tinfo("", 0, 0, PRTYPE_1LINE, funcdata.rettype, "",
                                  "")
    args = []
    for i in range(funcdata.size()):
        arg_type = idaapi.print_tinfo("", 0, 0, PRTYPE_1LINE, funcdata[i].type,
                                      "", "")
        args.append(
            [i, funcdata[i].name, arg_type, funcdata[i].argloc.atype()])
    return [func_type, ret_type, args]
예제 #8
0
    def get_variable(self, address):
        """Given an address, return a `Variable` instance, or
    raise an `InvalidVariableException` exception."""
        if address in self._variables:
            return self._variables[address]

        arch = self._arch

        seg_ref = [None]
        if not _find_segment_containing_ea(address, seg_ref):
            raise InvalidVariableException(
                "No variable defined at or containing address {:x}".format(
                    address))

        seg = seg_ref[0]

        tif = ida_typeinf.tinfo_t()
        if not ida_nalt.get_tinfo(tif, address):
            ida_typeinf.guess_tinfo(tif, address)

        # Try to handle a variable type, otherwise make it big and empty.
        try:
            var_type = get_type(tif)
        except UnhandledTypeException as e:
            # TODO(pag): Make it a big empty array type? (especially if it's in .bss)
            raise InvalidVariableException(
                "Could not assign type to function at address {:x}: {}".format(
                    address, str(e)))

        var = IDAVariable(arch, address, var_type, seg)
        self._variables[address] = var
        return var
예제 #9
0
def _get_tif_with_guess_type(address: int) -> Optional[ida_typeinf.tinfo_t]:
    """
    Attempt to get the tinfo_t object for the function using the "guess_type" function.

    :raises: RuntimeError on failure.
    :returns: tinfo_t object on success.
    """
    guessed_type = idc.guess_type(address)
    if guessed_type is None:
        return None

    func_name = idc.get_func_name(address)
    if func_name is None:
        return None

    # Documentation states the type must be ';' terminated, also the function name must be inserted
    guessed_type = re.sub(r"\(", f" {func_name}(", f"{guessed_type};")
    set_type_result = idc.SetType(address, guessed_type)
    if not set_type_result:
        logger.warning(
            f"Failed to SetType for function at 0x{address:X} with guessed type {guessed_type!r}"
        )

    tif = ida_typeinf.tinfo_t()
    if not ida_nalt.get_tinfo(tif, address):
        return None
    return tif
예제 #10
0
def _get_type(ty, context):
    """Type class that gives access to type sizes, printings, etc."""

    if isinstance(ty, Type):
        return ty

    elif isinstance(ty, Function):
        return ty.type()

    elif isinstance(ty, Location):
        return ty.type()

    elif isinstance(ty, ida_typeinf.tinfo_t):
        return _convert_ida_type(ty, {}, 0, context)

    tif = ida_typeinf.tinfo_t()
    try:
        if not ida_nalt.get_tinfo(tif, ty):
            ida_typeinf.guess_tinfo(tif, ty)
    except:
        pass

    if not tif.empty():
        return _convert_ida_type(tif, {}, 0, context)

    if not ty:
        return VoidType()

    raise UnhandledTypeException("Unrecognized type passed to `Type`.", ty)
예제 #11
0
파일: utils.py 프로젝트: ddash-ct/kordesii
def _get_function_tif_with_guess_type(offset):
    """
    Attempt to get the tinfo_t object of a function using the "guess_type" function.

    :param offset: Offset of function.
    :raises: RuntimeError on failure.
    :returns: tinfo_t object on success.
    """
    tif = ida_typeinf.tinfo_t()

    guessed_type = idc.guess_type(offset)
    if guessed_type is None:
        raise RuntimeError(
            "Failed to guess function type for offset 0x{:X}".format(offset))

    func_name = idc.get_func_name(offset)
    if func_name is None:
        raise RuntimeError(
            "Failed to get function name for offset 0x{:X}".format(offset))

    # Documentation states the type must be ';' terminated, also the function name must be inserted
    guessed_type = re.sub(r"\(", " {}(".format(func_name),
                          "{};".format(guessed_type))
    set_type_result = idc.SetType(offset, guessed_type)
    if not set_type_result:
        logger.warning(
            "Failed to SetType for function at 0x{:X} with guessed type {!r}".
            format(offset, guessed_type))
    # Try one more time to get the tinfo_t object
    if not ida_nalt.get_tinfo(tif, offset):
        raise RuntimeError(
            "Failed to obtain tinfo_t object for offset 0x{:X}".format(offset))

    return tif
예제 #12
0
    def __init__(self, cpu_context, start_ea, operand: Operand = None):
        """
        :param cpu_context: ProcessorContext to use for pulling argument values.
        :param start_ea: Starting address of function to create function signature from.
        :param operand: Optional Operand object containing the address of the function in it's value.
            This is used for dynamically resolved functions. (e.g. call eax)

        :raises RuntimeError: If a function type could not be created from given ea.
        """
        self._cpu_context = cpu_context
        self.start_ea = start_ea
        # TODO: Possibly move the get_function_data work into this class?
        self._func_type_data = utils.get_function_data(self.start_ea,
                                                       operand=operand)
        if operand:
            tif = operand._tif
        else:
            tif = ida_typeinf.tinfo_t()
            ida_nalt.get_tinfo(tif, self.start_ea)
        self._tif = tif
예제 #13
0
파일: biptype.py 프로젝트: xcode2010/bip
    def is_set_at(ea):
        """
            This function allow to test if a type is defined at a particular
            address. This function will return False if a type is not set but
            ida may be able to guess it. This means that this function may
            return False while :func:`BipType.get_at` return a type, if this
            function return True :func:`BipType.get_at` should always return
            a type.

            :param ea: The address at which to make the test.
            :return: True if a type is defined at the address given in
                argument, False otherwise.
        """
        tif = tinfo_t()
        return ida_nalt.get_tinfo(tif, ea)
예제 #14
0
    def data(self):
        # get function type info
        ti = ida_typeinf.tinfo_t()
        ida_nalt.get_tinfo(ti, self.offset)

        # skip it if it's empty
        if ti.empty():
            return None

        # if type equals guessed type, no need to save annotation
        if str(ti) == ida_typeinf.idc_guess_type(self.offset):
            return None

        # if this is a type info comes from a type library, we don't need to
        # serialize it
        # if ti.is_from_subtil():
        #     return None

        d = {}
        d['type_info_serialize'] = ti.serialize()
        d['type_info'] = str(ti)
        d['type_info_decltype'] = ti.get_decltype()
        d['type_info_realtype'] = ti.get_realtype()
        d['type_info_til_desc'] = ti.get_til().desc
        d['type_info_subtil'] = ti.is_from_subtil()
        d['type_info_nargs'] = ti.get_nargs()
        args = [ti.get_nth_arg(i) for i in range(-1, ti.get_nargs())]
        d['type_info_args'] = [str(arg) for arg in args]

        for arg in args:
            if not arg.is_struct():
                continue

            self.depend_on(StructureAnnotation, str(arg))

        return d
예제 #15
0
파일: biptype.py 프로젝트: xcode2010/bip
    def get_at(ea=None):
        """
            Function which will create an object which inherit from
            :class:`BipType` representing the type at the current address.
            This function will **not** set the type at the address given and
            it may not be set if it was guess by ida.

            Internally this function will first try to get the type at the
            address, if no type are defined it will try to guess it. If ida
            is not able to guess it it will return ``None``.

            .. todo:: make something better when no type are set ?

            .. note:: **Implementation**

                Ida allow to guess the type but this "guess" ignore the fact
                that this may have been set. It seems necessary to use
                ida_nalt.get_tinfo for recuperating the type set, it will fail
                if no type has been set. If no type were set the guess_tinfo
                is then used, it will typically fail if the data is undefined,
                in this case None will be return. This may change in the
                future as by default a tinfo_t ``empty`` is true (but not the
                tinfo_t.is_unknown).

            :param ea: The address at which to get the type. If ``None``
                the screen address will be used.
            :return: An object which inherit from :class:`BipType`
                representing the type at the address given in argument.
                ``None`` will be return if no type is define and ida was not
                able to guess it .
        """
        if ea is None:
            ea = ida_kernwin.get_screen_ea()
        tif = tinfo_t()
        # try to get the define type
        # this seems to be define in ida_nalt...
        if ida_nalt.get_tinfo(tif, ea):
            # no need to make a copy in this case
            return BipType.from_tinfo_no_copy(tif)

        # no type define, try to guess it
        # don't know when GUESS_FUNC_TRIVIAL is return so consider failure
        if guess_tinfo(tif, ea) == GUESS_FUNC_OK:
            return BipType.from_tinfo_no_copy(tif)

        # not able to guess, this should be a tinfo_t empty ? (tif.empty() ?)
        return None
예제 #16
0
파일: ida.py 프로젝트: stjordanis/anvill
    def get_variable(self, address):
        """Given an address, return a `Variable` instance, or
    raise an `InvalidVariableException` exception."""
        if address in self._variables:
            return self._variables[address]

        arch = self._arch

        seg_ref = [None]
        address, backup_var_type = _invent_var_type(address, seg_ref)
        if not backup_var_type:
            raise InvalidVariableException(
                "No variable defined at or containing address {:x}".format(
                    address))

        assert not isinstance(backup_var_type, VoidType)

        tif = ida_typeinf.tinfo_t()
        if not ida_nalt.get_tinfo(tif, address):
            if ida_typeinf.GUESS_FUNC_FAILED == ida_typeinf.guess_tinfo(
                    tif, address):
                tif = backup_var_type

        # Try to handle a variable type, otherwise make it big and empty.
        try:
            var_type = get_type(tif, TYPE_CONTEXT_GLOBAL_VAR)
            if isinstance(var_type, VoidType):
                var_type = backup_var_type

        except UnhandledTypeException as e:
            print(
                "Could not assign type to variable at address {:x}: {}".format(
                    address, str(e)))
            var_type = backup_var_type

        assert not isinstance(var_type, VoidType)
        assert not isinstance(var_type, FunctionType)

        var = IDAVariable(arch, address, var_type,
                          _find_segment_containing_ea(address, seg_ref))
        self._variables[address] = var
        return var
예제 #17
0
    def get_function_impl(self, address):
        """Given an address, return a `Function` instance or
        raise an `InvalidFunctionException` exception."""
        arch = self._arch
        os = self._os

        pfn = ida_funcs.get_func(address)
        if not pfn:
            pfn = ida_funcs.get_prev_func(address)

        seg_ref = [None]
        seg = find_segment_containing_ea(address, seg_ref)

        # Check this function.
        if not pfn or not seg:
            raise InvalidFunctionException(
                "No function defined at or containing address {:x}".format(address)
            )

        elif (
            not ida_funcs.func_contains(pfn, address)
            and not _is_extern_seg(seg)
            and not is_imported_table_seg(seg)
        ):
            raise InvalidFunctionException(
                "No function defined at or containing address {:x}".format(address)
            )

        # Reset to the start of the function, and get the type of the function.
        address = pfn.start_ea

        tif = ida_typeinf.tinfo_t()
        if not ida_nalt.get_tinfo(tif, address):
            if ida_typeinf.GUESS_FUNC_OK != ida_typeinf.guess_tinfo(tif, address):
                raise InvalidFunctionException(
                    "Can't guess type information for function at address {:x}".format(
                        address
                    )
                )

        if not tif.is_func():
            raise InvalidFunctionException(
                "Type information at address {:x} is not a function: {}".format(
                    address, tif.dstr()
                )
            )

        ftd = ida_typeinf.func_type_data_t()
        if not tif.get_func_details(ftd):
            raise InvalidFunctionException(
                "Could not get function details for function at address {:x}".format(
                    address
                )
            )

        # Make sure we can handle the basic signature of the function. This might
        # not be the final signature that we go with, but it's a good way to make
        # sure we can handle the relevant types.
        try:
            func_type = _get_type(tif, TYPE_CONTEXT_FUNCTION)
        except UnhandledTypeException as e:
            raise InvalidFunctionException(
                "Could not assign type to function at address {:x}: {}".format(
                    address, str(e)
                )
            )

        # Get the calling convention. The CC might override `is_variadic`, e.g. how
        # old style C functions declared as `foo()` actually imply `foo(...)`.
        cc, is_variadic = _get_calling_convention(arch, os, ftd)
        if is_variadic:
            func_type.set_is_variadic()

        # Go look into each of the parameters and their types. Each parameter may
        # refer to multiple locations, so we want to split each of those locations
        # into unique
        i = 0
        max_i = ftd.size()
        param_list = []
        while i < max_i:
            funcarg = ftd[i]
            i += 1

            arg_type = _get_type(funcarg.type, TYPE_CONTEXT_PARAMETER)
            arg_type_str = arg_type.serialize(arch, {})

            j = len(param_list)
            _expand_locations(arch, pfn, arg_type, funcarg.argloc, param_list)

            # If we have a parameter name, then give a name to each of the expanded
            # locations associated with this parameter.
            if funcarg.name:
                if (j + 1) == len(param_list):
                    param_list[-1].set_name(funcarg.name)
                else:
                    k = j
                    while k < len(param_list):
                        param_list[-1].set_name("{}_{}".format(funcarg.name, k - j))
                        k += 1

        # Build up the list of return values.
        ret_list = []
        ret_type = _get_type(ftd.rettype, TYPE_CONTEXT_RETURN)
        if not isinstance(ret_type, VoidType):
            _expand_locations(arch, pfn, ret_type, ftd.retloc, ret_list)

        func = IDAFunction(
            arch, address, param_list, ret_list, pfn, ftd.is_noret(), func_type, cc
        )
        self.add_symbol(address, _function_name(address))
        return func
예제 #18
0
def get_function_data(offset, operand: Operand = None):
    """
    Obtain a idaapi.func_type_data_t object for the function with the provided start EA.

    :param int offset: start EA of function
    :param operand: operand containing function address in it's value.
        This can be provided when function is dynamically generated at runtime. (e.g. call eax)

    :return: idaapi.func_type_data_t object

    :raise RuntimeError: if func_type_data_t object cannot be obtained
    """
    global _func_types

    tif = ida_typeinf.tinfo_t()

    try:
        func_type = idc.get_type(offset)
    except TypeError:
        raise RuntimeError("Not a valid offset: {!r}".format(offset))

    # First see if it's a type we already set before.
    if func_type and offset in _func_types:
        ida_nalt.get_tinfo(tif, offset)

    else:
        # Otherwise, try to use the Hexrays decompiler to determine function signature.
        # (It's better than IDA's guess_type)

        try:
            # This requires Hexrays decompiler, load it and make sure it's available before continuing.
            if not idaapi.init_hexrays_plugin():
                idc.load_and_run_plugin("hexrays", 0) or idc.load_and_run_plugin("hexx64", 0)
            if not idaapi.init_hexrays_plugin():
                raise RuntimeError("Unable to load Hexrays decompiler.")

            # Pull type from decompiled C code.
            try:
                decompiled = idaapi.decompile(offset)
            except idaapi.DecompilationFailure:
                decompiled = None
            if decompiled is None:
                raise RuntimeError("Cannot decompile function at 0x{:X}".format(offset))
            decompiled.get_func_type(tif)

            # Save type for next time.
            fmt = decompiled.print_dcl()
            fmt = "".join(c for c in fmt if c in string.printable and c not in ("\t", "!"))
            # The 2's remove the unknown bytes always found at the start and end.
            set_type_result = idc.SetType(offset, "{};".format(fmt))
            if not set_type_result:
                logger.warning("Failed to SetType for function at 0x{:X} with decompiler type {!r}".format(offset, fmt))

        # If we fail, resort to using guess_type+
        except RuntimeError:
            if func_type:
                # If IDA's disassembler set it already, go with that.
                ida_nalt.get_tinfo(tif, offset)
            else:
                # Otherwise try to pull it from guess_type()
                guessed_type = idc.guess_type(offset)
                if guessed_type is None:
                    raise RuntimeError("failed to guess function type for offset 0x{:X}".format(offset))

                func_name = idc.get_func_name(offset)
                if func_name is None:
                    raise RuntimeError("failed to get function name for offset 0x{:X}".format(offset))

                # Documentation states the type must be ';' terminated, also the function name must be inserted
                guessed_type = re.sub(r"\(", " {}(".format(func_name), "{};".format(guessed_type))
                set_type_result = idc.SetType(offset, guessed_type)
                if not set_type_result:
                    logger.warning(
                        "Failed to SetType for function at 0x{:X} with guessed type {!r}".format(offset, guessed_type)
                    )
                # Try one more time to get the tinfo_t object
                if not ida_nalt.get_tinfo(tif, offset):
                    raise RuntimeError("failed to obtain tinfo_t object for offset 0x{:X}".format(offset))

    funcdata = ida_typeinf.func_type_data_t()
    success = tif.get_func_details(funcdata)
    if success:
        # record that we have processed this function before. (and that we can grab it from the offset)
        _func_types.add(offset)
        return funcdata

    # If we have still failed, we have one more trick under our sleeve.
    # Try to pull the type information from the operand of the call instruction.
    # This could be set if the function has been dynamically created.
    if operand:
        tif = operand._tif
        success = tif.get_func_details(funcdata)
        if success:
            return funcdata

    raise RuntimeError("failed to obtain func_type_data_t object for offset 0x{:X}".format(offset))
예제 #19
0
def get_function_data(offset):
    """
    Obtain a idaapi.func_type_data_t object for the function with the provided start EA.

    :param int offset: start EA of function

    :return: idaapi.func_type_data_t object

    :raise RuntimeError: if func_type_data_t object cannot be obtained
    """
    global _func_types

    tif = ida_typeinf.tinfo_t()

    try:
        func_type = idc.get_type(offset)
    except TypeError:
        raise RuntimeError('Not a valid offset: {!r}'.format(offset))

    # First see if it's a type we already set before.
    if func_type and offset in _func_types:
        ida_nalt.get_tinfo(tif, offset)

    else:
        # Otherwise, try to use the Hexrays decompiler to determine function signature.
        # (It's better than IDA's guess_type)
        try:
            # This requires Hexrays decompiler, load it and make sure it's available before continuing.
            if not idaapi.init_hexrays_plugin():
                idc.load_and_run_plugin(
                    "hexrays", 0) or idc.load_and_run_plugin("hexx64", 0)
            if not idaapi.init_hexrays_plugin():
                raise RuntimeError('Unable to load Hexrays decompiler.')

            # Pull type from decompiled C code.
            try:
                decompiled = idaapi.decompile(offset)
            except idaapi.DecompilationFailure:
                decompiled = None
            if decompiled is None:
                raise RuntimeError(
                    "Cannot decompile function at 0x{:X}".format(offset))
            decompiled.get_func_type(tif)

            # Save type for next time.
            format = decompiled.print_dcl()
            # The 2's remove the unknown bytes always found at the start and end.
            idc.SetType(offset, "{};".format(format[2:-2]))

        # If we fail, resort to using guess_type+
        except RuntimeError:
            if func_type:
                # If IDA's disassembler set it already, go with that.
                ida_nalt.get_tinfo(tif, offset)
            else:
                # Otherwise try to pull it from guess_type()
                guessed_type = idc.guess_type(offset)
                if guessed_type is None:
                    raise RuntimeError(
                        "failed to guess function type for offset 0x{:X}".
                        format(offset))

                func_name = idc.get_func_name(offset)
                if func_name is None:
                    raise RuntimeError(
                        "failed to get function name for offset 0x{:X}".format(
                            offset))

                # Documentation states the type must be ';' terminated, also the function name must be inserted
                guessed_type = re.sub("\(", " {}(".format(func_name),
                                      "{};".format(guessed_type))
                idc.SetType(offset, guessed_type)
                # Try one more time to get the tinfo_t object
                if not ida_nalt.get_tinfo(tif, offset):
                    raise RuntimeError(
                        "failed to obtain tinfo_t object for offset 0x{:X}".
                        format(offset))

    funcdata = ida_typeinf.func_type_data_t()
    if not tif.get_func_details(funcdata):
        raise RuntimeError(
            "failed to obtain func_type_data_t object for offset 0x{:X}".
            format(offset))

    # record that we have processed this function before.
    _func_types.add(offset)

    return funcdata
print "Starting analysis"
current_index = 0
for ea in idautils.Functions():
    flags = idc.GetFunctionFlags(ea)
    func_name = idc.get_func_name(ea)
    if (current_index % 1000 == 0):
        print "Processing function %d" % current_index
    if flags & FUNC_THUNK and not func_name.startswith(
            "sub_") and not func_name.startswith(
                "j__ZdlPv") and not "null" in func_name:
        # Revert weird designations
        # could also use ida_funcs.set_func_name_if_jumpfunc(ea, None)
        func_name = func_name.replace("j_", "")
        funcdata = ida_typeinf.func_type_data_t()
        tinfo = ida_typeinf.tinfo_t()
        ida_nalt.get_tinfo(tinfo, ea)
        tinfo.get_func_details(funcdata)
        if (flags & FUNC_NORET):
            retcode = ''
        else:
            retcode = 'N'
        mcsema_def = ("%s %d C %s" %
                      (func_name, funcdata.size(), retcode)).strip()
        sdk_funcs_file.write(mcsema_def + '\n')

        if func_name.endswith("_1"):
            func_name = func_name.replace("_1", "")
        if func_name.endswith("_0"):
            func_name = func_name.replace("_0", "")

        demangled_str = subprocess.check_output([cppfilt_path, func_name],
예제 #21
0
def get_func_type_info(address: int, operand: Tuple[int, int] = None) -> Tuple[ida_typeinf.func_type_data_t, ida_typeinf.tinfo_t]:
    """
    Obtain a idaapi.func_type_data_t object for the function with the provided start address.

    :param address: start address of the function
    :param operand: Optional address and index pair for an operand containing the function address in its value.
        This can be provided when function is dynamically generated at runtime. (e.g. call eax)

    :return: ida_typeinf.func_type_data_t object, ida_typeinf.tinfo_t object

    :raise RuntimeError: if func_type_data_t object cannot be obtained
    """
    func_type = idc.get_type(address)

    # First see if it's a type we already set before.
    if func_type and address in _seen_func_types:
        tif = ida_typeinf.tinfo_t()
        ida_nalt.get_tinfo(tif, address)

    # Otherwise, try to use the Hexrays decompiler to determine function signature.
    # (It's better than IDA's guess_type)
    else:
        # First try to get type information from the decompiled code produced
        # by the Hex Rays plugin.
        tif = _get_tif_with_hex_rays(address)

        if not tif:
            # Otherwise, if IDA's disassembler set it already, go with that.
            if func_type:
                tif = ida_typeinf.tinfo_t()
                ida_nalt.get_tinfo(tif, address)

            # Finally, see if we can obtain it with guess_type()
            else:
                tif = _get_tif_with_guess_type(address)

    if tif:
        func_type_data = ida_typeinf.func_type_data_t()

        # In IDA 7.6, imported functions are now function pointers.
        # To handle this, check if we need to pull out a pointed object first
        if tif.is_funcptr():
            tif = tif.get_pointed_object()

        success = tif.get_func_details(func_type_data)
        if success:
            # record that we have processed this function before. (and that we can grab it from the offset)
            _seen_func_types.add(address)
            return func_type_data, tif

    # If we have still failed, we have one more trick under our sleeve.
    # Try to pull the type information from the operand of the call instruction.
    # This could be set if the function has been dynamically created.
    if operand:
        tif = ida_typeinf.tinfo_t()
        ida_nalt.get_op_tinfo(tif, operand.address, operand.index)
        func_type_data = ida_typeinf.func_type_data_t()
        success = tif.get_func_details(func_type_data)
        if success:
            return func_type_data, tif

    raise RuntimeError(f"Failed to obtain func_type_data_t object for offset 0x{address:X}")
예제 #22
0
파일: utils.py 프로젝트: ddash-ct/kordesii
def get_function_data(offset, operand: Operand = None):
    """
    Obtain a idaapi.func_type_data_t object for the function with the provided start EA.

    :param int offset: start EA of function
    :param operand: operand containing function address in it's value.
        This can be provided when function is dynamically generated at runtime. (e.g. call eax)

    :return: ida_typeinf.func_type_data_t object, ida_typeinf.tinfo_t object

    :raise RuntimeError: if func_type_data_t object cannot be obtained
    """
    global _func_types

    tif = None

    try:
        func_type = idc.get_type(offset)
    except TypeError:
        raise RuntimeError("Not a valid offset: {!r}".format(offset))

    # First see if it's a type we already set before.
    if func_type and offset in _func_types:
        tif = ida_typeinf.tinfo_t()
        ida_nalt.get_tinfo(tif, offset)

    else:
        # Otherwise, try to use the Hexrays decompiler to determine function signature.
        # (It's better than IDA's guess_type)
        try:
            tif = _get_function_tif_with_hex_rays(offset)

        # If we fail, resort to using guess_type+
        except RuntimeError:
            if func_type:
                # If IDA's disassembler set it already, go with that.
                tif = ida_typeinf.tinfo_t()
                ida_nalt.get_tinfo(tif, offset)
            else:
                try:
                    tif = _get_function_tif_with_guess_type(offset)
                except RuntimeError:
                    # Don't allow to fail if we could pull from operand.
                    pass

    if tif:
        funcdata = ida_typeinf.func_type_data_t()

        # In IDA 7.6, imported functions are now function pointers.
        # To handle this, check if we need to pull out a pointed object first
        if tif.is_funcptr():
            tif = tif.get_pointed_object()

        success = tif.get_func_details(funcdata)
        if success:
            # record that we have processed this function before. (and that we can grab it from the offset)
            _func_types.add(offset)
            return funcdata, tif

    # If we have still failed, we have one more trick under our sleeve.
    # Try to pull the type information from the operand of the call instruction.
    # This could be set if the function has been dynamically created.
    if operand:
        tif = operand._tif
        funcdata = ida_typeinf.func_type_data_t()
        success = tif.get_func_details(funcdata)
        if success:
            return funcdata, tif

    raise RuntimeError(
        "failed to obtain func_type_data_t object for offset 0x{:X}".format(
            offset))
예제 #23
0
    def get_function(self, address):
        """Given an address, return a `Function` instance or
    raise an `InvalidFunctionException` exception."""
        arch = self._arch

        pfn = ida_funcs.get_func(address)
        if not pfn:
            pfn = ida_funcs.get_prev_func(address)

        # Check this function.
        if not pfn or not ida_funcs.func_contains(pfn, address):
            raise InvalidFunctionException(
                "No function defined at or containing address {:x}".format(
                    address))

        # Reset to the start of the function, and get the type of the function.
        address = pfn.start_ea
        if address in self._functions:
            return self._functions[address]

        tif = ida_typeinf.tinfo_t()
        if not ida_nalt.get_tinfo(tif, address):
            ida_typeinf.guess_tinfo(tif, address)

        if not tif.is_func():
            raise InvalidFunctionException(
                "Type information at address {:x} is not a function: {}".
                format(address, tif.dstr()))

        ftd = ida_typeinf.func_type_data_t()
        if not tif.get_func_details(ftd):
            raise InvalidFunctionException(
                "Could not get function details for function at address {:x}".
                format(address))

        # Make sure we can handle the basic signature of the function. This might
        # not be the final signature that we go with, but it's a good way to make
        # sure we can handle the relevant types.
        try:
            func_type = get_type(tif)
        except UnhandledTypeException as e:
            raise InvalidFunctionException(
                "Could not assign type to function at address {:x}: {}".format(
                    address, str(e)))

        # Go look into each of the parameters and their types. Each parameter may
        # refer to multiple locations, so we want to split each of those locations
        # into unique
        i = 0
        max_i = ftd.size()
        param_list = []
        while i < max_i:
            funcarg = ftd[i]
            i += 1

            arg_type = get_type(funcarg.type)
            arg_type_str = arg_type.serialize(arch, {})

            j = len(param_list)
            _expand_locations(arch, pfn, arg_type, funcarg.argloc, param_list)

            # If we have a parameter name, then give a name to each of the expanded
            # locations associated with this parameter.
            if funcarg.name:
                if (j + 1) == len(param_list):
                    param_list[-1].set_name(funcarg.name)
                else:
                    k = j
                    while k < len(param_list):
                        param_list[-1].set_name("{}_{}".format(
                            funcarg.name, k - j))
                        k += 1

        # Build up the list of return values.
        ret_list = []
        ret_type = get_type(ftd.rettype)
        if not isinstance(ret_type, VoidType):
            _expand_locations(arch, pfn, ret_type, ftd.retloc, ret_list)

        func = IDAFunction(arch, address, param_list, ret_list, pfn)
        self._functions[address] = func
        return func