Пример #1
0
    def save_changes(self):
        hash = 0
        for char in self.name:
            hash *= 3
            hash += ord(char)
            hash &= 0xFFFF
        self.name_hash = hash

        # Set or clear compressed type bits
        if not self.is_dir and Yaz0.check_is_compressed(self.data):
            self.type |= 0x84
        else:
            self.type &= ~0x84

        type_and_name_offset = (self.type << 24) | (self.name_offset
                                                    & 0x00FFFFFF)

        if self.is_dir:
            data_offset_or_node_index = self.node_index
        else:
            data_offset_or_node_index = self.data_offset

        if self.is_dir:
            self.data_size = 0x10
        else:
            self.data_size = data_len(self.data)

        write_u16(self.rarc.data, self.entry_offset + 0x00, self.id)
        write_u16(self.rarc.data, self.entry_offset + 0x02, self.name_hash)
        write_u32(self.rarc.data, self.entry_offset + 0x04,
                  type_and_name_offset)
        write_u32(self.rarc.data, self.entry_offset + 0x08,
                  data_offset_or_node_index)
        write_u32(self.rarc.data, self.entry_offset + 0x0C, self.data_size)
        write_u32(self.rarc.data, self.entry_offset + 0x10, 0)  # Unused?
Пример #2
0
    def update_compression_flags_from_data(self):
        if self.is_dir:
            self.type &= ~RARCFileAttrType.COMPRESSED
            self.type &= ~RARCFileAttrType.YAZ0_COMPRESSED
            return

        if Yaz0.check_is_compressed(self.data):
            self.type |= RARCFileAttrType.COMPRESSED
            self.type |= RARCFileAttrType.YAZ0_COMPRESSED
        elif try_read_str(self.data, 0, 4) == "Yay0":
            self.type |= RARCFileAttrType.COMPRESSED
            self.type &= ~RARCFileAttrType.YAZ0_COMPRESSED
        else:
            self.type &= ~RARCFileAttrType.COMPRESSED
            self.type &= ~RARCFileAttrType.YAZ0_COMPRESSED
Пример #3
0
    def save_changes(self):
        hash = 0
        for char in self.name:
            hash *= 3
            hash += ord(char)
            hash &= 0xFFFF
        self.name_hash = hash

        # Set or clear compressed type bits.
        if not self.is_dir and Yaz0.check_is_compressed(self.data):
            self.type |= RARCFileAttrType.COMPRESSED
            self.type |= RARCFileAttrType.YAZ0_COMPRESSED
        else:
            self.type &= ~RARCFileAttrType.COMPRESSED
            self.type &= ~RARCFileAttrType.YAZ0_COMPRESSED

        type_and_name_offset = (self.type << 24) | (self.name_offset
                                                    & 0x00FFFFFF)

        if self.is_dir:
            data_offset_or_node_index = self.node_index
        else:
            data_offset_or_node_index = self.data_offset

        if self.is_dir:
            self.data_size = 0x10
        else:
            self.data_size = data_len(self.data)

        write_u16(self.rarc.data, self.entry_offset + 0x00, self.id)
        write_u16(self.rarc.data, self.entry_offset + 0x02, self.name_hash)
        write_u32(self.rarc.data, self.entry_offset + 0x04,
                  type_and_name_offset)
        write_u32(self.rarc.data, self.entry_offset + 0x08,
                  data_offset_or_node_index)
        write_u32(self.rarc.data, self.entry_offset + 0x0C, self.data_size)
        write_u32(self.rarc.data, self.entry_offset + 0x10,
                  0)  # Pointer to the file's data, filled at runtime.
Пример #4
0
    def __init__(self, data):
        if Yaz0.check_is_compressed(data):
            data = Yaz0.decompress(data)
        self.data = data

        self.read()
Пример #5
0
 def decompress_data_if_necessary(self):
     if Yaz0.check_is_compressed(self.data):
         self.data = Yaz0.decompress(self.data)
         self.update_compression_flags_from_data()
Пример #6
0
    def read(self, data):
        self.data = data

        if Yaz0.check_is_compressed(self.data):
            self.data = Yaz0.decompress(self.data)

        data = self.data

        # Read header.
        self.magic = read_str(data, 0, 4)
        assert self.magic == "RARC"
        self.size = read_u32(data, 4)
        self.data_header_offset = read_u32(data, 0x8)
        assert self.data_header_offset == 0x20
        self.file_data_list_offset = read_u32(data,
                                              0xC) + self.data_header_offset
        self.total_file_data_size = read_u32(data, 0x10)
        self.mram_file_data_size = read_u32(data, 0x14)
        self.aram_file_data_size = read_u32(data, 0x18)
        self.unknown_1 = read_u32(data, 0x1C)
        assert self.unknown_1 == 0

        # Read data header.
        self.num_nodes = read_u32(data, self.data_header_offset + 0x00)
        self.node_list_offset = read_u32(
            data, self.data_header_offset + 0x04) + self.data_header_offset
        self.total_num_file_entries = read_u32(data,
                                               self.data_header_offset + 0x08)
        self.file_entries_list_offset = read_u32(
            data, self.data_header_offset + 0x0C) + self.data_header_offset
        self.string_list_size = read_u32(data, self.data_header_offset + 0x10)
        self.string_list_offset = read_u32(
            data, self.data_header_offset + 0x14) + self.data_header_offset
        self.next_free_file_id = read_u16(data, self.data_header_offset + 0x18)
        self.keep_file_ids_synced_with_indexes = read_u8(
            data, self.data_header_offset + 0x1A)
        self.unknown_2 = read_u8(data, self.data_header_offset + 0x1B)
        assert self.unknown_2 == 0
        self.unknown_3 = read_u32(data, self.data_header_offset + 0x1C)
        assert self.unknown_3 == 0

        self.nodes = []
        for node_index in range(self.num_nodes):
            offset = self.node_list_offset + node_index * Node.ENTRY_SIZE
            node = Node(self)
            node.read(offset)
            self.nodes.append(node)

        self.file_entries = []
        for file_index in range(self.total_num_file_entries):
            file_entry_offset = self.file_entries_list_offset + file_index * FileEntry.ENTRY_SIZE
            file_entry = FileEntry(self)
            file_entry.read(file_entry_offset)
            self.file_entries.append(file_entry)

            if file_entry.is_dir and file_entry.node_index != 0xFFFFFFFF:
                file_entry.node = self.nodes[file_entry.node_index]
                if file_entry.name not in [".", ".."]:
                    assert file_entry.node.dir_entry is None
                    file_entry.node.dir_entry = file_entry

        for node in self.nodes:
            for file_index in range(node.first_file_index,
                                    node.first_file_index + node.num_files):
                file_entry = self.file_entries[file_index]
                file_entry.parent_node = node
                node.files.append(file_entry)

        self.instantiated_object_files = {}
Пример #7
0
 def __init__(self, data):
     if Yaz0.check_is_compressed(data):
         data = Yaz0.decompress(data)
     super(BTIFile, self).__init__(data)
Пример #8
0
 def read(self, data):
   self.data = data
   
   if Yaz0.check_is_compressed(self.data):
     self.data = Yaz0.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*RELSection.ENTRY_SIZE
     section = RELSection()
     section.read(data, section_info_offset)
     self.sections.append(section)
   
   self.name_offset = read_u32(data, 0x14)
   self.name_length = read_u32(data, 0x18)
   self.rel_format_version = read_u32(data, 0x1C)
   
   self.bss_size = read_u32(data, 0x20)
   
   relocation_data_offset_for_module = OrderedDict()
   self.relocation_table_offset = read_u32(data, 0x24)
   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)
     relocation_data_offset_for_module[module_num] = relocation_data_offset
     offset += 8
   
   self.relocation_entries_for_module = OrderedDict()
   curr_section_num = None
   for module_num, relocation_data_offset in 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 = RELRelocationType(read_u8(data, offset+2))
       if relocation_type == RELRelocationType.R_DOLPHIN_END:
         break
       
       relocation_data_entry = RELRelocation()
       relocation_data_entry.read(data, offset, prev_relocation_offset, curr_section_num)
       prev_relocation_offset = relocation_data_entry.relocation_offset
       
       if relocation_data_entry.relocation_type == RELRelocationType.R_DOLPHIN_SECTION:
         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 += RELRelocation.ENTRY_SIZE
   
   self.prolog_section = read_u8(data, 0x30)
   self.epilog_section = read_u8(data, 0x31)
   self.unresolved_section = read_u8(data, 0x32)
   self.prolog_offset = read_u32(data, 0x34)
   self.epilog_offset = read_u32(data, 0x38)
   self.unresolved_offset = read_u32(data, 0x3C)
   
   self.alignment = read_u32(data, 0x40)
   self.bss_alignment = read_u32(data, 0x44)
   
   # 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.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.bss_offset
       break
Пример #9
0
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)

    demangled_map_path = os.path.join(ASM_PATH, "maps-out",
                                      "framework.map.out")
    if os.path.isfile(demangled_map_path):
        with open(demangled_map_path, "rb") as f:
            framework_map_contents = BytesIO(f.read())
    else:
        framework_map_contents = self.gcm.read_file_data(
            "files/maps/framework.map")
    framework_map_contents = read_all_bytes(framework_map_contents).decode(
        "ascii")
    main_symbols = get_main_symbols(framework_map_contents)

    all_rel_paths = get_list_of_all_rels(self)
    files_to_disassemble = all_rel_paths.copy()
    files_to_disassemble.append("sys/main.dol")

    for file_path_in_gcm in files_to_disassemble:
        basename_with_ext = os.path.basename(file_path_in_gcm)

        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_in_gcm)
            if Yaz0.check_is_compressed(data):
                data = Yaz0.decompress(data)

        basename, file_ext = os.path.splitext(basename_with_ext)

        bin_path = os.path.join(out_dir, basename_with_ext)
        with open(bin_path, "wb") as f:
            data.seek(0)
            f.write(data.read())

    all_rels_by_path = OrderedDict()
    all_rel_symbols_by_path = OrderedDict()
    for file_path_in_gcm in all_rel_paths:
        basename_with_ext = os.path.basename(file_path_in_gcm)
        basename, file_ext = os.path.splitext(basename_with_ext)

        bin_path = os.path.join(out_dir, basename_with_ext)
        rel = REL()
        rel.read_from_file(bin_path)
        all_rels_by_path[file_path_in_gcm] = rel

        demangled_map_path = os.path.join(ASM_PATH, "maps-out",
                                          basename + ".map.out")
        if os.path.isfile(demangled_map_path):
            with open(demangled_map_path, "rb") as f:
                rel_map_data = BytesIO(f.read())
        else:
            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")

        all_rel_symbols_by_path[file_path_in_gcm] = get_rel_symbols(
            rel, rel_map_data)

    for file_path_in_gcm in files_to_disassemble:
        basename_with_ext = os.path.basename(file_path_in_gcm)
        print(basename_with_ext)

        basename, file_ext = os.path.splitext(basename_with_ext)

        bin_path = os.path.join(out_dir, basename_with_ext)
        asm_path = os.path.join(out_dir, basename + ".asm")

        disassemble_file(bin_path, asm_path)

        is_rel = (file_ext == ".rel")
        if is_rel:
            add_relocations_and_symbols_to_rel(asm_path, bin_path,
                                               file_path_in_gcm, main_symbols,
                                               all_rel_symbols_by_path,
                                               all_rels_by_path)
        else:
            add_symbols_to_main(self, asm_path, main_symbols)