def __init__(self, data): self.data = data if try_read_str(self.data, 0, 4) == "Yaz0": self.data = Yaz0Decompressor.decompress(self.data) data = self.data self.size = read_u32(data, 4) self.file_data_list_offset = read_u32(data, 0xC) + 0x20 self.file_data_total_size = read_u32(data, 0x10) self.file_data_total_size_2 = read_u32(data, 0x14) self.file_data_total_size_3 = read_u32(data, 0x18) num_nodes = read_u32(data, 0x20) node_list_offset = 0x40 self.total_num_file_entries = read_u32(data, 0x28) file_entries_list_offset = read_u32(data, 0x2C) + 0x20 self.string_list_offset = read_u32(data, 0x34) + 0x20 self.nodes = [] for node_index in range(0, num_nodes): offset = node_list_offset + node_index*0x10 node = Node(data, offset) self.nodes.append(node) self.file_entries = [] for node in self.nodes: for file_index in range(node.first_file_index, node.first_file_index+node.num_files): file_entry_offset = file_entries_list_offset + file_index*0x14 file_entry = FileEntry(data, file_entry_offset, self) self.file_entries.append(file_entry) node.files.append(file_entry) self.instantiated_object_files = {}
def disassemble_all_code(self): if not os.path.isfile( r"C:\devkitPro\devkitPPC\bin\powerpc-eabi-objdump.exe"): raise Exception( r"Failed to disassemble code: Could not find devkitPPC. devkitPPC should be installed to: C:\devkitPro\devkitPPC" ) rels_arc = self.get_arc("files/RELS.arc") out_dir = os.path.join(self.randomized_output_folder, "disassemble") if not os.path.isdir(out_dir): os.mkdir(out_dir) main_symbols = get_main_symbols(self) files_to_disassemble = get_list_of_all_rels(self) files_to_disassemble.append("sys/main.dol") for file_path in files_to_disassemble: basename_with_ext = os.path.basename(file_path) print(basename_with_ext) rel_file_entry = rels_arc.get_file_entry(basename_with_ext) if rel_file_entry: rel_file_entry.decompress_data_if_necessary() data = rel_file_entry.data else: data = self.gcm.read_file_data(file_path) if try_read_str(data, 0, 4) == "Yaz0": data = Yaz0Decompressor.decompress(data) basename, file_ext = os.path.splitext(basename_with_ext) is_rel = (file_ext == ".rel") bin_path = os.path.join(out_dir, basename_with_ext) with open(bin_path, "wb") as f: data.seek(0) f.write(data.read()) asm_path = os.path.join(out_dir, basename + ".asm") disassemble_file(bin_path, asm_path) if is_rel: rel_map_data = self.gcm.read_file_data("files/maps/" + basename + ".map") rel_map_data.seek(0) rel_map_data = rel_map_data.read() # Copy the map file to the output directory rel_map_path = os.path.join(out_dir, basename + ".map") with open(rel_map_path, "wb") as f: f.write(rel_map_data) rel_map_data = rel_map_data.decode("ascii") add_relocations_and_symbols_to_rel(asm_path, bin_path, main_symbols, rel_map_data) else: add_symbols_to_main(asm_path, main_symbols)
def __init__(self, file_path): self.file_path = file_path with open(self.file_path, "rb") as file: self.data = BytesIO(file.read()) if try_read_str(self.data, 0, 4) == "Yaz0": self.data = Yaz0Decompressor.decompress(self.data) data = self.data self.id = read_u32(data, 0) self.sections = [] self.num_sections = read_u32(data, 0xC) self.section_info_table_offset = read_u32(data, 0x10) for section_index in range(0, self.num_sections): section_info_offset = self.section_info_table_offset + section_index * 8 section = Section(data, section_info_offset) self.sections.append(section) self.relocation_data_offset_for_module = {} self.imp_table_offset = read_u32(data, 0x28) self.imp_table_length = read_u32(data, 0x2C) offset = self.imp_table_offset while offset < self.imp_table_offset + self.imp_table_length: module_num = read_u32(data, offset) relocation_data_offset = read_u32(data, offset + 4) self.relocation_data_offset_for_module[ module_num] = relocation_data_offset offset += 8 self.relocation_entries_for_module = {} curr_section_num = None for module_num, relocation_data_offset in self.relocation_data_offset_for_module.items( ): self.relocation_entries_for_module[module_num] = [] offset = relocation_data_offset prev_relocation_offset = 0 while True: relocation_type = read_u8(data, offset + 2) if relocation_type == 0xCB: # R_RVL_STOP break relocation_data_entry = RelocationDataEntry( data, offset, prev_relocation_offset, curr_section_num) prev_relocation_offset = relocation_data_entry.relocation_offset if relocation_data_entry.relocation_type == 0xCA: # R_RVL_SECT curr_section_num = relocation_data_entry.section_num_to_relocate_against prev_relocation_offset = 0 else: self.relocation_entries_for_module[module_num].append( relocation_data_entry) offset += 8
def disassemble_all_code(self): rels_arc = self.get_arc("files/RELS.arc") out_dir = os.path.join(self.randomized_output_folder, "disassemble") if not os.path.isdir(out_dir): os.mkdir(out_dir) main_symbols = get_main_symbols(self) files_to_disassemble = get_list_of_all_rels(self) files_to_disassemble.append("sys/main.dol") for file_path in files_to_disassemble: basename_with_ext = os.path.basename(file_path) print(basename_with_ext) rel_file_entry = rels_arc.get_file_entry(basename_with_ext) if rel_file_entry: rel_file_entry.decompress_data_if_necessary() data = rel_file_entry.data else: data = self.gcm.read_file_data(file_path) if try_read_str(data, 0, 4) == "Yaz0": data = Yaz0Decompressor.decompress(data) basename, file_ext = os.path.splitext(basename_with_ext) is_rel = (file_ext == ".rel") bin_path = os.path.join(out_dir, basename_with_ext) with open(bin_path, "wb") as f: data.seek(0) f.write(data.read()) asm_path = os.path.join(out_dir, basename + ".asm") disassemble_file(bin_path, asm_path) if is_rel: rel_map_data = self.gcm.read_file_data("files/maps/" + basename + ".map") rel_map_data.seek(0) rel_map_data = rel_map_data.read().decode("ascii") add_relocations_and_symbols_to_rel(asm_path, bin_path, main_symbols, rel_map_data) else: add_symbols_to_main(asm_path, main_symbols)
def get_raw_file(self, file_path): file_path = file_path.replace("\\", "/") if file_path in self.raw_files_by_path: return self.raw_files_by_path[file_path] else: if file_path.startswith("files/rels/"): rel_name = os.path.basename(file_path) rels_arc = self.get_arc("files/RELS.arc") rel_file_entry = rels_arc.get_file_entry(rel_name) else: rel_file_entry = None if rel_file_entry: rel_file_entry.decompress_data_if_necessary() data = rel_file_entry.data else: data = self.gcm.read_file_data(file_path) if try_read_str(data, 0, 4) == "Yaz0": data = Yaz0Decompressor.decompress(data) self.raw_files_by_path[file_path] = data return data
def decompress_data_if_necessary(self): if try_read_str(self.data, 0, 4) == "Yaz0": self.data = Yaz0Decompressor.decompress(self.data) self.type &= ~0x84 # Clear compressed type bits
def __init__(self, data): self.data = data if try_read_str(self.data, 0, 4) == "Yaz0": self.data = Yaz0Decompressor.decompress(self.data) data = self.data self.size = read_u32(data, 4) self.file_data_list_offset = read_u32(data, 0xC) + 0x20 self.file_data_total_size = read_u32(data, 0x10) self.file_data_total_size_2 = read_u32(data, 0x14) self.file_data_total_size_3 = read_u32(data, 0x18) num_nodes = read_u32(data, 0x20) node_list_offset = 0x40 self.total_num_file_entries = read_u32(data, 0x28) file_entries_list_offset = read_u32(data, 0x2C) + 0x20 self.string_list_offset = read_u32(data, 0x34) + 0x20 self.nodes = [] for node_index in range(0, num_nodes): offset = node_list_offset + node_index*0x10 node = Node(data, offset) self.nodes.append(node) self.file_entries = [] self.dzx_files = [] self.event_list_files = [] self.bmg_files = [] self.bdl_files = [] self.bti_files = [] self.chart_lists = [] for node in self.nodes: for file_index in range(node.first_file_index, node.first_file_index+node.num_files): file_entry_offset = file_entries_list_offset + file_index*0x14 file_entry = FileEntry(data, file_entry_offset, self) self.file_entries.append(file_entry) node.files.append(file_entry) if file_entry.is_dir: continue if file_entry.name.endswith(".dzs"): dzx = DZx(file_entry) self.dzx_files.append(dzx) elif file_entry.name.endswith(".dzr"): dzx = DZx(file_entry) self.dzx_files.append(dzx) elif file_entry.name == "event_list.dat": event_list = EventList(file_entry) self.event_list_files.append(event_list) elif file_entry.name.endswith(".bmg"): bmg = BMG(file_entry) self.bmg_files.append(bmg) elif file_entry.name.endswith(".bdl"): bdl = BDL(file_entry) self.bdl_files.append(bdl) elif file_entry.name.endswith(".bti"): bti = BTIFile(file_entry) self.bti_files.append(bti) elif file_entry.name == "cmapdat.bin": chart_list = ChartList(file_entry) self.chart_lists.append(chart_list)
def __init__(self, file_path): self.file_path = file_path with open(self.file_path, "rb") as file: self.data = BytesIO(file.read()) if try_read_str(self.data, 0, 4) == "Yaz0": self.data = Yaz0Decompressor.decompress(self.data) data = self.data self.id = read_u32(data, 0) self.sections = [] self.num_sections = read_u32(data, 0xC) self.section_info_table_offset = read_u32(data, 0x10) for section_index in range(0, self.num_sections): section_info_offset = self.section_info_table_offset + section_index * 8 section = Section(data, section_info_offset) self.sections.append(section) self.relocation_data_offset_for_module = {} self.imp_table_offset = read_u32(data, 0x28) self.imp_table_length = read_u32(data, 0x2C) offset = self.imp_table_offset while offset < self.imp_table_offset + self.imp_table_length: module_num = read_u32(data, offset) relocation_data_offset = read_u32(data, offset + 4) self.relocation_data_offset_for_module[ module_num] = relocation_data_offset offset += 8 self.relocation_entries_for_module = {} curr_section_num = None for module_num, relocation_data_offset in self.relocation_data_offset_for_module.items( ): self.relocation_entries_for_module[module_num] = [] offset = relocation_data_offset prev_relocation_offset = 0 while True: relocation_type = read_u8(data, offset + 2) if relocation_type == 0xCB: # R_RVL_STOP break relocation_data_entry = RelocationDataEntry( data, offset, prev_relocation_offset, curr_section_num) prev_relocation_offset = relocation_data_entry.relocation_offset if relocation_data_entry.relocation_type == 0xCA: # R_RVL_SECT curr_section_num = relocation_data_entry.section_num_to_relocate_against prev_relocation_offset = 0 else: self.relocation_entries_for_module[module_num].append( relocation_data_entry) offset += 8 # Space after this fix_size offset can be reused for other purposes. # Such as using the space that originally had the relocations list for .bss static variables instead. self.fix_size = read_u32(data, 0x48) self.fix_size = (self.fix_size + 0x1F) & ~(0x1F) # Round up to nearest 0x20 self.bss_section_index = None # The byte at offset 0x33 in the REL is reserved for this value at runtime. for section_index, section in enumerate(self.sections): if section.is_bss: self.bss_section_index = section_index section.offset = self.fix_size break