def remove_rettype(self, vu): if vu.item.citype == idaapi.VDI_FUNC: # current function ea = vu.cfunc.entry_ea old_func_type = idaapi.tinfo_t() if not vu.cfunc.get_func_type(old_func_type): return False elif vu.item.citype == idaapi.VDI_EXPR and vu.item.e.is_expr() and vu.item.e.type.is_funcptr(): # call xxx ea = vu.item.get_ea() old_func_type = idaapi.tinfo_t() func = idaapi.get_func(ea) if func: try: cfunc = idaapi.decompile(func) except idaapi.DecompilationFailure: return False if not cfunc.get_func_type(old_func_type): return False else: return False else: return False fi = idaapi.func_type_data_t() if ea != idaapi.BADADDR and old_func_type.get_func_details(fi): # Return type is already void if fi.rettype.is_decl_void(): # Restore ret type if ea not in self.ret_type: return True ret = self.ret_type[ea] else: # Save ret type and change it to void self.ret_type[ea] = fi.rettype ret = idaapi.BT_VOID # Create new function info with new rettype fi.rettype = idaapi.tinfo_t(ret) # Create new function type with function info new_func_type = idaapi.tinfo_t() new_func_type.create_func(fi) # Apply new function type if idaapi.apply_tinfo2(ea, new_func_type, idaapi.TINFO_DEFINITE): return vu.refresh_view(True) return False
def getUserDeclType(self, decl): tinfo = idaapi.tinfo_t() ret = idaapi.parse_decl2(idaapi.cvar.idati, decl, 'blah', tinfo, 0) if not ret: self.logger.info('parse_decl2 failed') return None return tinfo
def parse_decl(arg): '''str -> tinfo_t''' ti = idaapi.tinfo_t() success = idaapi.parse_decl2(idaapi.cvar.idati, arg + ';', '', ti, 0) if success is False: raise ParseDeclError("%s: couldn't parse type" % arg) return ti
def get_or_guess_tinfo(ea): '''ea_t -> tinfo_t''' # XXX mutates (blah_tinfo2, unavoidable) ti = idaapi.tinfo_t() idaapi.get_tinfo2(ea, ti) or idaapi.guess_tinfo2(ea, ti) return ti
def getUserDeclType(self, decl): tinfo = idaapi.tinfo_t() #logger.debug('Trying to parse declaration: %r', decl) ret = idaapi.parse_decl2(idaapi.cvar.idati, decl, tinfo, idaapi.PT_TYP) #logger.debug('Return from parse_decl2: %r', ret) if ret is None: logger.info('parse_decl2 failed') return None return tinfo
def getLocalType(self): ret = idaapi.choose_local_tinfo(idaapi.cvar.idati, 'Choose local type to apply', None, None) if not ret: self.logger.debug('User canceled. Bailing out') return #ret is a numbered type rather than the name tinfo = idaapi.tinfo_t() tinfo.get_numbered_type(idaapi.cvar.idati, ret) return tinfo
def get_stkvar_map(ea): '''ea_t -> {int : (str, tinfo_t)}''' # NOTE mutates d frame = idaapi.get_frame(ea) def make_map(d, (off, name, _)): mem = idaapi.get_member(frame, off) ti = idaapi.tinfo_t() idaapi.get_or_guess_member_tinfo2(mem, ti) d[off] = (name, ti) return d
def getBuiltinGlobalTypePython(self): self.logger.debug('Getting GlobalType the Python way') sym = idaapi.til_symbol_t() ret = idaapi.choose_named_type2(idaapi.cvar.idati, 'Choose type to apply', idaapi.NTF_SYMM, None, sym) if not ret: self.logger.debug('User canceled. Bailing out') return tuple = idaapi.get_named_type(sym.til, sym.name, 0) if tuple == None: self.logger.debug('Could not find %s', sym.name) return tinfo = idaapi.tinfo_t() tinfo.deserialize(sym.til, tuple[1], tuple[2]) return tinfo
def update_local_type(self): if self.modified: final_tinfo = idaapi.tinfo_t() udt_data = idaapi.udt_type_data_t() self.tinfo.get_udt_details(udt_data) if len(udt_data) == len(self.virtual_functions): for udt_member, virtual_function in zip( udt_data, self.virtual_functions): udt_member.name = virtual_function.name udt_member.type = virtual_function.tinfo virtual_function.commit() final_tinfo.create_udt(udt_data, idaapi.BTF_STRUCT) final_tinfo.set_numbered_type(idaapi.cvar.idati, self.ordinal, idaapi.NTF_REPLACE, self.name) self.modified = False else: print( "[ERROR] Something have been modified in Local types. Please refresh this view" )
def test_xx(idx, ctx): import ida_typeinf uni = ctx.get_expr('union_type') var = ctx.get_var('v1') tname = var.typ.dstr().split(' ')[0] tinfo = idaapi.tinfo_t() if tname == 'class1': idaapi.parse_decl2(idaapi.cvar.idati, 'vptr1_1 *;', tinfo, idaapi.PT_TYP) uni[0].type = tinfo uni[0].m = 0 elif tname == "class2": idaapi.parse_decl2(idaapi.cvar.idati, 'struc_5 *;', tinfo, idaapi.PT_TYP) uni[0].type = tinfo uni[0].m = 1 else: return False return True
def visit_expr(self, expression): if expression.op == idaapi.cot_add and expression.x.op == idaapi.cot_var and expression.y.op == idaapi.cot_num: # print "ADD TYPE", expression.type.dstr() index = expression.x.v.idx if index in self.negative_lvars: offset = expression.y.numval() if offset >= self.negative_lvars[index].size: self.create_containing_record(expression, index, offset) elif expression.op == idaapi.cot_sub and expression.x.op == idaapi.cot_var and expression.y.op == idaapi.cot_num: # print "SUB TYPE", expression.type.dstr(), expression.x.type.dstr() index = expression.x.v.idx if index in self.negative_lvars: offset = -expression.y.n.value(idaapi.tinfo_t(idaapi.BT_INT)) self.create_containing_record(expression, index, offset) # elif expression.op == idaapi.cot_var: # index = expression.v.idx # if index in self.negative_lvars: # self.create_containing_record(expression, index, 0) return 0
def __init__(self, ea, iatEA=None, library_name=None): """ Ctor """ self.logger = logging.getLogger(__name__) self.ea = ea # Effective Address of the function self.iatEA = iatEA # If imported function, the address in the IAT try: function = sark.Function(ea) except sark.exceptions.SarkNoFunction: raise DIE.Lib.DIE_Exceptions.DieNoFunction( "No Function at 0x%08X" % (ea, )) self.funcName = get_function_name(function.ea) self.func_start = function.startEA self.func_end = function.endEA self.proto_ea = self.getFuncProtoAdr() # Address of function prototype self.typeInfo = idaapi.tinfo_t() # Function type info self.funcInfo = idaapi.func_type_data_t() # Function info self.argNum = 0 # Number of input arguments self.args = [] # Function argument list self.retArg = None # Return argument self.library_name = library_name # If library function, name of containing library self.isLibFunc = False if self.iatEA: self.isLibFunc = True # Is this a library function elif sark.Function(ea).flags & (idaapi.FUNC_LIB | idaapi.FUNC_THUNK): self.isLibFunc = True try: self.getArguments() except Exception as ex: self.logger.error( "Failed to get function arguments for function %s: %s", self.funcName, ex)
def activate(self, ctx): # ctx - action_activation_ctx_t vu = idaapi.get_tform_vdui(ctx.form) function_tinfo = idaapi.tinfo_t() if not vu.cfunc.get_func_type(function_tinfo): return function_details = idaapi.func_type_data_t() function_tinfo.get_func_details(function_details) convention = idaapi.CM_CC_MASK & function_details.cc if convention == idaapi.CM_CC_CDECL: function_details.cc = idaapi.CM_CC_SPECIAL elif convention in (idaapi.CM_CC_STDCALL, idaapi.CM_CC_FASTCALL, idaapi.CM_CC_PASCAL, idaapi.CM_CC_THISCALL): function_details.cc = idaapi.CM_CC_SPECIALP elif convention == idaapi.CM_CC_ELLIPSIS: function_details.cc = idaapi.CM_CC_SPECIALE else: return function_tinfo.create_func(function_details) idaapi.apply_tinfo2(vu.cfunc.entry_ea, function_tinfo, idaapi.TINFO_DEFINITE) vu.refresh_view(True)
def create_padding_udt_member(offset, size): # type: (long, long) -> idaapi.udt_member_t """ Creates internal IDA structure with name gap_XXX and appropriate size and offset """ udt_member = idaapi.udt_member_t() udt_member.name = "gap_{0:X}".format(offset) udt_member.offset = offset udt_member.size = size if size == 1: udt_member.type = const.BYTE_TINFO else: array_data = idaapi.array_type_data_t() array_data.base = 0 array_data.elem_type = const.BYTE_TINFO array_data.nelems = size tmp_tinfo = idaapi.tinfo_t() tmp_tinfo.create_array(array_data) udt_member.type = tmp_tinfo return udt_member
def __init__(self, cdg, name, return_type=idaapi.tinfo_t(idaapi.BT_VOID)): self.emitted = False self.cdg = cdg self.callinfo = ida_hexrays.mcallinfo_t() self.callinfo.callee = idaapi.BADADDR self.callinfo.solid_args = 0x00 self.callinfo.call_spd = 0x00 self.callinfo.stkargs_top = 0x00 self.callinfo.cc = idaapi.CM_CC_FASTCALL self.callinfo.return_type = return_type self.callinfo.flags = idaapi.FCI_SPLOK | idaapi.FCI_FINAL | idaapi.FCI_PROP self.callinfo.role = idaapi.ROLE_UNK glbhigh_off = cdg.mba.get_stack_region( ).off + cdg.mba.get_stack_region().size # what memory is visible to the call : GLBLOW - GLBHIGH self.callinfo.visible_memory.add(ida_hexrays.ivl_t(0x00, 0x100000)) self.callinfo.visible_memory.add( ida_hexrays.ivl_t(glbhigh_off, 0xFFFFFFFFFFFFFFFF - glbhigh_off)) # spoiled locations : GLBLOW - GLBHIGH self.callinfo.spoiled.mem.add(ida_hexrays.ivl_t(0x00, 0x100000)) self.callinfo.spoiled.mem.add( ida_hexrays.ivl_t(glbhigh_off, 0xFFFFFFFFFFFFFFFF - glbhigh_off)) self.callins = MicroInstruction(ida_hexrays.m_call, self.cdg.insn.ea) self.callins.l.make_helper(name) self.callins.d.t = ida_hexrays.mop_f self.callins.d.size = 0x00 self.callins.d.f = self.callinfo if (return_type.is_void()): self.ins = self.callins else: self.callins.d.size = return_type.get_size() self.ins = MicroInstruction(ida_hexrays.m_mov, self.cdg.insn.ea) self.ins.l.t = ida_hexrays.mop_d self.ins.l.d = self.callins self.ins.l.size = self.callins.d.size self.ins.d.t = ida_hexrays.mop_r self.ins.d.r = 0x00 self.ins.d.size = self.callins.d.size
def processStructIDA7(self, regPrefix, struc, sid): members = loadMembers(struc, sid) foundFunctions = 0 for off, name, memb in members: funcname = self.filterName(regPrefix, name) tup = idaapi.get_named_type(None, funcname, idaapi.NTF_SYMM) if tup is None: continue code, type_str, fields_str, cmt, field_cmts, sclass, value = tup foundFunctions += 1 tif = idaapi.tinfo_t() tif.deserialize(None, type_str, fields_str, cmt) if not tif.is_func(): logger.debug('Found named type, but not a function: %s', funcname) continue tif.create_ptr(tif) ret = idaapi.set_member_tinfo(struc, memb, off, tif, 0) if ret != idaapi.SMT_OK: logger.info("Got set_member_tinfo ret code: %d" % ret) else: logger.info('set_member_tinfo: %s', tif.dstr())
def set_first_argument_type(self, name): func_data = idaapi.func_type_data_t() func_tinfo = self.tinfo.get_pointed_object() class_tinfo = idaapi.tinfo_t() if func_tinfo.get_func_details(func_data) and func_tinfo.get_nargs() and \ class_tinfo.get_named_type(idaapi.cvar.idati, name): class_tinfo.create_ptr(class_tinfo) first_arg_tinfo = func_data[0].type if (first_arg_tinfo.is_ptr() and first_arg_tinfo.get_pointed_object().is_udt()) or \ helper.is_legal_type(func_data[0].type): func_data[0].type = class_tinfo func_data[0].name = "this" func_tinfo.create_func(func_data) func_tinfo.create_ptr(func_tinfo) if func_tinfo.dstr() != self.tinfo.dstr(): self.tinfo = func_tinfo self.tinfo_modified = True for parent in self.parents: parent.modified = True else: print("[Warning] function {0} probably have wrong type".format(self.name))
def get_winapi_decl(name): ''' fetch the C function declaration for the given Windows API function. ''' tup = idaapi.get_named_type(None, name, idaapi.NTF_SYMM) if tup is None: raise ValueError("failed to fetch type") code, type_str, fields_str, cmt, field_cmts, sclass, value = tup ti = idaapi.tinfo_t() ti.deserialize(None, type_str, fields_str, cmt) # the rendered declaration from IDA doesn't include the function name, # so insert the function name, naively. # # for example; # # > DWORD (DWORD a, DWORD b) # < DWORD foo(DWORD a, DWORD b); decl = str(ti).replace("(", " " + name + "(") + ";" return decl
def get_padding_member(offset, size): udt_member = idaapi.udt_member_t() if size == 1: udt_member.name = "gap_{0:X}".format(offset) udt_member.type = Const.BYTE_TINFO udt_member.size = Const.BYTE_TINFO.get_size() udt_member.offset = offset return udt_member array_data = idaapi.array_type_data_t() array_data.base = 0 array_data.elem_type = Const.BYTE_TINFO array_data.nelems = size tmp_tinfo = idaapi.tinfo_t() tmp_tinfo.create_array(array_data) udt_member.name = "gap_{0:X}".format(offset) udt_member.type = tmp_tinfo udt_member.size = size udt_member.offset = offset return udt_member
def get_member(self, offset, index, **kwargs): # Handling all sorts of functions call try: call_expr, arg_expr = kwargs['call'], kwargs['arg'] arg_index, arg_type = Helper.get_func_argument_info( call_expr, arg_expr) if arg_type.equals_to(Const.PVOID_TINFO) or arg_type.equals_to( Const.CONST_PVOID_TINFO): if SCAN_ALL_ARGUMENTS or not arg_index: self.scan_function(call_expr.x.obj_ea, offset, arg_index) return self.create_member(offset, index) elif arg_type.equals_to(Const.X_WORD_TINFO) or arg_type.equals_to(Const.PX_WORD_TINFO) or \ arg_type.equals_to(Const.PBYTE_TINFO): nice_tinfo = Helper.get_nice_pointed_object(arg_type) if nice_tinfo: return self.create_member(offset, index, nice_tinfo) if SCAN_ALL_ARGUMENTS or not arg_index: self.scan_function(call_expr.x.obj_ea, offset, arg_index) return self.create_member(offset, index, pvoid_applicable=True) arg_type.remove_ptr_or_array() return self.create_member(offset, index, arg_type) except KeyError: pass # When we have pointer dereference on the left side and expression on the right try: right_expr, cast_type = kwargs['object'], kwargs['default'] if right_expr.op in (idaapi.cot_ref, idaapi.cot_cast): right_expr = right_expr.x if right_expr.op == idaapi.cot_obj: member_type = idaapi.tinfo_t(right_expr.type) member_type.create_ptr(member_type) return self.create_member(offset, index, member_type, right_expr.obj_ea) if right_expr.op in Const.COT_ARITHMETIC: return self.create_member(offset, index, cast_type) return self.create_member(offset, index, right_expr.type) except KeyError: pass
def visit_expr(self, expression): # Checks if expression is reference by pointer or by value if expression.op == idaapi.cot_memptr: struct_type = expression.x.type.get_pointed_object() elif expression.op == idaapi.cot_memref: struct_type = expression.x.type else: return 0 # Getting information about structure, field offset, address and one line corresponding to code ordinal = struct_type.get_ordinal() if ordinal == 0: t = idaapi.tinfo_t() struct_name = struct_type.dstr().split()[ -1] # Get rid of `struct` prefix or something else t.get_named_type(idaapi.cvar.idati, struct_name) ordinal = t.get_ordinal() field_offset = expression.m ea = self.__find_ref_address(expression) usage_type = self.__get_type(expression) if ea == idaapi.BADADDR or not ordinal: logger.warning( "Failed to parse at address {0}, ordinal - {1}, type - {2}". format(Helper.to_hex(ea), ordinal, struct_type.dstr())) one_line = self.__get_line() occurrence_offset = ea - self.__function_address xref_info = (occurrence_offset, one_line, usage_type) # Saving results if ordinal not in self.__result: self.__result[ordinal] = {field_offset: [xref_info]} elif field_offset not in self.__result[ordinal]: self.__result[ordinal][field_offset] = [xref_info] else: self.__result[ordinal][field_offset].append(xref_info) return 0
def parse_declaration(declaration): m = re.search(r"^(\w+[ *]+)(\w+)(\[(\d+)\])?$", declaration) if m is None: logger.error("Member declaration should be like `TYPE_NAME NAME[SIZE]` (Array is optional)") return type_name, field_name, _, arr_size = m.groups() if field_name[0].isdigit(): logger.error("Bad field name") return result = idc.parse_decl(type_name, 0) if result is None: logger.error("Failed to parse member type. It should be like `TYPE_NAME NAME[SIZE]` (Array is optional)") return _, tp, fld = result tinfo = idaapi.tinfo_t() tinfo.deserialize(idaapi.cvar.idati, tp, fld, None) if arr_size: assert tinfo.create_array(tinfo, int(arr_size)) return tinfo, field_name
def __init__(self, ea, iatEA=None, library_name=None): """ Ctor """ self.logger = logging.getLogger(__name__) self.ea = ea # Effective Address of the function self.iatEA = iatEA # If imported function, the address in the IAT try: function = sark.Function(ea) except sark.exceptions.SarkNoFunction: raise DIE.Lib.DIE_Exceptions.DieNoFunction("No Function at 0x%08X" % (ea, )) self.funcName = get_function_name(function.ea) self.func_start = function.startEA self.func_end = function.endEA self.proto_ea = self.getFuncProtoAdr() # Address of function prototype self.typeInfo = idaapi.tinfo_t() # Function type info self.funcInfo = idaapi.func_type_data_t() # Function info self.argNum = 0 # Number of input arguments self.args = [] # Function argument list self.retArg = None # Return argument self.library_name = library_name # If library function, name of containing library self.isLibFunc = False if self.iatEA: self.isLibFunc = True # Is this a library function elif sark.Function(ea).flags & (idaapi.FUNC_LIB | idaapi.FUNC_THUNK): self.isLibFunc = True try: self.getArguments() except Exception as ex: self.logger.error("Failed to get function arguments for function %s: %s", self.funcName, ex)
def imp_cb(self, ea, name, ord_nb): """ get import type and add used types in local types to ensure "correct" export """ # Get type imp_t = idaapi.tinfo_t() if idaapi.get_tinfo(imp_t, ea): if not imp_t.is_func(): self.imports.append(idaapi.print_type(ea, PRTYPE_1LINE) + ";") else: # Iterate over ret type and args for i in range(-1, imp_t.get_nargs()): arg_t = imp_t.get_nth_arg(i) if arg_t.is_ptr_or_array(): no_ptr = arg_t no_ptr.remove_ptr_or_array() self.import_name(str(no_ptr)) self.import_name(str(arg_t)) self.imports.append(idaapi.print_type(ea, PRTYPE_1LINE) + " {}") return True
def index_types_for_this_idb(self, purge_locally_deleted=False): """Indexes local types from this IDB into the DB.""" cursor = self.db.cursor() # Create or update types. local_types = set() for cur_named_type in LocalTypesIter(): local_types.add(cur_named_type) code, type_str, fields_str, cmt, field_cmts, sclass, value = idaapi.get_named_type64( idaapi.cvar.idati, cur_named_type, idaapi.NTF_TYPE | idaapi.NTF_SYMM, ) ti = idaapi.tinfo_t() ti.deserialize(idaapi.cvar.idati, type_str, fields_str) c_type = ti._print( cur_named_type, idaapi.PRTYPE_1LINE | idaapi.PRTYPE_TYPE | idaapi.PRTYPE_SEMI, 0, 0, None, cmt, ) # TODO: prefer more concrete type rather than stupidly replacing. cursor.execute( "INSERT OR REPLACE INTO types (name, is_fwd_decl, c_type) VALUES (?, ?, ?)", [cur_named_type, ti.is_forward_decl(), c_type], ) # If requested, remove locally deleted types from index. if purge_locally_deleted: cursor.execute("SELECT id, name FROM types") deleted_types = [x['id'] for x in cursor.fetchall() if x['name'] not in local_types] if deleted_types: print("[continuum] Deleting {} types".format(len(deleted_types))) query_fmt = "DELETE FROM types WHERE id IN ({})" cursor.execute(query_fmt.format(','.join('?' * len(deleted_types))), deleted_types) self.db.commit()
def make_helper_call(ret_type, name, arg_types): # type: (str, str, typing.List[str]) -> hr.cexpr_t """Make a call expression to a helper function (non-existing function with arbitrary name).""" helper_expr = hr.cexpr_t() helper_expr.ea = idaapi.BADADDR helper_expr.op = hr.cot_helper helper_expr.helper = name call_expr = hr.cexpr_t() call_expr.op = hr.cot_call call_expr.x = helper_expr call_expr.a = hr.carglist_t() # EXTREMELY IMPORTANT: set the expression types. Without this, Hex-Rays will crash # in mysterious ways. t = idaapi.tinfo_t() idaapi.parse_decl2(idaapi.cvar.idati, "%s (__cdecl *)(%s);" % (ret_type, ','.join(arg_types)), t, idaapi.PT_TYP) helper_expr.type = t call_expr.a.functype = t call_expr.type = t.get_rettype() return call_expr
def setData(self, column, value): if column == 0: if idaapi.is_ident(value) and self.name != value: self.name = value self.name_modified = True for parent in self.parents: parent.modified = True return True elif column == 1: tinfo = idaapi.tinfo_t() split = value.split('(') if len(split) == 2: value = split[0] + ' ' + self.name + '(' + split[1] + ';' if idaapi.parse_decl(tinfo, idaapi.cvar.idati, value, idaapi.PT_TYP) is not None: if tinfo.is_func(): tinfo.create_ptr(tinfo) if tinfo.dstr() != self.tinfo.dstr(): self.tinfo = tinfo self.tinfo_modified = True for parent in self.parents: parent.modified = True return True return False
def export(self): if self.existed() and not self.f_update: info('{}: The sample records are present in DB. skipped.'.format( self.sha256)) return False self.cur.execute("REPLACE INTO sample values(?, ?)", (self.sha256, self.idb_path)) pnum = tnum = 0 records = [] for fva in idautils.Functions(): fname = get_func_name(fva) tnum += 1 if self.exclude_libthunk(fva, fname): continue fhd, bsize = self.calc_fn_ssdeep(fva, fname) fhm, cfgnum = self.calc_fn_machoc(fva, fname) if fhd and fhm: pnum += 1 f_ana = bool( self.ana_pat.search(fname)) if self.f_ana_exp else False tinfo = idaapi.tinfo_t() idaapi.get_tinfo(fva, tinfo) ptype = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, tinfo, fname, '') ptype = ptype + ';' if ptype is not None else ptype records.append( (self.sha256, fname, fhd, fhm, f_ana, bsize, ptype)) self.debug( 'EXPORT {}: ssdeep={} (size={}), machoc={} (num of CFG={})' .format(fname, fhd, bsize, fhm, cfgnum)) self.cur.executemany( "REPLACE INTO function values (?, ?, ?, ?, ?, ?, ?)", records) success('{} of {} functions exported'.format(pnum, tnum)) return True
def visit_expr(self, expression): if expression.op == idaapi.cot_call and expression.x.op == idaapi.cot_helper and len(expression.a) == 3: if expression.x.helper == "CONTAINING_RECORD": if expression.a[0].op == idaapi.cot_var: idx = expression.a[0].v.idx if expression.a[1].op == idaapi.cot_helper and expression.a[2].op == idaapi.cot_helper: parent_name = expression.a[1].helper member_name = expression.a[2].helper parent_tinfo = idaapi.tinfo_t() if not parent_tinfo.get_named_type(idaapi.cvar.idati, parent_name): return 0 udt_data = idaapi.udt_type_data_t() parent_tinfo.get_udt_details(udt_data) udt_member = filter(lambda x: x.name == member_name, udt_data) if udt_member: tinfo = udt_member[0].type self.result[idx] = NegativeLocalInfo( tinfo, parent_tinfo, udt_member[0].offset / 8, member_name ) return 1 return 0
def create_class(ordinal): tinfo = idaapi.tinfo_t() tinfo.get_numbered_type(idaapi.cvar.idati, ordinal) vtables = {} if tinfo.is_struct(): udt_data = idaapi.udt_type_data_t() tinfo.get_udt_details(udt_data) for field_udt in udt_data: if field_udt.type.is_ptr(): possible_vtable = field_udt.type.get_pointed_object() if possible_vtable.is_struct(): v_udt_data = idaapi.udt_type_data_t() possible_vtable.get_udt_details(v_udt_data) for possible_func_udt in v_udt_data: if not possible_func_udt.type.is_funcptr(): break else: vtables[field_udt.offset // 8] = possible_vtable if vtables: class_ = Class(tinfo.dstr(), tinfo, ordinal) for offset, vtable_tinfo in vtables.items(): vtables[offset] = VirtualTable.create(vtable_tinfo, class_) class_.vtables = vtables return class_
def recognize_shape(self, indices): min_idx = max_idx = None if indices: min_idx, max_idx = min(indices), max(indices, key=lambda x: (x.row(), x.column())) if min_idx == max_idx: tinfo = self.get_recognized_shape() if tinfo: tinfo.create_ptr(tinfo) for scanned_var in self.get_unique_scanned_variables(origin=0): scanned_var.apply_type(tinfo) self.clear() else: # indices = sorted(indices) start, stop = min_idx.row(), max_idx.row() + 1 base = self.items[start].offset tinfo = self.get_recognized_shape(start, stop) if tinfo: ptr_tinfo = idaapi.tinfo_t() ptr_tinfo.create_ptr(tinfo) for scanned_var in self.get_unique_scanned_variables(base): scanned_var.apply_type(ptr_tinfo) self.items = filter(lambda x: x.offset < base or x.offset >= base + tinfo.get_size(), self.items) self.add_row(Member(base, tinfo, None))
def get_member_type(struct, idx): """ Retrieve the type information for the struct member :return: Type string """ member = ida_struct.get_member(struct, idx) tif = idaapi.tinfo_t() ida_struct.get_member_tinfo(tif, member) elements = str(tif).split(' ') typ = None if len(elements) == 2 and elements[0] == 'unsigned': if elements[1] == '__int8': typ = 'uint8_t' elif elements[1] == '__int16': typ = 'uint16_t' elif elements[1] == '__int32': typ = 'uint32_t' elif elements[1] == '__int64': typ = 'uint64_t' elif elements[1] != '': typ = elements[1] elif len(elements) == 1: if elements[0] == '__int8': typ = 'int8_t' elif elements[0] == '__int16': typ = 'int16_t' elif elements[0] == '__int32': typ = 'int32_t' elif elements[0] == '__int64': typ = 'int64_t' elif elements[0] != '': typ = str(tif) return typ
def create_padding_udt_member(offset, size): # type: (long, long) -> idaapi.udt_member_t """ Creates internal IDA structure with name gap_XXX and appropriate size and offset """ udt_member = idaapi.udt_member_t() udt_member.name = "gap_{0:X}".format(offset) udt_member.offset = offset udt_member.size = size if size == 1: udt_member.type = const.BYTE_TINFO else: if size < 1 or size > 0xffffffff: print( "HexRaysPyTools::core::helper::create_padding_udt_member: size is out of uint32 range (offset:{} size:{})" .format(offset, size)) array_data = idaapi.array_type_data_t() array_data.base = 0 array_data.elem_type = const.BYTE_TINFO array_data.nelems = size tmp_tinfo = idaapi.tinfo_t() tmp_tinfo.create_array(array_data) udt_member.type = tmp_tinfo return udt_member
def load(types, fields=None, cmts=None, lib=None): ti = idaapi.tinfo_t() if not ti.deserialize(lib, types, fields, cmts): ti = None return ti
def get_ptr_tinfo(self): ptr_tinfo = idaapi.tinfo_t() ptr_tinfo.create_ptr(self.tinfo) return ptr_tinfo
def tinfo(self): print "[INFO] Ignoring import function at 0x{0:08X}".format(self.address) tinfo = idaapi.tinfo_t() if idaapi.guess_tinfo2(self.address, tinfo): return tinfo return Const.DUMMY_FUNC
def getBuiltinGlobalType(self): sym = idaapi.til_symbol_t() #dang - no predicate func support via idapython :( #idaapi.choose_named_type2(idaapi.cvar.idati, 'Choose type to apply', idaapi.NTF_SYMM, predFunc, sym) ret = idaapi.choose_named_type2(idaapi.cvar.idati, 'Choose type to apply', idaapi.NTF_SYMM, None, sym) if not ret: self.logger.debug('User canceled. Bailing out') return til = sym.til funcname = sym.name typ_type = ctypes.POINTER(ctypes.c_ubyte)() typ_fields = ctypes.POINTER(ctypes.c_ubyte)() typ_cmt = ctypes.POINTER(ctypes.c_ubyte)() typ_fieldcmts = ctypes.POINTER(ctypes.c_ubyte)() typ_sclass = ctypes.c_ulong() value = ctypes.c_ulong() ret = get_named_type( long(til.this), funcname, idaapi.NTF_SYMM, ctypes.byref(typ_type), ctypes.byref(typ_fields), ctypes.byref(typ_cmt), ctypes.byref(typ_fieldcmts), ctypes.byref(typ_sclass), ctypes.byref(value) ) if ret == 0: self.logger.debug('Could not find %s', funcname) return ######################################## # the following isn't needed, as moved to tinfo_t usage #if typ_type[0] != idaapi.BT_FUNC: # #not positive that the first type value has to be BT_FUNC or not... # # and whether it's important to only apply to funcs or not # self.logger.debug('Found named type, but not a function: %s', funcname) # return #type_arr = ctypes.create_string_buffer(0x400) #type_arr[0] = chr(idaapi.BT_PTR) #manualTypeCopy(type_arr, 1, len(type_arr), typ_type) #name_buffer = ctypes.create_string_buffer(0x400) #print_type_to_one_line( # name_buffer, # len(name_buffer), # long(til.this), # typ_type, # funcname, # typ_cmt, # typ_fields, # typ_fieldcmts #) #self.logger.info('Found type: %s', name_buffer.value) ######################################## #this works as well, but it's deprecated #self.logger.info('Trying to set type: %s', name_buffer.value) #ret = g_dll.apply_callee_type( # ctypes.c_uint(here), # type_arr, # typ_fields #) tinfo = idaapi.tinfo_t() #self.logger.info('Trying to deserialize stuff') #self.logger.info('Type of til: %s', type(til)) #self.logger.info('Type of typ_type: %s', type(typ_type)) ret = g_dll.deserialize_tinfo( long(tinfo.this), long(til.this), ctypes.byref(typ_type), ctypes.byref(typ_fields), ctypes.byref(typ_fieldcmts) ) return tinfo
def type(self): self.ti = idaapi.tinfo_t() if not idaapi.get_member_tinfo(self.ti, self.member): print "[-] can't get member `%s` type" % self.name return return Type(self.ti)
def get_ptr_tinfo(self): # print self.tinfo.dstr() ptr_tinfo = idaapi.tinfo_t() ptr_tinfo.create_ptr(self.tinfo) return ptr_tinfo
def pack(self, start=0, stop=None): if self.collisions[start:stop].count(True): print("[Warning] Collisions detected") return final_tinfo = idaapi.tinfo_t() udt_data = idaapi.udt_type_data_t() origin = self.items[start].offset if start else 0 offset = origin for item in [x for x in self.items[start:stop] if x.enabled]: # Filter disabled members gap_size = item.offset - offset if gap_size: udt_data.push_back( helper.create_padding_udt_member(offset - origin, gap_size)) if item.is_array: array_size = self.calculate_array_size( bisect.bisect_left(self.items, item)) if array_size: udt_data.push_back( item.get_udt_member(array_size, offset=origin)) offset = item.offset + item.size * array_size continue udt_data.push_back(item.get_udt_member(offset=origin)) offset = item.offset + item.size final_tinfo.create_udt(udt_data, idaapi.BTF_STRUCT) cdecl = idaapi.print_tinfo( None, 4, 5, idaapi.PRTYPE_MULTI | idaapi.PRTYPE_TYPE | idaapi.PRTYPE_SEMI, final_tinfo, self.get_name(), None) cdecl = idaapi.ask_text(0x10000, '#pragma pack(push, 1)\n' + cdecl, "The following new type will be created") if cdecl: structure_name = idaapi.idc_parse_decl(idaapi.cvar.idati, cdecl, idaapi.PT_TYP)[0] previous_ordinal = idaapi.get_type_ordinal(idaapi.cvar.idati, structure_name) if previous_ordinal: reply = QtWidgets.QMessageBox.question( None, "HexRaysPyTools", "Structure already exist. Do you want to overwrite it?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) if reply == QtWidgets.QMessageBox.Yes: idaapi.del_numbered_type(idaapi.cvar.idati, previous_ordinal) ordinal = idaapi.idc_set_local_type( previous_ordinal, cdecl, idaapi.PT_TYP) else: return else: ordinal = idaapi.idc_set_local_type(-1, cdecl, idaapi.PT_TYP) if ordinal: print("[Info] New type {0} was added to Local Types".format( structure_name)) tid = idaapi.import_type(idaapi.cvar.idati, -1, structure_name) if tid: tinfo = idaapi.create_typedef(structure_name) ptr_tinfo = idaapi.tinfo_t() ptr_tinfo.create_ptr(tinfo) for scanned_var in self.get_unique_scanned_variables( origin): scanned_var.apply_type(ptr_tinfo) return tinfo else: print("[ERROR] Structure {0} probably already exist".format( structure_name))
def getBuiltinGlobalTypeCtypes(self): self.logger.debug('Getting GlobalType the Ctypes way') ############################################################ # Several type-related functions aren't accessibly via IDAPython # so have to do things with ctypes idaname = "ida64" if idc.__EA64__ else "ida" if sys.platform == "win32": g_dll = ctypes.windll[idaname + ".wll"] elif sys.platform == "linux2": g_dll = ctypes.cdll["lib" + idaname + ".so"] elif sys.platform == "darwin": g_dll = ctypes.cdll["lib" + idaname + ".dylib"] ############################################################ # Specifying function types for a few IDA SDK functions to keep the # pointer-to-pointer args clear. get_named_type = g_dll.get_named_type get_named_type.argtypes = [ ctypes.c_void_p, #const til_t *ti, ctypes.c_char_p, #const char *name, ctypes.c_int, #int ntf_flags, ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), #const type_t **type=NULL, ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), #const p_list **fields=NULL, ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), #const char **cmt=NULL, ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), #const p_list **fieldcmts=NULL, ctypes.POINTER(ctypes.c_ulong), #sclass_t *sclass=NULL, ctypes.POINTER(ctypes.c_ulong), #uint32 *value=NULL); ] sym = idaapi.til_symbol_t() #dang - no predicate func support via idapython :( #idaapi.choose_named_type2(idaapi.cvar.idati, 'Choose type to apply', idaapi.NTF_SYMM, predFunc, sym) ret = idaapi.choose_named_type2(idaapi.cvar.idati, 'Choose type to apply', idaapi.NTF_SYMM, None, sym) if not ret: self.logger.debug('User canceled. Bailing out') return til = sym.til funcname = sym.name typ_type = ctypes.POINTER(ctypes.c_ubyte)() typ_fields = ctypes.POINTER(ctypes.c_ubyte)() typ_cmt = ctypes.POINTER(ctypes.c_ubyte)() typ_fieldcmts = ctypes.POINTER(ctypes.c_ubyte)() typ_sclass = ctypes.c_ulong() value = ctypes.c_ulong() ret = get_named_type( long(til.this), funcname, idaapi.NTF_SYMM, ctypes.byref(typ_type), ctypes.byref(typ_fields), ctypes.byref(typ_cmt), ctypes.byref(typ_fieldcmts), ctypes.byref(typ_sclass), ctypes.byref(value) ) if ret == 0: self.logger.debug('Could not find %s', funcname) return ######################################## # the following isn't needed, as moved to tinfo_t usage #if typ_type[0] != idaapi.BT_FUNC: # #not positive that the first type value has to be BT_FUNC or not... # # and whether it's important to only apply to funcs or not # self.logger.debug('Found named type, but not a function: %s', funcname) # return #type_arr = ctypes.create_string_buffer(0x400) #type_arr[0] = chr(idaapi.BT_PTR) #manualTypeCopy(type_arr, 1, len(type_arr), typ_type) #name_buffer = ctypes.create_string_buffer(0x400) #print_type_to_one_line( # name_buffer, # len(name_buffer), # long(til.this), # typ_type, # funcname, # typ_cmt, # typ_fields, # typ_fieldcmts #) #self.logger.info('Found type: %s', name_buffer.value) ######################################## #this works as well, but it's deprecated #self.logger.info('Trying to set type: %s', name_buffer.value) #ret = g_dll.apply_callee_type( # ctypes.c_uint(here), # type_arr, # typ_fields #) tinfo = idaapi.tinfo_t() #self.logger.info('Trying to deserialize stuff') #self.logger.info('Type of til: %s', type(til)) #self.logger.info('Type of typ_type: %s', type(typ_type)) ret = g_dll.deserialize_tinfo( long(tinfo.this), long(til.this), ctypes.byref(typ_type), ctypes.byref(typ_fields), ctypes.byref(typ_fieldcmts) ) return tinfo