Example #1
0
def define_cfstrings_plugin(view: BinaryView):
    log_debug("define_cfstrings_plugin")

    from_bytes = _get_from_bytes(view)

    cfstring_type = view.get_type_by_name('CFString')
    if cfstring_type is None:
        cfstring_type = view.platform.parse_types_from_source(
            _cfstring_definition).types['CFString']

        view.define_user_type('CFString', cfstring_type)

        wchar_type = view.platform.parse_types_from_source(
            _wchar_definition).types['wchar']

    cfstring = Type.named_type_from_type('CFString', cfstring_type)

    __cfstring = view.get_section_by_name('__cfstring')

    if __cfstring is None:
        return

    buffer = cfstring_type.structure['buffer']
    length = cfstring_type.structure['length']

    for addr in range(__cfstring.start, __cfstring.end, cfstring_type.width):
        view.define_user_data_var(addr, cfstring)

        for xref in view.get_data_refs(addr):
            view.define_user_data_var(xref, Type.pointer(view.arch, cfstring))

        string_pointer = from_bytes(
            view.read(addr + buffer.offset, buffer.type.width))

        string_length = from_bytes(
            view.read(addr + length.offset, length.type.width), ) + 1

        string_section = view.get_sections_at(string_pointer)

        if not string_section:
            return

        if string_section[0].name == '__ustring':
            char_type = wchar_type
        else:
            char_type = Type.char()

        view.define_user_data_var(string_pointer,
                                  Type.array(char_type, string_length))
Example #2
0
    def from_address(cls, address: int, view: BinaryView):
        if address == 0:
            return None

        from_bytes = get_from_bytes(view)

        protocol_list_t_type = view.get_type_by_name('protocol_list_t')

        protocol_list_t = Type.named_type_from_type('protocol_list_t',
                                                    protocol_list_t_type)

        protocol_t = view.get_type_by_name('protocol_t')

        members = get_structure_members(address, protocol_list_t_type, view)

        view.define_user_data_var(address, protocol_list_t)

        protocols = {}
        start = address + protocol_list_t_type.width
        end = start + members['count'] * view.address_size
        step = view.address_size
        for protocol_ptr in range(start, end, step):
            if not view.get_data_var_at(protocol_ptr):
                view.define_user_data_var(protocol_ptr,
                                          Type.pointer(view.arch, protocol_t))
            protocol = Protocol.from_address(
                from_bytes(view.read(protocol_ptr, view.address_size)), view)

            protocols[protocol.name] = protocol

        return cls(address, **members, protocols=protocols)
Example #3
0
def _define_classes(view: BinaryView, class_t: Type):
    __objc_data = view.sections.get('__objc_data')

    if __objc_data is None:
        raise KeyError('This binary has no __objc_data section')

    for addr in range(__objc_data.start, __objc_data.end, class_t.width):
        current_class = Class.from_address(addr, view)

        log_debug(f"Created {current_class}")

    __objc_classrefs = view.sections.get('__objc_classrefs')

    if __objc_classrefs is None:
        raise KeyError('This binary has no __objc_classrefs section')

    for addr in range(__objc_classrefs.start, __objc_classrefs.end,
                      view.address_size):
        view.define_user_data_var(addr, Type.pointer(view.arch, class_t))

        class_addr = int.from_bytes(
            view.read(addr, view.address_size),
            "little" if view.endianness is Endianness.LittleEndian else "big")

        class_ = view.session_data['ClassList'].get(
            class_addr) if class_addr else None

        if class_ is not None:
            log_debug(f"{addr:x} points to {class_!r}")
            view.define_user_symbol(
                Symbol(SymbolType.DataSymbol, addr,
                       f"_OBJC_CLASS_$_{class_.vtable.name}@GOT"))
Example #4
0
def _get_structure_members(address: int, t: Type, view: BinaryView) -> dict:
    from_bytes = _get_from_bytes(view)

    return {
        m.name: from_bytes(view.read(address + m.offset, m.type.width))
        for m in t.structure.members
    }
Example #5
0
 def __init__(self, data: BinaryView):
     actual_data = data.read(0, len(data)).decode('utf8')
     binfile = BinFile()
     binfile.add(actual_data)
     decoded = b''.join(s.data for s in binfile.segments)
     parent = BinaryView.new(data=decoded)
     self.hex_segments = binfile.segments
     BinaryView.__init__(self, file_metadata=data.file, parent_view=parent)
Example #6
0
    def from_address(cls, address: int, class_name: str, view: BinaryView):
        if address == 0:
            return None

        from_bytes = get_from_bytes(view)

        ivar_t_type = view.types['ivar_t']
        ivar_t = Type.named_type_from_type(
            'ivar_t', ivar_t_type
        )

        members = get_structure_members(address, ivar_t_type, view)
        member_dict = {m.name: m for m in ivar_t_type.structure.members}

        # x64 uses uint64_t for offset, but everything else
        # uses uint32_t
        ivar_offset_type = (
            member_dict['offset'].type.target
            if view.arch != Architecture['x86_64']
            else Type.int(8, False)
        )
        ivar_offset_type.const = True

        if view.get_data_var_at(address) is None:
            view.define_user_data_var(address, ivar_t)

        if members['name'] != 0:
            name_string = view.get_ascii_string_at(members['name'], 1)
            if name_string is not None:
                members['name'] = name_string.value
        else:
            members['name'] = ''

        if members['type']:
            type_string = view.get_ascii_string_at(members['type'], 1).value
            members['type'] = _lookup_type(type_string, view)

        if not members['type']:
            members['type'] = Type.pointer(view.arch, Type.void())

        if members['offset']:
            view.define_user_data_var(members['offset'], ivar_offset_type)
            view.define_user_symbol(
                Symbol(
                    SymbolType.DataSymbol,
                    members['offset'],
                    f'{members["name"]}_offset',
                    namespace=class_name
                )
            )
            members['offset'] = from_bytes(
                view.read(members['offset'],
                          member_dict['offset'].type.target.width)
            )
        else:
            members['offset'] = None

        return cls(address, **members)
Example #7
0
def _add_xrefs(view: BinaryView):
    log_debug('_add_xrefs')
    method_t = view.types.get('method_t')
    if method_t is None:
        return

    method_t_struct = method_t.structure

    method_t_name = method_t_struct['name']

    for function in view.functions:
        data_refs = view.get_data_refs(function.start)

        log_debug(f'{function.name}: {data_refs}')

        method_t_list = [
            var
            for var in map(
                view.get_data_var_at,
                (ref for ref in data_refs)
            )
        ]

        log_debug(f'{function.name}: {method_t_list}')

        for method in method_t_list:
            name_ptr = int.from_bytes(
                view.read(method.address + method_t_name.offset, view.address_size),
                "little" if view.endianness == Endianness.LittleEndian else "big"
            )

            for xref in view.get_code_refs(name_ptr):
                xref_mlil = xref.function.get_low_level_il_at(xref.address).mmlil

                if xref_mlil is None:
                    log_debug(f'{xref.address:x}')
                    return

                if xref_mlil.operation == MediumLevelILOperation.MLIL_SET_VAR:
                    call_mlil = next(
                        (use
                        for use in xref_mlil.function.get_ssa_var_uses(xref_mlil.ssa_form.dest)
                        if (use.instr_index > xref_mlil.instr_index and
                            use.il_basic_block == xref_mlil.il_basic_block)),
                        None
                    )
                else:
                    return

                if call_mlil is not None:
                    xref.function.set_user_xref(call_mlil.address, function.start)
Example #8
0
    def get_string(self, bv: BinaryView):
        s = bv.get_string_at(self.const, partial=True)

        if s:
            s = s.value
        else:
            # Get string with size of 3 or less (get_string_at does not return these)
            s = str(bv.read(self.const, 4))
            if "\x00" not in s:
                s = None
            else:
                s = s.split("\x00", 1)[0]
                s = str(s)

        return s
Example #9
0
    def from_address(cls, address: int, view: BinaryView, is_meta=False):
        from .protocol_t import ProtocolList
        if address == 0:
            return None

        elif address in view.session_data['ClassROList']:
            return view.session_data['ClassROList']

        from_bytes = partial(int.from_bytes,
                             byteorder=("little" if view.endianness
                                        == Endianness.LittleEndian else "big"))

        class_ro_t = Type.named_type_from_type('class_ro_t',
                                               view.types['class_ro_t'])

        if view.get_data_var_at(address) is None:
            view.define_user_data_var(address, class_ro_t)

        members = {
            m.name: from_bytes(view.read(address + m.offset, m.type.width))
            for m in view.types['class_ro_t'].structure.members
        }

        members['name'] = (view.get_ascii_string_at(members['name'], 1).value
                           if members['name'] != 0 else '')

        members['ivarLayout'] = (view.get_ascii_string_at(
            members['ivarLayout'], 1).value
                                 if members['ivarLayout'] != 0 else '')

        members['ivars'] = IvarList.from_address(members['ivars'],
                                                 members['name'], view)

        members['baseMethods'] = MethodList.from_address(
            members['baseMethods'], members['name'], view, is_meta)

        members['baseProtocols'] = ProtocolList.from_address(
            members['baseProtocols'], view)

        members['baseProperties'] = PropertyList.from_address(
            members['baseProperties'], view)

        new_class_ro = cls(address, **members)

        view.session_data['ClassROList'][address] = new_class_ro
        return new_class_ro
Example #10
0
def _define_protocols(view: BinaryView):
    __objc_protorefs = view.get_section_by_name('__objc_protorefs')

    if __objc_protorefs is None:
        return

    protocol_t = Type.named_type_from_type('protocol_t',
                                           view.get_type_by_name('protocol_t'))

    for address in range(__objc_protorefs.start, __objc_protorefs.end,
                         view.address_size):
        view.define_user_data_var(address, Type.pointer(view.arch, protocol_t))

        protocol_ptr = int.from_bytes(
            view.read(address, view.address_size),
            "little" if view.endianness is Endianness.LittleEndian else "big")

        new_protocol = Protocol.from_address(protocol_ptr, view)
Example #11
0
def _define_selectors(view: BinaryView):
    __objc_selrefs = view.sections.get('__objc_selrefs')

    if __objc_selrefs is None:
        raise KeyError('This binary has no __objc_selrefs section')

    SEL = view.get_type_by_name('SEL')
    if SEL is None:
        raise TypeError('The SEL type is not defined!')

    for addr in range(__objc_selrefs.start, __objc_selrefs.end, SEL.width):
        view.define_user_data_var(addr, SEL)
        selector = int.from_bytes(view.read(addr, SEL.width), "little")
        if selector != 0:
            name = view.get_ascii_string_at(selector, 3)
            if name is not None:
                view.define_user_data_var(
                    name.start, Type.array(Type.char(), name.length + 1))
Example #12
0
def _define_categories(view: BinaryView):
    __objc_catlist = view.sections.get('__objc_catlist')

    if __objc_catlist is None:
        return

    category_t = Type.named_type_from_type('category_t',
                                           view.types['category_t'])

    for address in range(__objc_catlist.start, __objc_catlist.end,
                         view.address_size):
        view.define_user_data_var(address, Type.pointer(view.arch, category_t))

        category_ptr = int.from_bytes(
            view.read(address, view.address_size),
            "little" if view.endianness is Endianness.LittleEndian else "big")

        new_category = Category.from_address(category_ptr, view)
Example #13
0
    def from_address(cls, address: int, view: BinaryView) -> Protocol:
        if address == 0:
            return None

        from .class_t import Class

        from_bytes = partial(int.from_bytes,
                             byteorder=("little" if view.endianness
                                        == Endianness.LittleEndian else "big"))

        protocol_t = Type.named_type_from_type(
            'protocol_t', view.get_type_by_name('protocol_t'))

        if not view.get_data_var_at(address):
            view.define_user_data_var(address, protocol_t)

        members = {
            m.name: from_bytes(view.read(address + m.offset, m.type.width))
            for m in view.get_type_by_name('protocol_t').structure.members
        }

        members['isa'] = Class.from_address(members['isa'], view)

        members['name'] = (view.get_ascii_string_at(members['name'], 1).value
                           if members['name'] != 0 else '')

        if members['name'] not in view.types:
            view.define_user_type(members['name'],
                                  Type.structure_type(Structure()))

        members['protocols'] = ProtocolList.from_address(
            members['protocols'], view)

        members['instanceMethods'] = MethodList.from_address(
            members['instanceMethods'], members['name'], view)

        members['optionalInstanceMethods'] = MethodList.from_address(
            members['optionalInstanceMethods'], members['name'], view)

        new_protocol = cls(address, **members)
        view.session_data['Protocols'][new_protocol.name] = new_protocol
        return new_protocol
Example #14
0
def rewrite_segments(view: BinaryView):
    class EmulatorBackgroundTask(BackgroundTaskThread):
        def __init__(self, view):
            self.view = view
            super().__init__()

        def run(self):
            self.view.update_analysis_and_wait()

    new_raw_view = BinaryView()
    current_addr = 0
    for segment in view.segments:
        segment_data = view.read(segment.start, segment.data_length)
        segment_data += b'\x00'*(len(segment) - segment.data_length)
        new_raw_view.write(current_addr, segment_data)
        current_addr += len(segment_data)

    new_view = BinaryViewType['Mapped'].create(new_raw_view)
    new_view.remove_auto_segment(0, len(new_raw_view))
    t = EmulatorBackgroundTask(new_view)
    t.start()
    t.join()

    current_addr = 0
    for segment in view.segments:
        new_view.add_user_segment(
            segment.start,
            len(segment),
            current_addr,
            len(segment),
            (
                (SegmentFlag.SegmentReadable if segment.readable else 0) |
                (SegmentFlag.SegmentWritable if segment.writable else 0) |
                (SegmentFlag.SegmentExecutable if segment.executable else 0)
            )
        )

        current_addr += len(segment)

    return new_view
    def __init__(self, function, view=None):
        super(Emilator, self).__init__()

        if not isinstance(function, LowLevelILFunction):
            raise TypeError('function must be a LowLevelILFunction')

        self._function = function

        if view is None:
            view = BinaryView()

        self._view = view

        self._regs = {}
        self._flags = {}
        self._memory = memory.Memory(function.arch.address_size)

        for segment in view.segments:
            self._memory.map(segment.start, segment.length, segment.flags,
                             view.read(segment.start, segment.length))

        self._function_hooks = {}
        self.instr_index = 0
Example #16
0
def _propagate_stret_types(view: BinaryView):
    log_debug('_propagate_stret_types')
    objc_msgSend_stret = next(
        (s for s in view.symbols.get('_objc_msgSend_stret', [])
         if s.type == SymbolType.ImportedFunctionSymbol),
        None
    )

    if objc_msgSend_stret is None:
        return

    for xref in view.get_code_refs(objc_msgSend_stret.address):
        xref_mlil = xref.function.get_low_level_il_at(xref.address).mlil
        log_debug(f"{xref.address:x} {xref_mlil}")

        if xref_mlil is None:
            continue

        if xref_mlil.operation != MediumLevelILOperation.MLIL_CALL:
            continue

        selector_ptr = xref_mlil.params[2]

        if not selector_ptr.value.is_constant or selector_ptr.value.value == 0:
            continue

        log_debug(f'selector_ptr is {selector_ptr.value.value:x}')

        selector = view.get_ascii_string_at(selector_ptr.value.value, 1)

        if selector is None:
            selector_ptr = int.from_bytes(
                view.read(selector_ptr.value.value, view.address_size),
                "little" if view.endianness is Endianness.LittleEndian else "big"
            )
            log_debug(f'{selector_ptr:x}')
            selector = view.get_ascii_string_at(selector_ptr)

        if selector is None:
            continue

        log_debug(f"selector is {selector.value}")

        receiver = xref_mlil.params[1]

        if receiver.operation != MediumLevelILOperation.MLIL_VAR:
            continue

        receiver_type = receiver.src.type

        log_debug(f'receiver_type is {receiver_type}')

        if (receiver_type.target is None or 
                receiver_type.target.type_class != TypeClass.NamedTypeReferenceClass):
            continue

        receiver_name = receiver_type.target.named_type_reference.name

        log_debug(f'receiver name is {receiver_name}')

        receiver_class = view.session_data['ClassNames'].get(receiver_name)

        if receiver_class is None:
            continue

        if receiver_class.vtable is None or receiver_class.vtable.baseMethods is None:
            continue

        method = receiver_class.vtable.baseMethods.methods.get(selector.value)

        if method is None:
            continue

        log_debug(f'method is {method}')

        ret_type = method.types.parameters[0].type

        xref.function.create_user_var(
            xref_mlil.params[0].src,
            ret_type,
            xref_mlil.params[0].src.name
        )
Example #17
0
 def is_valid_for_data(self, data: BinaryView):
     try:
         actual_data = data.read(0, len(data)).decode('utf8')
         return is_srec(actual_data)
     except:
         return False
Example #18
0
    def perform_get_lines_for_data(self, ctxt, view: BinaryView, addr: int,
                                   type_: Type, prefix: list, width: int,
                                   context):
        from_bytes = _get_from_bytes(view)

        symbol: Symbol = view.get_symbol_at(addr)

        cfstring = view.types.get('CFString')

        if cfstring is None:
            log_debug('CFString is not defined; how did we even get here?')
            return [DisassemblyTextLine(prefix, addr)]

        cfstring = cfstring.structure

        buffer = from_bytes(
            view.read(addr + cfstring['buffer'].offset, view.address_size))

        info = from_bytes(
            view.read(addr + cfstring['info'].offset,
                      cfstring['info'].type.width))

        length = from_bytes(
            view.read(addr + cfstring['length'].offset,
                      cfstring['length'].type.width))

        if info & 0xff == 0xc8:
            info_string = 'noinline,default,nofree,NI'
        elif info & 0xff == 0xd0:
            info_string = 'noinline,default,nofree,EUI'
        else:
            info_string = (
                f'{_cfstring_allocator_properties[(info >> 5) & 0x3]},'
                f'{"U" if info & 16 else ""}'
                f'{"N" if info & 8 else ""}'
                f'{"L" if info & 4 else ""}'
                f'{"I" if info & 1 else ""}')

        if 'U' not in info_string:
            string = view.get_ascii_string_at(buffer, 0)

            if string is None:
                log_debug('string returned None; how did we even get here?')
                return [DisassemblyTextLine(prefix, addr)]

            string = string.value
        else:
            string = view.read(buffer, length * 2)

        if symbol is None:
            name = f'data_{addr:x}'
        else:
            name = symbol.short_name

        prefix = [
            InstructionTextToken(InstructionTextTokenType.TypeNameToken,
                                 'CFString'),
            InstructionTextToken(InstructionTextTokenType.TextToken, ' '),
            InstructionTextToken(InstructionTextTokenType.AnnotationToken,
                                 f'{{{info_string}}}'),
            InstructionTextToken(InstructionTextTokenType.TextToken, ' '),
            InstructionTextToken(InstructionTextTokenType.DataSymbolToken,
                                 name, addr),
            InstructionTextToken(InstructionTextTokenType.TextToken, ' = '),
            InstructionTextToken(InstructionTextTokenType.StringToken,
                                 f'{string!r}', buffer),
            InstructionTextToken(InstructionTextTokenType.TextToken, ' ')
        ]
        return [DisassemblyTextLine(prefix, addr)]