コード例 #1
0
ファイル: entry.py プロジェクト: Nicba1010/PS-Tools
    def __init__(self, f: IO):
        #: Virtual Index ID
        self.virtual_index_id: bytes = f.read(8)
        logger.info(f'Key Offset: {hexlify(self.virtual_index_id)}')

        #: File Name
        self.file_name: str = f.read(65).decode('UTF-8').strip('\0').strip()
        logger.info(f'File Name: {self.file_name}')

        #: Padding 0
        self.padding_0: bytes = f.read(7)
        logger.info(f'Padding 0: {hexlify(self.padding_0)}')

        #: Key
        self.key: bytes = f.read(64)
        logger.info(f'Key: {hexlify(self.key)}')

        #: Real File Key
        # self.real_table_key: bytes = create_syscon_aes_cbc_cipher()

        #: File Hashes
        self.file_hashes: List[bytes] = []
        for i in range(4):
            file_hash: bytes = f.read(20)
            logger.info(f'File Hash #{i}: {hexlify(file_hash)}')
            self.file_hashes.append(file_hash)

        #: Padding 1
        self.padding_1: bytes = f.read(40)
        logger.info(f'Padding 1: {hexlify(self.padding_1)}')

        #: File Size
        self.file_size: int = read_u64(f, endianess=Endianess.BIG_ENDIAN)
        logger.info(f'File Size: {self.file_size}')
コード例 #2
0
ファイル: header.py プロジェクト: Nicba1010/PS-Tools
    def __init__(self, f: IO):
        super().__init__(f)

        self.revision: PkgRevision = PkgRevision(f.read(2))
        self.type: PkgType = PkgType(f.read(2))
        self.logger.info(f'PKG Revision: {self.revision}')
        self.logger.info(f'PKG Type: {self.type}')

        self.metadata_offset: int = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        self.metadata_count: int = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        self.metadata_size: int = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(f'Metadata Offset: {self.metadata_offset}')
        self.logger.info(f'Metadata Count: {self.metadata_count}')
        self.logger.info(f'Metadata Size: {self.metadata_size}')

        self.item_count: int = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(f'Item Count: {self.item_count}')

        self.total_size: int = read_u64(f, endianess=Endianess.BIG_ENDIAN)
        self.data_offset: int = read_u64(f, endianess=Endianess.BIG_ENDIAN)
        self.data_size: int = read_u64(f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(f'Total Size: {self.total_size}')
        self.logger.info(f'Data Offset: {self.data_offset}')
        self.logger.info(f'Data Size: {self.data_size}')

        self.content_id: str = f.read(0x24).decode('utf-8')
        self.logger.info(f'Content ID: {self.content_id}')

        self.padding: bytes = f.read(0x0C)

        self.digest: bytes = f.read(0x10)
        self.pkg_data_riv: bytes = f.read(0x10)
        self.header_cmac_hash: bytes = f.read(0x10)
        self.header_npdrm_signature: bytes = f.read(0x28)
        self.header_sha1_hash: bytes = f.read(0x08)
        self.logger.info(f'Digest: {hexlify(self.digest)}')
        self.logger.info(f'PKG Data Riv: {self.pkg_data_riv}')
        self.logger.info(f'Header CMAC Hash: {hexlify(self.header_cmac_hash)}')
        self.logger.info(
            f'Header NPDRM Signature: {hexlify(self.header_npdrm_signature)}')
        self.logger.info(f'Header SHA1 Hash: {hexlify(self.header_sha1_hash)}')

        if self.type == PkgType.PSP_PSVITA:
            self.ext_header: PkgExtHeader = PkgExtHeader(f)
コード例 #3
0
    def __init__(self, f: IO):
        super().__init__(f)

        #: TODO: Find what this unknown field is
        self.unknown_1: int = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        constant_check(self.logger, 'Unknown 1', self.unknown_1, 1)

        #: Header size
        self.header_size: int = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(f'Header Size: {self.header_size}')

        #: Data size
        self.data_size: int = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(f'Data Size: {self.data_size}')

        #: Main and EXT Headers HMAC offset TODO: Check this validity
        self.main_and_ext_headers_hmac_offset: int = read_u32(
            f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(
            f'Main and Ext Headers HMAC Offset: {self.main_and_ext_headers_hmac_offset}'
        )

        #: Metadata Header HMAC offset TODO: Check this validity
        self.metadata_header_hmac_offset: int = read_u32(
            f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(
            f'Metadata Header HMAC Offset: {self.metadata_header_hmac_offset}')

        #: Tail offset
        self.tail_offset: int = read_u64(f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(f'Tail Offset: {self.tail_offset}')

        #: Just padding probably
        self.padding_1: int = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        constant_check(self.logger, 'Padding 1', self.padding_1, 0)

        #: PKG Key ID
        self.pkg_key_id: PkgKeyID = PkgKeyID(
            read_u32(f, endianess=Endianess.BIG_ENDIAN))
        self.logger.info(f'PKG Key ID: {self.pkg_key_id}')

        #: Full Header HMAC offset TODO: Check this validity
        self.full_header_hmac_offset: int = read_u32(
            f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(
            f'Full Header HMAC Offset: {self.full_header_hmac_offset}')

        #: Just padding
        self.padding_2: bytes = f.read(0x14)
        constant_check(self.logger, 'Padding 2', self.padding_2,
                       bytes([0x00] * 0x14))
コード例 #4
0
ファイル: header.py プロジェクト: Nicba1010/PS-Tools
    def __init__(self, f: IO):
        super().__init__(f)

        #: File format version
        self.version: int = read_u64(f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(f'Version: {self.version}')

        #: If version isn't 3 or 4 raise an exception
        if self.version not in (0x03, 0x04):
            raise InvalidPFDVersionException

        #: Header Table IV
        self.header_table_iv: bytes = f.read(16)
        self.logger.info(f'Header Table IV: {hexlify(self.header_table_iv)}')

        #: Header Table Cipher
        self.header_table_cipher: Cipher = create_syscon_aes_cbc_cipher(
            self.header_table_iv)

        #: Header Table Decryptor
        self.header_table_decryptor: CipherContext = self.header_table_cipher.decryptor(
        )

        #: Header Table Encrypted
        self.header_table_encrypted: bytes = f.read(64)
        self.logger.info(
            f'Header Table Encrypted: {hexlify(self.header_table_encrypted)}')

        #: Header Table Decrypted
        self.header_data_decrypted: bytearray = bytearray()
        self.header_data_decrypted += self.header_table_decryptor.update(
            self.header_table_encrypted)
        self.header_data_decrypted += self.header_table_decryptor.finalize()
        self.logger.info(
            f'Header Table Decrypted: {hexlify(self.header_data_decrypted)}')

        #: Y Table HMAC
        self.y_table_hmac: bytes = bytes(self.header_data_decrypted[0:20])
        self.logger.info(
            f'Y Table HMAC: {hexlify(self.header_data_decrypted)}')

        #: X Table & Entry Table HMAC
        self.x_table_entry_table_hmac: bytes = bytes(
            self.header_data_decrypted[20:40])
        self.logger.info(
            f'X Table & Entry Table HMAC Table HMAC: {hexlify(self.x_table_entry_table_hmac)}'
        )

        #: File HMAC Key
        self.file_hmac_key: bytes = bytes(self.header_data_decrypted[40:60])
        self.logger.info(f'File HMAC Key: {hexlify(self.file_hmac_key)}')

        #: Padding
        self.padding: bytes = bytes(self.header_data_decrypted[60:64])
        self.logger.info(f'Padding: {hexlify(self.padding)}')

        if self.version == 3:
            self.real_key: bytes = self.file_hmac_key
        elif self.version == 4:
            self.real_key: bytes = hmac_sha256(KEYGEN_KEY, self.file_hmac_key)
        self.logger.info(f'Real Key: {hexlify(self.real_key)}')

        #: XY Tables Reserved Entries
        self.xy_tables_reserved_entry_count: int = read_u64(
            f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(
            f'XY Tables Reserved Entries: {self.xy_tables_reserved_entry_count}'
        )

        #: Protected Files Table Reserved Entries
        self.protected_files_table_reserved_entry_count: int = read_u64(
            f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(
            f'Protected Files Table Reserved Entries: {self.protected_files_table_reserved_entry_count}'
        )

        #: Protected Files Table Used Entries
        self.protected_files_table_used_entry_count: int = read_u64(
            f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(
            f'Protected Files Table Used Entries: {self.protected_files_table_used_entry_count}'
        )
コード例 #5
0
    def __init__(self, f: IO):
        super().__init__(f)

        #: EDAT file format version
        self.version: int = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(f"EDAT Version: {self.version}")

        #: Licence Type
        self.licence_type: LicenceType = LicenceType(read_u32(f, endianess=Endianess.BIG_ENDIAN))
        self.logger.info(f"Licence Type: {self.licence_type}")

        #: Application Type
        self.application_type: ApplicationType = ApplicationType(read_u32(f, endianess=Endianess.BIG_ENDIAN))
        self.logger.info(f"Application Type: {self.application_type}")

        #: Content ID
        self.content_id: str = f.read(0x30).decode('UTF-8')
        self.logger.info(f"Content ID: {self.content_id}")

        #: Digest
        """
         (seems like to be a SHA-1 hash of the non-finalized file)
         hash of the original data which is unknown until the whole 
         file is read, can not be used as check. Can be used as 
         watermark or zeroed on forged file.
        """
        # TODO: Do hashcheck
        self.qa_digest: bytearray = f.read(0x10)
        self.logger.info(f"QA Digest: {hexlify(self.qa_digest)}")

        #: NPD Hash 1
        """
         CID-FN hash (an AES CMAC hash of concatenation of Content
         ID and File Name using the third NPDRM OMAC pkg_internal_fs_key as CMAC pkg_internal_fs_key)
        """
        # TODO: Do hashcheck
        self.npd_hash_1: bytearray = f.read(0x10)
        self.logger.info(f"NPD Hash 1: {hexlify(self.npd_hash_1)}")

        #: NPD Hash 2
        """
         header hash (an AES CMAC hash of the 0x60 bytes from the 
         beginning of file using xored bytes of the developer's 
         klicensee and the second NPDRM OMAC pkg_internal_fs_key as CMAC pkg_internal_fs_key)
        """
        # TODO: Do hashcheck
        self.npd_hash_2: bytearray = f.read(0x10)
        self.logger.info(f"NPD Hash 2: {hexlify(self.npd_hash_2)}")

        #: Activation Time (start of the validity period, filled with 0x00 if not used)
        # TODO: Reverse date format
        self.activation_time: bytearray = f.read(0x08)
        self.logger.info(f"Activation Time: {hexlify(self.activation_time)}")

        #: Deactivation Time (end of the validity period, filled with 0x00 if not used)
        # TODO: Reverse date format
        self.deactivation_time: bytearray = f.read(0x08)
        self.logger.info(f"Deactivation Time: {hexlify(self.deactivation_time)}")

        #: Npd Type
        # TODO: (Separated from Metadata type for wiki format)
        self.npd_type: NpdType = NpdType(read_u8(f, endianess=Endianess.BIG_ENDIAN))
        self.logger.info(f"Npd Type: {self.npd_type}")

        #: Metadata Type
        # TODO: (Outdated Flags description from talk page)
        self.metadata_type: MetadataType = MetadataType(
            unpack_u32(bytes([0]) + f.read(0x03), endianess=Endianess.BIG_ENDIAN)
        )
        self.logger.info(f"Metadata Type: {self.metadata_type}")

        #: Block Size
        self.block_size: int = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(f"Block Size: {self.block_size}")
        if self.block_size > 0x8000:
            raise InvalidEDATBlockSizeException()

        #: Data Size
        self.data_size: int = read_u64(f, endianess=Endianess.BIG_ENDIAN)
        self.logger.info(f"Data Size: {self.data_size}")

        #: Metadata Sections Hash
        # TODO: Do hashcheck
        self.metadata_sections_hash: bytearray = f.read(0x10)
        self.logger.info(f"Metadata Sections Hash: {hexlify(self.metadata_sections_hash)}")

        #: Extended Header Hash
        """
         An AES CMAC hash of 160 bytes from the beginning of file) 
         uses the hash pkg_internal_fs_key as CMAC pkg_internal_fs_key and it depends on the file 
         flags and keys
        """
        # TODO: Do hashcheck
        self.extended_header_hash: bytearray = f.read(0x10)
        self.logger.info(f"Extended Header Hash: {hexlify(self.extended_header_hash)}")

        #: ECDSA Metadata Signature
        """
         Can be zeroed on forged file. curve_type is vsh type 0x02, 
         pub is vsh public pkg_internal_fs_key,
        """
        # TODO: Do hashcheck
        self.ecdsa_metadata_signature: bytearray = f.read(0x28)
        self.logger.info(f"Extended Header Hash: {hexlify(self.ecdsa_metadata_signature)}")

        #: ECDSA Header Signature
        """
         Enabled (only?) for PS2 classic: all custom firmwares are 
         patched to skip the ECDSA check. Can be zeroed on forged file. 
         curve_type is vsh type 0x02, pub is vsh public pkg_internal_fs_key.
        """
        # TODO: Do hashcheck
        self.ecdsa_header_signature: bytearray = f.read(0x28)
        self.logger.info(f"ECDSA Header Signature: {hexlify(self.ecdsa_header_signature)}")
コード例 #6
0
    def __init__(self, f: IO):
        """
        Init
        """
        super().__init__()

        self.flags: int = read_u64(f, endianess=Endianess.BIG_ENDIAN)
        self.logger.debug(f"Flags: {self.flags}")

        self.menu_call: bool = get_flag(self.flags, 0)
        self.logger.debug(f"Menu Call: {self.menu_call}")

        self.title_search: bool = get_flag(self.flags, 1)
        self.logger.debug(f"Title Search: {self.title_search}")

        self.chapter_search: bool = get_flag(self.flags, 2)
        self.logger.debug(f"Chapter Search: {self.chapter_search}")

        self.time_search: bool = get_flag(self.flags, 3)
        self.logger.debug(f"Time Search: {self.time_search}")

        self.skip_to_next_point: bool = get_flag(self.flags, 4)
        self.logger.debug(f"Skip To Next Point: {self.skip_to_next_point}")

        self.skip_to_prev_point: bool = get_flag(self.flags, 5)
        self.logger.debug(f"Skip To Prev Point: {self.skip_to_next_point}")

        self.reserved_1: bool = get_flag(self.flags, 6)
        self.logger.debug(f"Reserved 1: {self.reserved_1}")

        self.stop: bool = get_flag(self.flags, 7)
        self.logger.debug(f"Stop: {self.stop}")

        self.pause_on: bool = get_flag(self.flags, 8)
        self.logger.debug(f"Pause On: {self.pause_on}")

        self.reserved_2: bool = get_flag(self.flags, 9)
        self.logger.debug(f"Reserved 2: {self.reserved_2}")

        self.still_off: bool = get_flag(self.flags, 10)
        self.logger.debug(f"Still Off: {self.still_off}")

        self.forward_play: bool = get_flag(self.flags, 11)
        self.logger.debug(f"Forward Play: {self.forward_play}")

        self.backward_play: bool = get_flag(self.flags, 12)
        self.logger.debug(f"Backward Play: {self.backward_play}")

        self.resume: bool = get_flag(self.flags, 13)
        self.logger.debug(f"Resume: {self.resume}")

        self.move_up_selected_button: bool = get_flag(self.flags, 14)
        self.logger.debug(
            f"Move Up Selected Button: {self.move_up_selected_button}")

        self.move_down_selected_button: bool = get_flag(self.flags, 15)
        self.logger.debug(
            f"Move Down Selected Button: {self.move_down_selected_button}")

        self.move_left_selected_button: bool = get_flag(self.flags, 16)
        self.logger.debug(
            f"Move Left Selected Button: {self.move_left_selected_button}")

        self.move_right_selected_button: bool = get_flag(self.flags, 17)
        self.logger.debug(
            f"Move Right Selected Button: {self.move_right_selected_button}")

        self.select_button: bool = get_flag(self.flags, 18)
        self.logger.debug(f"Select Button: {self.select_button}")

        self.activate_button: bool = get_flag(self.flags, 19)
        self.logger.debug(f"Activate Button: {self.activate_button}")

        self.select_and_activate_button: bool = get_flag(self.flags, 20)
        self.logger.debug(
            f"Select and Activate Button: {self.select_and_activate_button}")

        self.primary_audio_stream_number_change: bool = get_flag(
            self.flags, 21)
        self.logger.debug(
            f"Primary Audio Stream Number Change: {self.primary_audio_stream_number_change}"
        )

        self.reserved_3: bool = get_flag(self.flags, 22)
        self.logger.debug(f"Reserved 3: {self.reserved_3}")

        self.angle_number_change: bool = get_flag(self.flags, 23)
        self.logger.debug(f"Angle Number Change: {self.angle_number_change}")

        self.popup_on: bool = get_flag(self.flags, 24)
        self.logger.debug(f"Popup On: {self.popup_on}")

        self.popup_off: bool = get_flag(self.flags, 25)
        self.logger.debug(f"Popup Off: {self.popup_off}")

        self.primary_pg_enable_disable: bool = get_flag(self.flags, 26)
        self.logger.debug(
            f"Primary PG Enable Disable: {self.primary_pg_enable_disable}")

        self.primary_pg_stream_number_change: bool = get_flag(self.flags, 27)
        self.logger.debug(
            f"Primary PG Stream Number Change: {self.primary_pg_stream_number_change}"
        )

        self.secondary_video_enable_disable: bool = get_flag(self.flags, 28)
        self.logger.debug(
            f"Secondary Video Enable Disable: {self.secondary_video_enable_disable}"
        )

        self.secondary_video_stream_number_change: bool = get_flag(
            self.flags, 29)
        self.logger.debug(
            f"Secondary Video Stream Number Change: {self.secondary_video_stream_number_change}"
        )

        self.secondary_audio_enable_disable: bool = get_flag(self.flags, 30)
        self.logger.debug(
            f"Secondary Audio Enable Disable: {self.secondary_audio_enable_disable}"
        )

        self.secondary_audio_stream_number_change: bool = get_flag(
            self.flags, 31)
        self.logger.debug(
            f"Secondary Audio Stream Number Change: {self.secondary_audio_stream_number_change}"
        )

        self.reserved_3: bool = get_flag(self.flags, 32)
        self.logger.debug(f"Reserved 3: {self.reserved_3}")

        self.secondary_pg_stream_number_change: bool = get_flag(self.flags, 33)
        self.logger.debug(
            f"Secondary PG Stream Number Change: {self.secondary_pg_stream_number_change}"
        )
コード例 #7
0
    def read_from_file(f: PkgInternalIO) -> PkgEntry:
        """
        Reads data into the entry from the file

        Args:
            f: file handle

        Returns:
            constructed PkgEntry
        """
        #: Initialize entry
        entry: PkgEntry = PkgEntry()

        entry.name_offset = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        entry.logger.debug(f"Name Offset: {entry.name_offset}")

        entry.name_size = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        entry.logger.debug(f"Name Size: {entry.name_size}")

        entry.file_offset = read_u64(f, endianess=Endianess.BIG_ENDIAN)
        entry.logger.debug(f"File Offset: {entry.file_offset}")

        entry.file_size = read_u64(f, endianess=Endianess.BIG_ENDIAN)
        entry.logger.info(f"File Size: {entry.file_size}")

        # TODO: Use flags or do this better somehow
        #: Read entry flags & type
        entry_flags = read_u32(f, endianess=Endianess.BIG_ENDIAN)

        entry.overwrite = (entry_flags >> 24 & 0x80) > 0
        entry.logger.debug(f"Overwrite: {entry.overwrite}")

        #: Should we use the PSP_GPKG_KEY to decrypt data & name
        entry.is_psp = (entry_flags >> 24 & 0x10) > 0
        entry.logger.debug(f"PSP: {entry.is_psp}")

        #: Entry type
        entry.entry_type = EntryType(entry_flags & 0xFF)
        entry.logger.info(f"Entry Type: {entry.entry_type}")

        #: Pad to 32 bytes
        entry.padding = read_u32(f, endianess=Endianess.BIG_ENDIAN)
        constant_check(entry.logger, "Padding", entry.padding, valid=0)

        # TODO
        #  It's ugly but I don't have a better solution for now, the only other thing that could be done would be to
        #  read the name data separately from reading the metadata, this gives us a problem with having to take the
        #  is_psp value externally and change it per file so I think this is the best way, period
        if f.encryption_key == PSP_GPKG_KEY and not entry.is_psp:
            entry.__data_key = PS3_GPKG_KEY
        else:
            entry.__data_key = f.encryption_key

        #: Seek to the name offset, relative to the header.data_offset value
        f.seek(entry.name_offset, PkgInternalIO.SEEK_DATA_OFFSET)
        #: Name data in bytes
        name_data: bytes = f.read(entry.name_size, entry.data_key)

        try:
            #: File name, including path
            entry.name: str = name_data.decode('UTF-8')
        except UnicodeDecodeError as e:
            try:
                #: File name codec fallback
                entry.name = name_data.decode(
                    name_codec_map[sha1(name_data)].strip())
            except KeyError:
                #: If all else fails, try all codecs and find a suitable one, add this to naming_exceptions.txt manually
                for codec, string in decode_data_with_all_codecs(name_data):
                    entry.logger.error(
                        f'{codec:15}('
                        f'{hexlify(sha1(name_data)).decode().upper()},'
                        f'{codec:15},'
                        f'{name_data.decode(errors="backslashreplace")}'
                        f') -> {string}')
                raise e
        entry.logger.info(f"Name: {entry.name}")

        return entry