Esempio n. 1
0
def _parse_function_type(type_string: str,
                         self_name: str,
                         view: BinaryView,
                         is_class=False) -> Type:
    log_debug(f'_parse_function_type {type_string}')
    ret_type_str = type_string[0]

    # Handle structures defined in the function types
    if ret_type_str == '{':
        ret_type, type_string = _parse_structure(type_string[1:], view)
    else:
        ret_type = _lookup_type(ret_type_str, view)
        type_string = type_string[1:]

    stack_size = ''.join(takewhile(str.isdigit, type_string))
    type_string = type_string[len(stack_size):]
    stack_size = int(stack_size) if stack_size else None

    args = []
    while type_string:
        if type_string[0] == '{':
            arg_type, type_string = _parse_structure(type_string[1:], view)
            args.append(Type.pointer(view.arch, arg_type))
        else:
            arg_type = ''.join(
                takewhile(lambda i: not str.isdigit(i), type_string))
            type_string = type_string[len(arg_type):]
            args.append(_lookup_type(arg_type, view))

        arg_stack_offset = ''.join(takewhile(str.isdigit, type_string))
        type_string = type_string[len(arg_stack_offset):]

    # we know that the first parameter is the 'self' parameter if it's not
    # an objc_msgSend_stret or objc_msgSendSuper_stret. Otherwise it's the
    # second one.
    if ret_type.type_class == TypeClass.NamedTypeReferenceClass:
        log_debug(f'return value is {ret_type}')
        ret_type = Type.pointer(view.arch, ret_type)
        args.insert(0, FunctionParameter(ret_type, 'ret_value'))

        if len(args) < 2:
            args.append(None)

        args[1] = FunctionParameter(
            Type.pointer(
                view.arch,
                (Type.named_type_from_type(self_name, view.types[self_name])
                 if not is_class else Type.named_type_from_type(
                     'class_t', view.get_type_by_name('class_t')))), 'self')
    else:
        args[0] = FunctionParameter(
            Type.pointer(
                view.arch,
                (Type.named_type_from_type(self_name, view.types[self_name])
                 if not is_class else Type.named_type_from_type(
                     'class_t', view.get_type_by_name('class_t')))), 'self')

    function_type = Type.function(ret_type, args)

    return function_type
Esempio n. 2
0
    def _add_vmt_methods(bv: BinaryView, vmt: DelphiVMT, out_struct: types.Structure) -> bool:
        offset_ptr_size = vmt.offset_ptr_size

        if not vmt.seek_to_vmt_offset(vmt.vmt_offsets.cVmtParent + offset_ptr_size):
            return False

        for _ in range(len(vmt.virtual_methods)):
            value = vmt.read_ptr()

            if value == 0:
                continue

            if value not in vmt.virtual_methods:
                prev_offset = vmt.br_offset - offset_ptr_size
                raise RuntimeError(
                    f'Invalid method address detected at 0x{prev_offset:08x} ({vmt.class_name})')

            # Create function if not exists
            if bv.get_function_at(value) is None:
                bv.create_user_function(value)

            function = bv.get_function_at(value)

            # Set method name if not already set
            function_name = function.name
            method_name = vmt.virtual_methods[value]

            if function_name.startswith('sub_'):
                bv.define_user_symbol(Symbol(
                    SymbolType.FunctionSymbol,
                    value,
                    method_name
                ))

            # Add field to structure
            field_type = Type.pointer(
                bv.arch,
                Type.function(
                    function.return_type,
                    [(Type.void() if x.type is None else x.type) for x in function.parameter_vars],
                    function.calling_convention
                )
            )

            field_name = method_name.split('.')[-1]
            out_struct.append(field_type, field_name)

        return True
Esempio n. 3
0
 def fix_tailcall(self, func, function_parameter_list, return_type, func_cc):
     # PE's sometimes use a tailcall that jumps to the IAT\GOT entry of the function.
     # This function will label the tailcall as the same type as the function its jumping into (since its not
     # changing any registers\variables).
     xref_list = self.bv.get_code_refs(func.start)
     if len(xref_list) == 1:
         caller_func = xref_list[0].function
         if caller_func.mlil[0].operation == enums.MediumLevelILOperation.MLIL_TAILCALL:
             # If the first instruction is a tailcall, then change the functions' type to the called function type
             try:
                 function_type = Type.function(return_type, function_parameter_list, func_cc)
                 caller_func.set_user_type(function_type)
                 caller_func.name = '__j_' + func.name
                 return True
             except Exception as e:
                 print("Failed to fix the tailcall to function: ", func)
                 print(str(e))
                 return False
     return True
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))
Esempio n. 5
0
    def FUNCTION_DECL_handler(self, current_node_hash):

        with self.driver.session() as session:
            result = session.run("MATCH (func:FUNCTION_DECL {Hash: {current_node_hash}})-[:FunctionArgument]->"
                                 "(func_param:PARM_DECL) "
                                 "RETURN func_param.Hash as param_hash, "
                                 "       func_param.TypeDefinition as type_definition,"
                                 "       func_param.TypeName as type_name ",
                                 current_node_hash=current_node_hash)

            # Parse function arguments
            function_parameter_list = list()
            if result.peek():
                for record in result:
                    # If parameter type is already defined move on to the next parameter
                    if not self.type_definition_cache.get(record['param_hash']):
                        if self.insert_type_definition_into_binaryView('PARM_DECL', record['param_hash']):
                            self.type_definition_cache[record['param_hash']] = True
                        else:
                            print("Failed to insert definition for function parameter ", record['type_name'])
                            return False

                    try:
                        # Define the Function parameter binaryNinja object
                        function_parameter_list.append(
                            types.FunctionParameter(self.bv.get_type_by_name(record['type_name']),
                                                    record['type_name']))
                    except Exception as e:
                        print("FUNCTION_DECL_handler: Failed to process function parameter" + str(e))
                        return False

            # Parse return value and function name
            result = session.run("MATCH (func:FUNCTION_DECL {Hash: {current_node_hash}})-[:ReturnType]->"
                                 "(return_type) "
                                 "RETURN return_type.Hash as return_hash, "
                                 "       labels(return_type)[0] as return_label, "
                                 "       return_type.TypeDefinition as type_definition, "
                                 "       return_type.TypeName as type_name ",
                                 current_node_hash=current_node_hash)

            return_type = types.Type.void()

            if result.peek():
                for record in result:
                    # If return type is already defined move on, otherwise define it
                    if not self.type_definition_cache.get(record['return_hash']):
                        if self.insert_type_definition_into_binaryView(record['return_label'], record['return_hash']):
                            self.type_definition_cache[record['return_hash']] = True
                        else:
                            print("Failed to insert definition for function return value ", record['type_name'])
                            return False

                    try:
                        # Define the Function return value binaryNinja type object
                        if record['type_definition'] == 'PointerTo':
                            # Return type is a pointer
                            var_type, name = self.bv.parse_type_string(record['type_name'][:-1])
                            return_type = Type.pointer(self.bv.arch, var_type)
                        else:
                            var_type, name = self.bv.parse_type_string(
                                record['type_definition'] + " " + record['type_name'])
                            self.bv.define_user_type(name, var_type)
                            return_type = Type.named_type_from_type(name, self.bv.get_type_by_name(name))
                    except Exception as e:
                        print("FUNCTION_DECL_handler: Failed to process return value, " + str(e))
                        return False
            else:
                # A function might not have any return value or arguments
                pass

            # Define the function itself
            result = session.run("MATCH (func:FUNCTION_DECL {Hash: {current_node_hash}}) "
                                 "RETURN func.TypeName as func_name",
                                 current_node_hash=current_node_hash)

            if result.peek():
                func_name = result.peek()['func_name']
                try:
                    for func in self.bv.functions:
                        if func.name == func_name:
                            func_cc = func.calling_convention
                            function_type = Type.function(return_type, function_parameter_list, func_cc)
                            func.set_user_type(function_type)
                            if not self.fix_tailcall(func, function_parameter_list, return_type, func_cc):
                                return False
                    self.type_definition_cache[current_node_hash] = True
                except Exception as e:
                    print("Failed to process function :", func_name)
                    print(str(e))
                    return False

        print("Successfully defined function: ", func_name)

        return True
)

LPCSTR_type = Type.pointer(Architecture["x86"], Type.char())
LPCSTR = Type.named_type_from_type('LPCSTR', LPCSTR_type)

DWORD = Type.int(4, sign=False, altname="DWORD")

advapi32_x86.add_named_type("HCRYPTPROV", HCRYPTPROV_type)

CryptAcquireContextA = Type.function(
    BOOL,
    [
        FunctionParameter(
            Type.pointer(Architecture["x86"], HCRYPTPROV), "phProv"
        ),
        FunctionParameter(LPCSTR, "szContainer"),
        FunctionParameter(LPCSTR, "szProvider"),
        FunctionParameter(DWORD, "dwProvType"),
        FunctionParameter(DWORD, "dwFlags"),
    ],
    calling_convention=Platform['windows-x86'].stdcall_calling_convention
)

CryptReleaseContext = Type.function(
    BOOL,
    [
        FunctionParameter(
            HCRYPTPROV, 'hProv'
        ),
        FunctionParameter(
            DWORD, 'dwFlags'