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}")
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)
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))
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
        )
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
            )
        )