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))
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)
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"))
def _get_structure_members(address: int, t: Type, view: BinaryView) -> dict: from_bytes = _get_from_bytes(view) return { m.name: from_bytes(view.read(address + m.offset, m.type.width)) for m in t.structure.members }
def __init__(self, data: BinaryView): actual_data = data.read(0, len(data)).decode('utf8') binfile = BinFile() binfile.add(actual_data) decoded = b''.join(s.data for s in binfile.segments) parent = BinaryView.new(data=decoded) self.hex_segments = binfile.segments BinaryView.__init__(self, file_metadata=data.file, parent_view=parent)
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)
def _add_xrefs(view: BinaryView): log_debug('_add_xrefs') method_t = view.types.get('method_t') if method_t is None: return method_t_struct = method_t.structure method_t_name = method_t_struct['name'] for function in view.functions: data_refs = view.get_data_refs(function.start) log_debug(f'{function.name}: {data_refs}') method_t_list = [ var for var in map( view.get_data_var_at, (ref for ref in data_refs) ) ] log_debug(f'{function.name}: {method_t_list}') for method in method_t_list: name_ptr = int.from_bytes( view.read(method.address + method_t_name.offset, view.address_size), "little" if view.endianness == Endianness.LittleEndian else "big" ) for xref in view.get_code_refs(name_ptr): xref_mlil = xref.function.get_low_level_il_at(xref.address).mmlil if xref_mlil is None: log_debug(f'{xref.address:x}') return if xref_mlil.operation == MediumLevelILOperation.MLIL_SET_VAR: call_mlil = next( (use for use in xref_mlil.function.get_ssa_var_uses(xref_mlil.ssa_form.dest) if (use.instr_index > xref_mlil.instr_index and use.il_basic_block == xref_mlil.il_basic_block)), None ) else: return if call_mlil is not None: xref.function.set_user_xref(call_mlil.address, function.start)
def get_string(self, bv: BinaryView): s = bv.get_string_at(self.const, partial=True) if s: s = s.value else: # Get string with size of 3 or less (get_string_at does not return these) s = str(bv.read(self.const, 4)) if "\x00" not in s: s = None else: s = s.split("\x00", 1)[0] s = str(s) return s
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
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)
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))
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)
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
def rewrite_segments(view: BinaryView): class EmulatorBackgroundTask(BackgroundTaskThread): def __init__(self, view): self.view = view super().__init__() def run(self): self.view.update_analysis_and_wait() new_raw_view = BinaryView() current_addr = 0 for segment in view.segments: segment_data = view.read(segment.start, segment.data_length) segment_data += b'\x00'*(len(segment) - segment.data_length) new_raw_view.write(current_addr, segment_data) current_addr += len(segment_data) new_view = BinaryViewType['Mapped'].create(new_raw_view) new_view.remove_auto_segment(0, len(new_raw_view)) t = EmulatorBackgroundTask(new_view) t.start() t.join() current_addr = 0 for segment in view.segments: new_view.add_user_segment( segment.start, len(segment), current_addr, len(segment), ( (SegmentFlag.SegmentReadable if segment.readable else 0) | (SegmentFlag.SegmentWritable if segment.writable else 0) | (SegmentFlag.SegmentExecutable if segment.executable else 0) ) ) current_addr += len(segment) return new_view
def __init__(self, function, view=None): super(Emilator, self).__init__() if not isinstance(function, LowLevelILFunction): raise TypeError('function must be a LowLevelILFunction') self._function = function if view is None: view = BinaryView() self._view = view self._regs = {} self._flags = {} self._memory = memory.Memory(function.arch.address_size) for segment in view.segments: self._memory.map(segment.start, segment.length, segment.flags, view.read(segment.start, segment.length)) self._function_hooks = {} self.instr_index = 0
def _propagate_stret_types(view: BinaryView): log_debug('_propagate_stret_types') objc_msgSend_stret = next( (s for s in view.symbols.get('_objc_msgSend_stret', []) if s.type == SymbolType.ImportedFunctionSymbol), None ) if objc_msgSend_stret is None: return for xref in view.get_code_refs(objc_msgSend_stret.address): xref_mlil = xref.function.get_low_level_il_at(xref.address).mlil log_debug(f"{xref.address:x} {xref_mlil}") if xref_mlil is None: continue if xref_mlil.operation != MediumLevelILOperation.MLIL_CALL: continue selector_ptr = xref_mlil.params[2] if not selector_ptr.value.is_constant or selector_ptr.value.value == 0: continue log_debug(f'selector_ptr is {selector_ptr.value.value:x}') selector = view.get_ascii_string_at(selector_ptr.value.value, 1) if selector is None: selector_ptr = int.from_bytes( view.read(selector_ptr.value.value, view.address_size), "little" if view.endianness is Endianness.LittleEndian else "big" ) log_debug(f'{selector_ptr:x}') selector = view.get_ascii_string_at(selector_ptr) if selector is None: continue log_debug(f"selector is {selector.value}") receiver = xref_mlil.params[1] if receiver.operation != MediumLevelILOperation.MLIL_VAR: continue receiver_type = receiver.src.type log_debug(f'receiver_type is {receiver_type}') if (receiver_type.target is None or receiver_type.target.type_class != TypeClass.NamedTypeReferenceClass): continue receiver_name = receiver_type.target.named_type_reference.name log_debug(f'receiver name is {receiver_name}') receiver_class = view.session_data['ClassNames'].get(receiver_name) if receiver_class is None: continue if receiver_class.vtable is None or receiver_class.vtable.baseMethods is None: continue method = receiver_class.vtable.baseMethods.methods.get(selector.value) if method is None: continue log_debug(f'method is {method}') ret_type = method.types.parameters[0].type xref.function.create_user_var( xref_mlil.params[0].src, ret_type, xref_mlil.params[0].src.name )
def is_valid_for_data(self, data: BinaryView): try: actual_data = data.read(0, len(data)).decode('utf8') return is_srec(actual_data) except: return False
def perform_get_lines_for_data(self, ctxt, view: BinaryView, addr: int, type_: Type, prefix: list, width: int, context): from_bytes = _get_from_bytes(view) symbol: Symbol = view.get_symbol_at(addr) cfstring = view.types.get('CFString') if cfstring is None: log_debug('CFString is not defined; how did we even get here?') return [DisassemblyTextLine(prefix, addr)] cfstring = cfstring.structure buffer = from_bytes( view.read(addr + cfstring['buffer'].offset, view.address_size)) info = from_bytes( view.read(addr + cfstring['info'].offset, cfstring['info'].type.width)) length = from_bytes( view.read(addr + cfstring['length'].offset, cfstring['length'].type.width)) if info & 0xff == 0xc8: info_string = 'noinline,default,nofree,NI' elif info & 0xff == 0xd0: info_string = 'noinline,default,nofree,EUI' else: info_string = ( f'{_cfstring_allocator_properties[(info >> 5) & 0x3]},' f'{"U" if info & 16 else ""}' f'{"N" if info & 8 else ""}' f'{"L" if info & 4 else ""}' f'{"I" if info & 1 else ""}') if 'U' not in info_string: string = view.get_ascii_string_at(buffer, 0) if string is None: log_debug('string returned None; how did we even get here?') return [DisassemblyTextLine(prefix, addr)] string = string.value else: string = view.read(buffer, length * 2) if symbol is None: name = f'data_{addr:x}' else: name = symbol.short_name prefix = [ InstructionTextToken(InstructionTextTokenType.TypeNameToken, 'CFString'), InstructionTextToken(InstructionTextTokenType.TextToken, ' '), InstructionTextToken(InstructionTextTokenType.AnnotationToken, f'{{{info_string}}}'), InstructionTextToken(InstructionTextTokenType.TextToken, ' '), InstructionTextToken(InstructionTextTokenType.DataSymbolToken, name, addr), InstructionTextToken(InstructionTextTokenType.TextToken, ' = '), InstructionTextToken(InstructionTextTokenType.StringToken, f'{string!r}', buffer), InstructionTextToken(InstructionTextTokenType.TextToken, ' ') ] return [DisassemblyTextLine(prefix, addr)]