예제 #1
0
    def from_address(cls, address: int, view: BinaryView):
        if address == 0:
            return None

        from_bytes = get_from_bytes(view)

        protocol_list_t_type = view.get_type_by_name('protocol_list_t')

        protocol_list_t = Type.named_type_from_type('protocol_list_t',
                                                    protocol_list_t_type)

        protocol_t = view.get_type_by_name('protocol_t')

        members = get_structure_members(address, protocol_list_t_type, view)

        view.define_user_data_var(address, protocol_list_t)

        protocols = {}
        start = address + protocol_list_t_type.width
        end = start + members['count'] * view.address_size
        step = view.address_size
        for protocol_ptr in range(start, end, step):
            if not view.get_data_var_at(protocol_ptr):
                view.define_user_data_var(protocol_ptr,
                                          Type.pointer(view.arch, protocol_t))
            protocol = Protocol.from_address(
                from_bytes(view.read(protocol_ptr, view.address_size)), view)

            protocols[protocol.name] = protocol

        return cls(address, **members, protocols=protocols)
예제 #2
0
    def __create_class_name_type(bv: BinaryView, vmt: DelphiVMT, out_struct: types.Structure) -> bool:
        vmt_offsets = vmt.vmt_offsets

        if not vmt.seek_to_vmt_offset(vmt_offsets.cVmtClassName):
            return False

        class_name_ptr = vmt.read_ptr()

        if class_name_ptr is None:
            return False

        if not vmt.seek_to_code(class_name_ptr):
            return False

        class_name_len = vmt.read8()

        if class_name_len is None:
            return False

        class_name_struct = types.Structure()
        class_name_struct.append(Type.int(1, False), 'length')
        class_name_struct.append(Type.array(Type.char(), class_name_len), 'value')
        struct_type = Type.structure_type(class_name_struct)

        bv.define_user_data_var(class_name_ptr, struct_type)
        out_struct.append(Type.pointer(bv.arch, struct_type), 'cVmtClassName')

        # Create Symbole for class name
        class_name_sym = Symbol(SymbolType.DataSymbol, class_name_ptr, f'{vmt.class_name}Name')
        bv.define_user_symbol(class_name_sym)

        return True
예제 #3
0
    def visit_MLIL_CONST(self, expr):
        view = expr.function.source_function.view
        class_symbol = view.get_symbol_at(expr.constant)

        if class_symbol is None:
            return

        log_debug(class_symbol.name)

        class_match = re.match(
            r'_OBJC_(META)?CLASS_\$_(?P<classname>[_A-Za-z0-9=/]+)(@GOT)?',
            class_symbol.name
        )

        class_name = class_match.group('classname')

        class_type = view.types.get(class_name)

        if class_type is None:
            view.define_user_type(class_name, Type.structure_type(Structure()))
            class_type = view.types.get(class_name)

        return Type.pointer(
            view.arch,
            Type.named_type_from_type(class_name, class_type)
        )
예제 #4
0
파일: rtti.py 프로젝트: admdev8/binja-msvc
def create_vtable(view, vtable_name, vtable_address, max_funcs = 64):
    pointer_t = BinjaStruct.Pointer(view)

    funcs = list()

    for i in range(max_funcs):
        func_pointer_address = vtable_address + (i * view.address_size)
        func_address, _ = pointer_t.read(view, func_pointer_address)

        if func_address is None:
            break

        if not view.is_offset_executable(func_address):
            break

        func = view.get_function_at(func_pointer_address)

        if func is None:
            if i and view.get_code_refs(func_pointer_address, view.address_size):
                break

        funcs.append(func_address)

    if funcs:
        view.define_user_symbol(Symbol(SymbolType.DataSymbol, vtable_address, vtable_name))
        view.define_user_data_var(vtable_address, Type.array(Type.pointer(view.arch, Type.void(), const = True), len(funcs)))

    return funcs
예제 #5
0
def _define_strings_in_sections(sections, view):
    for section_name in sections:
        section = view.sections[section_name]

        for s in view.get_strings(section.start, len(section)):
            view.define_user_data_var(s.start,
                                      Type.array(Type.char(), s.length + 1))
예제 #6
0
	def update_memory_view(self):
		if self.adapter == None:
			raise Exception('missing adapter')
		if self.memory_view == None:
			raise Exception('missing memory_view')

		addr_regs = {}
		reg_addrs = {}

		for reg in self.adapter.reg_list():
			addr = self.adapter.reg_read(reg)
			reg_symbol_name = '$' + reg

			if addr not in addr_regs.keys():
				addr_regs[addr] = [reg_symbol_name]
			else:
				addr_regs[addr].append(reg_symbol_name)
			reg_addrs[reg] = addr

		for symbol in self.old_symbols:
			# Symbols are immutable so just destroy the old one
			self.memory_view.undefine_auto_symbol(symbol)

		for dv in self.old_dvs:
			self.memory_view.undefine_data_var(dv)

		self.old_symbols = []
		self.old_dvs = set()
		new_dvs = set()

		for (reg, addr) in reg_addrs.items():
			symbol_name = '$' + reg
			self.memory_view.define_auto_symbol(Symbol(SymbolType.ExternalSymbol, addr, symbol_name, namespace=symbol_name))
			self.old_symbols.append(self.memory_view.get_symbol_by_raw_name(symbol_name, namespace=symbol_name))
			new_dvs.add(addr)

		for new_dv in new_dvs:
			self.memory_view.define_data_var(new_dv, Type.int(8))
			self.old_dvs.add(new_dv)

		# Special struct for stack frame
		if self.bv.arch.name == 'x86_64':
			width = reg_addrs['rbp'] - reg_addrs['rsp'] + self.bv.arch.address_size
			if width > 0:
				if width > 0x1000:
					width = 0x1000
				struct = Structure()
				struct.type = StructureType.StructStructureType
				struct.width = width
				for i in range(0, width, self.bv.arch.address_size):
					var_name = "var_{:x}".format(width - i)
					struct.insert(i, Type.pointer(self.bv.arch, Type.void()), var_name)
				self.memory_view.define_data_var(reg_addrs['rsp'], Type.structure_type(struct))
				self.memory_view.define_auto_symbol(Symbol(SymbolType.ExternalSymbol, reg_addrs['rsp'], "$stack_frame", raw_name="$stack_frame"))

				self.old_symbols.append(self.memory_view.get_symbol_by_raw_name("$stack_frame"))
				self.old_dvs.add(reg_addrs['rsp'])
		else:
			raise NotImplementedError('only x86_64 so far')
예제 #7
0
    def update_memory_view(self):
        if self.adapter == None:
            raise Exception('missing adapter')
        if self.memory_view == None:
            raise Exception('missing memory_view')

        for symbol in self.old_symbols:
            # Symbols are immutable so just destroy the old one
            self.memory_view.undefine_auto_symbol(symbol)

        for dv in self.old_dvs:
            self.memory_view.undefine_data_var(dv)

        self.old_symbols = []
        self.old_dvs = set()
        new_dvs = set()

        for (reg, addr) in self.registers:
            bits = self.registers.bits(reg)
            symbol_name = '$' + reg
            self.memory_view.define_auto_symbol(
                Symbol(SymbolType.ExternalSymbol,
                       addr,
                       symbol_name,
                       namespace=symbol_name))
            self.old_symbols.append(
                self.memory_view.get_symbol_by_raw_name(symbol_name,
                                                        namespace=symbol_name))
            self.memory_view.define_data_var(addr,
                                             Type.int(bits // 8, sign=False))
            self.old_dvs.add(addr)

        # Special struct for stack frame
        if self.remote_arch.name == 'x86_64':
            width = self.registers['rbp'] - self.registers[
                'rsp'] + self.remote_arch.address_size
            if width > 0:
                if width > 0x1000:
                    width = 0x1000
                struct = Structure()
                struct.type = StructureType.StructStructureType
                struct.width = width
                for i in range(0, width, self.remote_arch.address_size):
                    var_name = "var_{:x}".format(width - i)
                    struct.insert(i, Type.pointer(self.remote_arch,
                                                  Type.void()), var_name)
                self.memory_view.define_data_var(self.registers['rsp'],
                                                 Type.structure_type(struct))
                self.memory_view.define_auto_symbol(
                    Symbol(SymbolType.ExternalSymbol,
                           self.registers['rsp'],
                           "$stack_frame",
                           raw_name="$stack_frame"))

                self.old_symbols.append(
                    self.memory_view.get_symbol_by_raw_name("$stack_frame"))
                self.old_dvs.add(self.registers['rsp'])
        else:
            pass
예제 #8
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)
예제 #9
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
    )
예제 #10
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}")
예제 #11
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
예제 #12
0
    def STRUCT_DECL_handler(self, current_node_hash):

        with self.driver.session() as session:
            struct_name = session.run("MATCH (binja_struct:STRUCT_DECL {Hash: {current_node_hash}}) "
                                      "RETURN binja_struct.TypeName as struct_name",
                                      current_node_hash=current_node_hash).peek()['struct_name']

            result = session.run("MATCH (binja_struct:STRUCT_DECL {Hash: {current_node_hash}})-[:FieldDef]->"
                                 "(struct_field:StructFieldDecl) "
                                 "RETURN struct_field.Hash as field_hash, "
                                 "       struct_field.TypeDefinition as type_definition,"
                                 "       struct_field.TypeName as type_name ",
                                 current_node_hash=current_node_hash)

            if result.peek():
                # Structs can be recursively defined. In order to avoid such a situation the binja_struct is
                # immediately inserted into the cache instead of waiting for the full definition.
                self.type_definition_cache[current_node_hash] = True

                print(f'struct_name: {struct_name} Hash: {current_node_hash}')

                binja_struct = types.Structure()
                self.bv.define_user_type(struct_name, Type.structure_type(types.Structure()))

                for record in result:
                    if self.insert_type_definition_into_binaryView('StructFieldDecl', record['field_hash']):
                        self.type_definition_cache[record['field_hash']] = True
                    else:
                        print("Failed to insert definition for binja_struct field ", record['field_hash'])
                        return False

                    try:
                        # add binja_struct member
                        print(f'binja_struct def: {record["type_definition"]} , name: {record["type_name"]}')
                        type_string = record['type_definition'] + ' ' + record['type_name']
                        if record['type_definition'].startswith('AnonUnion'):
                            type_string = 'union' + ' ' + type_string
                        elif record['type_definition'].startswith('AnonStruct'):
                            type_string = 'struct' + ' ' + type_string
                        print('type_string: ', type_string)
                        var_type, name = self.bv.parse_type_string(type_string)
                        binja_struct.append(var_type, str(name))
                    except Exception as e:
                        print("STRUCT_DECL_handler: Failed to add a binja_struct member" + str(e))
                        return False
            else:
                print("Struct has no target, current binja_struct hash: ", current_node_hash)
                return False

            try:
                self.bv.define_user_type(struct_name, Type.structure_type(binja_struct))
                return True
            except Exception as e:
                print("STRUCT_DECL_handler: Failed to define Struct. " + str(e))
                return False
예제 #13
0
    def UNION_DECL_handler(self, current_node_hash):

        with self.driver.session() as session:
            union_name = session.run("MATCH (union:UNION_DECL {Hash: {current_node_hash}}) "
                                     "RETURN union.TypeName as union_name",
                                     current_node_hash=current_node_hash).peek()['union_name']

            result = session.run("MATCH (union:UNION_DECL {Hash: {current_node_hash}})-[:FieldDef]->"
                                 "(union_field) "
                                 "RETURN union_field.Hash as field_hash, "
                                 "       labels(union_field)[0] as field_label, "
                                 "       union_field.TypeDefinition as type_definition,"
                                 "       union_field.TypeName as type_name ",
                                 current_node_hash=current_node_hash)

            if result.peek():
                # Unions can be recursively defined. In order to avoid such a situation the struct is
                # immediately inserted into the cache instead of waiting for the full definition.
                self.type_definition_cache[current_node_hash] = True

                struct = types.Structure()
                # set type to union
                struct.type = types.StructureType.UnionStructureType
                self.bv.define_user_type(union_name, Type.structure_type(types.Structure()))

                for record in result:
                    if self.insert_type_definition_into_binaryView(record['field_label'], record['field_hash']):
                        self.type_definition_cache[record['field_hash']] = True
                    else:
                        print("Failed to insert definition for union field ", record['field_hash'])
                        return False

                    try:
                        # add struct member
                        if record['type_definition'] == 'PointerTo':
                            type_string = record['type_name']
                        else:
                            type_string = record['type_definition'] + ' ' + record['type_name']
                        var_type, name = self.bv.parse_type_string(type_string)
                        struct.append(var_type, str(name))
                    except Exception as e:
                        print("UNION_DECL_handler: Failed to add union member. " + str(e))
                        return False
            else:
                print("Union has no target, current Union hash: ", current_node_hash)
                return False

            try:
                self.bv.define_user_type(union_name, Type.structure_type(struct))
                return True
            except Exception as e:
                print("UNION_DECL_handler: Failed to define union. " + str(e))
                return False
예제 #14
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)
예제 #15
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))
예제 #16
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
예제 #17
0
    def from_address(cls,
                     address: int,
                     self_type: str,
                     view: BinaryView,
                     is_class=False):
        if address == 0:
            return None

        method_list_t_type = view.get_type_by_name('method_list_t')

        method_list_t = Type.named_type_from_type('method_list_t',
                                                  method_list_t_type)

        method_t = view.get_type_by_name('method_t')

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

        members = get_structure_members(address, method_list_t_type, view)

        methods = dict()
        start = address + method_list_t_type.width
        end = start + members['count'] * method_t.width
        step = method_t.width
        for method_addr in range(start, end, step):
            method = Method.from_address(method_addr, self_type, view,
                                         is_class)
            if method is not None:
                methods[method.name] = method

        return cls(address, **members, methods=methods)
예제 #18
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)
예제 #19
0
    def from_address(cls, address: int, view: BinaryView):
        if address == 0:
            return None

        property_list_t_type = view.types['property_list_t']

        property_list_t = Type.named_type_from_type(
            'property_list_t', property_list_t_type
        )

        property_t = view.types['property_t']

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

        members = get_structure_members(address, property_list_t_type, view)

        properties = dict()
        start = address + property_list_t_type.width
        end = start + members['count'] * property_t.width
        step = property_t.width
        for property_addr in range(start, end, step):
            property_ = Property.from_address(property_addr, view)
            if property_ is not None:
                properties[property_.name] = property_

        return cls(address, **members, properties=properties)
예제 #20
0
def _define_classes(view: BinaryView, class_t: Type):
    __objc_data = view.sections.get('__objc_data')

    if __objc_data is None:
        raise KeyError('This binary has no __objc_data section')

    for addr in range(__objc_data.start, __objc_data.end, class_t.width):
        current_class = Class.from_address(addr, view)

        log_debug(f"Created {current_class}")

    __objc_classrefs = view.sections.get('__objc_classrefs')

    if __objc_classrefs is None:
        raise KeyError('This binary has no __objc_classrefs section')

    for addr in range(__objc_classrefs.start, __objc_classrefs.end,
                      view.address_size):
        view.define_user_data_var(addr, Type.pointer(view.arch, class_t))

        class_addr = int.from_bytes(
            view.read(addr, view.address_size),
            "little" if view.endianness is Endianness.LittleEndian else "big")

        class_ = view.session_data['ClassList'].get(
            class_addr) if class_addr else None

        if class_ is not None:
            log_debug(f"{addr:x} points to {class_!r}")
            view.define_user_symbol(
                Symbol(SymbolType.DataSymbol, addr,
                       f"_OBJC_CLASS_$_{class_.vtable.name}@GOT"))
예제 #21
0
    def from_address(cls, address: int, class_name: str, view: BinaryView):
        if address == 0:
            return None

        from_bytes = get_from_bytes(view)

        ivar_list_t_type = view.types['ivar_list_t']

        ivar_list_t = Type.named_type_from_type(
            'ivar_list_t', ivar_list_t_type
        )

        ivar_t = view.types['ivar_t']

        members = get_structure_members(address, ivar_list_t_type, view)

        view.define_user_data_var(address, ivar_list_t)

        ivars = {}
        start = address + ivar_list_t_type.width
        end = start + members['count'] * ivar_t.width
        step = ivar_t.width
        for ivar in range(start, end, step):
            new_ivar = Ivar.from_address(ivar, class_name, view)
            ivars[new_ivar.name] = new_ivar

        return cls(address, **members, ivars=ivars)
예제 #22
0
def _define_protocols(view: BinaryView):
    __objc_protorefs = view.get_section_by_name('__objc_protorefs')

    if __objc_protorefs is None:
        return

    protocol_t = Type.named_type_from_type('protocol_t',
                                           view.get_type_by_name('protocol_t'))

    for address in range(__objc_protorefs.start, __objc_protorefs.end,
                         view.address_size):
        view.define_user_data_var(address, Type.pointer(view.arch, protocol_t))

        protocol_ptr = int.from_bytes(
            view.read(address, view.address_size),
            "little" if view.endianness is Endianness.LittleEndian else "big")

        new_protocol = Protocol.from_address(protocol_ptr, view)
예제 #23
0
def _define_categories(view: BinaryView):
    __objc_catlist = view.sections.get('__objc_catlist')

    if __objc_catlist is None:
        return

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

    for address in range(__objc_catlist.start, __objc_catlist.end,
                         view.address_size):
        view.define_user_data_var(address, Type.pointer(view.arch, category_t))

        category_ptr = int.from_bytes(
            view.read(address, view.address_size),
            "little" if view.endianness is Endianness.LittleEndian else "big")

        new_category = Category.from_address(category_ptr, view)
예제 #24
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))
예제 #25
0
    def init(self):
        try:
            hdr = self.parent_view.read(self.HDR_OFFSET, self.HDR_SIZE)
            self.rom_title = hdr[0:15]
            self.color = hdr[15]
            self.licensee_code = struct.unpack("H", hdr[16:18])[0]
            self.gb_type = hdr[18]
            self.cart_type = hdr[19]
            self.rom_banks = hdr[20]
            self.ram_banks = hdr[21]
            self.destination_code = hdr[22]
            self.old_licensee_code = hdr[23]
            self.mask_rom_version = hdr[24]
            self.complement_check = hdr[25]
            self.checksum = struct.unpack("H", hdr[26:])[0]
        except:
            log_error(traceback.format_exc())
            return False

        # Add ROM mappings
        # ROM0
        self.add_auto_segment(
            self.ROM0_OFFSET, self.ROM0_SIZE, self.ROM0_OFFSET, self.ROM0_SIZE,
            SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable)
        self.add_auto_section("ROM0", self.ROM0_OFFSET, self.ROM0_SIZE,
                              SectionSemantics.ReadOnlyCodeSectionSemantics)
        # ROM1
        self.add_auto_segment(
            self.ROM1_OFFSET, self.ROM1_SIZE, self.ROM1_OFFSET, self.ROM1_SIZE,
            SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable)
        self.add_auto_section("ROM1", self.ROM1_OFFSET, self.ROM1_SIZE,
                              SectionSemantics.ReadWriteDataSectionSemantics)

        # Add RAM mappings
        for _, address, length in self.RAM_SEGMENTS:
            self.add_auto_segment(
                address, length, 0, 0, SegmentFlag.SegmentReadable
                | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable)

        # Add IO registers
        for address, name in LR35902.IO_REGISTERS.items():
            self.define_auto_symbol_and_var_or_function(
                Symbol(SymbolType.DataSymbol, address, name), Type.int(1))

        # Define entrypoint
        self.define_auto_symbol(
            Symbol(SymbolType.FunctionSymbol, self.START_ADDR, "_start"))
        self.add_entry_point(self.START_ADDR)

        # Define interrupts
        for name, address in self.INTERRUPT_HANDLERS:
            self.define_auto_symbol(
                Symbol(SymbolType.FunctionSymbol, address, name))
            #self.define_auto_symbol_and_var_or_function(Symbol(SymbolType.FunctionSymbol, address, name), Type.function(Type.void(), []))

        return True
예제 #26
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)
예제 #27
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
예제 #28
0
    def from_address(cls, address: int, view: BinaryView) -> Class:
        if address == 0:
            return None
        elif address in view.session_data['ClassList']:
            return view.session_data['ClassList'][address]
        else:
            new_class = cls(address, view, None, None, None, {}, {})
            view.session_data['ClassList'][address] = new_class

        from_bytes = get_from_bytes(view)

        members = get_structure_members(address,
                                        view.get_type_by_name('class_t'), view)

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

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

        vtable = ClassRO.from_address(members['vtable'], view,
                                      new_class.is_meta)
        new_class.vtable = vtable

        class_t = Type.named_type_from_type('class_t',
                                            view.get_type_by_name('class_t'))

        view.define_user_data_var(address, class_t)

        if not new_class.is_meta:
            view.session_data['ClassNames'][vtable.name] = new_class
        else:
            view.session_data['ClassNames'][f"{vtable.name}_meta"] = new_class

        if not new_class.is_meta:
            new_class.define_type()
            symbol_name = f'_OBJC_CLASS_$_{vtable.name}'
        else:
            symbol_name = f'_OBJC_METACLASS_$_{vtable.name}'

        view.define_user_symbol(
            Symbol(SymbolType.DataSymbol, address, symbol_name))

        if vtable and vtable.baseMethods is not None:
            new_class._methods = vtable.baseMethods.methods

        if vtable and vtable.baseProtocols is not None:
            new_class._protocols = vtable.baseProtocols.protocols

        return new_class
예제 #29
0
    def define_type(self):
        structure = Structure()
        structure.type = StructureType.ClassStructureType
        structure.width = self.vtable.instanceSize

        structure.insert(0, Type.pointer(self._view.arch, Type.void()), 'isa')

        classes = [self]
        current_superclass = self.superclass
        while current_superclass:
            classes.append(current_superclass)
            current_superclass = current_superclass.superclass

        while classes:
            current_class = classes.pop()
            if current_class.vtable.ivars is None:
                continue

            ivar_list = current_class.vtable.ivars
            for name, ivar in ivar_list.ivars.items():
                structure.insert(ivar.offset, ivar.type, name)

        self._view.define_user_type(self.vtable.name,
                                    Type.structure_type(structure))
예제 #30
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