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
Beispiel #2
0
    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()
Beispiel #3
0
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)
Beispiel #5
0
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)
Beispiel #6
0
    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()
Beispiel #7
0
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))
Beispiel #10
0
                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
Beispiel #11
0
    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
Beispiel #12
0
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)