Beispiel #1
0
    def _check_and_prop_types_on_call(self, instr: HighLevelILInstruction):
        """Most UEFI modules don't assign globals in the entry function and instead call a initialization routine and
        pass the system table to it where global assignments are made. This function ensures that the types are applied
        to the initialization function params so that we can catch global assignments outside of the module entry

        :param instr: High level IL instruction object
        """

        if instr.operation not in [
                HighLevelILOperation.HLIL_TAILCALL,
                HighLevelILOperation.HLIL_CALL
        ]:
            return

        if instr.dest.operation != HighLevelILOperation.HLIL_CONST_PTR:
            return

        argv_is_passed = False
        for arg in instr.params:
            if 'ImageHandle' in str(
                    arg
            ) or 'SystemTable' or 'FileHandle' or 'PeiServices' in str(arg):
                argv_is_passed = True
                break

        if not argv_is_passed:
            return

        func = self.bv.get_function_at(instr.dest.constant)
        old = func.function_type
        call_args = instr.params
        new_params = []
        for arg, param in zip(call_args, old.parameters):
            if hasattr(arg, 'var'):
                new_type = arg.var.type
            else:
                new_type = param.type
            new_type.confidence = 256
            new_params.append(FunctionParameter(new_type, param.name))

        # TODO: this is a hack to account for odd behavior. func.function_type should be able to set directly to
        # Type.Function(...). However, during testing this isn't the case. I am only able to get it to work if I
        # set function_type to a string and update analysis.
        gross_hack = str(
            Type.function(old.return_value, new_params, old.calling_convention,
                          old.has_variable_arguments,
                          old.stack_adjustment)).replace(
                              '(', '{}('.format(func.name))
        try:
            func.function_type = gross_hack
            self.bv.update_analysis_and_wait()
        except SyntaxError:
            pass  # BN can't parse int48_t and other types despite that it uses it. Ran into this from a sidt instruction
def process_msvc_func(func):
    view = func.view
    arch = func.arch
    symbol = func.symbol

    mangled_name = symbol.raw_name

    if mangled_name.startswith('??_7') and not mangled_name.endswith(
            '@@6B@'):  # Skip buggy vtables
        return

    sym_type, sym_parts = demangle_ms(arch, mangled_name)

    if (sym_type is None) or (sym_type.type_class !=
                              TypeClass.FunctionTypeClass):
        return

    if isinstance(sym_parts, str):
        return

    params = [
        v.type for v in sym_type.parameters
        if v.type.type_class != TypeClass.VoidTypeClass
    ]
    return_type = sym_type.return_value

    tokens_before = [str(v) for v in sym_type.get_tokens_before_name()]

    convention = 'cdecl'

    if '__cdecl' in tokens_before:
        convention = 'cdecl'
    elif '__stdcall' in tokens_before:
        convention = 'stdcall'
    elif '__thiscall' in tokens_before:
        convention = 'thiscall'

    if (convention == 'thiscall') and len(sym_parts) >= 2:
        if 'static' not in tokens_before:
            type_name = '::'.join(sym_parts[:-1])
            this_type = Type.pointer(
                arch,
                Type.named_type(
                    NamedTypeReference(
                        NamedTypeReferenceClass.StructNamedTypeClass,
                        name=type_name)))
            params.insert(0, this_type)

    func.function_type = Type.function(return_type, params,
                                       arch.calling_conventions[convention],
                                       sym_type.has_variable_arguments)
Beispiel #3
0
 def get_symbol_type(self, sym):
     if self.bv.has_database:
         func = self.bv.get_function_at(sym.address)
         if func:
             return Type.function(
                 func.return_type, [
                     FunctionParameter(
                         param.type, param.name, location=param)
                     for param in func.parameter_vars
                 ],
                 calling_convention=func.calling_convention,
                 variable_arguments=func.has_variable_arguments,
                 stack_adjust=func.stack_adjustment)
         dvar = self.bv.get_data_var_at(sym.address)
         if dvar:
             return dvar.type
     return None
Beispiel #4
0
def process_msvc_func(func):
    arch = func.arch
    plat = func.platform

    sym_type, sym_parts = demangle_ms(arch, func.symbol.raw_name)

    if (sym_type is None) or (sym_type.type_class !=
                              TypeClass.FunctionTypeClass):
        return

    if isinstance(sym_parts, str):
        return

    params = [
        v.type for v in sym_type.parameters
        if v.type.type_class != TypeClass.VoidTypeClass
    ]
    return_type = sym_type.return_value

    tokens_before = [str(v) for v in sym_type.get_tokens_before_name()]

    is_member = ('public:' in tokens_before) or (
        'protected:' in tokens_before) or ('private:' in tokens_before)
    is_static = 'static' in tokens_before
    is_virtual = 'virtual' in tokens_before

    convention = plat.default_calling_convention

    if '__cdecl' in tokens_before:
        convention = plat.cdecl_calling_convention
    elif '__stdcall' in tokens_before:
        convention = plat.stdcall_calling_convention
    elif '__fastcall' in tokens_before:
        convention = plat.fastcall_calling_convention
    elif '__thiscall' in tokens_before:
        convention = arch.calling_conventions['thiscall']

    if return_type.type_class == TypeClass.NamedTypeReferenceClass and return_type.named_type_reference.type_class in {
            NamedTypeReferenceClass.ClassNamedTypeClass,
            NamedTypeReferenceClass.StructNamedTypeClass,
            NamedTypeReferenceClass.UnionNamedTypeClass
    }:
        # TODO: This should only added for large/non trivial types
        return_type = Type.pointer(arch, return_type)
        params.insert(0, FunctionParameter(return_type, name="retptr"))

    if len(sym_parts) >= 2 and (is_member or is_virtual) and not is_static:
        type_name = '::'.join(sym_parts[:-1])
        this_type = Type.pointer(
            arch,
            Type.named_type(
                NamedTypeReference(
                    NamedTypeReferenceClass.StructNamedTypeClass,
                    name=type_name)))
        params.insert(0, FunctionParameter(this_type, name="this"))

        if (sym_parts[-1] == sym_parts[-2]) and (return_type.type_class
                                                 == TypeClass.VoidTypeClass):
            return_type = this_type

    func_type = Type.function(return_type, params, convention,
                              sym_type.has_variable_arguments)

    func.function_type = func_type
    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)))
Beispiel #6
0
enum_type.append('BLUE', 4)
enum_type.append('INDIGO', 5)
enum_type.append('VIOLET', 6)
typelib.add_named_type('MyEnumerationType', enum_type)

# example: ArrayTypeClass
#
# unsigned char[256]
typelib.add_named_type('MyArrayType', Type.array(Type.int(1), 256))

# example: FunctionTypeClass
#
# int ()(int, int, int)
ret = Type.int(4)
params = [Type.int(4), Type.int(4), Type.int(4)]
ftype = Type.function(ret, params)
typelib.add_named_type('MyFunctionType', ftype)

#------------------------------------------------------------------------------
# PART2: Named Objects
#------------------------------------------------------------------------------

# example: any external/imported functions named _MySuperComputation
#  are typed int _MySuperComputation(int, int)

ret = Type.int(4)
params = [Type.int(4), Type.int(4)]
ftype = Type.function(ret, params)
typelib.add_named_object('_MySuperComputation', ftype)

# finalize