unpkg improved

Initial content_type parsing
Added PSP2 support
This commit is contained in:
Nekotekina 2017-02-28 12:22:50 +03:00
parent c3b424eb11
commit 45bb51ded8
2 changed files with 77 additions and 14 deletions

View file

@ -49,12 +49,6 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
}
}
if (header.header_size != PKG_HEADER_SIZE && header.header_size != PKG_HEADER_SIZE2)
{
LOG_ERROR(LOADER, "Wrong PKG header size (0x%x)", header.header_size);
return false;
}
if (header.pkg_size > pkg_f.size())
{
LOG_ERROR(LOADER, "PKG file size mismatch (pkg_size=0x%llx)", header.pkg_size);
@ -67,11 +61,54 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
return false;
}
be_t<u32> drm_type{0};
be_t<u32> content_type{0};
pkg_f.seek(header.pkg_info_off);
for (u32 i = 0; i < header.pkg_info_num; i++)
{
struct packet_T
{
be_t<u32> id;
be_t<u32> size;
} packet;
pkg_f.read(packet);
// TODO
switch (+packet.id)
{
case 0x1:
{
if (packet.size == sizeof(drm_type))
{
pkg_f.read(drm_type);
continue;
}
break;
}
case 0x2:
{
if (packet.size == sizeof(content_type))
{
pkg_f.read(content_type);
continue;
}
break;
}
}
pkg_f.seek(packet.size, fs::seek_cur);
}
// Allocate buffer with BUF_SIZE size or more if required
const std::unique_ptr<u128[]> buf(new u128[std::max<u64>(BUF_SIZE, sizeof(PKGEntry) * header.file_count) / sizeof(u128)]);
// Define decryption subfunction (`psp` arg selects the key for specific block)
auto decrypt = [&](u64 offset, u64 size, bool psp) -> u64
auto decrypt = [&](u64 offset, u64 size, const uchar* key) -> u64
{
pkg_f.seek(start_offset + header.data_offset + offset);
@ -114,7 +151,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
aes_context ctx;
// Set encryption key for stream cipher
aes_setkey_enc(&ctx, psp ? PKG_AES_KEY2 : PKG_AES_KEY, 128);
aes_setkey_enc(&ctx, key, 128);
// Initialize stream cipher for start position
be_t<u128> input = header.klicensee.value() + offset / 16;
@ -134,7 +171,24 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
return read;
};
decrypt(0, header.file_count * sizeof(PKGEntry), header.pkg_platform == PKG_PLATFORM_TYPE_PSP);
std::array<uchar, 16> dec_key;
if (header.pkg_platform == PKG_PLATFORM_TYPE_PSP && content_type >= 0x15 && content_type <= 0x17)
{
const uchar psp2t1[] = {0xE3, 0x1A, 0x70, 0xC9, 0xCE, 0x1D, 0xD7, 0x2B, 0xF3, 0xC0, 0x62, 0x29, 0x63, 0xF2, 0xEC, 0xCB};
const uchar psp2t2[] = {0x42, 0x3A, 0xCA, 0x3A, 0x2B, 0xD5, 0x64, 0x9F, 0x96, 0x86, 0xAB, 0xAD, 0x6F, 0xD8, 0x80, 0x1F};
const uchar psp2t3[] = {0xAF, 0x07, 0xFD, 0x59, 0x65, 0x25, 0x27, 0xBA, 0xF1, 0x33, 0x89, 0x66, 0x8B, 0x17, 0xD9, 0xEA};
aes_context ctx;
aes_setkey_enc(&ctx, content_type == 0x15 ? psp2t1 : content_type == 0x16 ? psp2t2 : psp2t3, 128);
aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast<const uchar*>(&header.klicensee), dec_key.data());
decrypt(0, header.file_count * sizeof(PKGEntry), dec_key.data());
}
else
{
std::memcpy(dec_key.data(), PKG_AES_KEY, dec_key.size());
decrypt(0, header.file_count * sizeof(PKGEntry), header.pkg_platform == PKG_PLATFORM_TYPE_PSP ? PKG_AES_KEY2 : dec_key.data());
}
std::vector<PKGEntry> entries(header.file_count);
@ -150,10 +204,12 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
continue;
}
decrypt(entry.name_offset, entry.name_size, is_psp);
decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : dec_key.data());
const std::string name(reinterpret_cast<char*>(buf.get()), entry.name_size);
LOG_NOTICE(LOADER, "Entry 0x%08x: %s", entry.type, name);
switch (entry.type & 0xff)
{
case PKG_FILE_ENTRY_NPDRM:
@ -161,6 +217,12 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
case PKG_FILE_ENTRY_SDAT:
case PKG_FILE_ENTRY_REGULAR:
case PKG_FILE_ENTRY_UNK1:
case 0xe:
case 0x10:
case 0x11:
case 0x13:
case 0x15:
case 0x16:
{
const std::string path = dir + name;
@ -172,7 +234,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
{
const u64 block_size = std::min<u64>(BUF_SIZE, entry.file_size - pos);
if (decrypt(entry.file_offset + pos, block_size, is_psp) != block_size)
if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : dec_key.data()) != block_size)
{
LOG_ERROR(LOADER, "Failed to extract file %s", path);
break;
@ -209,6 +271,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
}
case PKG_FILE_ENTRY_FOLDER:
case 0x12:
{
const std::string path = dir + name;

View file

@ -35,9 +35,9 @@ struct PKGHeader
nse_t<u32> pkg_magic; // Magic (0x7f504b47)
be_t<u16> pkg_type; // Release type (Retail:0x8000, Debug:0x0000)
be_t<u16> pkg_platform; // Platform type (PS3:0x0001, PSP:0x0002)
be_t<u32> header_size; // Header size (0xc0)
be_t<u32> unk1; // Some PKG version maybe?
be_t<u32> meta_size; // Size of metadata (block after header & hashes)
be_t<u32> pkg_info_off;
be_t<u32> pkg_info_num;
be_t<u32> header_size; // Header size
be_t<u32> file_count; // Number of files
be_t<u64> pkg_size; // PKG size in bytes
be_t<u64> data_offset; // Encrypted data offset