Esempio n. 1
0
def add_members(view: BinaryView, structure: StructureBuilder, start: int, length: int):
    offset = 0
    br = BinaryReader(view)

    if (dv := view.get_data_var_at(start)) is None:
        dv = view.get_next_data_var_after(start)
        offset = dv.address - start
Esempio n. 2
0
    def resolve_byte_sig_pattern(self, identifier):
        pattern = []
        for byte in identifier.split(' '):
            if byte == '?':
                pattern.append(byte)
            elif byte != '':
                pattern.append(int(byte, 16))
        br = BinaryReader(self)
        result = 0
        length = len(pattern) - 1
        for function in self.functions:
            br.seek(function.start)

            while self.get_functions_containing(
                    br.offset + length
            ) != None and function in self.get_functions_containing(br.offset +
                                                                    length):
                found = True
                count = 0
                for entry in pattern:
                    byte = br.read8()
                    count += 1
                    if entry != byte and entry != '?':
                        found = False
                        break

                br.offset -= count

                if found:
                    result = br.offset
                    break

                instruction_length = self.get_instruction_length(br.offset)
                #account for unknown or bad instruction
                if instruction_length == 0:
                    break
                br.offset += instruction_length

            if result != 0:
                break
        if result == 0:
            return None
        else:
            return self.get_functions_containing(result)[0].lowest_address
Esempio n. 3
0
    def parse_binary(self):
        br = BinaryReader(self.rawbv)
        br.seek(0)
        binary_bytes = br.read(self.rawbv.end)
        self.bininfo = ELF('thisbinary', binary_bytes)
        self.text_seg = None
        self.text_seg_index = 0
        for s in self.bininfo.segments:
            if s.header.p_type == PT.LOAD and s.header.p_flags & PF.EXEC:
                self.text_seg = s
                break
            self.text_seg_index += 1

        if self.text_seg is None:
            show_message_box('Parse Fail',
                             'Can\'t find text segment of binary!',
                             icon=MessageBoxIcon.ErrorIcon)
            return False

        return True
Esempio n. 4
0
def xor_dec(bv, key, xref_funcs, y_offsets):
    br = BinaryReader(bv)
    bw = BinaryWriter(bv)
    print "Decrypted strings:"
    for xref in xref_funcs[0]:
        # print xref.function, hex(xref.address)
        il = xref.function.get_low_level_il_at(xref.address).medium_level_il
        if (il.operation == MediumLevelILOperation.MLIL_CALL):
            enc_str = il.params[0].value.value
            str_size = il.params[1].value.value
            diff = il.params[2].value.value
            dec_str = ''
            br.seek(enc_str)
            bw.seek(enc_str)
            for i in xrange(str_size):
                enc_byte = br.read8()
                x = ((enc_byte - diff) ^ key) + diff
                dec_str = dec_str + chr(x)
                # Patch binary
                bw.write8(x)
Esempio n. 5
0
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))
Esempio n. 6
0
class GenericBinary(BinaryView):
    MAGIC = b''
    HDR_SIZE = 0
    ARCH = 'aarch64'
    TEXT = 0
    RODATA = 1
    DATA = 2
    BSS = 3
    app_name = ''
    base = 0
    bss_offset = 0
    bss_size = 0
    data_offset = 0
    data_size = 0
    dynamic = {}
    dynamic_offset = 0
    dynstr = b'\x00'
    entrypoint = 0
    eh_frame_hdr_size = 0
    eh_frame_hdr_start = 0
    hdr = b''
    hdr_read_offset = 0
    plt_entries = []
    reader = BinaryReader
    relocations = []
    rodata_offset = 0
    rodata_size = 0
    text_offset = 0
    text_size = 0
    writer = BinaryWriter

    def log(self, msg, error=False):
        msg = f'[Switch-Binja-Loader] {msg}'
        if not error:
            log_info(msg)
        else:
            log_error(msg)

    # Common Constructor
    def __init__(self, data):
        self.raw = data
        self.reader = BinaryReader(data, Endianness.LittleEndian)
        self.writer = BinaryWriter(data, Endianness.LittleEndian)

    @classmethod
    def is_valid_for_data(cls, data):
        return data.read(0, 4) == cls.MAGIC

    def page_align_up(self, value):
        return (value + 0xfff) // 0x1000 * 0x1000

    def page_align_down(self, value):
        return value // 0x1000 * 0x1000

    def page_pad(self, binary):
        return binary + b'\x00' * (self.page_align_up(len(binary)) -
                                   len(binary))

    def up_signed(self, val, size):
        return unpack(LE + SIGNED_SIZE_MAP[size], val)[0]

    def make_section(self, name, offset, size):
        FLAGS = {
            '.text': SectionSemantics.ReadOnlyCodeSectionSemantics,
            '.rodata': SectionSemantics.ReadOnlyDataSectionSemantics
        }
        self.log(
            f"Making section {name} {hex(offset)}-{hex(offset + size)} (len: {hex(size)})"
        )
        self.add_user_section(
            name, offset, size, FLAGS[name] if name in FLAGS else
            SectionSemantics.ReadWriteDataSectionSemantics)

    def make_segment(self,
                     name,
                     memory_offset,
                     file_offset,
                     size,
                     empty=False):
        FLAGS = { '.text': SegmentFlag.SegmentExecutable | SegmentFlag.SegmentReadable, '.rodata': SegmentFlag.SegmentReadable, \
                  '.data': SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable, '.bss': SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable }
        self.add_user_segment(memory_offset, size, file_offset,
                              size if not empty else 0, FLAGS[name])
        self.make_section(name, memory_offset, size)

    def get_dynstr(self, o):
        return self.dynstr[o:self.dynstr.index(b'\x00', o)]

    def process_relocations(self, offset, size):
        locations = set()
        self.reader.seek(self.HDR_SIZE + offset)
        relocation_size = 8 if self.armv7 else 0x18
        for x in range(size // relocation_size):
            if self.armv7:
                offset = self.reader.read32()
                info = self.reader.read32()
                addend = None
                r_type = info & 0xFF
                r_sym = info >> 8
            else:
                offset = self.reader.read64()
                info = self.reader.read64()
                addend = self.up_signed(self.reader.read(8), 8)
                r_type = info & 0xFFFFFFFF
                r_sym = info >> 32

            sym = self.syms[r_sym] if r_sym != 0 else None

            if r_type != R_AARCH64_TLSDESC and r_type != R_ARM_TLS_DESC:
                locations.add(offset)
            self.relocations.append((offset, r_type, sym, addend))
        return locations

    def try_unmangle(self, value):
        if value[:2] != b'_Z':
            return (None, value)

        decoded_name = value.decode('ascii')
        demangled_type, demangled_name = demangle_gnu3(Architecture[self.ARCH],
                                                       decoded_name)
        decoded_name = get_qualified_name(demangled_name)
        return (demangled_type, decoded_name)

    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
Esempio n. 7
0
 def __init__(self, data):
     self.raw = data
     self.reader = BinaryReader(data, Endianness.LittleEndian)
     self.writer = BinaryWriter(data, Endianness.LittleEndian)
Esempio n. 8
0
 def __init__(self, data):
     self.reader = BinaryReader(data, Endianness.LittleEndian)
     BinaryView.__init__(self, parent_view=data, file_metadata=data.file)
     self.data = data