def parse(info): '''Parse the string `info` into an ``idaapi.tinfo_t``.''' if idaapi.__version__ < 7.0: til, ti = idaapi.cvar.idati, idaapi.tinfo_t(), else: til, ti = idaapi.get_idati(), idaapi.tinfo_t(), # Convert info to a string if it's a tinfo_t info_s = "{!s}".format(info) if isinstance(info, idaapi.tinfo_t) else info # Firstly we need to ';'-terminate the type the user provided in order # for IDA's parser to understand it. terminated = info_s if info_s.endswith(';') else "{:s};".format(info_s) # Ask IDA to parse this into a tinfo_t for us. We pass the silent flag so # that we're responsible for raising an exception if there's a parsing # error of some sort. If it succeeds, then we can return our typeinfo. # Otherwise we return None because of the inability to parse it. if idaapi.__version__ < 6.9: return None if idaapi.parse_decl2(til, terminated, None, ti, idaapi.PT_SIL) is None else ti elif idaapi.__version__ < 7.0: return None if idaapi.parse_decl2(til, terminated, ti, idaapi.PT_SIL) is None else ti return None if idaapi.parse_decl(ti, til, terminated, idaapi.PT_SIL) is None else ti
def make_basic_structs(): strucid = ida_struct.get_struc_id("Vector") if strucid == idc.BADADDR: struc = ida_struct.get_struc( ida_struct.add_struc(idc.BADADDR, "Vector")) ida_struct.add_struc_member(struc, "x", idc.BADADDR, idc.FF_DWRD, None, 4) ida_struct.add_struc_member(struc, "y", idc.BADADDR, idc.FF_DWRD, None, 4) ida_struct.add_struc_member(struc, "z", idc.BADADDR, idc.FF_DWRD, None, 4) global VECTOR VECTOR = idaapi.tinfo_t() idaapi.parse_decl2(None, "Vector;", VECTOR, 0) strucid = ida_struct.get_struc_id("QAngle") if strucid == idc.BADADDR: struc = ida_struct.get_struc( ida_struct.add_struc(idc.BADADDR, "QAngle")) ida_struct.add_struc_member(struc, "x", idc.BADADDR, idc.FF_DWRD, None, 4) ida_struct.add_struc_member(struc, "y", idc.BADADDR, idc.FF_DWRD, None, 4) ida_struct.add_struc_member(struc, "z", idc.BADADDR, idc.FF_DWRD, None, 4)
def _replace_with_check_helper(self, ctx, l): # type: (...) -> None type_name_ea = ctx.type_info_obj.obj_ea name = idaapi.demangle_name(idaapi.get_name(type_name_ea), 0) if not name: name = idaapi.get_name(type_name_ea) type_name = name var_type = None if "::getRuntimeTypeInfoStatic(void)::typeInfo" in name: type_name = name.split("::getRuntimeTypeInfoStatic(void)::typeInfo")[0] var_type = idaapi.tinfo_t() idaapi.parse_decl2(idaapi.cvar.idati, type_name + "*;", var_type, idaapi.PT_TYP) if not str(var_type): var_type = None call_expr = make_helper_call("void*", "dynamic_cast<" + type_name + ">", ["void*"]) call_expr.a.push_back(make_carg_t(ctx.original_var)) asg_expr = hr.cexpr_t() asg_expr.op = hr.cot_asg asg_expr.x = hr.cexpr_t() asg_expr.x.assign(ctx.dynamic_cast_var) asg_expr.y = call_expr asg_expr.type = var_type if var_type else idaapi.tinfo_t(idaapi.BT_VOID) if var_type: self._types_to_set.append((ctx.dynamic_cast_var.v.idx, var_type)) replace_expr_with(l[0].cexpr, asg_expr) for item in l[1:]: item.cleanup()
def run(self, vu, tree, parent): # type: (...) -> None class ctx: string_vidx = int() def is_string_vtable_assignment(c, p): # type: (...) -> bool if c.op != hr.cot_asg: return False lhs = c.x if lhs.op != hr.cot_var: return False pointed_type = lhs.type.get_pointed_object() if not pointed_type or pointed_type.get_type_name() != SAFESTRINGBASE_VTABLE_STRUCT_NAME: return False rhs = c.y if rhs.op != hr.cot_ref: return False if rhs.x.op != hr.cot_obj: return False ctx.string_vidx = lhs.v.idx return True cv = ConstraintVisitor([ConstraintChecker(is_string_vtable_assignment)], "ctor") variables = [] # type: typing.List[int] cv.match(tree, parent, lambda l: variables.append(ctx.string_vidx)) t = idaapi.tinfo_t() idaapi.parse_decl2(idaapi.cvar.idati, "sead::SafeString;", t, idaapi.PT_TYP) for vidx in variables: vu.set_lvar_type(vu.cfunc.get_lvars()[vidx], t)
def import_vtable(classname, struc): ea = get_vtable(classname) if ea == idc.BADADDR: return # Mildly adapted from Asherkin's vtable dumper ea = ea + 8 # Skip typeinfo and thisoffs funcs = [] while ea != idc.BADADDR: offs = idc.get_wide_dword(ea) if not ida_bytes.is_code(ida_bytes.get_full_flags(offs)): break name = idc.get_name(offs, ida_name.GN_VISIBLE) funcs.append(name) ea = ida_bytes.next_not_tail(ea) # print(funcs) if not len(funcs): return strucid = add_struc_ex2(classname + "_vftable") vstruc = ida_struct.get_struc(strucid) for i in funcs: # Gotta do a fancy demangle, it can't have special chars # and there can't be multiples of the same name, so let's just jazz around all of that demangled = idc.demangle_name(i, idc.get_inf_attr(idc.INF_SHORT_DN)) if demangled == None: demangled = i else: demangled = demangled[demangled.find("::") + 2:demangled.find("(")] demangled = demangled.replace("~", "_").replace("<", "_").replace(">", "_") while 1: error = ida_struct.add_struc_member(vstruc, demangled, idc.BADADDR, idc.FF_DWRD, None, 4) if error == 0: break demangled = demangled + "_" # This is dumb but lol # Now assign the vtable to the actual struct ti = idaapi.tinfo_t() idaapi.parse_decl2(None, classname + "_vftable;", ti, 0) ti.create_ptr(ti) ida_struct.set_member_tinfo(struc, ida_struct.get_member(struc, 0), 0, ti, 0)
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
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 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 activate(self, ctx): sel = [] for idx in ctx.chooser_selection: # rename the function ea = get_name_ea_simple(self.items[idx][2]) sfname = str(self.items[idx][4]) #set_name(ea, sfname) idaapi.do_name_anyway(ea, sfname) success('{:#x}: renamed to {}'.format(ea, sfname)) # set the function prototype sptype = str(self.items[idx][5]) if sptype != 'None': tinfo = idaapi.tinfo_t() idaapi.parse_decl2(idaapi.cvar.idati, sptype, tinfo, 0) #idaapi.apply_callee_tinfo(ea, tinfo) if idaapi.apply_tinfo(ea, tinfo, 0): success('{:#x}: function prototype set to {}'.format( ea, sptype)) else: error( '{:#x}: function prototype set FAILED (maybe you should import the types?)' .format(ea)) if ask_yn(0, 'Do you import types from the secondary idb?' ) == 1: if self.import_types(): tinfo = idaapi.tinfo_t() idaapi.parse_decl2(idaapi.cvar.idati, sptype, tinfo, 0) if idaapi.apply_tinfo(ea, tinfo, 0): success('{:#x}: function prototype set to {}'. format(ea, sptype)) else: error( '{:#x}: function prototype set FAILED again' .format(ea)) # insert the comment score = self.items[idx][0] mmatch = self.items[idx][1] cmt = 'fn_fuzzy: ssdeep={}, machoc={}'.format(score, mmatch) set_func_cmt(ea, cmt, 1) #set_decomplier_cmt(ea, cmt) # not sure how to avoid orphan comment # update the Choose rows ida_kernwin.refresh_chooser(self.title)
def getUserDeclType(self, decl): tinfo = idaapi.tinfo_t() #self.logger.debug('Trying to parse declaration: %r', decl) ret = idaapi.parse_decl2(idaapi.cvar.idati, decl, tinfo, idaapi.PT_TYP) #self.logger.debug('Return from parse_decl2: %r', ret) if ret is None: self.logger.info('parse_decl2 failed') return None return tinfo
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 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.isident(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_decl2(idaapi.cvar.idati, value, '', tinfo, idaapi.PT_TYP): 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 parse(c, struc): if c.tag == "sendtable": if c.attrib.get("name", None) and c.attrib.get("name", None).startswith("DT_"): for i in c: parse(i, struc) elif c.tag == "property": classname = c.attrib.get("name", None) if classname != None: if classname == "baseclass": for p in c: parse(p, struc) else: t = c.find("type") if t == None: return offset = c.find("offset") offset = int(offset.text) if offset != None else None if offset == None or offset is 0: return # Have to be a little special with datatables if t.text == "datatable": ida_struct.add_struc_member(struc, classname, offset, idc.FF_DWRD, None, 4) sendtable = c.find("sendtable") if sendtable != None: mycls = sendtable.attrib.get("name", None) if mycls != None: if mycls.startswith("DT_"): mycls = mycls.replace("DT_", "C", 1) strucid = ida_struct.get_struc_id(mycls) if strucid == idc.BADADDR: # If this struct didn't exist, parse it strucid = ida_struct.add_struc( idc.BADADDR, mycls) parse(sendtable, ida_struct.get_struc(strucid)) ti = idaapi.tinfo_t( ) # Assign the sendtable type to the struct idaapi.parse_decl2(None, mycls + ";", ti, 0) if str( ti ) != "CAttributeList": # HACK; this one doesn't work and idk what else to try ida_struct.set_member_tinfo( struc, ida_struct.get_member(struc, offset), 0, ti, 0) else: # Iterate the array and update the struct member size, hackily flag, sizemult = get_sendtable_size(sendtable) if sizemult > 4: ida_struct.set_member_type( struc, offset, flag, None, sizemult) return sz = c.find("bits") sz = int(sz.text) if sz != None else None if sz == None: return flags, numbytes = calcszdata(sz) # if t.text == "float": # flags |= idc.FF_FLOAT # print(idc.FF_BYTE, idc.FF_DWRD) # print(flags, numbytes) if t.text == "vector": ida_struct.add_struc_member(struc, classname, offset, idc.FF_DWRD, None, 12) global VECTOR ida_struct.set_member_tinfo( struc, ida_struct.get_member(struc, offset), 0, VECTOR, 0) else: returnval = ida_struct.add_struc_member( struc, classname, offset, flags, None, numbytes) if returnval: print("Could not add struct member {}.{}! Error {}". format(ida_struct.get_struc_name(struc.id), classname, returnval))
def set_member_type_info(struc, member, decl): ti = idaapi.tinfo_t() idaapi.parse_decl2(None, decl, ti, 0) idaapi.set_member_tinfo(struc, member, 0, ti, 0)