Created
November 30, 2016 05:43
-
-
Save lialosiu/553a46afe60b88fee4b9388ce56b20b6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* PS Vita PKG Decrypt | |
* Decrypts PS Vita PKG files | |
* The code is a total mess, use at your own risk. | |
* Written by St4rk | |
* Special thanks to Proxima <3 | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <sys/stat.h> | |
#include <openssl/aes.h> | |
unsigned char pkg_key_psp[] = { | |
0x07, 0xF2, 0xC6, 0x82, 0x90, 0xB5, 0x0D, 0x2C, 0x33, 0x81, 0x8D, 0x70, 0x9B, 0x60, 0xE6, 0x2B | |
}; | |
unsigned char pkg_vita_2[] = { | |
0xE3, 0x1A, 0x70, 0xC9, 0xCE, 0x1D, 0xD7, 0x2B, 0xF3, 0xC0, 0x62, 0x29, 0x63, 0xF2, 0xEC, 0xCB | |
}; | |
unsigned char pkg_vita_3[] = { | |
0x42, 0x3A, 0xCA, 0x3A, 0x2B, 0xD5, 0x64, 0x9F, 0x96, 0x86, 0xAB, 0xAD, 0x6F, 0xD8, 0x80, 0x1F | |
}; | |
unsigned char pkg_vita_4[] = { | |
0xAF, 0x07, 0xFD, 0x59, 0x65, 0x25, 0x27, 0xBA, 0xF1, 0x33, 0x89, 0x66, 0x8B, 0x17, 0xD9, 0xEA | |
}; | |
typedef struct ctr { | |
unsigned char iv[AES_BLOCK_SIZE]; | |
unsigned char counter[AES_BLOCK_SIZE]; | |
unsigned int num; | |
} ctr; | |
/** Credits: http://www.psdevwiki.com/ps3/PKG_files */ | |
typedef struct PKG_FILE_HEADER { | |
unsigned int filename_offset; | |
unsigned int filename_size; | |
uint64_t data_offset; | |
uint64_t data_size; | |
unsigned int flags; | |
unsigned int padding; | |
} PKG_FILE_HEADER; | |
int main(int argc, char **argv) { | |
FILE *pkg = NULL; | |
if (argc > 1) { | |
pkg = fopen(argv[1], "rb"); | |
if (pkg == NULL) { | |
printf("PKG %s not found !\n", argv[1]); | |
return 0; | |
} | |
/** get pkg key type */ | |
unsigned int keyType = 0; | |
fseek(pkg, 0xE4, SEEK_SET); | |
fread(&keyType, sizeof(unsigned int), 1, pkg); | |
keyType = (keyType >> 24) & 7; | |
/** pkg key */ | |
unsigned char pkg_key[0x10] = {0}; | |
fseek(pkg, 0x70, SEEK_SET); | |
fread(pkg_key, 1, 0x10, pkg); | |
/** encrypted data information */ | |
uint64_t dataOffset = 0; | |
uint64_t dataSize = 0; | |
fseek(pkg, 0x20, SEEK_SET); | |
fread(&dataOffset, sizeof(uint64_t), 1, pkg); | |
fseek(pkg, 0x28, SEEK_SET); | |
fread(&dataSize, sizeof(uint64_t), 1, pkg); | |
dataSize = __builtin_bswap64(dataSize); | |
dataOffset = __builtin_bswap64(dataOffset); | |
printf("Offset: 0x%lX\n", dataOffset); | |
printf("Size: 0x%lX\n", dataSize); | |
AES_KEY key; | |
FILE *content = fopen("out.bin", "rwb"); | |
/** | |
* encrypt PKG Key with AES_Key to generate the CTR Key | |
* only with PKG Type 2, 3 and 4 | |
*/ | |
unsigned char ctr_key[0x10]; | |
switch (keyType) { | |
case 2: | |
AES_set_encrypt_key(pkg_vita_2, 128, &key); | |
AES_ecb_encrypt(pkg_key, ctr_key, &key, AES_ENCRYPT); | |
break; | |
case 3: | |
AES_set_encrypt_key(pkg_vita_3, 128, &key); | |
AES_ecb_encrypt(pkg_key, ctr_key, &key, AES_ENCRYPT); | |
break; | |
case 4: | |
AES_set_encrypt_key(pkg_vita_4, 128, &key); | |
AES_ecb_encrypt(pkg_key, ctr_key, &key, AES_ENCRYPT); | |
break; | |
} | |
/** | |
* Set AES CTR key and use PKG key as IV | |
*/ | |
/* decrypt chunks */ | |
unsigned char buffer[AES_BLOCK_SIZE]; | |
unsigned char out[AES_BLOCK_SIZE]; | |
int bytesOut = 0; | |
ctr d_ctr; | |
memcpy(d_ctr.iv, pkg_key, AES_BLOCK_SIZE); | |
memset(d_ctr.counter, 0, AES_BLOCK_SIZE); | |
d_ctr.num = 0; | |
/** | |
* AES CTR Decrypt, using the old key as IV | |
*/ | |
AES_set_encrypt_key(keyType != 1 ? ctr_key : pkg_key_psp, 128, &key); | |
printf("Decrypting..."); | |
fseek(pkg, dataOffset, SEEK_SET); | |
while (fread(buffer, 1, AES_BLOCK_SIZE, pkg) == AES_BLOCK_SIZE) { | |
AES_ctr128_encrypt(buffer, out, AES_BLOCK_SIZE, &key, d_ctr.iv, d_ctr.counter, &d_ctr.num); | |
fwrite(out, 1, AES_BLOCK_SIZE, content); | |
} | |
printf("Done !\n"); | |
/* total file entry */ | |
unsigned int itemCnt = 0; | |
fseek(pkg, 0x14, SEEK_SET); | |
fread(&itemCnt, sizeof(unsigned int), 1, pkg); | |
itemCnt = __builtin_bswap32(itemCnt); | |
printf("Item Cnt: %d\n", itemCnt); | |
PKG_FILE_HEADER fileEntry[itemCnt]; | |
rewind(content); | |
fread(fileEntry, sizeof(PKG_FILE_HEADER), itemCnt, content); | |
/** create out directory */ | |
struct stat st = {0}; | |
if (stat("out", &st) == -1) { | |
mkdir("out", 0777); | |
} | |
for (int i = 0; i < itemCnt; i++) { | |
switch ((__builtin_bswap32(fileEntry[i].flags) & 0xFF)) { | |
/** dir */ | |
case 4: | |
case 18: { | |
char dirName[0xFF]; | |
char fileName[0xFF]; | |
memset(dirName, 0, 0xFF); | |
memset(fileName, 0, 0xFF); | |
struct stat st = {0}; | |
/** read file name */ | |
fseek(content, __builtin_bswap32(fileEntry[i].filename_offset), SEEK_SET); | |
fread(fileName, sizeof(char), __builtin_bswap32(fileEntry[i].filename_size), content); | |
sprintf(dirName, "out/%s\0\n", fileName); | |
if (stat(dirName, &st) == -1) { | |
mkdir(dirName, 0777); | |
} | |
} | |
break; | |
case 0: | |
case 1: | |
case 3: | |
case 14: | |
case 15: | |
case 16: | |
case 17: | |
case 19: | |
case 21: | |
case 22: { | |
FILE *temp = NULL; | |
char dirName[0xFF]; | |
char fileName[0xFF]; | |
unsigned char *data = NULL; | |
memset(dirName, 0, 0xFF); | |
memset(fileName, 0, 0xFF); | |
/** read file name */ | |
fseek(content, __builtin_bswap32(fileEntry[i].filename_offset), SEEK_SET); | |
fread(fileName, sizeof(char), __builtin_bswap32(fileEntry[i].filename_size), content); | |
sprintf(dirName, "out/%s\0\n", fileName); | |
temp = fopen(dirName, "wb"); | |
data = (unsigned char*) malloc (sizeof(unsigned char) * __builtin_bswap64(fileEntry[i].data_size)); | |
/** read file data */ | |
fseek(content, __builtin_bswap64(fileEntry[i].data_offset), SEEK_SET); | |
fread(data, sizeof(unsigned char), __builtin_bswap64(fileEntry[i].data_size), content); | |
/** write file data */ | |
fwrite(data, sizeof(unsigned char), __builtin_bswap64(fileEntry[i].data_size), temp); | |
fclose(temp); | |
free(data); | |
} | |
break; | |
default: | |
break; | |
} | |
} | |
fclose(content); | |
fclose(pkg); | |
} else { | |
printf("Usage: pkg filename.pkg\n"); | |
printf("out.bin is the package decrypted and out folder\nhas the files inside of out.bin\n"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment