def test_demangle_ms(self): tests = ("??_V@YAPAXI@Z", "??_U@YAPAXI@Z") results = ("void* __cdecl operator delete[](uint32_t)", "void* __cdecl operator new[](uint32_t)") for i, test in enumerate(tests): t, n = demangle_ms(Architecture['x86'], test) self.get_type_string(t, n) == results[i]
def get_vtable_name(view, name): if name[:3] in [ '?AU', '?AV' ]: # demangle_ms doesn't support flags (UNDNAME_32_BIT_DECODE | UNDNAME_NAME_ONLY | UNDNAME_NO_ARGUMENTS | UNDNAME_NO_MS_KEYWORDS) demangle_type, demangle_name = demangle.demangle_ms(view.arch, '??_7{0}6B@'.format(name[3:])) if demangle_type is not None: return demangle.get_qualified_name(demangle_name) return 'vtable_{0}'.format(name)
def test_demangle_ms(self): tests = ("??_V@YAPAXI@Z", "??_U@YAPAXI@Z") oracle = ("void* __cdecl operator delete[](uint32_t)", "void* __cdecl operator new[](uint32_t)") for i, test in enumerate(tests): t, n = demangle_ms(Architecture['x86'], test) result = self.get_type_string(t, n) assert result == oracle[ i], f"oracle: {oracle[i]}\nresult: {result}"
def process_msvc_func(func): view = func.view arch = func.arch symbol = func.symbol mangled_name = symbol.raw_name if mangled_name.startswith('??_7') and not mangled_name.endswith( '@@6B@'): # Skip buggy vtables return sym_type, sym_parts = demangle_ms(arch, mangled_name) if (sym_type is None) or (sym_type.type_class != TypeClass.FunctionTypeClass): return if isinstance(sym_parts, str): return params = [ v.type for v in sym_type.parameters if v.type.type_class != TypeClass.VoidTypeClass ] return_type = sym_type.return_value tokens_before = [str(v) for v in sym_type.get_tokens_before_name()] convention = 'cdecl' if '__cdecl' in tokens_before: convention = 'cdecl' elif '__stdcall' in tokens_before: convention = 'stdcall' elif '__thiscall' in tokens_before: convention = 'thiscall' if (convention == 'thiscall') and len(sym_parts) >= 2: if 'static' not in tokens_before: type_name = '::'.join(sym_parts[:-1]) this_type = Type.pointer( arch, Type.named_type( NamedTypeReference( NamedTypeReferenceClass.StructNamedTypeClass, name=type_name))) params.insert(0, this_type) func.function_type = Type.function(return_type, params, arch.calling_conventions[convention], sym_type.has_variable_arguments)
def fix_mangled_symbols(thread, view): for sym in view.symbols.values(): if thread.cancelled: break if not isinstance(sym, Symbol): continue if sym.short_name.startswith('?') and not sym.raw_name.startswith('?'): demangled_type, demangled_name = demangle_ms( view.arch, sym.short_name) if demangled_type is not None: new_symbol = Symbol( sym.type, sym.address, short_name=get_qualified_name(demangled_name), full_name=get_qualified_name(demangled_name), raw_name=sym.short_name, binding=sym.binding, namespace=sym.namespace, ordinal=sym.ordinal) view.undefine_user_symbol(sym) view.define_user_symbol(new_symbol) view.define_user_data_var(new_symbol.address, demangled_type) sym = new_symbol # Create vtables if 'vftable\'' in sym.full_name: create_vtable(view, None, sym.address) # Create strings if sym.raw_name.startswith('??_C@_'): view.undefine_user_symbol(sym) ascii_string = view.get_ascii_string_at(sym.address) if (ascii_string is not None) and (ascii_string.start == sym.address): view.define_user_data_var( sym.address, Type.array(Type.char(), ascii_string.length)) for func in view.functions: if thread.cancelled: break process_msvc_func(func)
def load_map_file(thread, view, filename): lines = open(filename, 'r').readlines() symbols = parse_map_file(lines) arch = view.arch for name, addr in symbols: if not view.is_valid_offset(addr): continue current_sym = view.get_symbol_at(addr) if current_sym is not None: if not current_sym.auto: continue if current_sym.type not in [ SymbolType.DataSymbol, SymbolType.FunctionSymbol ]: continue view.undefine_user_symbol(current_sym) sym_type, sym_parts = demangle_ms(arch, name) if sym_type is None: sym_type = Type.void() if isinstance(sym_parts, str): sym_parts = [sym_parts] sym_name = '::'.join(sym_parts) if view.is_offset_executable(addr): view.create_user_function(addr) view.define_user_symbol( Symbol(SymbolType.FunctionSymbol, addr, sym_name, raw_name=name)) else: view.define_data_var(addr, sym_type) view.define_user_symbol( Symbol(SymbolType.DataSymbol, addr, sym_name, raw_name=name)) fix_mangled_symbols(thread, view)
def demangle_name(bv, name, max_size=64): res = name if bv.platform.name.startswith("linux-") or bv.platform.name.startswith( "mac-"): _, demangled = demangle.demangle_gnu3(bv.arch, name) if not isinstance(demangled, list): res = demangled else: res = demangle.simplify_name_to_string( demangle.get_qualified_name(demangled)) elif bv.platform.name.startswith("windows-"): _, demangled = demangle.demangle_ms(bv.arch, name) if not isinstance(demangled, list): res = demangled else: res = demangle.simplify_name_to_string( demangle.get_qualified_name(demangled)) if len(res) > max_size: res = res[:max_size // 2 - 3] + "..." + res[-max_size // 2:] return res
def process_msvc_func(func): arch = func.arch plat = func.platform sym_type, sym_parts = demangle_ms(arch, func.symbol.raw_name) if (sym_type is None) or (sym_type.type_class != TypeClass.FunctionTypeClass): return if isinstance(sym_parts, str): return params = [ v.type for v in sym_type.parameters if v.type.type_class != TypeClass.VoidTypeClass ] return_type = sym_type.return_value tokens_before = [str(v) for v in sym_type.get_tokens_before_name()] is_member = ('public:' in tokens_before) or ( 'protected:' in tokens_before) or ('private:' in tokens_before) is_static = 'static' in tokens_before is_virtual = 'virtual' in tokens_before convention = plat.default_calling_convention if '__cdecl' in tokens_before: convention = plat.cdecl_calling_convention elif '__stdcall' in tokens_before: convention = plat.stdcall_calling_convention elif '__fastcall' in tokens_before: convention = plat.fastcall_calling_convention elif '__thiscall' in tokens_before: convention = arch.calling_conventions['thiscall'] if return_type.type_class == TypeClass.NamedTypeReferenceClass and return_type.named_type_reference.type_class in { NamedTypeReferenceClass.ClassNamedTypeClass, NamedTypeReferenceClass.StructNamedTypeClass, NamedTypeReferenceClass.UnionNamedTypeClass }: # TODO: This should only added for large/non trivial types return_type = Type.pointer(arch, return_type) params.insert(0, FunctionParameter(return_type, name="retptr")) if len(sym_parts) >= 2 and (is_member or is_virtual) and not is_static: type_name = '::'.join(sym_parts[:-1]) this_type = Type.pointer( arch, Type.named_type( NamedTypeReference( NamedTypeReferenceClass.StructNamedTypeClass, name=type_name))) params.insert(0, FunctionParameter(this_type, name="this")) if (sym_parts[-1] == sym_parts[-2]) and (return_type.type_class == TypeClass.VoidTypeClass): return_type = this_type func_type = Type.function(return_type, params, convention, sym_type.has_variable_arguments) func.function_type = func_type