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)
def __process_function_typeinfo(self, info, func): tinfo = ida_typeinf.tinfo_t() func_type_data = ida_typeinf.func_type_data_t() if ida_pro.IDA_SDK_VERSION >= 740: ida_typeinf.guess_tinfo(tinfo,func.start_ea) else: ida_typeinf.guess_tinfo(func.start_ea,tinfo) tinfo.get_func_details(func_type_data) #calling convention info['calling_convention'] = self.__describe_callingconvention(func_type_data.cc) func_type_data.rettype #return tpye 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
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
def processFunctionTypeinfo(function): tinfo = ida_typeinf.tinfo_t() func_type_data = ida_typeinf.func_type_data_t() tinfo.get_named_type ida_typeinf.guess_tinfo(function['start_ea'], tinfo) tinfo.get_func_details(func_type_data) #calling convention function['calling_convention'] = describe_callingconvention( func_type_data.cc) func_type_data.rettype #return tpye function['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': describe_argloc(funcarg.argloc.atype()) } arguments.append(arginfo) function['arguments'] = arguments
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
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
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
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
def guess_tinfo(ea): """@return: tuple(type, fields) just like idc.get_tinfo()""" tif = ida_typeinf.tinfo_t() if ida_typeinf.guess_tinfo(tif, ea): return tif.serialize()[:-1] return None