def init(self): user_choice = get_choice_input("Select MCU family", "MCU selection", self.MCUS) if user_choice is not None: chosen_mcu = self.MCUS[user_choice] mcu_lib = importlib.import_module("binaryninja_cortex.platforms." + chosen_mcu) mcu = mcu_lib.Chip else: mcu_lib = importlib.import_module("binaryninja_cortex.platforms") mcu = mcu_lib.MCU #Add RAM segment self.add_auto_segment( mcu.RAM_OFF, 0xffff, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) # Add peripherals segment self.add_auto_segment( mcu.PERIPH_OFF, 0x10000000, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable) #Add flash segment, assume flash < 2MB self.add_auto_segment( mcu.ROM_OFF, 0x200000, 0, 0x200000, SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) #Add IVT symbols #SP_VALUE is a data pointer self.define_auto_symbol_and_var_or_function( Symbol(SymbolType.DataSymbol, mcu.ROM_OFF, mcu.IRQ[0]), Type.pointer(self.arch, Type.void(), const=True), self.platform) addr = struct.unpack("<I", self.parent_view.read(0, 4))[0] self.define_auto_symbol( Symbol(SymbolType.DataSymbol, addr, "p_{}".format(mcu.IRQ[0]))) #All other vectory are function pointers for i in range(1, len(mcu.IRQ)): self.define_auto_symbol_and_var_or_function( Symbol(SymbolType.DataSymbol, mcu.ROM_OFF + (4 * i), mcu.IRQ[i]), Type.pointer(self.arch, Type.void(), const=True), self.platform) addr = struct.unpack("<I", self.parent_view.read(4 * i, 4))[0] & ~1 self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, addr, "f_{}".format(mcu.IRQ[i]))) self.add_function(addr, self.platform) #Add entry point to RESET_IRQ self.add_entry_point(self.symbols['f_RESET_IRQ'].address, self.platform) return True
def import_selected(self): selected_type_indexes: List[ QtCore.QModelIndex] = self.types_table.selectedIndexes() selected = set(i.row() for i in selected_type_indexes) for row in selected: name, type_ = self.types_table.model().types[row] self.view.define_user_type(name, type_) selected_object_indexes: List[ QtCore.QModelIndex] = self.objects_table.selectedIndexes() selected = set(i.row() for i in selected_object_indexes) for row in selected: name, type_ = self.objects_table.model().types[row] symbol = next( (s for s in self.view.get_symbols_by_name(str(name)) if s.type in (SymbolType.ImportAddressSymbol, SymbolType.ImportedDataSymbol)), None, ) if symbol is None: log.log_warn(f"Could not find symbol `{name}` in the binary!") continue ptr_type = Type.pointer(self.view.arch, type_) self.view.define_user_data_var(symbol.address, ptr_type) self.view.update_analysis()
def set_symbol_type(bv, sym, type): """ Re-type symbol to given type """ func = bv.get_function_at(sym.address) if func: func.set_user_type(type) return dvar = bv.get_data_var_at(sym.address) if dvar: bv.undefine_data_var(dvar.address) bv.define_user_data_var(dvar.address, Type.pointer(bv.arch, type)) return
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 find_dynamically_linked_funcs(bv): platform_info = get_platform_info(bv) funcs_to_check = set() for lookup in platform_info["sym_lookups"]: for ref in bv.get_code_refs(lookup): ref.function.analysis_skip_override = FunctionAnalysisSkipOverride.NeverSkipFunctionAnalysis funcs_to_check.add(ref.function) bv.update_analysis() time.sleep(1) for f in funcs_to_check: mlil_ssa = f.medium_level_il.ssa_form for call in find_mlil_calls_to_targets(mlil_ssa, platform_info["sym_lookups"]): if len(call.params) < 2 or len(call.output.vars_written) < 1: continue symbol_name_addr = call.params[1].value if symbol_name_addr.type not in [ RegisterValueType.ConstantPointerValue, RegisterValueType.ConstantValue ]: continue output_var = call.output.vars_written[0] symbol_name = bv.get_ascii_string_at(symbol_name_addr.value).value #Add confidence to both the args and the return of zero symbol_type = Type.pointer(bv.arch, bv.parse_type_string("void foo()")[0]) if len(symbol_name) == 0: continue bv.define_user_data_var(symbol_name_addr.value, Type.array(Type.int(1), len(symbol_name))) output_name = symbol_name + "@DYN" f.create_user_var(output_var.var, symbol_type, output_name) propagate_var_name(f, mlil_ssa, output_var, output_name, symbol_type)
def import_all(self): self.view.add_type_library(self.lib) for name, type_ in self.lib.named_types.items(): self.view.define_user_type(name, type_) for name, type_ in self.lib.named_objects.items(): symbol = next( (s for s in self.view.get_symbols_by_name(str(name)) if s.type in (SymbolType.ImportAddressSymbol, SymbolType.ImportedDataSymbol)), None, ) if symbol is None: continue ptr_type = Type.pointer(self.view.arch, type_) self.view.define_user_data_var(symbol.address, ptr_type) self.view.update_analysis()
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
def ty_from_demangler_node(node, cv_qual=frozenset(), arg_count_hint=None): if node.kind == 'builtin': if node.value in ty_for_cxx_builtin: return ty_for_cxx_builtin[node.value] else: return None elif node.kind in ['name', 'qual_name']: named_ty_ref = NamedTypeReference(name=str(node)) return Type.named_type(named_ty_ref) elif node.kind in ['pointer', 'lvalue', 'rvalue']: pointee_ty = ty_from_demangler_node(node.value) if pointee_ty is None: return None is_const = ('const' in cv_qual) is_volatile = ('volatile' in cv_qual) if node.kind == 'pointer': return Type.pointer(arch, pointee_ty, is_const, is_volatile) elif node.kind == 'lvalue': return Type.pointer( arch, pointee_ty, is_const, is_volatile, ref_type=ReferenceType.ReferenceReferenceType) elif node.kind == 'rvalue': return Type.pointer(arch, pointee_ty, is_const, is_volatile, ref_type=ReferenceType.RValueReferenceType) elif node.kind == 'cv_qual': return ty_from_demangler_node(node.value, cv_qual=node.qual) elif node.kind == 'func': is_ctor_dtor = False if node.name and node.name.kind == 'qual_name': qual_name = node.name.value if qual_name[-1].kind in ['ctor', 'dtor']: is_ctor_dtor = True if is_ctor_dtor: ret_ty = Type.void() elif node.ret_ty is not None: ret_ty = ty_from_demangler_node(node.ret_ty) if ret_ty is None: return None else: ret_ty = Type.int(arch.default_int_size).with_confidence(0) arg_nodes = list(node.arg_tys) arg_tys = [] var_arg = False if arg_nodes[-1].kind == 'builtin' and arg_nodes[-1].value == '...': arg_nodes.pop() var_arg = True elif arg_nodes[0].kind == 'builtin' and arg_nodes[ 0].value == 'void': arg_nodes = arg_nodes[1:] this_arg = False if node.name and node.name.kind == 'qual_name': qual_name = node.name.value if is_ctor_dtor or (arg_count_hint is not None and len(arg_nodes) == arg_count_hint - 1): this_arg = True this_node = Node('qual_name', qual_name[:-1]) this_ty = ty_from_demangler_node(this_node) if this_ty is None: return None arg_tys.append(Type.pointer(arch, this_ty)) for arg_node in arg_nodes: arg_ty = ty_from_demangler_node(arg_node) if arg_ty is None: return None arg_tys.append(arg_ty) ty = Type.function(ret_ty, arg_tys, variable_arguments=var_arg) if arg_count_hint is not None: # toplevel invocation, so return whether we inferred a this argument return this_arg, ty else: return ty else: log.log_warn("Cannot convert demangled AST {} to a type".format( repr(node)))
def analyze_cxx_abi(view, start=None, length=None, task=None): platform = view.platform arch = platform.arch void_p_ty = Type.pointer(arch, Type.void()) char_p_ty = Type.pointer(arch, Type.int(1)) unsigned_int_ty = Type.int(arch.default_int_size, False) signed_int_ty = Type.int(arch.default_int_size, True) base_type_info_ty = Type.named_type( NamedTypeReference(name='std::type_info')) base_type_info_ptr_ty = Type.pointer(arch, base_type_info_ty) def char_array_ty(length): return Type.array(Type.int(1), strings[0].length) def type_info_ty(kind=None): type_info_struct = Structure() type_info_struct.append(void_p_ty, 'vtable') type_info_struct.append(char_p_ty, 'name') if kind == 'si_class': type_info_struct.append(base_type_info_ptr_ty, 'base_type') return Type.structure_type(type_info_struct) def vtable_ty(vfunc_count): vtable_struct = Structure() vtable_struct.append(signed_int_ty, 'top_offset') vtable_struct.append(base_type_info_ptr_ty, 'typeinfo') vtable_struct.append(Type.array(void_p_ty, vfunc_count), 'functions') return Type.structure_type(vtable_struct) if platform.name.startswith("windows-"): long_size = arch.default_int_size else: long_size = arch.address_size if arch.name.startswith('x86'): char_signed = True else: char_signed = False # not always true short_size = 2 # not always true long_long_size = 8 # not always true ty_for_cxx_builtin = { 'void': Type.void(), 'wchar_t': Type.int(2, sign=char_signed, altname='wchar_t'), 'bool': Type.bool(), 'char': Type.int(1, sign=char_signed), 'signed char': Type.int(1, sign=True), 'unsigned char': Type.int(1, sign=False), 'short': Type.int(short_size, sign=True), 'unsigned short': Type.int(short_size, sign=False), 'int': Type.int(arch.default_int_size, sign=True), 'unsigned int': Type.int(arch.default_int_size, sign=False), 'long': Type.int(long_size, sign=True), 'unsigned long': Type.int(long_size, sign=False), 'long long': Type.int(long_long_size, sign=True), 'unsigned long long': Type.int(long_long_size, sign=False), '__int128': Type.int(16, sign=True), 'unsigned __int128': Type.int(16, sign=False), 'float': Type.float(4), 'double': Type.float(8), '__float80': Type.float(10), '__float128': Type.float(16), 'char32_t': Type.int(4, sign=char_signed, altname='char32_t'), 'char16_t': Type.int(2, sign=char_signed, altname='char16_t'), } def ty_from_demangler_node(node, cv_qual=frozenset(), arg_count_hint=None): if node.kind == 'builtin': if node.value in ty_for_cxx_builtin: return ty_for_cxx_builtin[node.value] else: return None elif node.kind in ['name', 'qual_name']: named_ty_ref = NamedTypeReference(name=str(node)) return Type.named_type(named_ty_ref) elif node.kind in ['pointer', 'lvalue', 'rvalue']: pointee_ty = ty_from_demangler_node(node.value) if pointee_ty is None: return None is_const = ('const' in cv_qual) is_volatile = ('volatile' in cv_qual) if node.kind == 'pointer': return Type.pointer(arch, pointee_ty, is_const, is_volatile) elif node.kind == 'lvalue': return Type.pointer( arch, pointee_ty, is_const, is_volatile, ref_type=ReferenceType.ReferenceReferenceType) elif node.kind == 'rvalue': return Type.pointer(arch, pointee_ty, is_const, is_volatile, ref_type=ReferenceType.RValueReferenceType) elif node.kind == 'cv_qual': return ty_from_demangler_node(node.value, cv_qual=node.qual) elif node.kind == 'func': is_ctor_dtor = False if node.name and node.name.kind == 'qual_name': qual_name = node.name.value if qual_name[-1].kind in ['ctor', 'dtor']: is_ctor_dtor = True if is_ctor_dtor: ret_ty = Type.void() elif node.ret_ty is not None: ret_ty = ty_from_demangler_node(node.ret_ty) if ret_ty is None: return None else: ret_ty = Type.int(arch.default_int_size).with_confidence(0) arg_nodes = list(node.arg_tys) arg_tys = [] var_arg = False if arg_nodes[-1].kind == 'builtin' and arg_nodes[-1].value == '...': arg_nodes.pop() var_arg = True elif arg_nodes[0].kind == 'builtin' and arg_nodes[ 0].value == 'void': arg_nodes = arg_nodes[1:] this_arg = False if node.name and node.name.kind == 'qual_name': qual_name = node.name.value if is_ctor_dtor or (arg_count_hint is not None and len(arg_nodes) == arg_count_hint - 1): this_arg = True this_node = Node('qual_name', qual_name[:-1]) this_ty = ty_from_demangler_node(this_node) if this_ty is None: return None arg_tys.append(Type.pointer(arch, this_ty)) for arg_node in arg_nodes: arg_ty = ty_from_demangler_node(arg_node) if arg_ty is None: return None arg_tys.append(arg_ty) ty = Type.function(ret_ty, arg_tys, variable_arguments=var_arg) if arg_count_hint is not None: # toplevel invocation, so return whether we inferred a this argument return this_arg, ty else: return ty else: log.log_warn("Cannot convert demangled AST {} to a type".format( repr(node))) reader = BinaryReader(view) def read(size): if size == 4: return reader.read32() elif size == 8: return reader.read64() else: assert False symbols = view.get_symbols(start, length) if task: task.set_total(len(symbols)) mangled_re = re.compile('_?_Z') demangler_failures = 0 for symbol in symbols: if task and not task.advance(): break if not mangled_re.match(symbol.raw_name): continue is_data = (symbol.type == SymbolType.DataSymbol) is_code = (symbol.type in [ SymbolType.FunctionSymbol, SymbolType.ImportedFunctionSymbol ]) raw_name, suffix = symbol.raw_name, '' if '@' in raw_name: match = re.match(r'^(.+?)(@.+)$', raw_name) raw_name, suffix = match.group(1), match.group(2) try: name_ast = parse_mangled(raw_name) if name_ast is None: log.log_warn( "Demangler failed to recognize {}".format(raw_name)) demangler_failures += 1 except NotImplementedError as e: log.log_warn("Demangler feature missing on {}: {}".format( raw_name, str(e))) demangler_failures += 1 if name_ast: if name_ast.kind == 'func': short_name = str(name_ast.name) else: short_name = str(name_ast) symbol = Symbol(symbol.type, symbol.address, short_name=short_name + suffix, full_name=str(name_ast) + suffix, raw_name=symbol.raw_name) else: symbol = Symbol(symbol.type, symbol.address, short_name=symbol.raw_name, full_name=None, raw_name=symbol.raw_name) view.define_auto_symbol(symbol) if name_ast is None: continue elif is_data and name_ast.kind == 'typeinfo_name': strings = view.get_strings(symbol.address, 1) if not strings: continue view.define_data_var(symbol.address, char_array_ty(length)) elif is_data and name_ast.kind == 'typeinfo': reader.offset = symbol.address + arch.address_size * 2 kind = None # heuristic: is this is an abi::__si_class_type_info? base_or_flags = read(arch.default_int_size) base_symbol = view.get_symbol_at(base_or_flags) if base_symbol and base_symbol.raw_name.startswith('_ZTI'): kind = 'si_class' view.define_data_var(symbol.address, type_info_ty(kind)) elif is_data and name_ast.kind == 'vtable': vtable_addr = symbol.address reader.offset = vtable_addr + arch.address_size * 2 while True: vfunc_count = 0 check_next = True while True: vfunc_ptr_symbol = view.get_symbol_at(reader.offset) if vfunc_ptr_symbol and vfunc_ptr_symbol.raw_name.startswith( '_Z'): # any C++ symbol definitely terminates the vtable check_next = False break # heuristic: existing function vfunc_addr = read(arch.address_size) if view.get_function_at(vfunc_addr): vfunc_count += 1 continue # explicitly reject null pointers; in position-independent code # address zero can belong to the executable segment if vfunc_addr == 0: check_next = False break # heuristic: pointer to executable memory vfunc_segment = view.get_segment_at(vfunc_addr) if vfunc_addr != 0 and vfunc_segment and vfunc_segment.executable: view.add_function(vfunc_addr) vfunc_count += 1 log.log_info( 'Discovered function at {:#x} via {}'.format( vfunc_addr, symbol.full_name or symbol.short_name)) changed = True continue # we've fell off the end of the vtable break view.define_data_var(vtable_addr, vtable_ty(vfunc_count)) if check_next: # heuristic: can another vtable follow this one? let's see if it has typeinfo, # since that should be always true for when we have a virtual base typeinfo_ptr = read(arch.address_size) typeinfo_ptr_symbol = view.get_symbol_at(typeinfo_ptr) if typeinfo_ptr_symbol and typeinfo_ptr_symbol.raw_name.startswith( '_ZTI'): vtable_addr = reader.offset - 2 * arch.address_size # documentat it with a symbol secondary_symbol_name = '{}_secondary_{:x}'.format( symbol.short_name, vtable_addr - symbol.address) secondary_symbol = Symbol( SymbolType.DataSymbol, vtable_addr, short_name=secondary_symbol_name) view.define_auto_symbol(secondary_symbol) continue break elif is_code and name_ast.kind == 'func': func = view.get_function_at(symbol.address) demangled = ty_from_demangler_node( name_ast, arg_count_hint=len(func.function_type.parameters)) if demangled is not None: this_arg, ty = demangled func.apply_auto_discovered_type(ty) view.update_analysis() if demangler_failures: log.log_warn('{} demangler failures'.format(demangler_failures))
if view.address_size == 4 else br.read16() if view.address_size == 2 else br.read8() ) # If this field is pointing at a symbol, let's rename the field to be that symbol if ptr_symbol := view.get_symbol_at(ptr): field_name = simplify_name_to_string(ptr_symbol.short_name).split("::")[ -1 ] # If this field points to a function, we should make a function pointer for that # function. This is very useful for C++ vtables and other function tables. if function := view.get_function_at(ptr): type_ = Type.pointer(function.arch, function.function_type) # If this field points to a data variable, we should make a pointer to that type. elif ptr_dv := view.get_data_var_at(ptr): type_ = Type.pointer(view.arch, ptr_dv.type) # Determine if this structure should be packed based on the alignment of the field. if offset % type_.width != 0: structure.packed = True structure.insert(offset, type_, field_name) if (dv := view.get_next_data_var_after(dv.address)) is None: break offset = dv.address - start
def init(self): self.log(f'Loading {self.name} {self.app_name}') self.raw = b'' self.platform = Architecture[self.ARCH].standalone_platform self.reader.seek(self.HDR_SIZE + 4) mod_offset = self.reader.read32() mod_file_offset = self.HDR_SIZE + mod_offset offset = self.HDR_SIZE self.make_segment('.text', self.base + self.text_offset, offset, self.text_size) offset += self.text_size self.make_segment('.rodata', self.base + self.rodata_offset, offset, self.rodata_size) offset += self.rodata_size self.make_segment('.data', self.base + self.data_offset, offset, self.data_size) offset += self.data_size self.reader.seek(mod_file_offset) if self.reader.read(4) != b'MOD0': self.log(f'MOD0(@ {hex(mod_offset)}) Magic invalid') else: self.log('Parsing MOD0') self.dynamic_offset = mod_offset + self.up_signed( self.reader.read(4), 4) dynamic_file_offset = self.HDR_SIZE + self.dynamic_offset if self.bss_offset == 0: self.bss_offset = mod_offset + self.up_signed( self.reader.read(4), 4) dynamic_size = self.bss_offset - self.dynamic_offset if self.bss_size == 0: bss_end = mod_offset + self.up_signed(self.reader.read(4), 4) self.bss_size = bss_end - self.bss_offset self.reader.seek(mod_file_offset + 0x10) self.eh_frame_hdr_start = mod_offset + self.up_signed( self.reader.read(4), 4) eh_frame_hdr_end = mod_offset + self.up_signed( self.reader.read(4), 4) self.eh_frame_hdr_size = eh_frame_hdr_end - self.eh_frame_hdr_start self.module_offset = mod_offset + self.up_signed( self.reader.read(4), 4) libnx = False if self.reader.read(4) == b'LNY0': libnx = True libnx_got_start = mod_offset + self.up_signed( self.reader.read(4), 4) libnx_got_end = mod_offset + self.up_signed( self.reader.read(4), 4) self.make_section('.got', self.base + libnx_got_start, libnx_got_end - libnx_got_start) self.reader.seek(dynamic_file_offset) tag1 = self.reader.read64() self.reader.seek(dynamic_file_offset + 0x10) tag2 = self.reader.read64() self.reader.seek(dynamic_file_offset) self.armv7 = tag1 > 0xFFFFFFFF or tag2 > 0xFFFFFFFF offset_size = 4 if self.armv7 else 8 self.reader.seek(dynamic_file_offset) self.dynamic = {x: [] for x in MULTIPLE_DTS} for index in range(dynamic_size // 0x10): if self.armv7: tag = self.reader.read32() val = self.reader.read32() else: tag = self.reader.read64() val = self.reader.read64() if tag == DT_NULL: break if tag in MULTIPLE_DTS: self.dynamic[tag].append(val) else: self.dynamic[tag] = val self.make_section('.dynamic', self.base + self.dynamic_offset, dynamic_size) if DT_STRTAB in self.dynamic and DT_STRSZ in self.dynamic: self.log("Reading .dynstr") self.reader.seek(self.HDR_SIZE + self.dynamic[DT_STRTAB]) self.dynstr = self.reader.read(self.dynamic[DT_STRSZ]) for start_key, size_key, name in [ (DT_STRTAB, DT_STRSZ, '.dynstr'), (DT_INIT_ARRAY, DT_INIT_ARRAYSZ, '.init_array'), (DT_FINI_ARRAY, DT_FINI_ARRAYSZ, '.fini_array'), (DT_RELA, DT_RELASZ, '.rela.dyn'), (DT_REL, DT_RELSZ, '.rel.dyn'), (DT_JMPREL, DT_PLTRELSZ, ('.rel.plt' if self.armv7 else '.rela.plt')), ]: if start_key in self.dynamic and size_key in self.dynamic: self.make_section(name, self.base + self.dynamic[start_key], self.dynamic[size_key]) needed = [self.get_dynstr(i) for i in self.dynamic[DT_NEEDED]] self.syms = [ ] # symbols, symbols is already an attribute for BinaryView if DT_SYMTAB in self.dynamic and DT_STRTAB in self.dynamic: self.reader.seek(self.HDR_SIZE + self.dynamic[DT_SYMTAB]) while True: if self.dynamic[DT_SYMTAB] < self.dynamic[ DT_STRTAB] and self.reader.offset - self.HDR_SIZE >= self.dynamic[ DT_STRTAB]: break if self.armv7: st_name = self.reader.read32() st_value = self.reader.read32() st_size = self.reader.read32() st_info = self.reader.read8() st_other = self.reader.read8() st_shndx = self.reader.read16() else: st_name = self.reader.read32() st_info = self.reader.read8() st_other = self.reader.read8() st_shndx = self.reader.read16() st_value = self.reader.read64() st_size = self.reader.read64() if st_name > len(self.dynstr): break self.syms.append( ElfSym(self.get_dynstr(st_name), st_info, st_other, st_shndx, st_value, st_size)) self.make_section('.dynsym', self.base + self.dynamic[DT_SYMTAB], (self.reader.offset - self.HDR_SIZE) - self.dynamic[DT_SYMTAB]) locations = set() plt_got_end = None if DT_REL in self.dynamic and DT_RELSZ in self.dynamic: locations |= self.process_relocations(self.dynamic[DT_REL], self.dynamic[DT_RELSZ]) if DT_RELA in self.dynamic and DT_RELASZ in self.dynamic: locations |= self.process_relocations(self.dynamic[DT_RELA], self.dynamic[DT_RELASZ]) if DT_JMPREL in self.dynamic and DT_PLTRELSZ in self.dynamic: plt_locations = self.process_relocations( self.dynamic[DT_JMPREL], self.dynamic[DT_PLTRELSZ]) locations |= plt_locations plt_got_start = min(plt_locations) plt_got_end = max(plt_locations) + offset_size if DT_PLTGOT in self.dynamic: self.make_section('.got.plt', self.base + self.dynamic[DT_PLTGOT], plt_got_end - plt_got_start) if not self.armv7: self.reader.seek(self.HDR_SIZE) text = self.reader.read(self.text_size) last = 12 while True: # This block was straight copy pasted from https://github.com/reswitched/loaders/blob/30a2f1f1d6c997a46cc4225c1f443c19d21fc66c/nxo64.py#L406 pos = text.find(pack('<I', 0xD61F0220), last) if pos == -1: break last = pos + 1 if (pos % 4) != 0: continue off = pos - 12 a, b, c, d = unpack_from('<IIII', text, off) if d == 0xD61F0220 and ( a & 0x9f00001f) == 0x90000010 and ( b & 0xffe003ff) == 0xf9400211: base = off & ~0xFFF immhi = (a >> 5) & 0x7ffff immlo = (a >> 29) & 3 paddr = base + ((immlo << 12) | (immhi << 14)) poff = ((b >> 10) & 0xfff) << 3 target = paddr + poff if plt_got_start <= target < plt_got_end: self.plt_entries.append((off, target)) text = b'' plt_start = min(self.plt_entries)[0] plt_end = max(self.plt_entries)[0] + 0x10 self.make_section('.plt', self.base + plt_start, plt_end - plt_start) if not libnx: if plt_got_end is not None: got_ok = False got_end = plt_got_end + offset_size while got_end in locations and ( DT_INIT_ARRAY not in self.dynamic or got_end < self.dynamic[DT_INIT_ARRAY]): got_ok = True got_end += offset_size if got_ok: self.make_section('.got', self.base + plt_got_end, got_end - plt_got_end) else: plt_got_start = 0 plt_got_end = 0 self.bss_offset = self.bss_offset self.bss_size = self.page_align_up(self.bss_size) self.make_segment('.bss', self.base + self.bss_offset, 0, self.bss_size, empty=True) undefined_count = 0 for sym in self.syms: if not sym.shndx and sym.name: undefined_count += 1 last_ea = max([self.base + seg.end for seg in self.segments]) undef_ea = self.page_align_up(last_ea) + 8 undef_offset = self.base + plt_got_start for idx, symbol in enumerate(self.syms): if symbol.name: symbol.resolved = self.base + symbol.value decoded_type, decoded_name = self.try_unmangle(symbol.name) if symbol.shndx: if symbol.type == STT_FUNC: self.create_user_function(symbol.resolved) self.define_user_symbol( Symbol(SymbolType.FunctionSymbol, symbol.resolved, decoded_name)) if decoded_type is not None: self.get_function_at( symbol.resolved).set_user_type(decoded_type) else: if decoded_type is not None: self.define_data_var(symbol.resolved, decoded_type) self.define_user_symbol( Symbol(SymbolType.DataSymbol, symbol.resolved, decoded_name)) else: self.define_user_symbol( Symbol(SymbolType.ImportedFunctionSymbol, undef_ea, decoded_name)) undef_ea += offset_size got_name_lookup = {} for offset, r_type, symbol, addend in self.relocations: target = self.base + offset if symbol != None: decoded_type, decoded_name = self.try_unmangle(symbol.name) if decoded_type != None: self.define_data_var( target, Type.pointer(Architecture[self.ARCH], decoded_type)) self.define_auto_symbol( Symbol(SymbolType.DataSymbol, target, decoded_name)) else: decoded_type = decoded_name = None packed = None offset_raw = None if r_type in [R_ARM_GLOB_DAT, R_ARM_JUMP_SLOT, R_ARM_ABS32]: if symbol: offset_raw = symbol.resolved packed = pack(LE + UNSIGNED_SIZE_MAP[4], offset_raw) elif r_type == R_ARM_RELATIVE: self.reader.seek(target) offset_raw = self.base + self.reader.read32() packed = pack(LE + UNSIGNED_SIZE_MAP[4], offset_raw) elif r_type in [ R_AARCH64_GLOB_DAT, R_AARCH64_JUMP_SLOT, R_AARCH64_ABS64 ]: offset_raw = symbol.resolved + addend packed = pack(LE + UNSIGNED_SIZE_MAP[8], offset_raw) if addend == 0: got_name_lookup[offset] = symbol.name elif r_type == R_AARCH64_RELATIVE: offset_raw = self.base + addend packed = pack(LE + UNSIGNED_SIZE_MAP[8], offset_raw) if packed is not None: if offset_raw != self.base and offset_raw != self.base + 0x10 and offset_raw < self.base + self.text_offset + self.text_size: self.create_user_function(offset_raw) if decoded_type is not None: self.get_function_at(offset_raw).set_user_type( decoded_type) self.write(target, packed) for func, target in self.plt_entries: if target in got_name_lookup: addr = self.base + func decoded_type, decoded_name = self.try_unmangle( got_name_lookup[target]) self.define_user_symbol( Symbol(SymbolType.ImportedFunctionSymbol, addr, decoded_name)) # Try to find entrypoint if not already set if self.entrypoint == 0: for sym in self.syms: if sym.name == b'_init': self.entrypoint = sym.resolved break if self.entrypoint != 0: self.add_entry_point(self.entrypoint) return True
typelib.add_named_type('MyVoidType', Type.void()) # example: BoolTypeClass typelib.add_named_type('MyBoolType', Type.bool()) # example: IntegerTypeClass typelib.add_named_type('MyCharType', Type.char()) typelib.add_named_type('MyIntType', Type.int(4, True)) typelib.add_named_type('MyUnsignedIntType', Type.int(4, False)) # example: FloatTypeClass typelib.add_named_type('MyFloatType', Type.float(4)) # example: PointerTypeClass # char * typelib.add_named_type('MyPointerType', Type.pointer(arch, Type.char())) # example of typedef to primitive type # typedef int MyTypedefType; typelib.add_named_type('MyTypedefType', Type.int(4)) # example of typedef to typedef # typedef MyTypedefType MySuperSpecialType; def create_named_type_reference(type_name: str, to_what: NamedTypeReferenceClass): return NamedTypeReferenceType.create(named_type_class=to_what, guid=None, name=type_name)