diff --git a/rpcs3.sln b/rpcs3.sln index 0d54438b39..fd82dacfc1 100644 --- a/rpcs3.sln +++ b/rpcs3.sln @@ -104,14 +104,6 @@ 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 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ribbon", "wxWidgets\build\msw\wx_vc10_ribbon.vcxproj", "{87B42A9C-3F5C-53D7-9017-2B1CAE39457D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stc", "wxWidgets\build\msw\wx_vc10_stc.vcxproj", "{23E1C437-A951-5943-8639-A17F3CF2E606}" diff --git a/rpcs3/Gui/AboutDialog.h b/rpcs3/Gui/AboutDialog.h index 3096f4c85b..1ac1839100 100644 --- a/rpcs3/Gui/AboutDialog.h +++ b/rpcs3/Gui/AboutDialog.h @@ -47,7 +47,7 @@ AboutDialog::AboutDialog(wxWindow *parent) wxBoxSizer* s_panel_credits(new wxBoxSizer(wxHORIZONTAL)); wxStaticText* t_section1 = new wxStaticText(this, wxID_ANY, "\nDevelopers:\n\nDH\nAlexAltea\nHykem\nOil", 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\n - PKG Installer based on ps3pkgtool (C) 2011-2013 by avtolstoy and PKG Finalize (C) by geohot", 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)); s_panel_credits->AddSpacer(12); s_panel_credits->Add(t_section1); diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index 916f960731..150c4be1e3 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -12,7 +12,7 @@ #include "Gui/AboutDialog.h" #include -#include "unpkg/unpkg.c" +#include "Loader/PKG.h" BEGIN_EVENT_TABLE(MainFrame, FrameBase) EVT_CLOSE(MainFrame::OnQuit) @@ -225,43 +225,21 @@ void MainFrame::InstallPkg(wxCommandEvent& WXUNUSED(event)) return; } - ConLog.Write("PKG: extracting..."); - Emu.Stop(); - - wxString fileName = ctrl.GetPath(); - if (!pkg_unpack(static_cast(fileName))) - ConLog.Error("Could not unpack PKG!"); - else ConLog.Success("PKG: extract done."); - - if (!wxRemoveFile(ctrl.GetPath()+".dec")) - ConLog.Warning("Could not delete the decoded DEC file"); - - pkg_header *header; - pkg_info(static_cast(fileName), &header); - - wxString titleID_full (header->title_id); - wxString titleID = titleID_full.SubString(7, 15); - - wxString mainDir = wxGetCwd(); - wxString gamePath = "\\dev_hdd0\\game\\"; - - wxString pkgDir = mainDir + gamePath + titleID; - - // Save the title ID. - Emu.SetTitleID(titleID); - - //Refresh game list - m_game_viewer->Refresh(); - if(Emu.BootGame(pkgDir.ToStdString())) + // Open and install PKG file + std::string filePath = ctrl.GetPath(); + wxFile pkg_f(filePath, wxFile::read); // TODO: Use VFS to install PKG files + + if (pkg_f.IsOpened()) { - ConLog.Success("Game: boot done."); - } - else - { - ConLog.Error("Ps3 executable not found in folder (%s)", pkgDir.wx_str()); + PKGLoader pkg(pkg_f); + pkg.Install("/dev_hdd0/game/"); + pkg.Close(); } + + // Refresh game list + m_game_viewer->Refresh(); } void MainFrame::BootElf(wxCommandEvent& WXUNUSED(event)) diff --git a/rpcs3/Loader/PKG.cpp b/rpcs3/Loader/PKG.cpp new file mode 100644 index 0000000000..fa861df607 --- /dev/null +++ b/rpcs3/Loader/PKG.cpp @@ -0,0 +1,242 @@ +#include "stdafx.h" +#include "PKG.h" +#include "scetool/aes.h" +#include "scetool/sha1.h" + +#include + +PKGLoader::PKGLoader(wxFile& f) : pkg_f(f) +{ +} + +bool PKGLoader::Install(std::string dest, bool show) +{ + // Initial checks + if(!pkg_f.IsOpened()) + return false; + + dest = wxGetCwd() + dest; + if (!dest.empty() && dest.back() != '/') + dest += '/'; + + if(!LoadHeader(show)) + return false; + + std::string titleID = std::string(m_header.title_id).substr(7, 9); + std::string decryptedFile = wxGetCwd() + "/dev_hdd1/" + titleID + ".dec"; + + if (wxDirExists(dest+titleID)) { + ConLog.Error("PKG Loader: Another installation found in: %s", wxString(titleID).wx_str()); + return false; + } + if (!wxMkdir(dest+titleID)) { + ConLog.Error("PKG Loader: Could not make the installation directory: %s", wxString(titleID).wx_str()); + return false; + } + + // Decrypt the PKG file + wxFile out; + out.Create(decryptedFile, true); + Decrypt(out); + out.Close(); + + // Unpack the decrypted file + wxFile dec(decryptedFile, wxFile::read); + LoadEntries(dec); + wxProgressDialog pdlg("PKG Decrypter / Installer", "Please wait, unpacking...", m_entries.size(), 0, wxPD_AUTO_HIDE | wxPD_APP_MODAL); + + for (const PKGEntry& entry : m_entries) + { + UnpackEntry(dec, entry, dest+titleID+'/'); + pdlg.Update(pdlg.GetValue() + 1); + } + pdlg.Update(m_entries.size()); + + // Delete decrypted file + dec.Close(); + wxRemoveFile(decryptedFile); + ConLog.Write("PKG Loader: Package successfully installed in: /dev_hdd0/game/%s", wxString(titleID.c_str()).wx_str()); + return true; +} + +bool PKGLoader::Close() +{ + return pkg_f.Close(); +} + +bool PKGLoader::LoadHeader(bool show) +{ + pkg_f.Seek(0); + if (pkg_f.Read(&m_header, sizeof(PKGHeader)) != sizeof(PKGHeader)) { + ConLog.Error("PKG Loader: Package file is too short!"); + return false; + } + + if (!CheckHeader()) + return false; + + return true; +} + +bool PKGLoader::CheckHeader() +{ + if (m_header.pkg_magic != 0x7F504B47) { + ConLog.Error("PKG Loader: Not a package file!"); + return false; + } + + switch (m_header.pkg_type) + { + case PKG_RELEASE_TYPE_DEBUG: break; + case PKG_RELEASE_TYPE_RELEASE: break; + default: + ConLog.Error("PKG Loader: Unknown PKG type!"); + return false; + } + + switch (m_header.pkg_platform) + { + case PKG_PLATFORM_TYPE_PS3: break; + case PKG_PLATFORM_TYPE_PSP: break; + default: + ConLog.Error("PKG Loader: Unknown PKG type!"); + return false; + } + + if (m_header.header_size != PKG_HEADER_SIZE) { + ConLog.Error("PKG Loader: Wrong header size!"); + return false; + } + + if (m_header.pkg_size != pkg_f.Length()) { + ConLog.Error("PKG Loader: File size mismatch."); + return false; + } + + if (m_header.data_size + m_header.data_offset + 0x60 != pkg_f.Length()) { + ConLog.Error("PKG Loader: Data size mismatch."); + return false; + } + + return true; +} + +bool PKGLoader::LoadEntries(wxFile& dec) +{ + m_entries.resize(m_header.file_count); + + dec.Seek(0); + dec.Read(&m_entries[0], sizeof(PKGEntry) * m_header.file_count); + + if (m_entries[0].name_offset / sizeof(PKGEntry) != m_header.file_count) { + ConLog.Error("PKG Loader: Entries are damaged!"); + return false; + } + + return true; +} + +bool PKGLoader::UnpackEntry(wxFile& dec, const PKGEntry& entry, std::string dir) +{ + u8 buf[BUF_SIZE]; + + dec.Seek(entry.name_offset); + dec.Read(buf, entry.name_size); + buf[entry.name_size] = 0; + + switch (entry.type & (0xffff)) + { + case PKG_FILE_ENTRY_NPDRM: + case PKG_FILE_ENTRY_NPDRMEDAT: + case PKG_FILE_ENTRY_SDAT: + case PKG_FILE_ENTRY_REGULAR: + { + wxFile out; + out.Create(dir + buf); + dec.Seek(entry.file_offset); + + for (u64 size = 0; size < entry.file_size; ) { + size += dec.Read(buf, BUF_SIZE); + if (size > entry.file_size) + out.Write(buf, BUF_SIZE - (size - entry.file_size)); + else + out.Write(buf, BUF_SIZE); + } + out.Close(); + } + break; + + case PKG_FILE_ENTRY_FOLDER: + wxMkdir(dir + buf); + break; + } + return true; +} + +void PKGLoader::Decrypt(wxFile& out) +{ + aes_context c; + u8 iv[HASH_LEN]; + u8 buf[BUF_SIZE]; + u8 ctr[BUF_SIZE]; + + // Debug key + u8 key[0x40]; + memset(key, 0, 0x40); + memcpy(key+0x00, &m_header.qa_digest[0], 8); // &data[0x60] + memcpy(key+0x08, &m_header.qa_digest[0], 8); // &data[0x60] + memcpy(key+0x10, &m_header.qa_digest[8], 8); // &data[0x68] + memcpy(key+0x18, &m_header.qa_digest[8], 8); // &data[0x68] + + pkg_f.Seek(m_header.data_offset); + u32 parts = (m_header.data_size + BUF_SIZE - 1) / BUF_SIZE; + + wxProgressDialog pdlg("PKG Decrypter / Installer", "Please wait, decrypting...", parts, 0, wxPD_AUTO_HIDE | wxPD_APP_MODAL); + + memcpy(iv, m_header.klicensee, sizeof(iv)); + aes_setkey_enc(&c, PKG_AES_KEY, 128); + + for (u32 i=0; i*)&key[0x38] += 1; + } + } + + if (m_header.pkg_type == PKG_RELEASE_TYPE_RELEASE) + { + for (u32 j=0; j hi = *(be_t*)&iv[0]; + be_t lo = *(be_t*)&iv[8] + 1; + + if (lo == 0) + hi += 1; + + *(be_t*)&iv[0] = hi; + *(be_t*)&iv[8] = lo; + } + + for (u32 j=0; j pkg_magic; // Magic (0x7f504b47) + be_t pkg_type; // Release type (Retail:0x8000, Debug:0x0000) + be_t pkg_platform; // Platform type (PS3:0x0001, PSP:0x0002) + be_t header_size; // Header size (0xc0) + be_t unk1; // Some PKG version maybe? + be_t meta_size; // Size of metadata (block after header & hashes) + be_t file_count; // Number of files + be_t pkg_size; // PKG size in bytes + be_t data_offset; // Encrypted data offset + be_t 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 +}; + +struct PKGEntry +{ + be_t name_offset; // File name offset + be_t name_size; // File name size + be_t file_offset; // File offset + be_t file_size; // File size + be_t type; // File type + be_t pad; // Padding (zeros) +}; + +class PKGLoader +{ + wxFile& pkg_f; + PKGHeader m_header; + std::vector m_entries; + + virtual void Decrypt(wxFile& out); + +public: + PKGLoader(wxFile& f); + virtual bool Install(std::string dest, bool show = false); + + virtual bool LoadHeader(bool show = false); + virtual bool CheckHeader(); + + virtual bool LoadEntries(wxFile& dec); + virtual bool UnpackEntry(wxFile& dec, const PKGEntry& entry, std::string dir); + + virtual bool Close(); +}; diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index dd103943cc..e60df54659 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -318,6 +318,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 67d1df150a..691c4365c9 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -406,6 +406,9 @@ Emu\FS + + Loader + diff --git a/unpkg/oddkeys.h b/unpkg/oddkeys.h deleted file mode 100644 index 9c53edab34..0000000000 --- a/unpkg/oddkeys.h +++ /dev/null @@ -1,20 +0,0 @@ -#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}; diff --git a/unpkg/ps3_common.h b/unpkg/ps3_common.h deleted file mode 100644 index 73d8e2185d..0000000000 --- a/unpkg/ps3_common.h +++ /dev/null @@ -1,106 +0,0 @@ -#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 - * - * 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" - -#include //in a *.c file ? - -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."); - wxProgressDialog pdlg ("PKG Decrypter / Installer", "Please wait, recrypting...", 0, 0, wxPD_AUTO_HIDE | wxPD_APP_MODAL); - - u8* data; - u8 sha_key[0x40]; - int i; - f= fopen(fname, "rb"); - _fseeki64(f, 0, SEEK_END); - int nlen = _ftelli64(f); - _fseeki64(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 - - _fseeki64(g, 0, SEEK_END); - tmp = _ftelli64(g); - } - break; - - - case PKG_RELEASE_TYPE_RELEASE: - { - ConLog.Warning ("UnPkg: Retail PKG detected."); - _fseeki64(f, 0, SEEK_END); - tmp = _ftelli64(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: 0x%x", ntohl(header->magic)); - ConLog.Write("Release Type: 0x%x", ntohl(header->rel_type) >> 16 & (0xffff)); - ConLog.Write("Platform Type: 0x%x", ntohl(header->rel_type) & (0xffff)); - ConLog.Write("Header size: 0x%x", ntohl(header->header_size)); - ConLog.Write("Unk1: 0x%x", ntohl(header->unk1)); - ConLog.Write("Metadata size: 0x%x", ntohl(header->meta_size)); - ConLog.Write("File count: %u", ntohl(header->file_count)); - ConLog.Write("Pkg size: %llu", ntohll(header->pkg_size)); - ConLog.Write("Data offset: 0x%llx", ntohll(header->data_offset)); - ConLog.Write("Data size: 0x%llu", ntohll(header->data_size)); - ConLog.Write("TitleID: %s", wxString(header->title_id, 48).wx_str()); - ConLog.Write("QA Digest: %s", wxString(qa, 33).wx_str()); - ConLog.Write("KLicensee: %s", wxString(kl, 33).wx_str()); -} - -static void *pkg_info(const char *fname, pkg_header **h_ptr) -{ - FILE *f; - pkg_header *header; - - f = (FILE*) pkg_open(fname); - if (f == NULL) - return NULL; - - if (pkg_sanity_check(f, NULL, &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; - - int max = len / BUF_SIZE; - wxProgressDialog pdlg("PKG Decrypter / Installer", "Please wait, decrypting...", max, 0, wxPD_AUTO_HIDE | wxPD_APP_MODAL); - - parts = len / BUF_SIZE; - if (len % BUF_SIZE != 0) - parts++; - - memcpy(iv, kl, sizeof(iv)); - aes_setkey_enc(&c, key, 128); - - for (i = 0; iname_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"); - _fseeki64(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; - } - return true; -} - -static void pkg_unpack_data(u32 file_count, FILE *dec) -{ - int max = file_count; - wxProgressDialog pdlg ("PKG Decrypter / Installer", "Please wait, unpacking...", max, 0, wxPD_AUTO_HIDE | wxPD_APP_MODAL); - - u32 i; - pkg_file_entry *file_table = NULL; - - _fseeki64(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; iname_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); - - if(pkg_unpack_file(file_table+i, dec)) pdlg.Update(i); - } - - free(file_table); - pdlg.Update(max); -} - -bool pkg_unpack(const char *fname) -{ - FILE *f, *dec; - char *dec_fname; - pkg_header *header; - struct stat sb; - - f = (FILE*) pkg_info(fname, &header); - - if (f == NULL) - return false; - - // Save the main dir. - wxString mainDir = wxGetCwd(); - - // Set the working directory. - wxSetWorkingDirectory(wxGetCwd() + "\\dev_hdd0\\game\\"); - - std::string gamePath = "\\dev_hdd0\\game\\"; - - // Get the PKG title ID from the header and format it (should match TITLE ID from PARAM.SFO). - std::string titleID_full (header->title_id); - std::string titleID = titleID_full.substr(7, 9); - std::string pkgDir = mainDir + gamePath + titleID; - - _fseeki64(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 false; - } - unlink(dec_fname); - - pkg_crypt(PKG_AES_KEY, header->klicensee, f, ntohll(header->data_size), - dec); - _fseeki64(dec, 0, SEEK_SET); - - fclose(f); - - if (stat(header->title_id, &sb) != 0) - { - if (mkdir(titleID.c_str()) < 0) - { - ConLog.Error("UnPkg: Could not mkdir."); - ConLog.Error("UnPkg: Possibly, folder already exists in dev_hdd0\\game : %s", wxString(titleID).wx_str()); - wxSetWorkingDirectory(mainDir); - free(header); - return false; - } - } - - chdir(titleID.c_str()); - - pkg_unpack_data(ntohl(header->file_count), dec); - fclose(dec); - - wxSetWorkingDirectory(mainDir); - return true; -} \ No newline at end of file diff --git a/unpkg/unpkg.h b/unpkg/unpkg.h deleted file mode 100644 index fa8262eb0e..0000000000 --- a/unpkg/unpkg.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2011 Andrey Tolstoy - * - * 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" - -#ifdef __GNUG__ -#include -#endif - -#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); - -bool pkg_unpack(const char *fname); - -static void pkg_unpack_data(u32 file_count, FILE *dec); - -static bool 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