def __init__(self, block): if read_at(block, 0x0, 0x4) != b'IVFC': print('[WARN] Invalid IVFC magic') if read_u32(block, 0x4) != 0x20000: print('[WARN] Invalid 0x20000 IVFC magic') self.master_hash_size = read_u32(block, 0x8) self.nb_lvl = read_u32(block, 0xC) self.lvls = [] for n in range(self.IVFC_MAX_LEVEL): lvl = io.BytesIO(read_at(block, 0x10 + n * 0x18, 0x18)) self.lvls.append(self.IVFClvl(lvl)) self.master_hash = read_at(block, 0xC0, self.master_hash_size)
def __init__(self, raw_header): self.rsa_sig_1 = read_at(raw_header, 0x0, 0x100) self.rsa_sig_2 = read_at(raw_header, 0x100, 0x100) self.magic = read_at(raw_header, 0x200, 0x4) self.is_game_card = bool(read_u8(raw_header, 0x204)) self.content_type = self.content_types[read_u8(raw_header, 0x205)] self.crypto_type = read_u8(raw_header, 0x206) self.kaek_ind = read_u8(raw_header, 0x207) self.size = read_u64(raw_header, 0x208) self.tid = read_u64(raw_header, 0x210) self.sdk_rev = '.'.join( str(read_u8(raw_header, 0x21C + n)) for n in range(4))[::-1] self.crypto_type_2 = read_u8(raw_header, 0x220) self.sig_key_gen = read_u8(raw_header, 0x221) self.rights_id = read_at(raw_header, 0x230, 0x10) self.section_tables = [] for n in range(4): raw_section_table = io.BytesIO( read_at(raw_header, 0x240 + 0x10 * n, 0x10)) self.section_tables.append(SectionTable(raw_section_table)) self.hash_table = [] for n in range(4): self.hash_table.append(read_at(raw_header, 0x280 + n * 0x20, 0x20)) self.enc_key_area = read_at(raw_header, 0x300, 0x40) self.section_headers = [] for n in range(4): if self.section_tables[n].start_offset: # Sections exists raw_section_header = io.BytesIO( read_at(raw_header, 0x400 + n * FS_HEADER_LENGTH, FS_HEADER_LENGTH)) self.section_headers.append( SectionHeader(raw_section_header, self.section_tables[n]))
def _parse(self): if read_u64(self.f, 0x0) != 0x50: print('[WARN] RomFS header size isn\'t 0x50') self.dir_table = io.BytesIO( read_at(self.f, read_u64(self.f, 0x18), read_u64(self.f, 0x20))) self.file_table = io.BytesIO( read_at(self.f, read_u64(self.f, 0x38), read_u64(self.f, 0x40))) self.data_offset = read_u64(self.f, 0x48) if self.data_offset != ROMFS_FILEPARTITION_OFS: print('[WARN] Data offset isn\'t 0x200') self.first_file = None _, self.root = self._parse_dir(0, None) self._gen_metadata()
def _parse_dir(self, offset, parent): cur_dir_dict = { 'Parent': read_u32(self.dir_table, offset + 0x0), 'Sibling': read_u32(self.dir_table, offset + 0x4), 'Child': read_u32(self.dir_table, offset + 0x8), 'File': read_u32(self.dir_table, offset + 0xC), 'Name': read_at(self.dir_table, offset + 0x18, read_u32(self.dir_table, offset + 0x14)).decode() } dir_entry = DirEntry(parent, cur_dir_dict['Name']) if cur_dir_dict[ 'Child'] != ROMFS_ENTRY_EMPTY: # if not cur_dir_dict['Child'] + 1 & 1 << 32: child_dict, child_entry = self._parse_dir(cur_dir_dict['Child'], dir_entry) dir_entry.childs.append(child_entry) while child_dict['Sibling'] != ROMFS_ENTRY_EMPTY: child_dict, child_entry = self._parse_dir( child_dict['Sibling'], dir_entry) dir_entry.childs.append(child_entry) if cur_dir_dict['File'] != ROMFS_ENTRY_EMPTY: file_dict, file_entry = self._parse_file(cur_dir_dict['File'], dir_entry) dir_entry.files.append(file_entry) while file_dict['Sibling'] != ROMFS_ENTRY_EMPTY: file_dict, file_entry = self._parse_file( file_dict['Sibling'], dir_entry) dir_entry.files.append(file_entry) return cur_dir_dict, dir_entry
def _parse(self): if read_at(self.f, 0x0, 0x4) != b'META': raise ValueError('Invalid META magic') self.mmu_flags = read_u8(self.f, 0xC) self.main_thread_priority = read_u8(self.f, 0xE) self.default_cpu_id = read_u8(self.f, 0xF) self.process_category = self.process_categories[read_u32(self.f, 0x18)] self.main_thread_stack_size = read_u32(self.f, 0x1C) self.title_name = read_at(self.f, 0x20, 0x50).strip(b'\0').decode() aci0_offset = read_u32(self.f, 0x70) aci0_size = read_u32(self.f, 0x74) acid_offset = read_u32(self.f, 0x78) acid_size = read_u32(self.f, 0x7C) self.acid = ACID(io.BytesIO(read_at(self.f, acid_offset, acid_size))) self.aci0 = ACI0(io.BytesIO(read_at(self.f, aci0_offset, aci0_size)))
def _parse(self): if read_at(self.f, 0x0, 0x4) != b'ACI0': raise ValueError('Invalid ACI0 magic') self.tid = read_u64(self.f, 0x10) fs_access_control_offset = read_u32(self.f, 0x20) fs_access_control_size = read_u32(self.f, 0x24) service_access_control_offset = read_u32(self.f, 0x28) service_access_control_size = read_u32(self.f, 0x2C) kernel_access_control_offset = read_u32(self.f, 0x30) kernel_access_control_size = read_u32(self.f, 0x34) self.fs_access_control = FsAccessControl(io.BytesIO(read_at(self.f, fs_access_control_offset, fs_access_control_size))) self.service_access_control = ServiceAccessControl(io.BytesIO(read_at(self.f, service_access_control_offset, service_access_control_size))) self.kernel_access_control = KernelAccessControl(io.BytesIO(read_at(self.f, kernel_access_control_offset, kernel_access_control_size)))
def _parse(self): self.rsa_sig = read_at(self.f, 0x0, 0x100) self.rsa_pubk = read_at(self.f, 0x100, 0x100) if read_at(self.f, 0x200, 0x4) != b'ACID': raise ValueError('Invalid ACID magic') self.flags = read_u32(self.f, 0x20C) self.tid_min = read_u64(self.f, 0x210) self.tid_max = read_u64(self.f, 0x218) fs_access_control_offset = read_u32(self.f, 0x220) fs_access_control_size = read_u32(self.f, 0x224) service_access_control_offset = read_u32(self.f, 0x228) service_access_control_size = read_u32(self.f, 0x22C) kernel_access_control_offset = read_u32(self.f, 0x230) kernel_access_control_size = read_u32(self.f, 0x234) self.fs_access_control = FsAccessControl( io.BytesIO( read_at(self.f, fs_access_control_offset, fs_access_control_size))) self.service_access_control = ServiceAccessControl( io.BytesIO( read_at(self.f, service_access_control_offset, service_access_control_size))) self.kernel_access_control = KernelAccessControl( io.BytesIO( read_at(self.f, kernel_access_control_offset, kernel_access_control_size)))
def _parse_file(self, offset, parent): file_dict = { 'Parent': read_u32(self.file_table, offset + 0x0), 'Sibling': read_u32(self.file_table, offset + 0x4), 'DataOffset': read_u64(self.file_table, offset + 0x8), 'Size': read_u32(self.file_table, offset + 0x10), 'Name': read_at(self.file_table, offset + 0x20, read_u32(self.file_table, offset + 0x1C)).decode() } file_entry = FileEntry(parent, file_dict['Name'], file_dict['Size']) file_entry.offset_in_romfs_data = file_dict['DataOffset'] file_entry.is_repacked = True return file_dict, file_entry
def __init__(self, raw_section_header, section_table): self.offset = section_table.start_offset self.size = section_table.end_offset - self.offset self.part_type = self.part_types[read_u8(raw_section_header, 0x2)] self.fs_type = self.fs_types[read_u8(raw_section_header, 0x3)] self.crypto_type = self.crypto_types[read_u8(raw_section_header, 0x4)] raw_superblock = io.BytesIO( read_at(raw_section_header, 0x8, self.SECTION_HEADER_LENGTH)) self.section_ctr = read_u64(raw_section_header, 0x140) if self.fs_type == 'PFS0': self.superblock = PFS0Superblock(raw_superblock) self.fs_offset = self.superblock.offset self.fs_size = self.superblock.size elif self.fs_type == 'RomFS': self.superblock = IVFCSuperblock(raw_superblock) self.fs_offset = self.superblock.lvls[-1].offset self.fs_size = self.superblock.lvls[-1].size
def ret(self): aci0_offset = read_u32(self.f, 0x70) aci0_size = read_u32(self.f, 0x74) acid_offset = read_u32(self.f, 0x78) acid_size = read_u32(self.f, 0x7C) return read_at(self.f, 0x0, acid_offset+acid_size)