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)
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 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)
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 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)
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}")
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 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 fix_printfs(view: BinaryView): printf = view.get_symbols_by_name('_printf') if not printf: printf = view.get_symbols_by_name('printf') if not printf: return for sym in printf: function = view.get_function_at(sym.address) if not function: continue xrefs = view.get_code_refs(function.start) for xref in xrefs: caller: Function = xref.function call_mlil = caller.get_low_level_il_at(xref.address).mlil print(call_mlil) if call_mlil is None: continue fmt_operand = call_mlil.params[0] if fmt_operand.operation == MediumLevelILOperation.MLIL_VAR: log.log_warn( f"Potential format string bug: {fmt_operand.address:x}") continue elif fmt_operand.operation in ( MediumLevelILOperation.MLIL_CONST_PTR, MediumLevelILOperation.MLIL_CONST): fmt_address = fmt_operand.constant fmt = view.get_ascii_string_at(fmt_address, 2) if fmt is None: continue fmt_value = fmt.value else: continue specifiers = fmt_value.split('%') param_types = [] for specifier in specifiers[1:]: if not specifier: continue if specifier.startswith('d'): param_types.append(Type.int(4, sign=True)) elif specifier.startswith('s'): param_types.append(Type.pointer(view.arch, Type.char())) elif specifier.startswith('p'): param_types.append(Type.pointer(view.arch, Type.void())) else: log.log_warn( f'Unknown format specifier: {specifier}; skipping') param_types.append(Type.pointer(view.arch, Type.void())) param_idx = 1 params = [ FunctionParameter(Type.pointer(view.arch, Type.char()), 'fmt') ] for param in param_types: params.append(FunctionParameter(param, f'arg{param_idx}')) param_idx += 1 caller.set_call_type_adjustment(xref.address, Type.function(Type.int(4), params))
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)]
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 parse_added_methods(view: BinaryView, class_addMethod: int): log_debug(f"parse_added_methods(view, {class_addMethod:x})") xrefs = view.get_code_refs(class_addMethod) for xref in xrefs: mlil = xref.function.mlil log_debug(f"{xref.address:x} Getting add_method_call") add_method_call = xref.function.get_low_level_il_at(xref.address).mlil log_debug(f"{xref.address:x} {add_method_call.operation!r}") if add_method_call.operation not in ( MediumLevelILOperation.MLIL_CALL, MediumLevelILOperation.MLIL_CALL_UNTYPED): continue class_param = add_method_call.params[0] if class_param.operation != MediumLevelILOperation.MLIL_VAR: log_debug(f"class_param is {class_param.operation!r}") continue cls_ = class_param.src.type log_debug(f"Checking {cls_!r}") if cls_.target is not None and cls_.target.named_type_reference is not None: class_name = cls_.target.named_type_reference.name else: log_debug(f"cls_ is {cls_}->{cls_.target}") continue log_debug("Getting selector_param") selector_param = add_method_call.params[1] if selector_param.operation == MediumLevelILOperation.MLIL_CONST: selector_ptr = selector_param elif selector_param.operation != MediumLevelILOperation.MLIL_VAR: log_debug(f"selector_param {selector_param.operation!r}") continue else: selector_ptr = None log_debug("Getting get_method_call") get_method_call = mlil.get_ssa_var_definition( selector_param.ssa_form.src) while get_method_call.operation != MediumLevelILOperation.MLIL_CALL: if get_method_call.operation != MediumLevelILOperation.MLIL_SET_VAR: log_debug(f"get_method_call {get_method_call.operation!r}") break if get_method_call.src.operation != MediumLevelILOperation.MLIL_VAR: log_debug(f"get_method_call.src {get_method_call.src!r}") break get_method_call = mlil.get_ssa_var_definition( get_method_call.ssa_form.src.src ) log_debug(f"{get_method_call!r}") else: log_debug(f"Found {get_method_call!r}") selector_ptr = get_method_call.params[1] if selector_ptr is None: log_debug("selector_ptr is None") continue if selector_ptr.operation not in ( MediumLevelILOperation.MLIL_CONST, MediumLevelILOperation.MLIL_CONST_PTR): log_debug(f"selector_ptr {selector_ptr.operation!r}") continue selector_str = view.get_ascii_string_at(selector_ptr.constant, 1) if selector_str is None: log_debug("selector_str is None") continue selector = selector_str.value method_string = f"-[{class_name} {selector}]" log_debug(f"method_string is {method_string}") method_ptr = add_method_call.params[2] if method_ptr.operation not in ( MediumLevelILOperation.MLIL_CONST, MediumLevelILOperation.MLIL_CONST_PTR): log_debug(f"method_ptr.operation {method_ptr.operation!r}") continue log_debug("Defining {method_string} @ {method_ptr.constant}") view.define_user_symbol( Symbol( SymbolType.FunctionSymbol, method_ptr.constant, method_string ) )