mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-12-16 04:09:07 +00:00
Deny PKG installation without RAP
This commit is contained in:
parent
54206c62b3
commit
06dcea4f41
@ -9,6 +9,7 @@
|
||||
#include "Emu/system_utils.hpp"
|
||||
#include "Emu/VFS.h"
|
||||
#include "unpkg.h"
|
||||
#include "unself.h"
|
||||
#include "util/sysinfo.hpp"
|
||||
#include "Loader/PSF.h"
|
||||
|
||||
@ -47,12 +48,23 @@ package_reader::package_reader(const std::string& path, fs::file file)
|
||||
return;
|
||||
}
|
||||
|
||||
const bool param_sfo_found = read_param_sfo();
|
||||
m_psf = psf::load_object(read_file("PARAM.SFO"), path + ":PARAM.SFO");
|
||||
|
||||
if (!param_sfo_found)
|
||||
if (m_psf.empty())
|
||||
{
|
||||
pkg_log.notice("PKG does not contain a PARAM.SFO");
|
||||
}
|
||||
|
||||
m_rap_file_path = get_rap_file_path_of_self(read_file("USRDIR/EBOOT.BIN"));
|
||||
|
||||
if (m_rap_file_path.empty())
|
||||
{
|
||||
pkg_log.notice("PKG needs RAP file: %s", m_rap_file_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
pkg_log.notice("PKG need not a license file.");
|
||||
}
|
||||
}
|
||||
|
||||
package_reader::~package_reader()
|
||||
@ -577,13 +589,14 @@ bool package_reader::read_entries(std::vector<PKGEntry>& entries)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool package_reader::read_param_sfo()
|
||||
fs::file package_reader::read_file(std::string_view relative_path)
|
||||
{
|
||||
std::vector<PKGEntry> entries;
|
||||
fs::file tmp;
|
||||
|
||||
if (!read_entries(entries))
|
||||
{
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<u8> data_buf;
|
||||
@ -609,13 +622,13 @@ bool package_reader::read_param_sfo()
|
||||
fmt::trim_back(name, "\0"sv);
|
||||
|
||||
// We're looking for the PARAM.SFO file, if there is any
|
||||
if (usz ndelim = name.find_first_not_of('/'); ndelim == umax || name.substr(ndelim) != "PARAM.SFO")
|
||||
if (usz ndelim = name.find_first_not_of('/'); ndelim == umax || name.substr(ndelim) != relative_path)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read the package's PARAM.SFO
|
||||
fs::file tmp = fs::make_stream<std::vector<uchar>>();
|
||||
tmp = fs::make_stream<std::vector<uchar>>();
|
||||
{
|
||||
for (u64 pos = 0; pos < entry.file_size; pos += BUF_SIZE)
|
||||
{
|
||||
@ -625,32 +638,20 @@ bool package_reader::read_param_sfo()
|
||||
|
||||
if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), data_buf.data()) != block_size)
|
||||
{
|
||||
pkg_log.error("Failed to decrypt PARAM.SFO file");
|
||||
return false;
|
||||
pkg_log.error("Failed to decrypt %s file", relative_path);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (tmp.write(data_buf.data(), block_size) != block_size)
|
||||
{
|
||||
pkg_log.error("Failed to write to temporary PARAM.SFO file");
|
||||
return false;
|
||||
}
|
||||
ensure(tmp.write(data_buf.data(), block_size) == block_size);
|
||||
}
|
||||
|
||||
tmp.seek(0);
|
||||
|
||||
m_psf = psf::load_object(tmp, name);
|
||||
|
||||
if (m_psf.empty())
|
||||
{
|
||||
// Invalid
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
tmp.close();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// TODO: maybe also check if VERSION matches
|
||||
|
||||
@ -361,10 +361,15 @@ public:
|
||||
return m_file;
|
||||
}
|
||||
|
||||
const std::string& gep_needed_rap_file_path() const
|
||||
{
|
||||
return m_rap_file_path;
|
||||
}
|
||||
|
||||
private:
|
||||
bool read_header();
|
||||
bool read_metadata();
|
||||
bool read_param_sfo();
|
||||
fs::file read_file(std::string_view relative_path);
|
||||
bool set_decryption_key();
|
||||
bool read_entries(std::vector<PKGEntry>& entries);
|
||||
void archive_seek(s64 new_offset, const fs::seek_mode damode = fs::seek_set);
|
||||
@ -400,4 +405,5 @@ private:
|
||||
|
||||
// Expose bootable file installed (if installed such)
|
||||
std::string m_bootable_file_path;
|
||||
std::string m_rap_file_path;
|
||||
};
|
||||
|
||||
@ -1068,6 +1068,37 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string SELFDecrypter::GetRapFilePath()
|
||||
{
|
||||
// Check if we have a valid NPDRM control info structure.
|
||||
// If not, the data has no NPDRM layer.
|
||||
const NPD_HEADER* npd = GetNPDHeader();
|
||||
if (!npd)
|
||||
{
|
||||
self_log.trace("No NPDRM control info found!");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (npd->license == 1) // Network license.
|
||||
{
|
||||
return rpcs3::utils::get_rap_file_path(npd->content_id);
|
||||
}
|
||||
else if (npd->license == 2) // Local license.
|
||||
{
|
||||
return rpcs3::utils::get_rap_file_path(npd->content_id);
|
||||
}
|
||||
else if (npd->license == 3) // Free license.
|
||||
{
|
||||
//
|
||||
}
|
||||
else
|
||||
{
|
||||
self_log.error("Invalid NPDRM license type!");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const NPD_HEADER* SELFDecrypter::GetNPDHeader() const
|
||||
{
|
||||
// Parse the control info structures to find the NPDRM control info.
|
||||
@ -1082,6 +1113,7 @@ const NPD_HEADER* SELFDecrypter::GetNPDHeader() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool SELFDecrypter::LoadMetadata(const u8* klic_key)
|
||||
{
|
||||
aes_context aes;
|
||||
@ -1435,6 +1467,46 @@ fs::file decrypt_self(const fs::file& elf_or_self, const u8* klic_key, SelfAddit
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string get_rap_file_path_of_self(const fs::file& elf_or_self)
|
||||
{
|
||||
if (!elf_or_self)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
elf_or_self.seek(0);
|
||||
|
||||
// Check SELF header first. Check for a debug SELF.
|
||||
u32 file_type = umax;
|
||||
elf_or_self.read_at(0, &file_type, sizeof(file_type));
|
||||
|
||||
if (file_type == "SCE\0"_u32)
|
||||
{
|
||||
if (fs::file res = CheckDebugSelf(elf_or_self))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
// Check the ELF file class (32 or 64 bit).
|
||||
const bool isElf32 = IsSelfElf32(elf_or_self);
|
||||
|
||||
// Start the decrypter on this SELF file.
|
||||
SELFDecrypter self_dec(elf_or_self);
|
||||
|
||||
// Load the SELF file headers.
|
||||
if (!self_dec.LoadHeaders(isElf32, nullptr))
|
||||
{
|
||||
self_log.error("Failed to load SELF file headers!");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Load and decrypt the SELF file metadata.
|
||||
return self_dec.GetRapFilePath();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key, NPD_HEADER* npd_out)
|
||||
{
|
||||
if (!self)
|
||||
|
||||
@ -481,6 +481,7 @@ public:
|
||||
bool DecryptNPDRM(u8 *metadata, u32 metadata_size);
|
||||
const NPD_HEADER* GetNPDHeader() const;
|
||||
static bool GetKeyFromRap(const char *content_id, u8 *npdrm_key);
|
||||
std::string GetRapFilePath();
|
||||
|
||||
private:
|
||||
template<typename EHdr, typename SHdr, typename PHdr>
|
||||
@ -562,5 +563,6 @@ private:
|
||||
fs::file decrypt_self(const fs::file& elf_or_self, const u8* klic_key = nullptr, SelfAdditionalInfo* additional_info = nullptr);
|
||||
bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key = nullptr, NPD_HEADER* npd_out = nullptr);
|
||||
bool get_npdrm_self_header(const fs::file& self, NPD_HEADER& npd);
|
||||
std::string get_rap_file_path_of_self(const fs::file& elf_or_self);
|
||||
|
||||
u128 get_default_self_klic();
|
||||
|
||||
@ -1005,10 +1005,6 @@ bool main_window::HandlePackageInstallation(QStringList file_paths, bool from_bo
|
||||
}
|
||||
gui_log.notice("About to install packages:\n%s", fmt::merge(path_vec, "\n"));
|
||||
|
||||
progress_dialog pdlg(tr("RPCS3 Package Installer"), tr("Installing package, please wait..."), tr("Cancel"), 0, 1000, false, this);
|
||||
pdlg.setAutoClose(false);
|
||||
pdlg.show();
|
||||
|
||||
package_install_result result = {};
|
||||
|
||||
auto get_app_info = [](compat::package_info& package)
|
||||
@ -1047,6 +1043,42 @@ bool main_window::HandlePackageInstallation(QStringList file_paths, bool from_bo
|
||||
readers.emplace_back(info.path.toStdString());
|
||||
}
|
||||
|
||||
std::string missing_licenses;
|
||||
std::string missing_licenses_short;
|
||||
|
||||
for (const auto& reader : readers)
|
||||
{
|
||||
if (std::string filepath = reader.gep_needed_rap_file_path(); !filepath.empty() && fs::is_file(filepath))
|
||||
{
|
||||
missing_licenses += filepath;
|
||||
missing_licenses += "\n";
|
||||
|
||||
if (std::count(missing_licenses_short.begin(), missing_licenses_short.end(), '\n') < 5)
|
||||
{
|
||||
missing_licenses_short += std::string_view(filepath).substr(filepath.find_last_of(fs::delim) + 1);
|
||||
missing_licenses_short += "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!missing_licenses.empty())
|
||||
{
|
||||
gui_log.fatal("Failed to locate the game license file(s):\n%s"
|
||||
"\nEnsure the .rap license file is placed in the dev_hdd0/home/%s/exdata folder with a lowercase file extension."
|
||||
"\nIf you need assistance on dumping the license file from your PS3, read our quickstart guide: https://rpcs3.net/quickstart", missing_licenses, Emu.GetUsr());
|
||||
|
||||
QString error = tr("Failed to locate the game license file(s):\n\n%1\nEnsure the .rap license file(s) are placed in the dev_hdd0 folder with a lowercase file extension.").arg(QString::fromStdString(missing_licenses_short));
|
||||
|
||||
QMessageBox* mb = new QMessageBox(QMessageBox::Warning, tr("PKG Installer: Missing License(s) For PKG(s)"), error, QMessageBox::Ok, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowStaysOnTopHint);
|
||||
mb->setAttribute(Qt::WA_DeleteOnClose);
|
||||
mb->open();
|
||||
return false;
|
||||
}
|
||||
|
||||
progress_dialog pdlg(tr("RPCS3 Package Installer"), tr("Installing package, please wait..."), tr("Cancel"), 0, 1000, false, this);
|
||||
pdlg.setAutoClose(false);
|
||||
pdlg.show();
|
||||
|
||||
std::deque<std::string> bootable_paths;
|
||||
|
||||
// Run PKG unpacking asynchronously
|
||||
|
||||
@ -71,10 +71,14 @@ bool qt_camera_video_sink::present(const QVideoFrame& frame)
|
||||
// Flip image if necessary
|
||||
if (flip_horizontally || flip_vertically)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
|
||||
Qt::Orientations orientation {};
|
||||
orientation.setFlag(Qt::Orientation::Horizontal, flip_horizontally);
|
||||
orientation.setFlag(Qt::Orientation::Vertical, flip_vertically);
|
||||
image.flip(orientation);
|
||||
#else
|
||||
image.mirror(flip_horizontally, flip_vertically);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (image.format() != QImage::Format_RGBA8888)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user