#pragma once #include #include "Types.h" #include #include #include #include enum PKGFlags : U32 { PKG_FLAGS_UNKNOWN = 0x01, PKG_FLAGS_VER_1 = 0x01000000, PKG_FLAGS_VER_2 = 0x02000000, PKG_FLAGS_INTERNAL = 0x40000000, PKG_FLAGS_FINALIZED = 0x80000000, }; enum PKGDrmType : U32 { PKG_DRM_TYPE_NONE = 0x0, PKG_DRM_TYPE_PS4 = 0xF, }; enum PKGContentType : U32 { /* pkg_ps4_app, pkg_ps4_patch, pkg_ps4_remaster */ PKG_CONTENT_TYPE_GD = 0x1A, /* pkg_ps4_ac_data, pkg_ps4_sf_theme, pkg_ps4_theme */ PKG_CONTENT_TYPE_AC = 0x1B, /* pkg_ps4_ac_nodata */ PKG_CONTENT_TYPE_AL = 0x1C, /* pkg_ps4_delta_patch */ PKG_CONTENT_TYPE_DP = 0x1E, }; enum PKGContentFlags : U32 { PKG_CONTENT_FLAGS_FIRST_PATCH = 0x00100000, PKG_CONTENT_FLAGS_PATCHGO = 0x00200000, PKG_CONTENT_FLAGS_REMASTER = 0x00400000, PKG_CONTENT_FLAGS_PS_CLOUD = 0x00800000, PKG_CONTENT_FLAGS_GD_AC = 0x02000000, PKG_CONTENT_FLAGS_NON_GAME = 0x04000000, PKG_CONTENT_FLAGS_Unk_x8000000 = 0x08000000, PKG_CONTENT_FLAGS_SUBSEQUENT_PATCH = 0x40000000, PKG_CONTENT_FLAGS_DELTA_PATCH = 0x41000000, PKG_CONTENT_FLAGS_CUMULATIVE_PATCH = 0x60000000, }; enum IROTag : U32 { PKG_IRO_TAG_NONE = 0, /* SHAREfactory theme */ PKG_IRO_TAG_SF_THEME = 0x1, /* System Software theme */ PKG_IRO_TAG_SS_THEME = 0x2, }; struct PKGHeader { /*BE*/U32 magic;// Magic /*BE*/U32 pkg_flags; /*BE*/U32 pkg_0x8; //unknown field /*BE*/U32 pkg_file_count; /*BE*/U32 pkg_table_entry_count; /*BE*/U16 pkg_sc_entry_count; /*BE*/U16 pkg_table_entry_count_2;// same as pkg_entry_count /*BE*/U32 pkg_table_entry_offset;//file table offset /*BE*/U32 pkg_sc_entry_data_size; /*BE*/U64 pkg_body_offset;//offset of PKG entries /*BE*/U64 pkg_body_size;//length of all PKG entries /*BE*/U64 pkg_content_offset; /*BE*/U64 pkg_content_size; U08 pkg_content_id[0x24];//packages' content ID as a 36-byte string U08 pkg_padding[0xC];//padding /*BE*/U32 pkg_drm_type;//DRM type /*BE*/U32 pkg_content_type;//Content type /*BE*/U32 pkg_content_flags;//Content flags /*BE*/U32 pkg_promote_size; /*BE*/U32 pkg_version_date; /*BE*/U32 pkg_version_hash; /*BE*/U32 pkg_0x088; /*BE*/U32 pkg_0x08C; /*BE*/U32 pkg_0x090; /*BE*/U32 pkg_0x094; /*BE*/U32 pkg_iro_tag; /*BE*/U32 pkg_drm_type_version; U08 pkg_zeroes_1[0x60]; /* Digest table */ U08 digest_entries1[0x20]; // sha256 digest for main entry 1 U08 digest_entries2[0x20]; // sha256 digest for main entry 2 U08 digest_table_digest[0x20]; // sha256 digest for digest table U08 digest_body_digest[0x20]; // sha256 digest for main table U08 pkg_zeroes_2[0x280]; U32 pkg_0x400; U32 pfs_image_count; // count of PFS images U64 pfs_image_flags; // PFS flags U64 pfs_image_offset; // offset to start of external PFS image U64 pfs_image_size; // size of external PFS image U64 mount_image_offset; U64 mount_image_size; U64 pkg_size; U32 pfs_signed_size; U32 pfs_cache_size; U08 pfs_image_digest[0x20]; U08 pfs_signed_digest[0x20]; U64 pfs_split_size_nth_0; U64 pfs_split_size_nth_1; U08 pkg_zeroes_3[0xB50]; U08 pkg_digest[0x20]; }; inline void ReadBE(PKGHeader& s) { ReadBE(s.magic); ReadBE(s.pkg_flags); ReadBE(s.pkg_0x8); ReadBE(s.pkg_file_count); ReadBE(s.pkg_table_entry_count); ReadBE(s.pkg_sc_entry_count); ReadBE(s.pkg_table_entry_count_2); ReadBE(s.pkg_table_entry_offset); ReadBE(s.pkg_sc_entry_data_size); ReadBE(s.pkg_body_offset); ReadBE(s.pkg_body_size); ReadBE(s.pkg_content_offset); ReadBE(s.pkg_content_size); ReadBE(s.pkg_drm_type); ReadBE(s.pkg_content_type); ReadBE(s.pkg_content_flags); ReadBE(s.pkg_promote_size); ReadBE(s.pkg_version_date); ReadBE(s.pkg_version_hash); ReadBE(s.pkg_0x088); ReadBE(s.pkg_0x08C); ReadBE(s.pkg_0x090); ReadBE(s.pkg_0x094); ReadBE(s.pkg_iro_tag); ReadBE(s.pkg_drm_type_version); ReadBE(s.pkg_0x400); ReadBE(s.pfs_image_count); ReadBE(s.pfs_image_flags); ReadBE(s.pfs_image_offset); ReadBE(s.pfs_image_size); ReadBE(s.mount_image_offset); ReadBE(s.mount_image_size); ReadBE(s.pfs_signed_size); ReadBE(s.pfs_cache_size); ReadBE(s.pkg_size); ReadBE(s.pfs_split_size_nth_0); ReadBE(s.pfs_split_size_nth_1); } struct PKGEntry { U32 id; // File ID, useful for files without a filename entry U32 filename_offset; // Offset into the filenames table (ID 0x200) where this file's name is located U32 flags1; // Flags including encrypted flag, etc U32 flags2; // Flags including encryption key index, etc U32 offset; // Offset into PKG to find the file U32 size; // Size of the file U64 padding; // blank padding }; inline void ReadBE(PKGEntry& s) { ReadBE(s.id); ReadBE(s.filename_offset); ReadBE(s.flags1); ReadBE(s.flags2); ReadBE(s.offset); ReadBE(s.size); ReadBE(s.padding); } class PKG { private: U08* pkg; U64 pkgSize = 0; S08 pkgTitleID[9]; std::string extractPath; PKGHeader pkgheader; public: PKG(); ~PKG(); bool open(const std::string& filepath); U64 getPkgSize() { return pkgSize; } std::string getTitleID() { return std::string(pkgTitleID,9); } bool extract(const std::string& filepath, const std::string& extractPath, std::string& failreason); void* mmap(size_t sLength, std::FILE* nFd) { HANDLE hHandle; void* pStart=nullptr; hHandle = CreateFileMapping( (HANDLE)_get_osfhandle(_fileno((nFd))), NULL, // default security PAGE_WRITECOPY, // read/write access 0, // maximum object size (high-order DWORD) 0, // maximum object size (low-order DWORD) NULL); // name of mapping object if (hHandle != NULL) { pStart = MapViewOfFile(hHandle, FILE_MAP_COPY, 0, 0, sLength); } if(pStart == NULL) { return nullptr; } return pStart; } int munmap(void* pStart) { if (UnmapViewOfFile(pStart) != 0) return FALSE; return TRUE; } typedef struct { U32 type; std::string name; } pkg_entry_value; std::string getEntryNameByType(U32 type) { pkg_entry_value entries[] = { { 0x0001, "digests" }, { 0x0010, "entry_keys" }, { 0x0020, "image_key" }, { 0x0080, "general_digests" }, { 0x0100, "metas" }, { 0x0200, "entry_names" }, { 0x0400, "license.dat" }, { 0x0401, "license.info" }, { 0x0402, "nptitle.dat" }, { 0x0403, "npbind.dat" }, { 0x0409, "psreserved.dat" }, { 0x1000, "param.sfo" }, { 0x1001, "playgo-chunk.dat" }, { 0x1002, "playgo-chunk.sha" }, { 0x1003, "playgo-manifest.xml" }, { 0x1004, "pronunciation.xml" }, { 0x1005, "pronunciation.sig" }, { 0x1006, "pic1.png" }, { 0x1007, "pubtoolinfo.dat" }, { 0x100B, "shareparam.json" }, { 0x100C, "shareoverlayimage.png" }, { 0x100E, "shareprivacyguardimage.png"}, { 0x1200, "icon0.png" }, { 0x1220, "pic0.png" }, { 0x1240, "snd0.at9" }, { 0x1280, "icon0.dds" }, { 0x12A0, "pic0.dds" }, { 0x12C0, "pic1.dds" }, { 0x1400, "trophy/trophy00.trp" } }; std::string entry_name=""; for (size_t i = 0; i < sizeof entries / sizeof entries[0]; i++) { if (type == entries[i].type) { entry_name = entries[i].name; break; } } return entry_name; } void printPkgHeader() { printf("PS4 PKG header:\n"); printf("- PKG magic: 0x%X\n", pkgheader.magic); printf("- PKG flags: 0x%X", pkgheader.pkg_flags); if (pkgheader.pkg_flags & PKG_FLAGS_UNKNOWN) printf(" unknown"); if (pkgheader.pkg_flags & PKG_FLAGS_VER_1) printf(" ver_1"); if (pkgheader.pkg_flags & PKG_FLAGS_VER_2) printf(" ver_2"); if (pkgheader.pkg_flags & PKG_FLAGS_INTERNAL) printf(" internal"); if(pkgheader.pkg_flags & PKG_FLAGS_FINALIZED) printf(" finalized"); printf("\n"); printf("- PKG 0x8: 0x%X\n", pkgheader.pkg_0x8); printf("- PKG file count: %u\n", pkgheader.pkg_file_count); printf("- PKG table entries count: %u\n", pkgheader.pkg_table_entry_count); printf("- PKG system entries count: %u\n", pkgheader.pkg_sc_entry_count); printf("- PKG table entries2 count: %u\n", pkgheader.pkg_table_entry_count_2); printf("- PKG table offset: 0x%X\n", pkgheader.pkg_table_entry_offset); printf("- PKG table entry data size: 0x%X\n", pkgheader.pkg_sc_entry_data_size); printf("- PKG body offset: 0x%" PRIx64 "\n", pkgheader.pkg_body_offset); printf("- PKG body size: 0x%" PRIx64 "\n", pkgheader.pkg_body_size); printf("- PKG content offset: 0x%" PRIx64 "\n", pkgheader.pkg_content_offset); printf("- PKG content size: 0x%" PRIx64 "\n", pkgheader.pkg_content_offset); printf("- PKG pkg_content_id: %s\n", pkgheader.pkg_content_id); printf("- PKG drm type: 0x%X", pkgheader.pkg_drm_type); if (pkgheader.pkg_drm_type == PKG_DRM_TYPE_NONE) printf(" None"); if (pkgheader.pkg_drm_type == PKG_DRM_TYPE_PS4) printf(" PS4"); printf("\n"); printf("- PKG content type: 0x%X", pkgheader.pkg_content_type); if (pkgheader.pkg_content_type == PKG_CONTENT_TYPE_GD) printf(" GD"); if (pkgheader.pkg_content_type == PKG_CONTENT_TYPE_AC) printf(" AC"); if (pkgheader.pkg_content_type == PKG_CONTENT_TYPE_AL) printf(" AL"); if (pkgheader.pkg_content_type == PKG_CONTENT_TYPE_DP) printf(" DP"); printf("\n"); printf("- PKG content flags: 0x%X", pkgheader.pkg_content_flags); if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_FIRST_PATCH) printf(" First_patch"); if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_PATCHGO) printf(" Patch_go"); if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_REMASTER) printf(" Remastered"); if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_PS_CLOUD) printf(" Cloud"); if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_GD_AC) printf(" AC"); if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_NON_GAME) printf(" Non_game"); if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_Unk_x8000000) printf(" Unk_x8000000"); if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_SUBSEQUENT_PATCH) printf(" Subsequent_patch"); if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_DELTA_PATCH) printf(" Delta_patch"); if (pkgheader.pkg_content_flags & PKG_CONTENT_FLAGS_CUMULATIVE_PATCH) printf(" Cumulative_patch"); printf("\n"); printf("- PKG promote size: 0x%X\n", pkgheader.pkg_promote_size); printf("- PKG version date: 0x%X\n", pkgheader.pkg_version_date); printf("- PKG version hash: 0x%X\n", pkgheader.pkg_version_hash); printf("- PKG 0x088: 0x%X\n", pkgheader.pkg_0x088); printf("- PKG 0x08C: 0x%X\n", pkgheader.pkg_0x08C); printf("- PKG 0x090: 0x%X\n", pkgheader.pkg_0x090); printf("- PKG 0x094: 0x%X\n", pkgheader.pkg_0x094); printf("- PKG iro tag: 0x%X", pkgheader.pkg_iro_tag); if (pkgheader.pkg_iro_tag == PKG_IRO_TAG_NONE) printf(" None"); if (pkgheader.pkg_iro_tag == PKG_IRO_TAG_SF_THEME) printf(" SF Theme"); if (pkgheader.pkg_iro_tag == PKG_IRO_TAG_SS_THEME) printf(" SS Theme"); printf("\n"); printf("- PKG drm type version: 0x%X\n", pkgheader.pkg_drm_type_version); printf("- PKG digest_entries1: "); for (U08 s = 0; s < 0x20; s++) printf("%X", pkgheader.digest_entries1[s]); printf("\n"); printf("- PKG digest_entries2: "); for (U08 s = 0; s < 0x20; s++)printf("%X", pkgheader.digest_entries2[s]); printf("\n"); printf("- PKG digest_table_digest: "); for (U08 s = 0; s < 0x20; s++)printf("%X", pkgheader.digest_table_digest[s]); printf("\n"); printf("- PKG digest_body_digest: "); for (U08 s = 0; s < 0x20; s++)printf("%X", pkgheader.digest_body_digest[s]); printf("\n"); printf("- PKG 0x400: 0x%X\n", pkgheader.pkg_0x400); printf("- PKG pfs_image_count: 0x%X\n", pkgheader.pfs_image_count); printf("- PKG pfs_image_flags: 0x%" PRIx64 "\n", pkgheader.pfs_image_flags); printf("- PKG pfs_image_offset: 0x%" PRIx64 "\n", pkgheader.pfs_image_offset); printf("- PKG mount_image_offset: 0x%" PRIx64 "\n", pkgheader.mount_image_offset); printf("- PKG mount_image_size: 0x%" PRIx64 "\n", pkgheader.mount_image_size); printf("- PKG size: 0x%" PRIx64 "\n", pkgheader.pkg_size); printf("- PKG pfs_signed_size: 0x%X\n", pkgheader.pfs_signed_size); printf("- PKG pfs_cache_size: 0x%X\n", pkgheader.pfs_cache_size); printf("- PKG pfs_image_digest: "); for (U08 s = 0; s < 0x20; s++)printf("%X", pkgheader.pfs_image_digest[s]); printf("\n"); printf("- PKG pfs_signed_digest: "); for (U08 s = 0; s < 0x20; s++)printf("%X", pkgheader.pfs_signed_digest[s]); printf("\n"); printf("- PKG pfs_split_size_nth_0: 0x%" PRIx64 "\n", pkgheader.pfs_split_size_nth_0); printf("- PKG pfs_split_size_nth_1: 0x%" PRIx64 "\n", pkgheader.pfs_split_size_nth_1); printf("- PKG pkg_digest: "); for (U08 s = 0; s < 0x20; s++)printf("%X", pkgheader.pkg_digest[s]); printf("\n"); printf("\n\n"); } void printPkgFileEntry(PKGEntry entry, std::string name) { printf("-PS4 File Entry:\n"); printf("--found name: %s\n", name.c_str()); printf("--id: 0x%X\n", entry.id); printf("--filename_offset: 0x%X\n", entry.filename_offset); printf("--flags1: 0x%X\n", entry.flags1); printf("--flags2: 0x%X\n", entry.flags2); printf("--offset: 0x%X\n", entry.offset); printf("--size: 0x%X\n", entry.size); } };