예제 #1
0
def _lookup_type(type_string: str, view: BinaryView):
    if type_string in basic_types:
        return basic_types[type_string]
    elif type_string == '*':
        return Type.pointer(view.arch, Type.char())
    elif type_string.startswith('@'):
        if type_string[2:-1] in view.types:
            return Type.pointer(
                view.arch,
                Type.named_type_from_type(
                    type_string[2:-1],
                    view.types[type_string[2:-1]]
                )
            )
        elif type_string != '@?' and type_string != '@':
            if type_string[2:-1]:
                new_type = Type.named_type_from_type(
                    type_string[2:-1], Type.structure_type(Structure()))
                view.define_user_type(type_string[2:-1], new_type)
            else:
                new_type = Type.void()
            return Type.pointer(view.arch, new_type)
        else:
            return Type.pointer(view.arch, Type.void())
    elif type_string.startswith('#'):
        return Type.pointer(view.arch, Type.void())
    elif type_string == ':':
        return view.types['SEL']
    else:
        return Type.pointer(view.arch, Type.void())
예제 #2
0
def _parse_structure(type_string: str, view: BinaryView) -> Type:
    type_name = ''.join(
        takewhile(lambda i: i != '=', type_string)
    )

    type_string = type_string[len(type_name)+1:]

    fields = []
    while type_string:
        if type_string[0] == '{':
            field_type, type_string = _parse_structure(type_string[1:], view)
            fields.append(field_type)

        elif type_string[0] == '}':
            type_string = type_string[1:]
            break

        elif type_string[0] == '[':
            array_size = ''.join(takewhile(str.isdigit, type_string[1:]))
            array_type = ''.join(
                takewhile(lambda i: i != ']', type_string[1:])
            )
            type_string = type_string[len(array_size)+len(array_type)+2:]

            fields.append(
                Type.array(_lookup_type(array_type, view), int(array_size))
            )

        elif type_string[0] == ']':
            type_string = type_string[1:]
            continue

        elif _lookup_type(type_string[0], view):
            fields.append(_lookup_type(type_string[0], view))
            type_string = type_string[1:]

        else:
            log_debug(f"Not sure what is going on with this type: {type_string!r}")
            raise NotImplementedError(f"{type_string!r}")

    parsed_struct = Structure()

    for field in fields:
        parsed_struct.append(field)

    log_debug(f"Created {type_name}={parsed_struct}")
        
    view.define_user_type(type_name, Type.structure_type(parsed_struct))

    return (
        Type.named_type_from_type(
            type_name,
            view.types.get(type_name)
        ),
        type_string
    )
예제 #3
0
def var_decl(node: Cursor, bv: bn.BinaryView):
    bn.log.log_debug(f'var_decl: Processing var {node.underlying_typedef_type.spelling} {node.spelling}')
    var_type, name = bv.parse_type_string(f'{node.type.spelling} {node.spelling}')

    try:
        bv.define_user_type(name, var_type)
        bn.log.log_debug(f'var_decl: Successfully processed var {node.underlying_typedef_type.spelling} '
                         f'{node.spelling}')
        return str(name), var_type
    except Exception as e:
        bn.log.log_debug(f'var_decl: Failed Processing var {node.underlying_typedef_type.spelling} {node.spelling} '
                         f'with exception {e}')
예제 #4
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)
예제 #5
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))
예제 #6
0
def enum_decl(node: Cursor, bv: bn.BinaryView):
    bn.log.log_debug(f'enum_decl: Processing enum {node.type.spelling} {node.spelling}')

    enum = bn.Enumeration()
    for enum_member in node.get_children():
        enum.append(enum_member.spelling, enum_member.enum_value)

    try:
        if node.spelling:
            enum_name = node.spelling
        else:
            enum_name = node.type.spelling
        bv.define_user_type(enum_name, bn.Type.enumeration_type(bv.arch, enum))
        bn.log.log_debug(f'enum_decl: Successfully processed enum {node.spelling}')
        return node.spelling, bn.Type.enumeration_type(bv.arch, enum)
    except Exception as e:
        bn.log.log_debug(f'enum_decl: Failed Processing enum {node.spelling} with exception {e}')
예제 #7
0
def typedef_decl(node: Cursor, bv: bn.BinaryView):
    bn.log.log_debug(f'typedef_decl: {node.underlying_typedef_type.spelling} {node.spelling}, \n'
                     f'underlying_typedef_type: {node.underlying_typedef_type.kind}')
    if node.spelling and bv.get_type_by_name(node.spelling):
        bn.log.log_debug(f'typedef_decl: Type already defined')
        return node.spelling, bv.get_type_by_name(node.spelling)
    elif not node.underlying_typedef_type.spelling:
        try:
            var_type, name = bv.parse_type_string(f'{node.type.spelling} {node.spelling}')
        except Exception as e:
            bn.log.log_debug(f'typedef_decl: Failed to parse {node.type.spelling} {node.spelling}, with exception {e}')
    else:

        # Sanitize the type - remove any compiler directives such as __aligned and such.
        underlying_typedef_type_string = remove_compiler_directives(node.underlying_typedef_type.spelling)
        try:
            var_type, name = bv.parse_type_string(f'{underlying_typedef_type_string}')
            # The reason we are not using the name inside the parsed string is that sometimes you get a typedef
            # like 'int [1] td', and if you parse it like that it's a binaryNinja exception.
            # instead we parse 'int [1]' and attach the name of the typedef to it afterwards.
            name = node.spelling
            bn.log.log_debug(f'typedef_decl: Successfully parsed {underlying_typedef_type_string} {node.spelling}')
        except SyntaxError as se:
            if 'syntax error' in str(se):
                if node.spelling.endswith('_t'):
                    # Some variables names are internal to binaryNinja and cannot be used. These var names usually
                    # end with _t, for example size_t \ ptrdiff_t etc.
                    # In order to not clash with the internal vars, change the _t to _T.
                    altered_spelling = node.spelling[:-1] + 'T'
                    var_type, name = bv.parse_type_string(f'{underlying_typedef_type_string} {altered_spelling}')
                elif 'is not defined' in str(se):
                    var_type, name = bv.define_user_type(underlying_typedef_type_string)
                else:
                    bn.log.log_debug(f'typedef_decl: Failed to parse {node.underlying_typedef_type.spelling} '
                                     f'{node.spelling}')

    try:
        bv.define_user_type(name, var_type)
        bn.log.log_debug(f'typedef_decl: Successfully processed {node.underlying_typedef_type.spelling} '
                         f'{node.spelling}')
        return str(name), var_type
    except Exception as e:
        bn.log.log_debug(f'typedef_decl: Failed Processing {node.underlying_typedef_type.spelling} '
                         f'{node.spelling} with exception {e}')
예제 #8
0
def make_struct_here(view: BinaryView, address: int, length: int):
    structure_name = f"struct_{address:x}"

    structure = StructureBuilder()
    structure.width = length

    add_members(view, structure, address, length)

    structure_type = Type.structure_type(structure)

    view.begin_undo_actions()

    view.define_user_type(structure_name, structure_type)

    named_type = Type.named_type_from_type(structure_name, structure_type)

    view.define_user_data_var(address, named_type)

    view.commit_undo_actions()
예제 #9
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
예제 #10
0
def struct_decl(node: Cursor, bv: bn.BinaryView):
    struct = bn.Structure()
    struct.width = node.type.get_size()
    struct.alignment = node.type.get_align()
    if node.spelling:
        struct_name = node.spelling
    else:
        # A struct can be defined anonymously and assigned via a typedef, which means the struct_decl node itself
        # will have no spelling.
        # example: typedef struct {
        #                   DWORD Version;
        #                   GUID Guid;
        #                   SYSTEM_POWER_CONDITION PowerCondition;
        #                   DWORD DataLength;
        #                   BYTE Data[1];
        #                 } SET_POWER_SETTING_VALUE, *PSET_POWER_SETTING_VALUE;
        struct_name = node.type.spelling

    bn.log.log_debug(f'struct_decl: Processing struct {node.spelling}')

    # In order to avoid recursion problems with structs, always define the struct name as a binaryNinja forward decl
    bv.define_user_type(struct_name, bn.Type.structure_type(bn.Structure()))

    # check if struct is a forward declaration within the source code - if it is not a definition, then it is a forward
    # decl, and no fields should be defined at this point.
    if node.is_definition():
        for field in node.type.get_fields():
            bn.log.log_debug(f'struct_decl: Processing struct field {field.spelling}')

            if is_recursive_field(field, bv):
                forward_decl_struct = bn.Structure()
                forward_decl_struct_name = field.type.get_pointee().get_declaration().spelling
                bv.define_user_type(forward_decl_struct_name, bn.Type.structure_type(forward_decl_struct))
                t = bv.get_type_by_name(forward_decl_struct_name)
                struct.append(t, forward_decl_struct_name)
            else:
                var_type = bv.get_type_by_name(field.spelling)
                if not var_type:
                    # Need to define the field type
                    var_name, var_type = define_type(field.get_definition(), bv)
                struct.append(var_type, field.spelling)
            bn.log.log_debug(f'struct_decl: Successfully processed  struct field {field.spelling}')

    try:
        if node.kind == CursorKind.UNION_DECL:
            # set type to union
            struct.type = bn.StructureType.UnionStructureType

        bv.define_user_type(struct_name, bn.Type.structure_type(struct))
        bn.log.log_debug(f'struct_decl: Successfully processed struct {struct_name}')
        return struct_name, bn.Type.structure_type(struct)
    except Exception as e:
        bn.log.log_debug(f'struct_decl: Failed Processing struct {struct_name} with exception {e}')
def pre_define_types(bv: bn.BinaryView, library):
    for var_type, var_name in library.pre_load_definition.items():
        t, n = bv.parse_type_string(f'{var_type} {var_name}')
        bv.define_user_type(n, t)

    for forward_decl_struct in library.forward_declarations['struct']:
        struct = bn.Structure()
        bv.define_user_type(forward_decl_struct,
                            bn.Type.structure_type(bn.Structure()))
    for forward_decl_typedef in library.forward_declarations['typedef']:
        print(forward_decl_typedef)
        var_type, var_name = bv.parse_type_string(f'{forward_decl_typedef};')
        bv.define_user_type(var_name, var_type)
예제 #12
0
def pointer_type(node: Cursor, bv: bn.BinaryView):
    bn.log.log_debug(f'pointer_type: {node.type.spelling} {node.spelling}, \n'
                     f'node.type.kind: {node.type.kind} \n')
    if node.type.kind == TypeKind.TYPEDEF:
        pointee_type = node.underlying_typedef_type.get_pointee()
    elif node.type.kind == TypeKind.POINTER:
        pointee_type = node.type.get_pointee()
    else:
        bn.log.log_debug(f'pointer_type: Unhandled node type: {node.type.kind}')
        return

    if check_if_base_type(pointee_type):
        pointee_type_spelling = pointee_type.spelling
        if pointee_type_spelling in void_types:
            # BinaryNinja can't parse the expression 'const void'.
            pointee_type_spelling = 'void'
        # If its a base type then no need to define pointee type.
        bn.log.log_debug(f'pointer_type: Parsing type string: {pointee_type_spelling}')
        bn_pointee_type, name = bv.parse_type_string(pointee_type_spelling)
        pointer = bn.Type.pointer(bv.arch, bn_pointee_type)
    else:
        pointee_node = pointee_type.get_declaration()
        if pointee_node.kind == CursorKind.NO_DECL_FOUND:
            # Some types of TypeKind.TYPEDEF have no declaration node because they the type is just a pointer.
            # example: typedef EXCEPTION_ROUTINE *PEXCEPTION_ROUTINE;
            bn.log.log_debug(f'pointer_type: No declaration found for: {pointee_type.spelling} \n'
                             f'                                        pointee_type.kind: {pointee_type.kind}')
            if pointee_type.kind == TypeKind.FUNCTIONPROTO:
                # A special case happens when a type is a typedef for a function pointer - the function might be
                # an anonymous function that was not previously defined, so we must define it first (can't just parse
                # the string  with parse_type_string().
                # Example: typedef void
                #               (__stdcall *PIMAGE_TLS_CALLBACK) (
                #                                                   PVOID DllHandle,
                #                                                   DWORD Reason,
                #                                                   PVOID Reserved
                #                                                 );
                bn_pointee_name, bn_pointee_type = function_decl(node, bv)
                pointer = bn.Type.pointer(bv.arch, bn_pointee_type)
            elif pointee_type.kind == TypeKind.FUNCTIONNOPROTO:
                # FUNCTIONNOPROTO means there are no arguments, only a possible return type
                pointee_result_type = pointee_type.get_result()
                if check_if_base_type(pointee_result_type):
                    # Result is a base type, thus no declaration node.
                    # Example: long ()
                    pointee_result_string = pointee_result_type.spelling
                    if pointee_result_string in void_types:
                        pointee_result_string = 'void'
                    bn_result_type, bn_result_name = bv.parse_type_string(pointee_result_string)
                else:
                    result_type = pointee_type.get_result().get_declaration()
                    bn_result_name, bn_result_type = define_type(result_type, bv)
                pointer = bn.Type.pointer(bv.arch, bn.Type.function(bn_result_type, []))
            elif pointee_type.kind == TypeKind.POINTER:
                # we are dealing with a pointer to a pointer
                if check_if_base_type(pointee_type.get_pointee()):
                    type_string = pointee_type.get_pointee().spelling
                    if type_string in void_types:
                        type_string = 'void'
                    bn_pointee_type, bn_pointee_name = bv.parse_type_string(type_string)
                elif pointee_type.get_pointee().kind == TypeKind.POINTER:
                    # We have multiple nested pointers.
                    # Example: int ****a;
                    # The problem here is that if the pointee type is also a pointer, then it has no declaration node,
                    # so we can't call pointer_type() on it directly.
                    nested_pointer_count = 1
                    current_pointer_type = pointee_type.get_pointee()
                    while current_pointer_type.kind == TypeKind.POINTER:
                        nested_pointer_count += 1
                        current_pointer_type = current_pointer_type.get_pointee()
                    if check_if_base_type(current_pointer_type):
                        bn_pointee_type, bn_pointee_name = bv.parse_type_string(current_pointer_type.spelling)
                    else:
                        bn_pointee_name, bn_pointee_type = define_type(current_pointer_type, bv)
                    temp_bn_pointer_type = bn.Type.pointer(bv.arch, bn_pointee_type)
                    for nesting_level in range(nested_pointer_count):
                        temp_bn_pointer_type = bn.Type.pointer(bv.arch, temp_bn_pointer_type)
                    bn_pointee_type = bn.Type.pointer(bv.arch, temp_bn_pointer_type)
                elif pointee_type.get_pointee().get_declaration().kind == CursorKind.NO_DECL_FOUND:
                    # For some reason there is no declaration of the pointee.
                    # Manually parse the type and hope it was previously defined.
                    # TODO: Find a way to handle a case where the type was not already defined.
                    print(f'pointee_type.get_pointee().get_named_type().kind: {pointee_type.get_pointee().get_named_type().kind}')
                    # The reason I am parsing the pointee_type and not pointee_type.get_pointee() is that in some
                    # cases the pointer is pointing to a function prototype that has no declaration, and it is much
                    # easier to just parse the pointer to a known type then parse the underlying type.
                    bn_pointee_type, bn_pointee_name = bv.parse_type_string(pointee_type.spelling)
                else:
                    bn_pointee_name, bn_pointee_type = define_type(pointee_type.get_pointee().get_declaration(), bv)
                pointer = bn.Type.pointer(bv.arch, bn_pointee_type)
            else:
                bn_pointee_type, bn_pointee_name = bv.parse_type_string(node.underlying_typedef_type.spelling)
                pointer = bn.Type.pointer(bv.arch, bn_pointee_type)
        else:
            bn_pointee_type = bv.get_type_by_name(pointee_node.spelling)
            if bn_pointee_type is None:
                # need to define the pointee type before declaring the pointer
                bn_pointee_name, bn_pointee_type = define_type(pointee_node, bv)
                pointer = bn.Type.pointer(bv.arch, bn_pointee_type)
            else:
                # type already defined in the binaryView.
                pointer = bn.Type.pointer(bv.arch, bn_pointee_type)

    bv.define_user_type(node.spelling, pointer)
    bn.log.log_debug(f'pointer_type: Successfully defined : {node.spelling}')
    return node.spelling, pointer
예제 #13
0
def function_decl(node: Cursor, bv: bn.BinaryView):
    func_params: List = list()
    variable_arguments = False
    function_calling_convention: bn.CallingConvention = bv.platform.default_calling_convention

    bn.log.log_debug(f'function_decl: Processing function {node.spelling} \n'
                     f'               node.kind: {node.kind}, node.type.kind: {node.type.kind}')

    if node.kind == CursorKind.TYPEDEF_DECL:
        if node.type.kind == TypeKind.TYPEDEF:
            if node.underlying_typedef_type.kind == TypeKind.POINTER:
                # A special case in which we have a typedef for a function pointer to an anonymous function, so the
                # underlying type is a POINTER and not the actual function declaration. because it is an anonymous
                # function defined within a typedef there is no declaration node for it, only a type node.
                # Example: typedef void
                #                   (__stdcall *PIMAGE_TLS_CALLBACK) (
                #                                                       PVOID DllHandle,
                #                                                       DWORD Reason,
                #                                                       PVOID Reserved
                #                                                    );
                arg_types = node.underlying_typedef_type.get_pointee().argument_types()
                node_result_type = node.underlying_typedef_type.get_pointee().get_result()
                variable_arguments = node.underlying_typedef_type.get_pointee().is_function_variadic()
            else:
                arg_types = node.underlying_typedef_type.argument_types()
                node_result_type = node.underlying_typedef_type.get_result()
                variable_arguments = node.underlying_typedef_type.is_function_variadic()
        else:
            arg_types = node.type.argument_types()
            node_result_type = node.type.get_result()
            variable_arguments = node.type.is_function_variadic()
        # This is a libclang function prototype - need to use node.argument_types() to get all types.
        for param_type in arg_types:
            bn.log.log_debug(f'function_decl: Processing parameter type - {param_type.spelling} \n'
                             f'               param_type.kind: {param_type.kind}')
            if param_type.kind == TypeKind.INCOMPLETEARRAY:
                # An incomplete array cannot be parsed by binary ninja, need to manually create it.
                # This type usually has no declaration node, so cannot call define_type() on it.
                # Example: int a[]
                if check_if_base_type(param_type.get_array_element_type()):
                    arr_var_type, var_name = bv.parse_type_string(param_type.get_array_element_type().spelling)
                elif param_type.get_array_element_type().kind == TypeKind.POINTER:
                    # Example: int *a[]
                    # The pointer type has no declaration node so can't call define_type() directly.
                    pointee_name, pointee_type = define_type(
                        param_type.get_array_element_type().get_pointee().get_declaration(), bv
                    )
                    arr_var_type = bn.Type.pointer(bv.arch, pointee_type)
                    # TODO: Need to figure out a way to get the name of a parameter of this type.
                    var_name = ''
                else:
                    var_name, arr_var_type = define_type(param_type.get_array_element_type().get_declaration(), bv)
                var_type = bn.Type.array(arr_var_type, INCOMPLETE_ARRAY_ARBITRARY_SIZE)
            else:
                var_type, var_name = bv.parse_type_string(f'{remove_compiler_directives(param_type.spelling)}')
            p = bn.FunctionParameter(var_type, str(var_name))
            func_params.append(p)
    elif node.type.kind == TypeKind.POINTER:
        # If we got here, it means the pointee type is a FUNCTIONPROTO but has no declaration (if it had a declaration
        # then node arguemnt would be the declaration node itself and not a pointer.
        # Example: typedef struct _NCB {
        #                               UCHAR ncb_command;
        #                               void (__stdcall *ncb_post)( struct _NCB * );
        #                               } NCB, *PNCB;
        # ncb_post is a pointer to a FUNCTIONPROTO that has no Cursor node, only a type node.
        arg_types = node.type.get_pointee().argument_types()
        node_result_type = node.type.get_pointee().get_result()
        variable_arguments = node.type.get_pointee().is_function_variadic()
        for param_type in arg_types:
            bn.log.log_debug(f'function_decl: Processing pointee parameter type - {param_type.spelling} \n'
                             f'                                  param_type.kind: {param_type.kind}')
            param_type_string = remove_compiler_directives(param_type.spelling)
            if param_type.kind == TypeKind.INCOMPLETEARRAY:
                # Special case where we have an incomplete array without a declaration node, so we can't use
                # define_type().
                # Example: const PROPSPEC []
                # Since we know the base type of the array is already defined, all we need to do is modify the string
                # slightly so that binaryNinja can parse it (binja parser doesn't accept an incomplete array, it must
                # have an array size.
                # TODO: Find a more elegant way to insert an array size to the string.
                param_type_string = param_type_string.replace('[]', f'[{INCOMPLETE_ARRAY_ARBITRARY_SIZE}]')
            var_type, var_name = bv.parse_type_string(param_type_string)
            p = bn.FunctionParameter(var_type, str(var_name))
            func_params.append(p)
    else:
        node_result_type = node.type.get_result()
        if node.type.kind == TypeKind.FUNCTIONNOPROTO:
            # FUNCTIONNOPROTO means there are no arguments, only a possible return type
            pass
        else:
            variable_arguments = node.type.is_function_variadic()
            for param in node.get_arguments():
                bn.log.log_debug(f'function_decl: Processing parameter - {param.type.spelling} {param.spelling} \n'
                                 f'               param.kind: {param.kind}, param.type.kind: {param.type.kind}')
                var_name, var_type = define_type(param, bv)
                p = bn.FunctionParameter(var_type, str(var_name))
                func_params.append(p)
                bn.log.log_debug(f'function_decl: Successfully Processed parameter - {param.type.spelling} '
                                 f'{param.spelling}')

    func_return_val_type, ret_name = bv.parse_type_string(remove_compiler_directives(node_result_type.spelling))

    # No direct way to get the calling convention specified in the source code, need to iterate tokens and find it
    for token in node.get_tokens():
        if token.kind == TokenKind.KEYWORD:
            if token.spelling == '__cdecl':
                function_calling_convention: bn.CallingConvention = bv.platform.cdecl_calling_convention
            elif token.spelling == '__fastcall':
                function_calling_convention: bn.CallingConvention = bv.platform.fastcall_calling_convention
            elif token.spelling == '__stdcall':
                function_calling_convention: bn.CallingConvention = bv.platform.stdcall_calling_convention

    function_type = bn.Type.function(func_return_val_type,
                                     func_params,
                                     calling_convention=function_calling_convention,
                                     variable_arguments=variable_arguments
                                     )

    try:
        bv.define_user_type(node.spelling, function_type)
        bn.log.log_debug(f'function_decl: Successfully processed function {node.spelling}')
        return node.spelling, function_type
    except Exception as e:
        bn.log.log_debug(f'function_decl: Failed Processing function {node.spelling} with exception {e}')
예제 #14
0
def constantarray_type(node: Cursor, bv: bn.BinaryView):
    bn.log.log_debug(f'constantarray_type: {node.type.spelling} {node.spelling} \n'
                     f'                    node.kind: {node.kind}, node.type.kind: {node.type.kind}')
    element_type = node.type.get_array_element_type()
    bn.log.log_debug(f'constantarray_type: element_type: {element_type.spelling} \n'
                     f'                    element_type.kind: {element_type.kind}')

    array = None
    element_type_node = None

    bn_element_type = bv.get_type_by_name(element_type.spelling)
    if bn_element_type:
        # element type is already defined in the binaryView
        array = bn.Type.array(bn_element_type, node.type.get_array_size())
        bn.log.log_debug(f'constantarray_type: {element_type.spelling} already defined in the binaryView.')
    elif node.type.get_array_element_type().get_declaration().is_anonymous():
        # Anonymous struct\union\enum as the array member type
        element_type_node = node.type.get_array_element_type().get_declaration()
        anonymous_name, bn_anonymous_type = define_anonymous_type(element_type_node, bv)
        array = bn.Type.array(bn_anonymous_type, node.type.get_array_size())
        bn.log.log_debug(f'constantarray_type: Successfully proccessed anonymous type: {bn_anonymous_type} .')
    else:
        if check_if_base_type(element_type):
            # If its a base type then it wont apear in bv.get_type_by_name() but it is still defined.
            var_type, name = bv.parse_type_string(element_type.spelling)
            array = bn.Type.array(var_type, node.type.get_array_size())
        else:
            # Not a libclang base type, need to define it normally in the binaryView.
            if node.type.get_array_element_type().kind == TypeKind.POINTER:
                # The element is a pointer, so it won't have a declaration.
                # Get the declaration of the pointed type and create a binaryNinja pointer object as the type.
                if check_if_base_type(node.type.get_array_element_type().get_pointee()):
                    # The pointed type is a base type, parse it directly.
                    bn_element_type, bn_element_name = bv.parse_type_string(
                        node.type.get_array_element_type().get_pointee().spelling
                    )
                    pointer = bn.Type.pointer(bv.arch, bn_element_type)
                    array = bn.Type.array(pointer, node.type.get_array_size())
                else:
                    element_type_node = node.type.get_array_element_type().get_pointee().get_declaration()
            elif node.type.get_array_element_type().kind == TypeKind.CONSTANTARRAY:
                # The element type is another constant array, meaning we are dealing with a matrix.
                # Example: int a[3][4][5]
                if check_if_base_type(node.type.get_array_element_type().get_array_element_type()):
                    # The underlying matrix type is a base type, parse it directly.
                    bn_element_type, bn_element_name = bv.parse_type_string(
                        node.type.get_array_element_type().get_array_element_type().spelling
                    )
                    temp_array = bn.Type.array(bn_element_type, node.type.get_array_element_type().get_array_size())
                    array = bn.Type.array(temp_array, node.type.get_array_size())
                else:
                    element_type_node = node.type.get_array_element_type().get_array_element_type().get_declaration()
            else:
                element_type_node = node.type.get_array_element_type().get_declaration()

            if not array:
                # If array is defined at this point it means we have an array of pointers or a matrix, in which case
                # it was already handled and defined above.
                bn_element_name, bn_element_type = define_type(element_type_node, bv)
                array = bn.Type.array(bn_element_type, node.type.get_array_size())
    bv.define_user_type(node.spelling, array)
    bn.log.log_debug(f'constantarray_type: Successfully defined: {node.type.spelling} {node.spelling}')
    return node.spelling, array