mirror of
https://github.com/mmozeiko/pkg2zip.git
synced 2026-09-02 19:23:09 +03:00
PSM pkg unpacking for use with NoPsmDrm
This commit is contained in:
@@ -2,14 +2,15 @@
|
||||
|
||||
[![Travis CI Build Status][img_travis]][travis] [![AppVeyor Build Status][img_appveyor]][appveyor] [![Downloads][img_downloads]][downloads] [![Release][img_latest]][latest] [![License][img_license]][license]
|
||||
|
||||
Utility that decrypts PlayStation Vita pkg file and creates zip package. Supports also PSX pkg files for use with [Adrenaline](https://github.com/TheOfficialFloW/Adrenaline).
|
||||
Utility that decrypts PlayStation Vita pkg file and creates zip package. Supported pkg files - main application, DLC, patch and PSM files. Supports also PSX files for use with [Adrenaline](https://github.com/TheOfficialFloW/Adrenaline).
|
||||
|
||||
Optionally saves [NoNpDrm](https://github.com/TheOfficialFloW/NoNpDrm) license into work.bin file. You must provide license key.
|
||||
Optionally writes [NoNpDrm](https://github.com/TheOfficialFloW/NoNpDrm) or [NoPsmDrm](https://github.com/frangarcj/NoPsmDrm) fake license file from zRIF string. You must provide license key.
|
||||
|
||||
# Requirements
|
||||
|
||||
* [Henkaku](https://henkaku.xyz/) / [Enso](https://enso.henkaku.xyz/)
|
||||
* [NoNpDrm](https://github.com/TheOfficialFloW/NoNpDrm)
|
||||
* [NoPsmDrm](https://github.com/frangarcj/NoPsmDrm) for PSM titles
|
||||
* to use DLC pkg files, [VitaShell](https://github.com/TheOfficialFloW/VitaShell) **v1.76** or newer required
|
||||
* [Adrenaline](https://github.com/TheOfficialFloW/Adrenaline) for PSX titles
|
||||
|
||||
@@ -19,12 +20,13 @@ Optionally saves [NoNpDrm](https://github.com/TheOfficialFloW/NoNpDrm) license i
|
||||
* **small**, has no external library dependencies and uses very minimal dynamic memory allocations.
|
||||
* **fast**, uses AESNI hardware accelerated AES decryption if supported by CPU (requires [AESNI](https://en.wikipedia.org/wiki/AES_instruction_set) and [SSSE3](https://en.wikipedia.org/wiki/SSSE3) instructions).
|
||||
* **simple**, creates zip package with same folder structure that Vita expects (just drag & drop all file from zip archive to ux0:). Zip file is created directly from pkg without any intermediate temporary files.
|
||||
* **DLC** and **PATCH** pkg unpacking.
|
||||
* **DLC**, **PATCH** and **PSM** pkg unpacking.
|
||||
* **PSX** pkg unpacking.
|
||||
|
||||
Limitations:
|
||||
|
||||
* currently no PSM, PSP or PSP Mini pkg files are supported.
|
||||
* currently no PSP or PSP Mini pkg files are supported.
|
||||
* currently no actual title name is extracted for PSM pkg files.
|
||||
|
||||
# Usage
|
||||
|
||||
|
||||
@@ -236,22 +236,25 @@ static void find_psp_sfo(const aes128_key* key, const aes128_key* ps3_key, const
|
||||
|
||||
static const char* get_region(const char* id)
|
||||
{
|
||||
if (memcmp(id, "PCSE", 4) == 0 || memcmp(id, "PCSA", 4) == 0)
|
||||
if (memcmp(id, "PCSE", 4) == 0 || memcmp(id, "PCSA", 4) == 0 ||
|
||||
memcmp(id, "NPNA", 4) == 0)
|
||||
{
|
||||
return "USA";
|
||||
}
|
||||
else if (memcmp(id, "PCSF", 4) == 0 || memcmp(id, "PCSB", 4) == 0)
|
||||
else if (memcmp(id, "PCSF", 4) == 0 || memcmp(id, "PCSB", 4) == 0 ||
|
||||
memcmp(id, "NPOA", 4) == 0)
|
||||
{
|
||||
return "EUR";
|
||||
}
|
||||
else if (memcmp(id, "PCSC", 4) == 0 || memcmp(id, "VCJS", 4) == 0 ||
|
||||
memcmp(id, "PCSG", 4) == 0 || memcmp(id, "VLJS", 4) == 0 ||
|
||||
memcmp(id, "VLJM", 4) == 0)
|
||||
memcmp(id, "VLJM", 4) == 0 || memcmp(id, "NPPA", 4) == 0)
|
||||
{
|
||||
return "JPN";
|
||||
}
|
||||
else if (memcmp(id, "VCAS", 4) == 0 || memcmp(id, "PCSH", 4) == 0 ||
|
||||
memcmp(id, "VLAS", 4) == 0 || memcmp(id, "PCSD", 4) == 0)
|
||||
memcmp(id, "VLAS", 4) == 0 || memcmp(id, "PCSD", 4) == 0 ||
|
||||
memcmp(id, "NPQA", 4) == 0)
|
||||
{
|
||||
return "ASA";
|
||||
}
|
||||
@@ -434,9 +437,10 @@ int main(int argc, char* argv[])
|
||||
meta_offset += 2 * sizeof(uint32_t) + size;
|
||||
}
|
||||
|
||||
int psx = content_type == 6;
|
||||
int psp = content_type == 7 || content_type == 0xf; // PSX, PSP, PSPMini
|
||||
int dlc = content_type == 0x16; // APP
|
||||
int psx = content_type == 6; // PSX
|
||||
int psp = content_type == 7 || content_type == 0xf; // PSP, PSPMini
|
||||
int dlc = content_type == 0x16; // Vita APP
|
||||
int psm = content_type == 0x18; // Vita PSM
|
||||
|
||||
aes128_key ps3_key;
|
||||
uint8_t main_key[16];
|
||||
@@ -475,23 +479,36 @@ int main(int argc, char* argv[])
|
||||
const char* id = content + 7;
|
||||
const char* id2 = id + 13;
|
||||
|
||||
// https://github.com/TheOfficialFloW/NoNpDrm/blob/v1.1/src/main.c#L42
|
||||
uint8_t rif[512];
|
||||
// first 512 - for vita games - https://github.com/TheOfficialFloW/NoNpDrm/blob/v1.1/src/main.c#L42
|
||||
// 1024 is used for PSM
|
||||
uint8_t rif[1024];
|
||||
uint32_t rif_size = 0;
|
||||
|
||||
if (psp || psx)
|
||||
{
|
||||
find_psp_sfo(&key, &ps3_key, iv, pkg, pkg_size, enc_offset, items_offset, item_count, title);
|
||||
id = (char*)pkg_header + 0x37;
|
||||
}
|
||||
else
|
||||
{
|
||||
parse_sfo(pkg, sfo_offset, sfo_size, &patch, title, content, min_version, pkg_version);
|
||||
if (psm)
|
||||
{
|
||||
memcpy(content, pkg_header + 0x30, 0x30);
|
||||
rif_size = 1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
parse_sfo(pkg, sfo_offset, sfo_size, &patch, title, content, min_version, pkg_version);
|
||||
rif_size = 512;
|
||||
}
|
||||
|
||||
if (!patch && zrif_arg != NULL)
|
||||
{
|
||||
zrif_decode(zrif_arg, rif);
|
||||
if (strncmp((char*)rif + 0x10, content, 0x30) != 0)
|
||||
zrif_decode(zrif_arg, rif, rif_size);
|
||||
const char* rif_contentid = (char*)rif + (psm ? 0x50 : 0x10);
|
||||
if (strncmp(rif_contentid, content, 0x30) != 0)
|
||||
{
|
||||
fatal("ERROR: zRIF content id '%s' doesn't match pkg '%s'\n", rif + 0x10, content);
|
||||
fatal("ERROR: zRIF content id '%s' doesn't match pkg '%s'\n", rif_contentid, content);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -501,14 +518,12 @@ int main(int argc, char* argv[])
|
||||
char root[1024];
|
||||
if (psp)
|
||||
{
|
||||
id = (char*)pkg_header + 0x37;
|
||||
const char* type_str = content_type == 7 ? "PSP" : "PSPMini";
|
||||
snprintf(root, sizeof(root), "%s [%.9s] [%s]%s", title, id, type_str, ext);
|
||||
printf("[*] unpacking %s\n", type_str);
|
||||
}
|
||||
else if (psx)
|
||||
{
|
||||
id = (char*)pkg_header + 0x37;
|
||||
snprintf(root, sizeof(root), "%s [%.9s] [PSX]%s", title, id, ext);
|
||||
printf("[*] unpacking PSX\n");
|
||||
}
|
||||
@@ -522,6 +537,11 @@ int main(int argc, char* argv[])
|
||||
snprintf(root, sizeof(root), "%s [%.9s] [%s] [PATCH] [v%s]%s", title, id, get_region(id), pkg_version, ext);
|
||||
printf("[*] unpacking PATCH\n");
|
||||
}
|
||||
else if (psm)
|
||||
{
|
||||
snprintf(root, sizeof(root), "%.9s [%s]%s", id, get_region(id), ext);
|
||||
printf("[*] unpacking PSM\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(root, sizeof(root), "%s [%.9s] [%s]%s", title, id, get_region(id), ext);
|
||||
@@ -583,6 +603,16 @@ int main(int argc, char* argv[])
|
||||
|
||||
sys_vstrncat(root, sizeof(root), "/");
|
||||
}
|
||||
else if (psm)
|
||||
{
|
||||
sys_vstrncat(root, sizeof(root), "psm");
|
||||
out_add_folder(root);
|
||||
|
||||
sys_vstrncat(root, sizeof(root), "/%.9s", id);
|
||||
out_add_folder(root);
|
||||
|
||||
sys_vstrncat(root, sizeof(root), "/");
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_vstrncat(root, sizeof(root), "app");
|
||||
@@ -644,7 +674,17 @@ int main(int argc, char* argv[])
|
||||
|
||||
if (flags == 4 || flags == 18)
|
||||
{
|
||||
if (!psx)
|
||||
if (psm)
|
||||
{
|
||||
// skip "content/" prefix
|
||||
char* slash = strchr(name, '/');
|
||||
if (slash != NULL)
|
||||
{
|
||||
snprintf(path, sizeof(path), "%sRO/%s/", root, name + 8);
|
||||
out_add_folder(path);
|
||||
}
|
||||
}
|
||||
else if (!psx)
|
||||
{
|
||||
snprintf(path, sizeof(path), "%s%s/", root, name);
|
||||
out_add_folder(path);
|
||||
@@ -674,6 +714,11 @@ int main(int argc, char* argv[])
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (psm)
|
||||
{
|
||||
// skip "content/" prefix
|
||||
snprintf(path, sizeof(path), "%sRO/%s", root, name + 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(path, sizeof(path), "%s%s", root, name);
|
||||
@@ -702,9 +747,9 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (!psp && !psx)
|
||||
if (!psp && !psx && !psm)
|
||||
{
|
||||
printf("[*] creating head.bin\n");
|
||||
printf("[*] creating sce_sys/package/head.bin\n");
|
||||
snprintf(path, sizeof(path), "%ssce_sys/package/head.bin", root);
|
||||
|
||||
out_begin_file(path);
|
||||
@@ -722,9 +767,9 @@ int main(int argc, char* argv[])
|
||||
out_end_file();
|
||||
}
|
||||
|
||||
if (!psp && !psx)
|
||||
if (!psp && !psx && !psm)
|
||||
{
|
||||
printf("[*] creating tail.bin\n");
|
||||
printf("[*] creating sce_sys/package/tail.bin\n");
|
||||
snprintf(path, sizeof(path), "%ssce_sys/package/tail.bin", root);
|
||||
|
||||
out_begin_file(path);
|
||||
@@ -740,9 +785,9 @@ int main(int argc, char* argv[])
|
||||
out_end_file();
|
||||
}
|
||||
|
||||
if (!psp && !psx)
|
||||
if (!psp && !psx && !psm)
|
||||
{
|
||||
printf("[*] creating stat.bin\n");
|
||||
printf("[*] creating sce_sys/package/stat.bin\n");
|
||||
snprintf(path, sizeof(path), "%ssce_sys/package/stat.bin", root);
|
||||
|
||||
uint8_t stat[768] = { 0 };
|
||||
@@ -753,17 +798,62 @@ int main(int argc, char* argv[])
|
||||
|
||||
if (!psp && !psx && !patch && zrif_arg != NULL)
|
||||
{
|
||||
printf("[*] creating work.bin\n");
|
||||
snprintf(path, sizeof(path), "%ssce_sys/package/work.bin", root);
|
||||
if (psm)
|
||||
{
|
||||
printf("[*] creating RO/License\n");
|
||||
snprintf(path, sizeof(path), "%sRO/License", root);
|
||||
out_add_folder(path);
|
||||
|
||||
printf("[*] creating RO/License/FAKE.rif\n");
|
||||
snprintf(path, sizeof(path), "%sRO/License/FAKE.rif", root);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[*] creating sce_sys/package/work.bin\n");
|
||||
snprintf(path, sizeof(path), "%ssce_sys/package/work.bin", root);
|
||||
}
|
||||
|
||||
out_begin_file(path);
|
||||
out_write(rif, sizeof(rif));
|
||||
out_write(rif, rif_size);
|
||||
out_end_file();
|
||||
}
|
||||
|
||||
if (psm)
|
||||
{
|
||||
printf("[*] creating RW\n");
|
||||
snprintf(path, sizeof(path), "%sRW", root);
|
||||
out_add_folder(path);
|
||||
|
||||
printf("[*] creating RW/Documents\n");
|
||||
snprintf(path, sizeof(path), "%sRW/Documents", root);
|
||||
out_add_folder(path);
|
||||
|
||||
printf("[*] creating RW/Temp\n");
|
||||
snprintf(path, sizeof(path), "%sRW/Temp", root);
|
||||
out_add_folder(path);
|
||||
|
||||
printf("[*] creating RW/System\n");
|
||||
snprintf(path, sizeof(path), "%sRW/System", root);
|
||||
out_add_folder(path);
|
||||
|
||||
printf("[*] creating RW/System/content_id\n");
|
||||
snprintf(path, sizeof(path), "%sRW/System/content_id", root);
|
||||
out_begin_file(path);
|
||||
out_write(pkg_header + 0x30, 0x30);
|
||||
out_end_file();
|
||||
|
||||
printf("[*] creating RW/System/pm.dat\n");
|
||||
snprintf(path, sizeof(path), "%sRW/System/pm.dat", root);
|
||||
|
||||
uint8_t pm[1 << 16] = { 0 };
|
||||
out_begin_file(path);
|
||||
out_write(pm, sizeof(pm));
|
||||
out_end_file();
|
||||
}
|
||||
|
||||
out_end();
|
||||
|
||||
if (!psp && !psx && !dlc)
|
||||
if (!psp && !psx && !dlc && !psm)
|
||||
{
|
||||
printf("[*] minimum fw version required: %s\n", min_version);
|
||||
}
|
||||
|
||||
+5
-5
@@ -171,17 +171,17 @@ static uint32_t zlib_inflate(const uint8_t* in, uint32_t inlen, uint8_t* out, ui
|
||||
return dlen;
|
||||
}
|
||||
|
||||
void zrif_decode(const char* str, uint8_t* rif)
|
||||
void zrif_decode(const char* str, uint8_t* rif, uint32_t rif_size)
|
||||
{
|
||||
uint8_t raw[512];
|
||||
uint8_t raw[1024];
|
||||
uint32_t len = base64_decode(str, raw);
|
||||
|
||||
uint8_t out[512 + sizeof(zrif_dict)];
|
||||
uint8_t out[sizeof(zrif_dict) + 1024];
|
||||
len = zlib_inflate(raw, len, out, sizeof(out));
|
||||
if (len != 512)
|
||||
if (len != rif_size)
|
||||
{
|
||||
fatal("ERROR: wrong size of zRIF, is it corrupted?\n");
|
||||
}
|
||||
|
||||
memcpy(rif, out, 512);
|
||||
memcpy(rif, out, rif_size);
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,4 +2,4 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void zrif_decode(const char* str, uint8_t* rif);
|
||||
void zrif_decode(const char* str, uint8_t* rif, uint32_t rif_size);
|
||||
|
||||
Reference in New Issue
Block a user