Пример #1
0
    def from_address(cls, address: int, view: BinaryView):
        if address == 0:
            return None

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

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

        members = get_structure_members(address, property_t_type, view)

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

        members['attributes'] = (
            view.get_ascii_string_at(members['attributes'], 1).value
            if members['attributes'] else ''
        )

        return cls(address, **members)
Пример #2
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)
Пример #3
0
    def from_address(cls,
                     address: int,
                     self_type: str,
                     view: BinaryView,
                     is_class=False):
        if address == 0:
            return None

        if self_type not in view.types:
            view.define_user_type(self_type, Type.structure_type(Structure()))

        method_t_type = view.get_type_by_name('method_t')
        method_t = Type.named_type_from_type('method_t', method_t_type)

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

        members = get_structure_members(address, method_t_type, view)

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

        members['types'] = parse_function_type(
            view.get_ascii_string_at(members['types'], 1).value
            if members['types'] else '', self_type, view, is_class)

        members['imp'] = view.get_function_at(members['imp'])

        if members['imp'] is not None:
            if not is_class:
                method_name = f'-[{self_type} {members["name"]}]'
            else:
                method_name = f'+[{self_type} {members["name"]}]'

            if view.symbols.get(method_name):
                namespace = f'{members["imp"].start}'
            else:
                namespace = None

            view.define_user_symbol(
                Symbol(SymbolType.FunctionSymbol,
                       members['imp'].start,
                       method_name,
                       namespace=namespace))

            if members['types'] is not None:
                members['imp'].function_type = members['types']

        return cls(address, **members)
Пример #4
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
Пример #5
0
    def from_address(cls, address: int, view: BinaryView) -> Category:
        if address == 0:
            return None

        from .class_t import Class, ClassRO

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

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

        members = get_structure_members(address, category_t_type, view)

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

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

        if members['cls'] is None:
            cls_offset = next(m.offset
                              for m in category_t_type.structure.members
                              if m.name == 'cls')
            cls_name = view.get_symbol_at(address + cls_offset)
            cls_name = cls_name.name if cls_name is not None else members[
                'name']

            class_match = re.match(
                r'_OBJC_(META)?CLASS_\$_(?P<classname>[_A-Za-z0-9=/]+)(@GOT)?',
                cls_name)
            if class_match is not None:
                cls_name = class_match.group('classname')
                cls_ = view.session_data['ClassNames'].get(cls_name)
                if cls_ is None:
                    cls_ = Class(None, view, None, None, None, {}, {})
                    cls_.vtable = ClassRO(address, *([None] * 11))
                    cls_.vtable.name = cls_name
                    view.session_data['ClassNames'][cls_name] = cls_

                members['cls'] = cls_
        else:
            cls_name = members['cls'].vtable.name

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

        if members['cls'] is not None and not members['cls'].methods:
            members['cls']._methods = members['instanceMethods'].methods
        elif members['cls'] is not None:
            members['cls']._methods.update(members['instanceMethods'].methods)

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

        return cls(address, **members)
Пример #6
0
def parse_get_class(view: BinaryView, objc_getClass: int):
    log_debug(f"parse_get_class(view, {objc_getClass:x})")
    xrefs = view.get_code_refs(objc_getClass)

    for xref in xrefs:
        mlil = xref.function.mlil
        get_class_call = xref.function.get_low_level_il_at(xref.address).mlil

        if not get_class_call.params:
            continue

        class_param = get_class_call.params[0]
        log_debug(f"class_param is {class_param.operation!r}")

        if class_param.operation in (
                MediumLevelILOperation.MLIL_CONST,
                MediumLevelILOperation.MLIL_CONST_PTR):
            class_name_ptr = view.get_ascii_string_at(class_param.constant, 1)
            if class_name_ptr is None:
                continue

            class_name = class_name_ptr.value

            cls_ = Type.named_type_from_type(
                class_name,
                view.types.get(class_name)
            )

            if cls_ is None:
                continue

            cls_ptr = Type.pointer(view.arch, cls_)

            output = get_class_call.output[0] if get_class_call.output else None

            if output is None:
                continue

            log_debug(f"Updating {output!r} to {cls_ptr}")
            xref.function.create_user_var(output, cls_ptr, output.name)
            log_debug(f"Now {output!r}")

            # Update any variable that is directly set to this variable (but not if
            # the variable just happened to be used in the expression)
            for use in mlil.get_ssa_var_uses(get_class_call.ssa_form.output.dest[0]):
                log_debug(f"Checking {use!r}")
                if use.operation != MediumLevelILOperation.MLIL_SET_VAR:
                    continue

                if use.src.operation != MediumLevelILOperation.MLIL_VAR:
                    continue

                log_debug(f"Updating {use.dest!r} to {cls_ptr}")
                xref.function.create_user_var(use.dest, cls_ptr, use.dest.name)
                log_debug(f"Now {use.dest!r}")
Пример #7
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))
Пример #8
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
def fix_printfs(view: BinaryView):
    printf = view.get_symbols_by_name('_printf')

    if not printf:
        printf = view.get_symbols_by_name('printf')

    if not printf:
        return

    for sym in printf:
        function = view.get_function_at(sym.address)
        if not function:
            continue

        xrefs = view.get_code_refs(function.start)

        for xref in xrefs:
            caller: Function = xref.function

            call_mlil = caller.get_low_level_il_at(xref.address).mlil
            print(call_mlil)
            if call_mlil is None:
                continue

            fmt_operand = call_mlil.params[0]
            if fmt_operand.operation == MediumLevelILOperation.MLIL_VAR:
                log.log_warn(
                    f"Potential format string bug: {fmt_operand.address:x}")
                continue

            elif fmt_operand.operation in (
                    MediumLevelILOperation.MLIL_CONST_PTR,
                    MediumLevelILOperation.MLIL_CONST):
                fmt_address = fmt_operand.constant
                fmt = view.get_ascii_string_at(fmt_address, 2)

                if fmt is None:
                    continue

                fmt_value = fmt.value

            else:
                continue

            specifiers = fmt_value.split('%')

            param_types = []

            for specifier in specifiers[1:]:
                if not specifier:
                    continue

                if specifier.startswith('d'):
                    param_types.append(Type.int(4, sign=True))
                elif specifier.startswith('s'):
                    param_types.append(Type.pointer(view.arch, Type.char()))
                elif specifier.startswith('p'):
                    param_types.append(Type.pointer(view.arch, Type.void()))
                else:
                    log.log_warn(
                        f'Unknown format specifier: {specifier}; skipping')
                    param_types.append(Type.pointer(view.arch, Type.void()))

            param_idx = 1
            params = [
                FunctionParameter(Type.pointer(view.arch, Type.char()), 'fmt')
            ]
            for param in param_types:
                params.append(FunctionParameter(param, f'arg{param_idx}'))
                param_idx += 1

            caller.set_call_type_adjustment(xref.address,
                                            Type.function(Type.int(4), params))
Пример #10
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)]
Пример #11
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
        )
Пример #12
0
def parse_added_methods(view: BinaryView, class_addMethod: int):
    log_debug(f"parse_added_methods(view, {class_addMethod:x})")
    xrefs = view.get_code_refs(class_addMethod)

    for xref in xrefs:
        mlil = xref.function.mlil
        log_debug(f"{xref.address:x} Getting add_method_call")
        add_method_call = xref.function.get_low_level_il_at(xref.address).mlil

        log_debug(f"{xref.address:x} {add_method_call.operation!r}")
        if add_method_call.operation not in (
                MediumLevelILOperation.MLIL_CALL,
                MediumLevelILOperation.MLIL_CALL_UNTYPED):
            continue

        class_param = add_method_call.params[0]
        if class_param.operation != MediumLevelILOperation.MLIL_VAR:
            log_debug(f"class_param is {class_param.operation!r}")
            continue

        cls_ = class_param.src.type

        log_debug(f"Checking {cls_!r}")
        if cls_.target is not None and cls_.target.named_type_reference is not None:
            class_name = cls_.target.named_type_reference.name
        else:
            log_debug(f"cls_ is {cls_}->{cls_.target}")
            continue

        log_debug("Getting selector_param")
        selector_param = add_method_call.params[1]
        if selector_param.operation == MediumLevelILOperation.MLIL_CONST:
            selector_ptr = selector_param
        elif selector_param.operation != MediumLevelILOperation.MLIL_VAR:
            log_debug(f"selector_param {selector_param.operation!r}")
            continue
        else:
            selector_ptr = None

            log_debug("Getting get_method_call")
            get_method_call = mlil.get_ssa_var_definition(
                selector_param.ssa_form.src)

            while get_method_call.operation != MediumLevelILOperation.MLIL_CALL:
                if get_method_call.operation != MediumLevelILOperation.MLIL_SET_VAR:
                    log_debug(f"get_method_call {get_method_call.operation!r}")
                    break

                if get_method_call.src.operation != MediumLevelILOperation.MLIL_VAR:
                    log_debug(f"get_method_call.src {get_method_call.src!r}")
                    break

                get_method_call = mlil.get_ssa_var_definition(
                    get_method_call.ssa_form.src.src
                )
                log_debug(f"{get_method_call!r}")
            else:
                log_debug(f"Found {get_method_call!r}")
                selector_ptr = get_method_call.params[1]

        if selector_ptr is None:
            log_debug("selector_ptr is None")
            continue

        if selector_ptr.operation not in (
                MediumLevelILOperation.MLIL_CONST,
                MediumLevelILOperation.MLIL_CONST_PTR):
            log_debug(f"selector_ptr {selector_ptr.operation!r}")
            continue

        selector_str = view.get_ascii_string_at(selector_ptr.constant, 1)

        if selector_str is None:
            log_debug("selector_str is None")
            continue

        selector = selector_str.value

        method_string = f"-[{class_name} {selector}]"

        log_debug(f"method_string is {method_string}")

        method_ptr = add_method_call.params[2]

        if method_ptr.operation not in (
                MediumLevelILOperation.MLIL_CONST,
                MediumLevelILOperation.MLIL_CONST_PTR):
            log_debug(f"method_ptr.operation {method_ptr.operation!r}")
            continue

        log_debug("Defining {method_string} @ {method_ptr.constant}")
        view.define_user_symbol(
            Symbol(
                SymbolType.FunctionSymbol,
                method_ptr.constant,
                method_string
            )
        )