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 __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
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, 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
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 _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
def create_vmt_struct(bv: BinaryView, vmt: DelphiVMT) -> bool: if not vmt.is_valid: return False vmt_struct = types.Structure() if not BNHelpers._add_vmt_fields(bv, vmt, vmt_struct): return False if not BNHelpers._add_vmt_methods(bv, vmt, vmt_struct): return False struct_type = Type.structure_type(vmt_struct) bv.define_user_data_var(vmt.start, struct_type) # bv.define_user_type(f'vmt{vmt.class_name}', struct_type) # Create Symbole for VMT vmt_sym = Symbol(SymbolType.DataSymbol, vmt.start, f'vmt{vmt.class_name}') bv.define_user_symbol(vmt_sym) return True
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 ) )