From e8bfce4ebdf712d35281df34bfa6ed432e23c562 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 11 Feb 2017 21:06:57 +0300 Subject: [PATCH] decrypt_self() function Fixed SPU self decryption Fixed PSV debug self load --- rpcs3/Crypto/unself.cpp | 87 ++++++++--------------------- rpcs3/Crypto/unself.h | 7 +-- rpcs3/Emu/Cell/Modules/sys_spu_.cpp | 17 ++---- rpcs3/Emu/Cell/PPUModule.cpp | 5 +- rpcs3/Emu/Cell/lv2/sys_prx.cpp | 2 +- rpcs3/Emu/Cell/lv2/sys_spu.cpp | 17 ++---- rpcs3/Emu/System.cpp | 42 +++++++++----- rpcs3/Gui/MainFrame.cpp | 19 +++++-- rpcs3/Gui/SettingsDialog.cpp | 3 +- 9 files changed, 81 insertions(+), 118 deletions(-) diff --git a/rpcs3/Crypto/unself.cpp b/rpcs3/Crypto/unself.cpp index 4653ed04ec..a77419372c 100644 --- a/rpcs3/Crypto/unself.cpp +++ b/rpcs3/Crypto/unself.cpp @@ -1038,15 +1038,10 @@ bool SELFDecrypter::DecryptData() return true; } -bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32) +fs::file SELFDecrypter::MakeElf(bool isElf32) { // Create a new ELF file. - fs::file e(elf, fs::rewrite); - if(!e) - { - LOG_ERROR(LOADER, "Could not create ELF file! (%s)", elf.c_str()); - return false; - } + fs::file e = fs::make_stream>(); // Set initial offset. u32 data_buf_offset = 0; @@ -1162,7 +1157,7 @@ bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32) } } - return true; + return e; } bool SELFDecrypter::GetKeyFromRap(u8 *content_id, u8 *npdrm_key) @@ -1201,23 +1196,11 @@ bool SELFDecrypter::GetKeyFromRap(u8 *content_id, u8 *npdrm_key) return true; } -bool IsSelf(const std::string& path) +static bool IsSelfElf32(const fs::file& f) { - fs::file f(path); - if (!f) return false; - SceHeader hdr; - hdr.Load(f); - - return hdr.CheckMagic(); -} - -bool IsSelfElf32(const std::string& path) -{ - fs::file f(path); - - if (!f) return false; + f.seek(0); SceHeader hdr; SelfHeader sh; @@ -1233,46 +1216,31 @@ bool IsSelfElf32(const std::string& path) return (elf_class[4] == 1); } -bool CheckDebugSelf(const std::string& self, const std::string& elf) +static bool CheckDebugSelf(fs::file& s) { - // Open the SELF file. - fs::file s(self); - - if (!s) + if (s.size() < 0x18) { - LOG_ERROR(LOADER, "Could not open SELF file! (%s)", self.c_str()); return false; } // Get the key version. s.seek(0x08); - u16 key_version; - s.read(&key_version, sizeof(key_version)); + const u16 key_version = s.read>(); // Check for DEBUG version. - if (swap16(key_version) == 0x8000) + if (key_version == 0x80 || key_version == 0xc0) { LOG_WARNING(LOADER, "Debug SELF detected! Removing fake header..."); // Get the real elf offset. s.seek(0x10); - u64 elf_offset; - s.read(&elf_offset, sizeof(elf_offset)); - // Start at the real elf offset. - elf_offset = swap64(elf_offset); - - s.seek(elf_offset); + s.seek(key_version == 0x80 ? +s.read>() : +s.read>()); // Write the real ELF file back. - fs::file e(elf, fs::rewrite); - if (!e) - { - LOG_ERROR(LOADER, "Could not create ELF file! (%s)", elf.c_str()); - return false; - } + fs::file e = fs::make_stream>(); // Copy the data. char buf[2048]; @@ -1281,6 +1249,7 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf) e.write(buf, size); } + s = std::move(e); return true; } @@ -1288,53 +1257,43 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf) return false; } -bool DecryptSelf(const std::string& elf, const std::string& self) +extern fs::file decrypt_self(fs::file elf_or_self) { - LOG_NOTICE(LOADER, "Decrypting %s", self); + elf_or_self.seek(0); - // Check for a debug SELF first. - if (!CheckDebugSelf(self, elf)) + // Check SELF header first. Check for a debug SELF. + if (elf_or_self.size() >= 4 && elf_or_self.read() == "SCE\0"_u32 && !CheckDebugSelf(elf_or_self)) { - // Set a virtual pointer to the SELF file. - fs::file self_vf(self); - - if (!self_vf) - return false; - // Check the ELF file class (32 or 64 bit). - bool isElf32 = IsSelfElf32(self); + bool isElf32 = IsSelfElf32(elf_or_self); // Start the decrypter on this SELF file. - SELFDecrypter self_dec(self_vf); + SELFDecrypter self_dec(elf_or_self); // Load the SELF file headers. if (!self_dec.LoadHeaders(isElf32)) { LOG_ERROR(LOADER, "SELF: Failed to load SELF file headers!"); - return false; + return fs::file{}; } // Load and decrypt the SELF file metadata. if (!self_dec.LoadMetadata()) { LOG_ERROR(LOADER, "SELF: Failed to load SELF file metadata!"); - return false; + return fs::file{}; } // Decrypt the SELF file data. if (!self_dec.DecryptData()) { LOG_ERROR(LOADER, "SELF: Failed to decrypt SELF file data!"); - return false; + return fs::file{}; } // Make a new ELF file from this SELF. - if (!self_dec.MakeElf(elf, isElf32)) - { - LOG_ERROR(LOADER, "SELF: Failed to make ELF file from SELF!"); - return false; - } + return self_dec.MakeElf(isElf32); } - return true; + return elf_or_self; } diff --git a/rpcs3/Crypto/unself.h b/rpcs3/Crypto/unself.h index 357284ca75..e79fdfa6c9 100644 --- a/rpcs3/Crypto/unself.h +++ b/rpcs3/Crypto/unself.h @@ -379,7 +379,7 @@ class SELFDecrypter public: SELFDecrypter(const fs::file& s); - bool MakeElf(const std::string& elf, bool isElf32); + fs::file MakeElf(bool isElf32); bool LoadHeaders(bool isElf32); void ShowHeaders(bool isElf32); bool LoadMetadata(); @@ -388,7 +388,4 @@ public: bool GetKeyFromRap(u8 *content_id, u8 *npdrm_key); }; -extern bool IsSelf(const std::string& path); -extern bool IsSelfElf32(const std::string& path); -extern bool CheckDebugSelf(const std::string& self, const std::string& elf); -extern bool DecryptSelf(const std::string& elf, const std::string& self); +extern fs::file decrypt_self(fs::file elf_or_self); diff --git a/rpcs3/Emu/Cell/Modules/sys_spu_.cpp b/rpcs3/Emu/Cell/Modules/sys_spu_.cpp index 26275824f4..2b33f8b8f5 100644 --- a/rpcs3/Emu/Cell/Modules/sys_spu_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_spu_.cpp @@ -67,25 +67,16 @@ s32 sys_raw_spu_load(s32 id, vm::cptr path, vm::ptr entry) { sysPrxForUser.warning("sys_raw_spu_load(id=%d, path=%s, entry=*0x%x)", id, path, entry); - const fs::file f(vfs::get(path.get_ptr())); - if (!f) + const fs::file elf_file = decrypt_self(fs::file(vfs::get(path.get_ptr()))); + + if (!elf_file) { sysPrxForUser.error("sys_raw_spu_load() error: %s not found!", path); return CELL_ENOENT; } - SceHeader hdr; - hdr.Load(f); - - if (hdr.CheckMagic()) - { - fmt::throw_exception("sys_raw_spu_load() error: %s is encrypted! Try to decrypt it manually and try again.", path); - } - - f.seek(0); - u32 _entry; - LoadSpuImage(f, _entry, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id); + LoadSpuImage(elf_file, _entry, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id); *entry = _entry | 1; diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index fc88722a35..8ca69ac598 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -2,6 +2,7 @@ #include "Utilities/Config.h" #include "Utilities/AutoPause.h" #include "Crypto/sha1.h" +#include "Crypto/unself.h" #include "Loader/ELF.h" #include "Emu/System.h" #include "Emu/IdManager.h" @@ -1120,7 +1121,7 @@ void ppu_load_exec(const ppu_exec_object& elf) if (g_cfg_load_liblv2) { - const ppu_prx_object obj = fs::file(lle_dir + "/liblv2.sprx"); + const ppu_prx_object obj = decrypt_self(fs::file(lle_dir + "/liblv2.sprx")); if (obj == elf_error::ok) { @@ -1135,7 +1136,7 @@ void ppu_load_exec(const ppu_exec_object& elf) { for (const auto& name : g_cfg_load_libs.get_set()) { - const ppu_prx_object obj = fs::file(lle_dir + '/' + name); + const ppu_prx_object obj = decrypt_self(fs::file(lle_dir + '/' + name)); if (obj == elf_error::ok) { diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index 6baed09041..0b110c788b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -18,7 +18,7 @@ s32 prx_load_module(std::string path, u64 flags, vm::ptr img, vm::cptr path) { sys_spu.warning("sys_spu_image_open(img=*0x%x, path=%s)", img, path); - const fs::file f(vfs::get(path.get_ptr())); - if (!f) + const fs::file elf_file = decrypt_self(fs::file(vfs::get(path.get_ptr()))); + + if (!elf_file) { sys_spu.error("sys_spu_image_open() error: %s not found!", path); return CELL_ENOENT; } - SceHeader hdr; - hdr.Load(f); - - if (hdr.CheckMagic()) - { - fmt::throw_exception("sys_spu_image_open() error: %s is encrypted! Try to decrypt it manually and try again.", path); - } - - f.seek(0); - u32 entry; - u32 offset = LoadSpuImage(f, entry); + u32 offset = LoadSpuImage(elf_file, entry); img->type = SYS_SPU_IMAGE_TYPE_USER; img->entry_point = entry; diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index b826314cee..d4081e00ba 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -84,6 +84,8 @@ void Emulator::Init() // Reload global configuration cfg::root.from_string(fs::file(fs::get_config_dir() + "/config.yml", fs::read + fs::create).to_string()); + + SetCPUThreadStop(0); } void Emulator::SetPath(const std::string& path, const std::string& elf_path) @@ -152,44 +154,55 @@ void Emulator::Load() { Init(); - if (!fs::is_file(m_path)) + // Open SELF or ELF + fs::file elf_file(m_path); + + LOG_NOTICE(LOADER, "Path: %s", m_path); + + if (!elf_file) { - LOG_ERROR(LOADER, "File not found: %s", m_path); + LOG_ERROR(LOADER, "Failed to open file: %s", m_path); return; } const std::string& elf_dir = fs::get_parent_dir(m_path); - if (IsSelf(m_path)) + // Check SELF header + if (elf_file.size() >= 4 && elf_file.read() == "SCE\0"_u32) { + // Decrypt SELF + elf_file = decrypt_self(std::move(elf_file)); + const std::size_t elf_ext_pos = m_path.find_last_of('.'); const std::string& elf_ext = fmt::to_upper(m_path.substr(elf_ext_pos != -1 ? elf_ext_pos : m_path.size())); const std::string& elf_name = m_path.substr(elf_dir.size()); + // Save ELF (TODO: configuration, cache and different file location) + std::string new_path = m_path; + if (elf_name.compare(elf_name.find_last_of("/\\", -1, 2) + 1, 9, "EBOOT.BIN", 9) == 0) { - m_path.erase(m_path.size() - 9, 1); // change EBOOT.BIN to BOOT.BIN + new_path.erase(new_path.size() - 9, 1); // change EBOOT.BIN to BOOT.BIN } else if (elf_ext == ".SELF" || elf_ext == ".SPRX") { - m_path.erase(m_path.size() - 4, 1); // change *.self to *.elf, *.sprx to *.prx + new_path.erase(new_path.size() - 4, 1); // change *.self to *.elf, *.sprx to *.prx } else { - m_path += ".decrypted.elf"; + new_path += ".decrypted.elf"; } - if (!DecryptSelf(m_path, elf_dir + elf_name)) + if (fs::file elf_out{new_path, fs::rewrite}) { - LOG_ERROR(LOADER, "Failed to decrypt %s", elf_dir + elf_name); - return; + elf_out.write(elf_file.to_vector()); + } + else + { + LOG_ERROR(LOADER, "Failed to save file: %s", new_path); } } - SetCPUThreadStop(0); - - LOG_NOTICE(LOADER, "Path: %s", m_path); - // Load custom config if (fs::file cfg_file{ m_path + ".yml" }) { @@ -197,7 +210,6 @@ void Emulator::Load() cfg::root.from_string(cfg_file.to_string()); } - const fs::file elf_file(m_path); ppu_exec_object ppu_exec; ppu_prx_object ppu_prx; spu_exec_object spu_exec; @@ -205,7 +217,7 @@ void Emulator::Load() if (!elf_file) { - LOG_ERROR(LOADER, "Failed to open %s", m_path); + LOG_ERROR(LOADER, "Failed to decrypt SELF: %s", m_path); return; } else if (ppu_exec.open(elf_file) == elf_error::ok) diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index 32c20bf60b..fa63458fcc 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -374,19 +374,30 @@ void MainFrame::DecryptSPRXLibraries(wxCommandEvent& WXUNUSED(event)) std::string prx_path = fmt::ToUTF8(module); const std::string& prx_dir = fs::get_parent_dir(prx_path); - if (IsSelf(prx_path)) + fs::file elf_file(prx_path); + + if (elf_file && elf_file.size() >= 4 && elf_file.read() == "SCE\0"_u32) { const std::size_t prx_ext_pos = prx_path.find_last_of('.'); const std::string& prx_ext = fmt::to_upper(prx_path.substr(prx_ext_pos != -1 ? prx_ext_pos : prx_path.size())); const std::string& prx_name = prx_path.substr(prx_dir.size()); + elf_file = decrypt_self(std::move(elf_file)); + prx_path.erase(prx_path.size() - 4, 1); // change *.sprx to *.prx - if (DecryptSelf(prx_path, prx_dir + prx_name)) + if (elf_file) { - LOG_SUCCESS(GENERAL, "Decrypted %s", prx_dir + prx_name); + if (fs::file new_file{prx_path, fs::rewrite}) + { + new_file.write(elf_file.to_string()); + LOG_SUCCESS(GENERAL, "Decrypted %s", prx_dir + prx_name); + } + else + { + LOG_ERROR(GENERAL, "Failed to create %s", prx_path); + } } - else { LOG_ERROR(GENERAL, "Failed to decrypt %s", prx_dir + prx_name); diff --git a/rpcs3/Gui/SettingsDialog.cpp b/rpcs3/Gui/SettingsDialog.cpp index 32063617e3..4f98b5b7fa 100644 --- a/rpcs3/Gui/SettingsDialog.cpp +++ b/rpcs3/Gui/SettingsDialog.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "stdafx_gui.h" #include "Utilities/Config.h" +#include "Crypto/unself.h" #include "Loader/ELF.h" #include "Emu/System.h" @@ -340,7 +341,7 @@ SettingsDialog::SettingsDialog(wxWindow* parent) for (const auto& prxf : fs::dir(lle_dir)) { // List found unselected modules - if (!prxf.is_directory && ppu_prx_object(fs::file(lle_dir + prxf.name)) == elf_error::ok && !set.count(prxf.name)) + if (!prxf.is_directory && ppu_prx_object(decrypt_self(fs::file(lle_dir + prxf.name))) == elf_error::ok && !set.count(prxf.name)) { lle_module_list_unselected.push_back(prxf.name); }