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 __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 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) )
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
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))
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')
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
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 _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 )
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 _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
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
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
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 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 _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 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)
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, 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)
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 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)
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_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 _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 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
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 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 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 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))
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