/* by xerpi (18-1-2013)*/
#include <stdio.h>
#include <stdlib.h>
#ifndef byte
#define byte unsigned char
#endif
typedef unsigned long long u64;
typedef struct{
u64 entry_ID;
u64 data_offset;
u64 data_length;
u64 unknown;
}File_table;
typedef struct{
u64 file_index;
byte *file_hash;
byte *unknown;
}Hash_table;
typedef struct{
u64 magic;
u64 package_version;
u64 image_version;
u64 file_count;
u64 header_length;
u64 package_length;
byte *unknown;
File_table *file_table;
Hash_table *hash_table;
byte *header_hash;
}PUP_header;
void pup_free_pup_header(PUP_header *pup_header);
int pup_read_header(PUP_header *pup_header, FILE *pup_file);
void pup_extract(PUP_header *pup_header, FILE *pup_file);
void pup_print_header(PUP_header *pup_header);
char *ID_to_filename(u64 entry_ID);
int main(int argc, char **argv){
if( argc < 2) {
printf("\nUsage: pupreader <file>\n");
return -1;
}
//Open the PUP file
FILE* pup_file = fopen(argv[1], "rb");
//Check if file is OK
if(pup_file == NULL){
printf("Could not open the file.");
return -1;
}
//Create the struct
PUP_header pup_header;
//Read the pup
printf("\nReading the header of: %s", argv[1]);
pup_read_header(&pup_header, pup_file);
//Print
pup_print_header(&pup_header);
//Extract files
printf("\n-> Extracting files...");
pup_extract(&pup_header, pup_file);
printf("\n\nEverything extracted!!! Press any key to exit.");
fclose(pup_file);
pup_free_pup_header(&pup_header);
getchar();
return 0;
}
void pup_free_pup_header(PUP_header *pup_header)
{
free(pup_header->file_table);
free(pup_header->hash_table);
free(pup_header->unknown);
free(pup_header->header_hash);
int i;
for(i = 0; i < pup_header->file_count; i++)
{
free(pup_header->hash_table[i].file_hash);
free(pup_header->hash_table[i].unknown);
}
}
int pup_read_header(PUP_header *pup_header, FILE *pup_file){
int i, size;
size = 0;
//Cursor at the beginning of the file
fseek(pup_file, 0, SEEK_SET);
//Allocate ememory for unknown
pup_header->unknown = (char *)malloc(sizeof(char) * 0x50);
//Start reading the header
size += fread( &(pup_header->magic), 1, 0x8, pup_file ); //Read magic
size += fread( &(pup_header->package_version), 1, 0x8, pup_file ); //Read Package Version
size += fread( &(pup_header->image_version), 1, 0x8, pup_file ); //Read Image Version
size += fread( &(pup_header->file_count), 1, 0x8, pup_file ); //Read File Count
size += fread( &(pup_header->header_length), 1, 0x8, pup_file ); //Read Header Length
size += fread( &(pup_header->package_length), 1, 0x8, pup_file ); //Read Package Length
size += fread( (pup_header->unknown), 1, 0x50, pup_file ); //Read ¿UNKNOWN?
//Allocate memory for the header
pup_header->file_table = (File_table *)malloc(sizeof(File_table) * 0x20 * pup_header->file_count);
pup_header->hash_table = (Hash_table *)malloc(sizeof(Hash_table) * 0x40 * pup_header->file_count);
//Read File Table
for(i = 0; i < pup_header->file_count; i++){
size += fread( &(pup_header->file_table[i].entry_ID), 1, 0x8, pup_file );
size += fread( &(pup_header->file_table[i].data_offset), 1, 0x8, pup_file );
size += fread( &(pup_header->file_table[i].data_length), 1, 0x8, pup_file );
size += fread( &(pup_header->file_table[i].unknown), 1, 0x8, pup_file );
}
//Read Hash Table
for(i = 0; i < pup_header->file_count; i++){
size += fread( &(pup_header->hash_table[i].file_index), 1, 0x8, pup_file ); //Read Entry_ID
//Allocate memory for file_hash and unknown¿?
pup_header->hash_table[i].file_hash = (char *)malloc(sizeof(char) * 0x20);
pup_header->hash_table[i].unknown = (char *)malloc(sizeof(char) * 0x18);
size += fread( (pup_header->hash_table[i].file_hash), 1, 0x20, pup_file ); //Read File Hash
size += fread( (pup_header->hash_table[i].unknown), 1, 0x18, pup_file ); //Read ¿UNKNOWN?
}
//Allocate memory for header_hash
pup_header->header_hash = (char *)malloc(sizeof(char) * 0x20);
//Header hash
size += fread( (pup_header->header_hash), 1, 0x20, pup_file ); //Read Header Hash
return size;
}
void pup_print_header(PUP_header *pup_header){
int i;
printf("\n\n");
printf("-> Magic 0x%llX\n", pup_header->magic); //Magic
printf("-> Package version 0x%llX\n", pup_header->package_version); //Package Version
printf("-> Image version 0x%llX\n", pup_header->image_version); //Image Version
printf("-> File count 0x%llX\n", pup_header->file_count); //File Count
printf("-> Header length 0x%llX\n", pup_header->header_length); //Header Length
printf("-> Package length 0x%llX\n", pup_header->package_length); //Package Length
printf("-> Unknown 0x%llX\n", *(u64 *)pup_header->unknown); //Unknown
printf("-> Header hash 0x%llX\n", *(u64 *)pup_header->unknown); //Header hash
//File Table and hash table
for(i = 0; i < pup_header->file_count; i++){
printf("\n-> File %i", i+1);
printf("\n----> File table\n");
printf("-------> Entry ID 0x%llX\n", pup_header->file_table[i].entry_ID);
printf("-------> Data offset 0x%llX\n", pup_header->file_table[i].data_offset);
printf("-------> Data length 0x%llX\n", pup_header->file_table[i].data_length);
printf("-------> Unknown 0x%llX\n", pup_header->file_table[i].unknown);
printf("----> Hash table\n");
printf("-------> File index 0x%llX\n", pup_header->hash_table[i].file_index);
printf("-------> File hash 0x%llX\n", *(u64 *)pup_header->hash_table[i].file_hash);
printf("-------> Unknown 0x%llX\n", *(u64 *)pup_header->hash_table[i].unknown);
}
return;
}
char *ID_to_filename(u64 entry_ID){
switch(entry_ID){
case 0x100:
return "version.txt";
case 0x101:
return "license.xml";
case 0x200:
return "psp2swu.self";
case 0x204:
return "exec_file.self";
case 0x301:
return "package_data01.pkg";
case 0x302:
return "package_data02.pkg";
case 0x303:
return "package_data03.pkg";
case 0x304:
return "package_data04.pkg";
case 0x305:
return "package_data05.pkg";
case 0x306:
return "package_data06.pkg";
case 0x307:
return "package_data07.pkg";
case 0x308:
return "package_data08.pkg";
case 0x309:
return "package_data09.pkg";
case 0x30a:
return "package_data10.pkg";
case 0x30b:
return "package_data11.pkg";
case 0x30c:
return "package_data12.pkg";
case 0x30d:
return "package_data13.pkg";
case 0x30e:
return "package_data14.pkg";
case 0x30f:
return "package_data15.pkg";
case 0x400:
return "package_scewm.wm";
case 0x401:
return "package_sceas.as";
default:
break;
}
return NULL;
}
void pup_extract(PUP_header *pup_header, FILE *pup_file){
int i, j;
char *output_name;
byte buffer[512];
unsigned int data_read;
FILE *output;
for(i = 0; i < pup_header->file_count; i++){
output_name = ID_to_filename(pup_header->file_table[i].entry_ID);
if(output_name != NULL){
//Creating file...
printf("\n\n----> Extracting file: %s", output_name);
//Set the cursor
fseek(pup_file, pup_header->file_table[i].data_offset, SEEK_SET);
//Create output file
output = fopen(output_name, "wb");
//Check if file is OK
if(output == NULL){
printf("\n-------> Could not extract the file.", output_name);
continue;
}
//Write
for(j = 0; j < pup_header->file_table[i].data_length; j++){
data_read = fread(buffer, 1, 512, pup_file);
fwrite(buffer, 1, data_read, output);
}
//Close
fflush(output);
fclose(output);
//File was successfully created
printf("\n-------> File successfully extracted!");
}
}
return;
}