mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 10:42:36 +01:00
Implemented PKG Installer, improved Boot game.
This commit is contained in:
parent
584d4eb9d4
commit
6d56f1ae86
@ -95,6 +95,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scetool", "scetool", "{AB33
|
||||
scetool\zlib.h = scetool\zlib.h
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unpkg", "unpkg", "{9F2D2094-BA46-4456-8C45-FD9EC108F1EE}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
unpkg\oddkeys.h = unpkg\oddkeys.h
|
||||
unpkg\ps3_common.h = unpkg\ps3_common.h
|
||||
unpkg\unpkg.c = unpkg\unpkg.c
|
||||
unpkg\unpkg.h = unpkg\unpkg.h
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
|
@ -47,7 +47,8 @@ AboutDialog::AboutDialog(wxWindow *parent)
|
||||
wxBoxSizer* s_panel_credits(new wxBoxSizer(wxHORIZONTAL));
|
||||
wxStaticText* t_section1 = new wxStaticText(this, wxID_ANY, "\nDevelopers:\n\nDH\nAlexAltea", wxDefaultPosition, wxSize(156,160));
|
||||
wxStaticText* t_section2 = new wxStaticText(this, wxID_ANY, "\nThanks:\n\nBlackDaemon", wxDefaultPosition, wxSize(156,160));
|
||||
wxStaticText* t_section3 = new wxStaticText(this, wxID_ANY, "\nExternal code:\n\n - SELF Decrypter based on scetool (C) 2011-2013 by naehrwert", wxDefaultPosition, wxSize(156,160));
|
||||
wxStaticText* t_section3 = new wxStaticText(this, wxID_ANY, "\nExternal code:\n\n - SELF Decrypter based on scetool (C) 2011-2013 by naehrwert\n\ - PKG Installer based on ps3pkgtool (C) 2011-2013 by avtolstoy and PKG Finalize (C) by geohot", wxDefaultPosition, wxSize(156,160));
|
||||
|
||||
s_panel_credits->AddSpacer(12);
|
||||
s_panel_credits->Add(t_section1);
|
||||
s_panel_credits->AddSpacer(8);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <wx/dynlib.h>
|
||||
|
||||
#include "scetool/scetool.cpp"
|
||||
#include "unpkg/unpkg.c"
|
||||
|
||||
BEGIN_EVENT_TABLE(MainFrame, FrameBase)
|
||||
EVT_CLOSE(MainFrame::OnQuit)
|
||||
@ -22,6 +23,7 @@ enum IDs
|
||||
id_boot_elf = 0x555,
|
||||
id_boot_self,
|
||||
id_boot_game,
|
||||
id_boot_pkg,
|
||||
id_sys_pause,
|
||||
id_sys_stop,
|
||||
id_sys_send_open_menu,
|
||||
@ -65,6 +67,7 @@ MainFrame::MainFrame()
|
||||
menubar.Append(&menu_help, "Help");
|
||||
|
||||
menu_boot.Append(id_boot_game, "Boot game");
|
||||
menu_boot.Append(id_boot_pkg, "Install PKG");
|
||||
menu_boot.AppendSeparator();
|
||||
menu_boot.Append(id_boot_elf, "Boot ELF");
|
||||
menu_boot.Append(id_boot_self, "Boot SELF");
|
||||
@ -88,6 +91,7 @@ MainFrame::MainFrame()
|
||||
AddPane(m_game_viewer, "Game List", wxAUI_DOCK_BOTTOM);
|
||||
|
||||
Connect( id_boot_game, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::BootGame) );
|
||||
Connect( id_boot_pkg, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::BootPkg) );
|
||||
Connect( id_boot_elf, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::BootElf) );
|
||||
Connect( id_boot_self, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::BootSelf) );
|
||||
|
||||
@ -167,9 +171,19 @@ void MainFrame::BootGame(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
if(wxFile::Access(ctrl.GetPath() + elf[i], wxFile::read))
|
||||
{
|
||||
Emu.SetPath(ctrl.GetPath() + elf[i]);
|
||||
ConLog.Write("Elf: booting...");
|
||||
ConLog.Write("SELF: booting...");
|
||||
|
||||
Emu.Stop();
|
||||
|
||||
wxString fileIn = ctrl.GetPath()+elf[i];
|
||||
wxString fileOut = (ctrl.GetPath()+elf[i])+".elf";
|
||||
scetool_decrypt((scetool::s8 *)fileIn.mb_str(), (scetool::s8 *)fileOut.mb_str());
|
||||
|
||||
Emu.SetPath((ctrl.GetPath()+elf[i])+".elf");
|
||||
Emu.Load();
|
||||
if (!wxRemoveFile((ctrl.GetPath()+elf[i])+".elf"))
|
||||
ConLog.Warning("Could not delete the decrypted ELF file");
|
||||
|
||||
ConLog.Write("Game: boot done.");
|
||||
return;
|
||||
}
|
||||
@ -179,6 +193,39 @@ void MainFrame::BootGame(wxCommandEvent& WXUNUSED(event))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void MainFrame::BootPkg(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
bool stopped = false;
|
||||
|
||||
if(Emu.IsRunning())
|
||||
{
|
||||
Emu.Pause();
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
wxFileDialog ctrl (this, L"Select PKG", wxEmptyString, wxEmptyString, "*.*",
|
||||
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
|
||||
if(ctrl.ShowModal() == wxID_CANCEL)
|
||||
{
|
||||
if(stopped) Emu.Resume();
|
||||
return;
|
||||
}
|
||||
|
||||
ConLog.Write("PKG: extracting...");
|
||||
|
||||
Emu.Stop();
|
||||
|
||||
wxString fileName = ctrl.GetPath();
|
||||
pkg_unpack((const char *)fileName.mb_str());
|
||||
|
||||
if (!wxRemoveFile(ctrl.GetPath()+".dec"))
|
||||
ConLog.Warning("Could not delete the decoded DEC file");
|
||||
|
||||
ConLog.Write("PKG: extract done.");
|
||||
}
|
||||
|
||||
void MainFrame::BootElf(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
bool stopped = false;
|
||||
|
@ -20,6 +20,7 @@ private:
|
||||
void OnQuit(wxCloseEvent& event);
|
||||
|
||||
void BootGame(wxCommandEvent& event);
|
||||
void BootPkg(wxCommandEvent& event);
|
||||
void BootElf(wxCommandEvent& event);
|
||||
void BootSelf(wxCommandEvent& event);
|
||||
void Pause(wxCommandEvent& event);
|
||||
|
20
unpkg/oddkeys.h
Normal file
20
unpkg/oddkeys.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
u8 retail_pkg_aes_key[] = {0x2E,0x7B,0x71,0xD7,0xC9,0xC9,0xA1,0x4E,0xA3,0x22,0x1F,0x18,0x88,0x28,0xB8,0xF8};
|
||||
|
||||
u8 npdrm_keypair_e[] = {
|
||||
0xA1,0xC0,0x13,0xAB,0xCE,0x98,0xA7,0xE3,0xDC,0x69,0x92,0x3B,0x07,0xC0,0x28,0x5F,
|
||||
0x75,0x54,0xC5,0x12,0xB0,0xB0,0xA9,0x6F,0x24,0x52,0x40,0xF2,0xFD,0x43,0x3A,0xF2,
|
||||
0x3F,0x4E,0xFE,0xC6,0xC1,0x83,0xEA,0x37,0x8D,0x1B,0xEC,0xB0,0x9D,0x88,0xDB,0x32,
|
||||
0x8F,0x2C,0x86,0x37,0xB7,0xAC,0x72,0x05,0x9B,0x15,0x56,0xB0,0xD9,0x5B,0x5B,0xE0};
|
||||
|
||||
u8 npdrm_keypair_d[] = {
|
||||
0x87,0xC7,0x4F,0xFE,0x66,0x93,0x0B,0xAA,0xA1,0x6F,0x86,0x40,0x91,0xC5,0x66,0xFB,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x08,0x28,0xB5,0x8F,0xAC,0xF9,0xDE,0xC8,0xD7,0x0D,0xFE,0xF0,0xF3,0x76,0x63,0xAE,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
|
||||
u8 npdrm_omac_key1[] = {0x72,0xF9,0x90,0x78,0x8F,0x9C,0xFF,0x74,0x57,0x25,0xF0,0x8E,0x4C,0x12,0x83,0x87};
|
||||
u8 npdrm_omac_key2[] = {0x6B,0xA5,0x29,0x76,0xEF,0xDA,0x16,0xEF,0x3C,0x33,0x9F,0xB2,0x97,0x1E,0x25,0x6B};
|
||||
u8 npdrm_omac_key3[] = {0x9B,0x51,0x5F,0xEA,0xCF,0x75,0x06,0x49,0x81,0xAA,0x60,0x4D,0x91,0xA5,0x4E,0x97};
|
106
unpkg/ps3_common.h
Normal file
106
unpkg/ps3_common.h
Normal file
@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
typedef struct {
|
||||
u32 magic;
|
||||
u32 debugFlag;
|
||||
u32 infoOffset;
|
||||
u32 unknown1;
|
||||
u32 headSize;
|
||||
u32 itemCount;
|
||||
u64 packageSize;
|
||||
u64 dataOffset;
|
||||
u64 dataSize;
|
||||
} pkg_header2;
|
||||
|
||||
u64 get_u64(void* vd) {
|
||||
u8 *d = (u8*)vd;
|
||||
return ((u64)d[0]<<56) | ((u64)d[1]<<48) | ((u64)d[2]<<40) | ((u64)d[3]<<32) | (d[4]<<24) | (d[5]<<16) | (d[6]<<8) | d[7];
|
||||
}
|
||||
|
||||
void set_u64(void* vd, u64 v) {
|
||||
u8 *d = (u8*)vd;
|
||||
d[0] = v>>56;
|
||||
d[1] = v>>48;
|
||||
d[2] = v>>40;
|
||||
d[3] = v>>32;
|
||||
d[4] = v>>24;
|
||||
d[5] = v>>16;
|
||||
d[6] = v>>8;
|
||||
d[7] = v>>0;
|
||||
}
|
||||
|
||||
void set_u32(void* vd, u32 v) {
|
||||
u8 *d = (u8*)vd;
|
||||
d[0] = v>>24;
|
||||
d[1] = v>>16;
|
||||
d[2] = v>>8;
|
||||
d[3] = v>>0;
|
||||
}
|
||||
|
||||
void set_u16(void* vd, u16 v) {
|
||||
u8 *d = (u8*)vd;
|
||||
d[0] = v>>8;
|
||||
d[1] = v>>0;
|
||||
}
|
||||
|
||||
u32 get_u32(void* vd) {
|
||||
u8 *d = (u8*)vd;
|
||||
return (d[0]<<24) | (d[1]<<16) | (d[2]<<8) | d[3];
|
||||
}
|
||||
|
||||
float get_float(u8* d) {
|
||||
float ret;
|
||||
u32 inter = (d[0]<<24) | (d[1]<<16) | (d[2]<<8) | d[3];
|
||||
memcpy(&ret, &inter, 4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 get_u16(void* vd) {
|
||||
u8 *d = (u8*)vd;
|
||||
return (d[0]<<8) | d[1];
|
||||
}
|
||||
|
||||
void hexdump(u8* d, int l) {
|
||||
int i;
|
||||
for(i=0;i<l;i++) {
|
||||
if(i!=0 && (i%16)==0) ConLog.Write("\n");
|
||||
ConLog.Write("%2.2X ", d[i]);
|
||||
}
|
||||
ConLog.Write("\n");
|
||||
}
|
||||
|
||||
|
||||
void hexdump_nl(u8* d, int l) {
|
||||
int i;
|
||||
for(i=0;i<l;i++) {
|
||||
ConLog.Write("%2.2X ", d[i]);
|
||||
}
|
||||
ConLog.Write("\n");
|
||||
}
|
||||
|
||||
void hexdump_ns(u8* d, int l) {
|
||||
int i;
|
||||
for(i=0;i<l;i++) {
|
||||
ConLog.Write("%2.2X", d[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void hexdump_c(u8* d, int l) {
|
||||
int i;
|
||||
for(i=0;i<l;i++) {
|
||||
ConLog.Write("0x%2.2X", d[i]);
|
||||
if(i!=(l-1)) {
|
||||
ConLog.Write(",");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hexdump_32(u8* d, int l) {
|
||||
int i;
|
||||
for(i=0;i<l;i+=4) {
|
||||
if(i!=0 && (i%16)==0) printf("\n");
|
||||
ConLog.Write("%8X ", get_u32(d+i));
|
||||
}
|
||||
ConLog.Write("\n");
|
||||
}
|
406
unpkg/unpkg.c
Normal file
406
unpkg/unpkg.c
Normal file
@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright 2011 Andrey Tolstoy <avtolstoy@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "unpkg.h"
|
||||
#include "ps3_common.h"
|
||||
#include "oddkeys.h"
|
||||
|
||||
static void hash_tostring(char *str, u8 *hash, u32 len)
|
||||
{
|
||||
u8 *p;
|
||||
memset(str, 0, 2*len+1);
|
||||
for (p = hash; p-hash < len; p++)
|
||||
{
|
||||
str += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void *pkg_open(const char *fname)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(fname, "rb");
|
||||
if (f == NULL)
|
||||
{
|
||||
ConLog.Error ("UnPkg: Could not open package file!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static int pkg_sanity_check(FILE *f, FILE *g, pkg_header **h_ptr, const char *fname)
|
||||
{
|
||||
pkg_header *header = (pkg_header*)malloc(sizeof(pkg_header));
|
||||
u64 tmp;
|
||||
|
||||
if (!fread(header, sizeof(pkg_header), 1, f))
|
||||
{
|
||||
ConLog.Error("UnPkg: Package file is too short!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// some sanity checks
|
||||
|
||||
if (ntohl(header->magic) != PKG_MAGIC)
|
||||
{
|
||||
ConLog.Error("UnPkg: Not a package file!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (ntohl(header->rel_type) >> 16 & (0xffff))
|
||||
{
|
||||
case PKG_RELEASE_TYPE_DEBUG:
|
||||
{
|
||||
ConLog.Warning ("UnPkg: Debug PKG detected.");
|
||||
u8* data;
|
||||
u8 sha_key[0x40];
|
||||
int i;
|
||||
f= fopen(fname, "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
int nlen = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
data = (u8*)malloc(nlen);
|
||||
fread(data, 1, nlen, f);
|
||||
fclose(f);
|
||||
|
||||
pkg_header2 *header = (pkg_header2 *)data;
|
||||
int data_offset = get_u64(&(header->dataOffset));
|
||||
int data_size = get_u64(&(header->dataSize));
|
||||
|
||||
// decrypt debug
|
||||
u8 sha_crap[0x40];
|
||||
memset(sha_crap, 0, 0x40);
|
||||
memcpy(sha_crap, &data[0x60], 8);
|
||||
memcpy(sha_crap+0x8, &data[0x60], 8);
|
||||
memcpy(sha_crap+0x10, &data[0x68], 8);
|
||||
memcpy(sha_crap+0x18, &data[0x68], 8);
|
||||
|
||||
int dptr;
|
||||
for(dptr = data_offset; dptr < (data_offset+data_size); dptr+=0x10) {
|
||||
u8 hash[0x14];
|
||||
sha1(sha_crap, 0x40, hash);
|
||||
for(i=0;i<0x10;i++) data[dptr+i] ^= hash[i];
|
||||
set_u64(sha_crap+0x38, get_u64(sha_crap+0x38)+1);
|
||||
}
|
||||
|
||||
// recrypt retail
|
||||
u8 pkg_key[0x10];
|
||||
memcpy(pkg_key, &data[0x70], 0x10);
|
||||
|
||||
//AES_KEY aes_key;
|
||||
aes_context aes_key;
|
||||
aes_setkey_enc(&aes_key, retail_pkg_aes_key, 128);
|
||||
|
||||
size_t num=0; u8 ecount_buf[0x10]; memset(ecount_buf, 0, 0x10);
|
||||
aes_crypt_ctr(&aes_key, data_size, &num, pkg_key, ecount_buf, &data[data_offset], &data[data_offset]);
|
||||
|
||||
// write back
|
||||
g = fopen(fname, "wb");
|
||||
data[4] = 0x80; // set finalize flag
|
||||
memset(&data[(data_offset+data_size)], 0, 0x60);
|
||||
|
||||
// add hash
|
||||
sha1(data, nlen-0x20, &data[nlen-0x20]);
|
||||
fwrite(data, 1, nlen, g);
|
||||
//fclose(g); // not close the file for continuing
|
||||
|
||||
fseek(g, 0, SEEK_END);
|
||||
tmp = ftell(g);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case PKG_RELEASE_TYPE_RELEASE:
|
||||
{
|
||||
ConLog.Warning ("UnPkg: Retail PKG detected.");
|
||||
fseek(f, 0, SEEK_END);
|
||||
tmp = ftell(f);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ConLog.Error("UnPkg: Unknown release type.");
|
||||
return 1;
|
||||
|
||||
|
||||
}
|
||||
switch (ntohl(header->rel_type) & (0xffff))
|
||||
{
|
||||
case PKG_PLATFORM_TYPE_PS3:
|
||||
case PKG_PLATFORM_TYPE_PSP:
|
||||
break;
|
||||
|
||||
default:
|
||||
ConLog.Error("UnPkg: Unknown platform type.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ntohl(header->header_size) != PKG_HEADER_SIZE)
|
||||
{
|
||||
ConLog.Error("UnPkg: Wrong header size: ");
|
||||
return 1;
|
||||
}
|
||||
|
||||
//fseek(g, 0, SEEK_END);
|
||||
//tmp = ftell(g);
|
||||
if (ntohll(header->pkg_size) != tmp)
|
||||
{
|
||||
ConLog.Error("UnPkg: File size mismatch.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
tmp -= ntohll(header->data_offset) + 0x60;
|
||||
if (ntohll(header->data_size) != tmp)
|
||||
{
|
||||
ConLog.Error("UnPkg: Data size mismatch.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (h_ptr != NULL)
|
||||
{
|
||||
(*h_ptr) = (pkg_header*) malloc(sizeof(pkg_header));
|
||||
memcpy(h_ptr, &header, sizeof(pkg_header*));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_pkg_header(pkg_header *header)
|
||||
{
|
||||
char qa[33], kl[33];
|
||||
|
||||
if (header == NULL)
|
||||
return;
|
||||
|
||||
hash_tostring(qa, header->qa_digest, sizeof(header->qa_digest));
|
||||
hash_tostring(kl, header->klicensee, sizeof(header->klicensee));
|
||||
|
||||
ConLog.Write("Magic: %x\n", ntohl(header->magic));
|
||||
ConLog.Write("Release Type: %x\n", ntohl(header->rel_type) >> 16 & (0xffff));
|
||||
ConLog.Write("Platform Type: %x\n", ntohl(header->rel_type) & (0xffff));
|
||||
ConLog.Write("Header size: %x\n", ntohl(header->header_size));
|
||||
ConLog.Write("Unk1: %x\n", ntohl(header->unk1));
|
||||
ConLog.Write("Metadata size: %x\n", ntohl(header->meta_size));
|
||||
ConLog.Write("File count: %u\n", ntohl(header->file_count));
|
||||
ConLog.Write("Pkg size: %llu\n", ntohll(header->pkg_size));
|
||||
ConLog.Write("Data offset: %llx\n", ntohll(header->data_offset));
|
||||
ConLog.Write("Data size: %llu\n", ntohll(header->data_size));
|
||||
ConLog.Write("TitleID: %s\n", header->title_id);
|
||||
ConLog.Write("QA Digest: %s\n", qa);
|
||||
ConLog.Write( "KLicensee: %s\n", kl);
|
||||
}
|
||||
|
||||
static void *pkg_info(const char *fname, pkg_header **h_ptr)
|
||||
{
|
||||
FILE *f;
|
||||
FILE *g;
|
||||
pkg_header *header;
|
||||
|
||||
f = (FILE*) pkg_open(fname);
|
||||
if (f == NULL)
|
||||
return NULL;
|
||||
|
||||
if (pkg_sanity_check(f, g, &header, fname))
|
||||
return NULL;
|
||||
|
||||
print_pkg_header(header);
|
||||
|
||||
if (h_ptr != NULL)
|
||||
{
|
||||
(*h_ptr) = header;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(header);
|
||||
}
|
||||
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
static void pkg_crypt(const u8 *key, const u8 *kl, FILE *f,
|
||||
u64 len, FILE *out)
|
||||
{
|
||||
aes_context c;
|
||||
u32 parts, bits;
|
||||
u32 i, j;
|
||||
u8 iv[HASH_LEN];
|
||||
u8 buf[BUF_SIZE];
|
||||
u8 ctr[BUF_SIZE];
|
||||
u8 out_buf[BUF_SIZE];
|
||||
u32 l;
|
||||
u64 hi, lo;
|
||||
|
||||
parts = len / BUF_SIZE;
|
||||
if (len % BUF_SIZE != 0)
|
||||
parts++;
|
||||
|
||||
memcpy(iv, kl, sizeof(iv));
|
||||
aes_setkey_enc(&c, key, 128);
|
||||
|
||||
for (i = 0; i<parts; i++)
|
||||
{
|
||||
l = fread(buf, 1, BUF_SIZE, f);
|
||||
bits = l / HASH_LEN;
|
||||
if (bits % HASH_LEN != 0)
|
||||
bits++;
|
||||
|
||||
for (j = 0; j<bits; j++)
|
||||
{
|
||||
aes_crypt_ecb(&c, AES_ENCRYPT, iv, ctr+j*HASH_LEN);
|
||||
|
||||
hi = unpack64(iv);
|
||||
lo = unpack64(iv+8) + 1;
|
||||
if (lo == 0)
|
||||
hi++;
|
||||
pack64(iv, hi);
|
||||
pack64(iv + 8, lo);
|
||||
}
|
||||
|
||||
|
||||
memset(out_buf, 0, sizeof(out_buf));
|
||||
for (j=0; j<l; j++)
|
||||
{
|
||||
out_buf[j] = buf[j] ^ ctr[j];
|
||||
}
|
||||
|
||||
fwrite(out_buf, 1, l, out);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void pkg_unpack_file(pkg_file_entry *fentry, FILE *dec)
|
||||
{
|
||||
FILE *out = NULL;
|
||||
u64 size;
|
||||
u32 tmp;
|
||||
u8 buf[BUF_SIZE];
|
||||
|
||||
fseek(dec, fentry->name_offset, SEEK_SET);
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
fread(buf, fentry->name_size, 1, dec);
|
||||
|
||||
switch (fentry->type & (0xffff))
|
||||
{
|
||||
case PKG_FILE_ENTRY_NPDRM:
|
||||
case PKG_FILE_ENTRY_NPDRMEDAT:
|
||||
case PKG_FILE_ENTRY_SDAT:
|
||||
case PKG_FILE_ENTRY_REGULAR:
|
||||
out = fopen((char *)buf, "wb");
|
||||
fseek(dec, fentry->file_offset, SEEK_SET);
|
||||
for (size = 0; size < fentry->file_size; )
|
||||
{
|
||||
size += fread(buf, sizeof(u8), BUF_SIZE, dec);
|
||||
if (size > fentry->file_size)
|
||||
tmp = size - fentry->file_size;
|
||||
else
|
||||
tmp = 0;
|
||||
|
||||
fwrite(buf, sizeof(u8), BUF_SIZE - tmp, out);
|
||||
}
|
||||
|
||||
fclose(out);
|
||||
break;
|
||||
|
||||
case PKG_FILE_ENTRY_FOLDER:
|
||||
mkdir ((char *)buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void pkg_unpack_data(u32 file_count, FILE *dec)
|
||||
{
|
||||
u32 i;
|
||||
pkg_file_entry *file_table = NULL;
|
||||
|
||||
fseek(dec, 0, SEEK_SET);
|
||||
|
||||
file_table = (pkg_file_entry *)malloc(sizeof(pkg_file_entry)*file_count);
|
||||
i = fread(file_table, sizeof(pkg_file_entry), file_count, dec);
|
||||
|
||||
if (ntohl(file_table->name_offset) / sizeof(pkg_file_entry) != file_count)
|
||||
{
|
||||
ConLog.Error("UnPkg: ERROR. Impossiburu!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i<file_count; i++)
|
||||
{
|
||||
(file_table+i)->name_offset = ntohl((file_table+i)->name_offset);
|
||||
(file_table+i)->name_size = ntohl((file_table+i)->name_size);
|
||||
(file_table+i)->file_offset = ntohll((file_table+i)->file_offset);
|
||||
(file_table+i)->file_size = ntohll((file_table+i)->file_size);
|
||||
(file_table+i)->type = ntohl((file_table+i)->type);
|
||||
|
||||
pkg_unpack_file(file_table+i, dec);
|
||||
|
||||
}
|
||||
|
||||
free(file_table);
|
||||
}
|
||||
|
||||
static void pkg_unpack(const char *fname)
|
||||
{
|
||||
FILE *f, *dec;
|
||||
char *dec_fname;
|
||||
pkg_header *header;
|
||||
int ret;
|
||||
struct stat sb;
|
||||
|
||||
f = (FILE*) pkg_info(fname, &header);
|
||||
|
||||
if (f == NULL)
|
||||
return;
|
||||
|
||||
fseek(f, ntohll(header->data_offset), SEEK_SET);
|
||||
|
||||
dec_fname = (char*)malloc(strlen(fname)+4);
|
||||
memset(dec_fname, 0, strlen(fname)+4);
|
||||
sprintf(dec_fname, "%s.dec", fname);
|
||||
|
||||
dec = fopen(dec_fname, "wb+");
|
||||
if (dec == NULL)
|
||||
{
|
||||
ConLog.Error("UnPkg: Could not create temp file for decrypted data.");
|
||||
free(header);
|
||||
return;
|
||||
}
|
||||
unlink(dec_fname);
|
||||
|
||||
pkg_crypt(PKG_AES_KEY, header->klicensee, f, ntohll(header->data_size),
|
||||
dec);
|
||||
fseek(dec, 0, SEEK_SET);
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (stat(header->title_id, &sb) != 0)
|
||||
{
|
||||
ret = mkdir(header->title_id);
|
||||
if (ret < 0)
|
||||
{
|
||||
ConLog.Error("UnPkg: Could not mkdir.");
|
||||
free(header);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
chdir(header->title_id);
|
||||
|
||||
pkg_unpack_data(ntohl(header->file_count), dec);
|
||||
fclose(dec);
|
||||
}
|
176
unpkg/unpkg.h
Normal file
176
unpkg/unpkg.h
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright 2011 Andrey Tolstoy <avtolstoy@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UNPKG_H_
|
||||
#define UNPKG_H_
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "scetool/aes.h"
|
||||
#include "scetool/sha1.h"
|
||||
|
||||
#define ntohll(x) (((u64) ntohl (x) << 32) | (u64) ntohl (x >> 32) )
|
||||
#define htonll(x) (((u64) htonl (x) << 32) | (u64) htonl (x >> 32) )
|
||||
#define conv_ntohl(x) { x = ntohl(x); }
|
||||
#define conv_ntohll(x) { x = ntohll(x); }
|
||||
#define conv_htonl(x) { x = htonl(x); }
|
||||
#define conv_htonll(x) { x = htonll(x); }
|
||||
|
||||
#define unpack32(x) ((u32) ((u32)*(x) << 24 | \
|
||||
(u32)*(x+1) << 16 | \
|
||||
(u32)*(x+2) << 8 | \
|
||||
(u32)*(x+3) << 0))
|
||||
|
||||
#define unpack64(x) ((u64)unpack32(x) << 32 | (u64)unpack32(x+4))
|
||||
|
||||
#define pack32(x, p) \
|
||||
{ \
|
||||
*(x) = (u8)(p >> 24); \
|
||||
*((x)+1) = (u8)(p >> 16); \
|
||||
*((x)+2) = (u8)(p >> 8); \
|
||||
*((x)+3) = (u8)(p >> 0); \
|
||||
}
|
||||
|
||||
#define pack64(x, p) { pack32((x + 4), p); pack32((x), p >> 32); }
|
||||
|
||||
#define HASH_LEN 16
|
||||
#define BUF_SIZE 4096
|
||||
|
||||
typedef struct {
|
||||
u32 magic; // magic 0x7f504b47
|
||||
u32 rel_type; // release type
|
||||
u32 header_size; // 0xc0
|
||||
u32 unk1; //some pkg version maybe
|
||||
u32 meta_size; //size of metadata (block after header & hashes)
|
||||
u32 file_count; // number of files
|
||||
u64 pkg_size; // pkg size in bytes
|
||||
u64 data_offset; // encrypted data offset
|
||||
u64 data_size; // encrypted data size in bytes
|
||||
char title_id[48]; // title id
|
||||
u8 qa_digest[16]; // this should be the hash of "files + attribs"
|
||||
u8 klicensee[16]; // nonce
|
||||
} pkg_header;
|
||||
|
||||
typedef struct {
|
||||
u8 hash1[16];
|
||||
u8 hash2[16];
|
||||
u8 hash3[16];
|
||||
u8 hash4[16];
|
||||
} pkg_unk_checksum;
|
||||
|
||||
/*
|
||||
is it in meta or sfo?
|
||||
# CATEGORY : HG
|
||||
# BOOTABLE : YES
|
||||
# VERSION : 01.00
|
||||
# APP_VER : 01.00
|
||||
# PS3_SYSTEM_VER : 03.0000
|
||||
*/
|
||||
|
||||
/* meta hell structure */
|
||||
typedef struct {
|
||||
u32 unk1;
|
||||
u32 unk2;
|
||||
u32 drm_type;
|
||||
u32 unk3;
|
||||
|
||||
u32 unk4;
|
||||
u32 unk5;
|
||||
u32 unk6;
|
||||
u32 unk7;
|
||||
|
||||
u32 unk8;
|
||||
u32 unk9;
|
||||
u32 unk10;
|
||||
u32 unk11;
|
||||
|
||||
u32 data_size;
|
||||
u32 unk12;
|
||||
u32 unk13;
|
||||
u32 packager;
|
||||
|
||||
u8 unk14[64];
|
||||
} pkg_meta;
|
||||
|
||||
typedef struct {
|
||||
u32 name_offset; // file name offset
|
||||
u32 name_size; // file name size
|
||||
u64 file_offset; // file offset
|
||||
u64 file_size; // file size
|
||||
u32 type; // file type
|
||||
/*
|
||||
0x80000003 - regular file
|
||||
0x80000001 - npdrm
|
||||
0x80000004 - folder
|
||||
0x80000009 - sdat ?
|
||||
0x80000002 - npdrm.edat ?
|
||||
*/
|
||||
u32 pad; // padding (zeros)
|
||||
} pkg_file_entry;
|
||||
|
||||
typedef struct {
|
||||
pkg_file_entry fe;
|
||||
char *name;
|
||||
char *path;
|
||||
} file_table_tr;
|
||||
|
||||
#define PKG_MAGIC 0x7f504b47 // \x7fPKG
|
||||
#define PKG_HEADER_SIZE sizeof(pkg_header) + sizeof(pkg_unk_checksum)
|
||||
#define PKG_RELEASE_TYPE_RELEASE 0x8000
|
||||
#define PKG_RELEASE_TYPE_DEBUG 0x0000
|
||||
#define PKG_PLATFORM_TYPE_PS3 0x0001
|
||||
#define PKG_PLATFORM_TYPE_PSP 0x0002
|
||||
|
||||
#define PKG_FILE_ENTRY_OVERWRITE 0x80000000
|
||||
#define PKG_FILE_ENTRY_NPDRM 0x0001
|
||||
#define PKG_FILE_ENTRY_NPDRMEDAT 0x0002 // npdrm.edat
|
||||
#define PKG_FILE_ENTRY_REGULAR 0x0003
|
||||
#define PKG_FILE_ENTRY_FOLDER 0x0004
|
||||
#define PKG_FILE_ENTRY_SDAT 0x0009 // .sdat ?
|
||||
|
||||
static const u8 PKG_AES_KEY[16] = {
|
||||
0x2e, 0x7b, 0x71, 0xd7,
|
||||
0xc9, 0xc9, 0xa1, 0x4e,
|
||||
0xa3, 0x22, 0x1f, 0x18,
|
||||
0x88, 0x28, 0xb8, 0xf8
|
||||
};
|
||||
|
||||
static void hash_tostring(char *str, u8 *hash, u32 len);
|
||||
|
||||
static void *pkg_open(const char *fname);
|
||||
|
||||
static int pkg_sanity_check(FILE *f, FILE *g, pkg_header **h_ptr, const char *fname);
|
||||
|
||||
static void print_pkg_header(pkg_header *header);
|
||||
|
||||
static void *pkg_info(const char *fname, pkg_header **h_ptr);
|
||||
|
||||
static void pkg_crypt(const u8 *key, const u8 *kl, FILE *f,
|
||||
u64 len, FILE *out);
|
||||
|
||||
static void pkg_unpack(const char *fname);
|
||||
|
||||
static void pkg_unpack_data(u32 file_count, FILE *dec);
|
||||
|
||||
static void pkg_unpack_file(pkg_file_entry *fentry, FILE *dec);;
|
||||
|
||||
static int pkg_pack_data(file_table_tr *ftr, pkg_file_entry *table,
|
||||
int file_count, sha1_context *ctx, FILE *out);
|
||||
|
||||
|
||||
static void *pkg_pack_create_filetable(file_table_tr *tr, int file_count,
|
||||
char **n_table, u32 *n_table_len);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user