def extract_rtti_info_from_typeinfo(cls, typeinfo_ea): if typeinfo_ea in cls.found_classes: return None rtti_obj = cls.parse_typeinfo(typeinfo_ea) if rtti_obj is None: return None log.info("%s: Parsed typeinfo", rtti_obj.name) cls.found_classes.add(rtti_obj.typeinfo_ea) for parent_typeinfo_ea, _, offset in rtti_obj.raw_parents: parent_updated_name = None parent_rtti_obj = cls.extract_rtti_info_from_typeinfo(parent_typeinfo_ea) if parent_rtti_obj: parent_updated_name = parent_rtti_obj.name else: built_rtti_obj_name = ida_name.get_ea_name(parent_typeinfo_ea) if built_rtti_obj_name.endswith(cls.RTTI_OBJ_STRUC_NAME): parent_updated_name = built_rtti_obj_name.rstrip("_" + cls.RTTI_OBJ_STRUC_NAME) if parent_updated_name is not None: rtti_obj.updated_parents.append((parent_updated_name, offset)) log.debug("%s: Finish setup parents", rtti_obj.name) if not rtti_obj.create_structs(): return None rtti_obj.make_rtti_obj_pretty() rtti_obj.find_vtables() return rtti_obj
def get_ea_name(ea, fromaddr=idc.BADADDR, true=False, user=False): """Get the name of an address. This function returns the name associated with the byte at the specified address. Arguments: ea: The linear address whose name to find. Options: fromaddr: The referring address. Default is BADADDR. Some addresses have a location-specific name (for example, labels within a function). If fromaddr is not BADADDR, then this function will try to retrieve the name of ea from fromaddr's perspective. The global name will be returned if no location-specific name is found. true: Retrieve the true name rather than the display name. Default is False. user: Return "" if the name is not a user name. Returns: The name of the address or "". """ if user and not idc.hasUserName(ida_bytes.get_full_flags(ea)): return "" if true: return ida_name.get_ea_name(fromaddr, ea) else: return idc.get_name( ea, ida_name.GN_VISIBLE | idc.calc_gtn_flags(fromaddr, ea))
def get_typeinfo_name(self, typeinfo_ea): name_ea = utils.get_ptr(typeinfo_ea + self.CLASS_TYPE_NAME_OFFSET) if name_ea is None or name_ea == BADADDR: mangled_class_name = ida_name.get_ea_name(typeinfo_ea) else: mangled_class_name = "_Z" + idc.get_strlit_contents(name_ea).decode() class_name = ida_name.demangle_name(mangled_class_name, idc.INF_LONG_DN) return GccRTTIParser.strip_class_name(class_name)
def _variable_name(ea): """Return the name of a variable.""" try: flags = ida_bytes.get_full_flags(ea) if ida_bytes.has_name(flags): return ida_name.get_ea_name(ea) except: pass return ""
def name(self): ea = self.address() try: flags = ida_bytes.get_full_flags(ea) if ida_bytes.has_name(flags): return ida_name.get_ea_name(ea) except: pass return ""
def visit_expr(self, e): if e.op == hr.cot_asg: # is x a var? if e.x.op == hr.cot_var: # handle "x = y" types of assignments if e.y.op == hr.cot_var: # get variable indexes x_idx = e.x.v.idx y_idx = e.y.v.idx # get lvar_t var_x = self.lvars[x_idx] var_y = self.lvars[y_idx] """ debug("Found: %s (user: %s, nice: %s) = %s (user: %s, nice: %s)" % ( var_x.name, var_x.has_user_name, var_x.has_nice_name, var_y.name, var_y.has_user_name, var_y.has_nice_name)) """ # if x has an autogenerated name and y has a custom name if not var_x.has_user_name and var_y.has_user_name: # rename x set_var_unique_name(var_x, var_y, self.lvars) else: debug("Skipped: %s = %s " % (var_x.name, var_y.name)) # handle "x = something.y" types of assignments elif e.y.op == hr.cot_memref: pass # handle "x = something->y" types of assignments elif e.y.op == hr.cot_memptr: #debug("Found: %s = [ %s (%s) and m = %d and ptrsize = %x ]" % (self.lvars[e.x.v.idx].name, get_expr_name_and_member(e.y), get_expr_struct_type(e.y, self.lvars), e.y.m, e.y.ptrsize)) # get var index and lvar_t x_idx = e.x.v.idx var_x = self.lvars[x_idx] # rename x set_struct_member_unique_name(var_x, e.y, self.lvars) # handle "x = y()" types of assignments elif e.y.op == hr.cot_call and e.y.x.op == hr.cot_obj: # get name of called function func_name = ida_name.get_ea_name(e.y.x.obj_ea) # get var index and lvar_t x_idx = e.x.v.idx var_x = self.lvars[x_idx] if not var_x.has_user_name: # rename x set_func_unique_name(var_x, func_name, self.lvars) else: debug("Skipped: %s = %s(...) " % (var_x.name, func_name)) return 0
def visit_expr(self, e): if e.op == hr.cot_asg: # is x a var? if e.x.op == hr.cot_var: # handle "x = y" types of assignments if e.y.op == hr.cot_var: # get variable indexes x_idx = e.x.v.idx y_idx = e.y.v.idx # get lvar_t var_x = self.lvars[x_idx] var_y = self.lvars[y_idx] """ debug_print("Found: %s (user: %s, nice: %s) = %s (user: %s, nice: %s)" % ( var_x.name, var_x.has_user_name, var_x.has_nice_name, var_y.name, var_y.has_user_name, var_y.has_nice_name)) """ # if x has an autogenerated name and y has a custom name if not var_x.has_user_name and var_y.has_user_name: # rename x set_var_unique_name(var_x, var_y, self.lvars) else: debug_print("Skipped: %s = %s " % (var_x.name, var_y.name)) # handle "x = y()" types of assignments elif e.y.op in [hr.cot_call, hr.cot_cast]: if e.y.op == hr.cot_call: tmp_y = e.y elif e.y.op == hr.cot_cast and e.y.x.op == hr.cot_call: tmp_y = e.y.x else: # TBD tmp_y = None if tmp_y and tmp_y.x.op == hr.cot_obj: # get name of called function func_name = ida_name.get_ea_name( tmp_y.x.obj_ea, ida_name.GN_VISIBLE | ida_name.GN_LOCAL) # get var index and lvar_t x_idx = e.x.v.idx var_x = self.lvars[x_idx] if not var_x.has_user_name: # rename x set_func_unique_name(var_x, func_name, self.lvars) else: debug_print("Skipped: %s = %s(...) " % (var_x.name, func_name)) return 0
def _add_real_xref(ea, ref_ea, out_ref_eas): """Sometimes IDA will have a operand like `[foo+10]` and the xref collector will give us the address of `foo`, but not the address of `foo+10`, so we will try to find it here.""" global _OPERANDS_NUMS, _REF_OPERAND_TYPES ref_name = ida_name.get_ea_name(ref_ea) for i in _OPERANDS_NUMS: try: op_type = idc.get_operand_type(ea, i) except: return if op_type not in _REF_OPERAND_TYPES: continue op_str = idc.print_operand(ea, i) if op_str is None: return if ref_name in op_str: op_val = idc.get_operand_value(ea, i) out_ref_eas.add(op_val)
def main(): global til til = ida_typeinf.get_idati() capstone_init() unicorn_init() all_names = list(idautils.Names()) # First, get inheritance tree for all classes # We do this in two passes: # First pass: for each class, gather class name, parent class name, # and superclass name, and connect them # Second pass: for each inheritance hierarchy object, we check # if the parent pointer is None (signaling a top-level # class), and add that to the `ihs` list # We can do this whole thing by processing xrefs to OSMetaClass::OSMetaClass OSMetaClass_ctor = get_OSMetaClass_ctor() if OSMetaClass_ctor == 0: print("Could not find OSMetaClass::OSMetaClass") return print("Got OSMetaClass::OSMetaClass at {}".format(hex(OSMetaClass_ctor))) # key,value pairs of all inheritance hierarchy objects ih_dict = {} # only those inheritance hierarchy objects which represent # a top-level parent class (aka inheriting from OSObject) ihs = [] xrefs = list(idautils.XrefsTo(OSMetaClass_ctor)) num = 0 for xref in xrefs: frm = xref.frm # test # frm = 0x63920 # print("xref from {}".format(hex(frm))) args = get_OSMetaClass_ctor_args(frm) pname = args[0] cname = args[1] if cname == "OSMetaClassBase": print("xref from {}".format(hex(frm))) print(args) if pname == cname: continue csz = args[2] # if pname == "AUAUnitDictionary" and cname == "AUAMixerUnitDictionary": # print(args) # return new_parent = pname is not None and pname not in ih_dict new_child = cname not in ih_dict if new_parent: ih_dict[pname] = InheritanceHierarchy(None, pname, csz, csz) if new_child: ih_dict[cname] = InheritanceHierarchy(None, cname, csz) else: # Update class size for only child classes ih_dict[cname].sz = csz if pname == None: # If this class has no superclass, it must be parent class, # so make its InheritanceHierarchy object ih_dict[cname] = InheritanceHierarchy(None, cname, csz) else: child_ih = ih_dict[cname] parent_ih = ih_dict[pname] parent_ih.add_child(child_ih) child_ih.parent = parent_ih child_ih.totsz = child_ih.sz + parent_ih.totsz # if cname == "AUAUnitDictionary": # print("AUAUnitDictionary sz: {}".format(ih_dict[pname].sz)) # print(args) # return # if cname == "AUAMixerUnitDictionary": # print("AUAMixerUnitDictionary sz: {}".format(ih_dict[cname].sz)) # print(args) # return num += 1 # if num == 10: # break print("First pass: {} classes processed".format(num)) num = 0 # Second pass for ih in ih_dict.values(): if ih.parent == None: # print("Adding {} to the ihs list".format(ih.name)) num += 1 ihs.append(ih) print("Second pass: {} classes added to ihs list".format(num)) num = 0 wants_class_hierarchy = ida_kernwin.ask_yn(0, "Dump class hierarchy?") if wants_class_hierarchy: hierch_file = open( "{}/iOS/Scripts/iokit_hier.txt".format(str(Path.home())), "w") for ih in ihs: dump_hierarchy_to_file(hierch_file, ih, 0) print("File written to {}".format(hierch_file.name)) hierch_file.close() return vtables = [] for cur_name in all_names: ea = cur_name[0] name = cur_name[1] if "ZTV" in name: vtables.append(cur_name) struct_file = open( "{}/iOS/Scripts/structs_from_vtabs.h".format(str(Path.home())), "w") is_standalone_kext = ida_kernwin.ask_yn(0, "Standalone kext?") if is_standalone_kext: # If this is from a standalone kext, I need to write some # definitions for common objects that follow my struct format, # otherwise, things get really screwed struct_file.write( "struct __cppobj ExpansionData {};\n\n" "struct __cppobj OSMetaClassBase_vtbl;\n\n" "struct __cppobj OSMetaClassBase_mbrs {};\n\n" "struct __cppobj OSMetaClassBase {\n" "\tOSMetaClassBase_vtbl *__vftable /*VFT*/;\n" "\tOSMetaClassBase_mbrs m;\n" "};\n\n" "struct __cppobj OSObject_mbrs : OSMetaClassBase_mbrs {\n" "\tint retainCount;\n" "};\n\n" "struct __cppobj OSObject_vtbl : OSMetaClassBase_vtbl {};\n\n" "struct __cppobj OSObject {\n" "\tOSObject_vtbl *__vftable;\n" "\tOSObject_mbrs m;\n" "};\n\n" "struct __cppobj OSMetaClass_mbrs : OSMetaClassBase_mbrs {\n" "\tExpansionData *reserved;\n" "\tconst OSMetaClass *superClassLink;\n" "\tconst OSSymbol *className;\n" "\tunsigned int classSize;\n" "\tunsigned int instanceCount;\n" "};\n\n" "struct __cppobj OSMetaClass {\n" "\tOSMetaClassBase_vtbl *__vftable;\n" "\tOSMetaClass_mbrs m;\n" "};\n\n" "struct __cppobj OSCollection_vtbl;\n" "struct __cppobj OSCollection_mbrs : OSObject_mbrs {\n" "\tunsigned int updateStamp;\n" "\tunsigned int fOptions;\n" "};\n\n" "struct __cppobj OSCollection {\n" "\tOSCollection_vtbl *__vftable;\n" "\tOSCollection_mbrs m;\n" "};\n\n" "struct __cppobj OSArray_vtbl;\n" "struct __cppobj OSArray_mbrs : OSCollection_mbrs {\n" "\tunsigned int count;\n" "\tunsigned int capacity;\n" "\tunsigned int capacityIncrement;\n" "\tvoid *array;\n" "};\n\n" "struct __cppobj OSArray {\n" "\tOSArray_vtbl *__vftable;\n" "\tOSArray_mbrs m;\n" "};\n\n" "struct __cppobj OSDictionary::dictEntry {\n" "\tconst OSSymbol *key;\n" "\tconst OSMetaClassBase *value;\n" "};\n\n" "struct __cppobj OSDictionary_vtbl;\n" "struct __cppobj OSDictionary_mbrs : OSCollection_mbrs {\n" "\tunsigned int count;\n" "\tunsigned int capacity;\n" "\tunsigned int capacityIncrement;\n" "\tOSDictionary::dictEntry *dict;\n" "};\n\n" "struct __cppobj OSDictionary {\n" "\tOSDictionary_vtbl *__vftable;\n" "\tOSDictionary_mbrs m;\n" "};\n\n" "struct __cppobj OSSet_vtbl;\n" "struct __cppobj OSSet_mbrs : OSCollection_mbrs {\n" "\tOSArray *members;\n" "};\n\n" "struct __cppobj OSSet {\n" "\tOSSet_vtbl *__vftable;\n" "\tOSSet_mbrs m;\n" "};\n\n" "struct __cppobj OSString_mbrs : OSObject_mbrs {\n" "\tunsigned __int32 flags : 14;\n" "\tunsigned __int32 length : 18;\n" "\tchar *string;\n" "};\n\n" "struct __cppobj OSString {\n" "\tOSObject_vtbl *__vftable;\n" "\tOSString_mbrs m;\n" "};\n\n" "struct __cppobj OSSymbol : OSString {};\n\n") num_failed_get_type = 0 cnt = 0 for vtable in vtables: demangled_name = idc.demangle_name(vtable[1], get_inf_attr(idc.INF_LONG_DN)) # unless this is a vtable for OSMetaClassBase, OSMetaClassMeta, # or OSMetaClass, skip anything metaclass related if "::MetaClass" in demangled_name: continue class_name = ida_name.extract_name(demangled_name, len("`vtable for'")) if class_name in BLACKLIST: continue ea = vtable[0] #+ 8; while ida_bytes.get_qword(ea) == 0: ea += 8 # print("EA: {}".format(hex(ea))) if is_unknown(ida_bytes.get_flags(ea)): continue # if class_name != "IOSkywalkPacket": # continue # if class_name != "AHTHSBufferStatic": # continue # if class_name != "HSMSPITest": # continue # if class_name != "AppleMesa": # continue # if class_name != "AppleUSBHostController": # continue # if class_name != "AppleEmbeddedPCIE": # continue # if class_name != "SimpleEval": # continue # if class_name != "AppleUSBCDCControl": # continue # if class_name != "IOHDCP2TransmitterAuthSession": # continue # if class_name != "IOAVService::DisplayIDParser::readDisplayID": # continue # if class_name != "IOMFB::TypedProp": # continue # if class_name != "IOMFB::UPBlock_GenPipe_v2": # continue # if class_name != "AppleMesaSEPDriver": # continue # if class_name != "IOAVController": # continue # if class_name != "AppleConvergedIPCICEBBBTIInterface": # continue # if class_name != "ApplePPM": # continue cnt += 1 # print("{}".format(class_name)) # skip NULL pointers until we hit a function while ida_bytes.get_qword(ea) == 0: ea += 8 num_virts = 0 num_dtors = 0 num_untyped = 0 num_noname = 0 fxn_name_list = [] fxn_name_dict = {} struct_fields = [] fwd_decls = set() fwd_decls.add(class_name) svt = SymbolicatedVtable(class_name) ioc = IOKitClass(svt) ioc.svt = svt # vtables seem to be NULL terminated while True: fxn_ea = ida_bytes.get_qword(ea) # end of vtable for this class if fxn_ea == 0: break # print("Type for {}/{} @ {}: {}".format(hex(fxn_ea), fxn_name, hex(ea), fxn_type)) # if fxn_type == None: # num_failed_get_type += 1 # ea += 8 # continue # default to this for ___cxa_pure_virtual fxn_args = "void" fxn_call_conv = "" fxn_mangled_name = ida_name.get_ea_name(fxn_ea) fxn_name = ida_name.demangle_name(fxn_mangled_name, get_inf_attr(idc.INF_LONG_DN)) if fxn_name == None: # ___cxa_pure_virtual fxn_name = ida_name.get_ea_name(fxn_ea) # some other thing? if len(fxn_name) == 0: fxn_name = "noname{}".format(num_noname) else: fxn_type = idc.get_type(fxn_ea) if fxn_type == None: # sometimes this happens, don't know why # the only thing fxn_type would have provided was # the calling convention, so we need to manually # reconstruct parameter list, and assume calling # convention is __fastcall # if mangled_fxn_name == "__ZN25IOGeneralMemoryDescriptor7doUnmapEP7_vm_mapyy": # exit(0) fxn_return_type = "__int64" fxn_call_conv = "__fastcall" fxn_args_string = fxn_name[fxn_name.find("(") + 1:fxn_name.rfind(")")] # if fxn_args_string == "IOService *, unsigned int, void *, void (*)(OSObject *, AppleUSBCDCControl*, void *, USBCDCNotification *)": # # print("Hello") # fxn_args_string = "IOService *, unsigned int, void *, void (*)(OSObject *, void (*)(TestType *, AppleUSBCDCControl*, void *, USBCDCNotification *), AppleUSBCDCControl*, void *, USBCDCNotification *)" # print("fxn args: {}".format(fxn_args_string)) # if fxn_args_string == "OSObject *, void (*)(OSObject *, IOHDCPAuthSession *), IOHDCPMessageTransport *, IOHDCPInterface *": # fxn_args_string = "OSObject *, void (*)(OSObject *, IOHDCPAuthSession *), IOHDCPMessageTransport *, IOHDCPInterface *, unsigned long long" fxn_args_string = fxn_args_string.replace( "{block_pointer}", "*") if fxn_args_string.find(",") != -1: # print("More than one arg: {}".format(fxn_args_list)) # extra comma makes the parser happy fxn_args_types_list = get_arg_type_list( fxn_args_string + ",") # print("More than one arg for {}: {}".format(fxn_name, fxn_args_types_list)) # print() fxn_args = "" argnum = 0 # print(type(fxn_args_types_list)) to_fwd_decl = get_fwd_decls(fxn_args_types_list) if len(to_fwd_decl) > 0: fwd_decls.update(to_fwd_decl) for arg_type in fxn_args_types_list: if argnum == 0: fxn_args += "{} *__hidden this, ".format( class_name) else: fxn_args += "{}, ".format(fix_type(arg_type)) argnum += 1 fxn_args = fxn_args[:-2] else: fxn_args = "{} *__hidden this".format(class_name) arg_type = fxn_name[fxn_name.find("(") + 1:fxn_name.rfind(")")] # print("Only one arg for {}: {}".format(fxn_name, arg_type)) arg_type_list = [arg_type] # print("Only one arg: {}".format(arg_type_list)) to_fwd_decl = get_fwd_decls(arg_type_list) if len(to_fwd_decl) > 0: fwd_decls.update(to_fwd_decl) if arg_type != "void" and len(arg_type) > 0: fxn_args += ", {}".format(fix_type(arg_type)) else: all_except_args = fxn_type[:fxn_type.find("(")] # first, if there's no spaces, there's no calling # convention specifed if all_except_args.find(" ") == -1: fxn_return_type = all_except_args # Also, this having no spaces could mean IDA messed # up, so we should use the demangled name instead # and parse that fxn_type = "(" + fxn_name[fxn_name.find("(") + 1:] # print("No spaces in args, using {} as fxn_type".format(fxn_type)) else: double_underscore = all_except_args.rfind("__") if double_underscore != -1: fxn_return_type = all_except_args[: double_underscore] fxn_call_conv = all_except_args[double_underscore:] else: fxn_return_type = all_except_args # get args # print("fxn_type: {}".format(fxn_type)) fxn_args = fxn_type[fxn_type.find("(") + 1:fxn_type.rfind(")")] fxn_args_type_list = get_arg_type_list(fxn_args + ",") fixed_fxn_args_type_list = [] # Fix up args for arg_type in fxn_args_type_list: # Remove __hidden arg_type = arg_type.replace("__hidden", "") # Check for a pointer. This is an easy case, we # just delete everything from the first * star = arg_type.find("*") if star != -1: arg_type = arg_type[0:star] else: # Otherwise, find the last space, and delete # from there # But in case there was no name for this # parameter, check if the token after the last # space is not an IDA type or primitive type lspace = arg_type.rfind(" ") if lspace != -1: token = arg_type[lspace:].replace(" ", "") if not is_primitive_type( token) and not is_ida_type(token): arg_type = arg_type[0:lspace] # print("arg_type: {}".format(arg_type)) fixed_fxn_args_type_list.append(arg_type) # to_fwd_decl = get_fwd_decls(fxn_args_type_list) to_fwd_decl = get_fwd_decls(fixed_fxn_args_type_list) if len(to_fwd_decl) > 0: fwd_decls.update(to_fwd_decl) # print("fxn_type is not None for {}: fxn args: {}".format(fxn_name, fxn_args_type_list)) # print("fxn_type is not None: will fwd declare: {}".format(to_fwd_decl)) # get function name # remove 'classname::' and params fxn_name = fxn_name[fxn_name.find("::") + 2:fxn_name.find("(") + 1] fxn_name = fxn_name[:fxn_name.find("(")] # replace any '~' fxn_name = fxn_name.replace("~", "DTOR{}_".format(num_dtors)) # remove any < and > fxn_name = fxn_name.replace("<", "") fxn_name = fxn_name.replace(">", "") if fxn_name in list(fxn_name_dict.keys()): fxn_name_dict[fxn_name] += 1 fxn_name += "_{}".format(fxn_name_dict[fxn_name]) else: fxn_name_dict[fxn_name] = -1 if "DTOR" in fxn_name: num_dtors += 1 curfield = "" if fxn_name == "___cxa_pure_virtual": # struct_fields.append("\tvoid __noreturn (__cdecl *___cxa_pure_virtual{})({});".format(num_virts, # fxn_args)) curfield = "\tvoid __noreturn (__cdecl *___cxa_pure_virtual{})({});".format( num_virts, fxn_args) num_virts += 1 else: # struct_fields.append("\t{} ({} *{})({});".format(fxn_return_type, # fxn_call_conv, fxn_name, fxn_args)) curfield = "\t{} ({} *{})({});".format(fxn_return_type, fxn_call_conv, fxn_name, fxn_args) svt.add(curfield) ea += 8 # return # Some classes won't have xrefs to OSMetaClass::OSMetaClass, # like OSMetaClassBase if class_name in ih_dict: ih_dict[class_name].ioc = ioc # Just write forward decls for now for decl in fwd_decls: struct_file.write("struct __cppobj {};\n".format(decl)) struct_file.write("\n") # cnt += 1 # if cnt == 5: # break print("{} IOKit vtables".format(len(vtables))) # Now create the header file to import into IDA # for ih in ihs: # dump_ih(ih, 0) generate_header_file(struct_file, ihs) # fixup_header_file(struct_file) struct_file.close()
def update_func_name_with_class(func_ea, class_name): name = ida_name.get_ea_name(func_ea) if name.startswith("sub_"): new_name = class_name + VTABLE_DELIMITER + name return utils.set_func_name(func_ea, new_name), True return name, False
def lvar_type_changed(self, vu, v, tif): if (vu.cfunc): func_tif = ida_typeinf.tinfo_t() vu.cfunc.get_func_type(func_tif) funcdata = idaapi.func_type_data_t() got_data = func_tif.get_func_details(funcdata) if (not got_data): # self._log("Didnt get the data") pass lvars = vu.cfunc.get_lvars() for j in range(len(vu.cfunc.argidx)): # for i in vu.cfunc.argidx: i = vu.cfunc.argidx[j] if (lvars[i].name == v.name): #self._log("lvar_type_changed: function argument changed = %s, index = %s, atype = %s" % (lvars[i].name, i, funcdata[j].argloc.atype())) if (funcdata[i].argloc.atype() == 3): # self._log("lvar_type_changed: reg is : %s" %(funcdata[i].argloc.reg1())) pass if (funcdata[i].argloc.atype() != 3 or funcdata[i].argloc.reg1() != RCX_REG): break #self._log("applyName = %s" % (applyName)) firstPtrRemove = ida_typeinf.remove_pointer(tif) #self._log("type name = %s" % (firstPtrRemove._print())) #self._log("remove_pointer.is_ptr = %s" % (firstPtrRemove.is_ptr())) #self._log("remove_pointer.is_struct = %s" % (firstPtrRemove.is_struct())) if (firstPtrRemove.is_struct() and not firstPtrRemove.is_ptr()): currentFuncName = ida_name.get_ea_name( vu.cfunc.entry_ea) # self._log("before demangle current func name = %s" % (currentFuncName)) demangled = idc.demangle_name( currentFuncName, idc.get_inf_attr(idc.INF_SHORT_DN)) if (demangled != None): self._log("Overriding mangled name = %s" % (currentFuncName)) currentFuncName = demangled # self._log("after demangle current func name = %s" % (currentFuncName)) tokens = currentFuncName.split("::") if len(tokens) > 1: currentFuncName = tokens[1] currentFuncName = currentFuncName.split("(")[0] # self._log("current func name = %s" % (currentFuncName)) idc.set_name( vu.cfunc.entry_ea, firstPtrRemove._print() + "::" + currentFuncName, idc.SN_NOWARN) idaapi.auto_wait() # self._log("Decomp Res : %s" % idaapi.decompile(vu.cfunc.entry_ea)) idaapi.refresh_idaview_anyway() vu.refresh_ctext() idaapi.refresh_idaview_anyway() vu.refresh_ctext() vu.refresh_view(True) current_widget = idaapi.get_current_widget() vu1 = idaapi.get_widget_vdui(current_widget) if vu1: vu1.refresh_ctext() break #self._log("lvar_type_changed: vu=%s, v=%s, tinfo=%s" % (vu, self._format_lvar(v), tif._print())) return 1