mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-07 15:31:26 +12:00
Fix #2397
This commit is contained in:
parent
0c8bda4f41
commit
3ecba8e57f
2 changed files with 137 additions and 40 deletions
|
@ -867,7 +867,7 @@ std::vector<fs::file> SCEDecrypter::MakeFile()
|
||||||
|
|
||||||
// Advance the data buffer offset by data size.
|
// Advance the data buffer offset by data size.
|
||||||
data_buf_offset += meta_shdr[i].data_size;
|
data_buf_offset += meta_shdr[i].data_size;
|
||||||
|
|
||||||
if (out_f.pos() != out_f.size())
|
if (out_f.pos() != out_f.size())
|
||||||
fmt::throw_exception("MakeELF written bytes (%llu) does not equal buffer size (%llu).", out_f.pos(), out_f.size());
|
fmt::throw_exception("MakeELF written bytes (%llu) does not equal buffer size (%llu).", out_f.pos(), out_f.size());
|
||||||
|
|
||||||
|
@ -877,24 +877,40 @@ std::vector<fs::file> SCEDecrypter::MakeFile()
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SELFDecrypter::LoadHeaders()
|
SELFDecrypter::SELFDecrypter(const fs::file& s)
|
||||||
|
: self_f(s)
|
||||||
|
, key_v()
|
||||||
|
, data_buf_length(0)
|
||||||
{
|
{
|
||||||
if(!SCEDecrypter::LoadHeaders()) return false;
|
}
|
||||||
|
|
||||||
|
bool SELFDecrypter::LoadHeaders(bool isElf32)
|
||||||
|
{
|
||||||
|
// Read SCE header.
|
||||||
|
self_f.seek(0);
|
||||||
|
sce_hdr.Load(self_f);
|
||||||
|
|
||||||
|
// Check SCE magic.
|
||||||
|
if (!sce_hdr.CheckMagic())
|
||||||
|
{
|
||||||
|
LOG_ERROR(LOADER, "SELF: Not a SELF file!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Read SELF header.
|
// Read SELF header.
|
||||||
self_hdr.Load(sce_f);
|
self_hdr.Load(self_f);
|
||||||
|
|
||||||
// Read the APP INFO.
|
// Read the APP INFO.
|
||||||
sce_f.seek(self_hdr.se_appinfooff);
|
self_f.seek(self_hdr.se_appinfooff);
|
||||||
app_info.Load(sce_f);
|
app_info.Load(self_f);
|
||||||
|
|
||||||
// Read ELF header.
|
// Read ELF header.
|
||||||
sce_f.seek(self_hdr.se_elfoff);
|
self_f.seek(self_hdr.se_elfoff);
|
||||||
|
|
||||||
if (isElf32)
|
if (isElf32)
|
||||||
elf32_hdr.Load(sce_f);
|
elf32_hdr.Load(self_f);
|
||||||
else
|
else
|
||||||
elf64_hdr.Load(sce_f);
|
elf64_hdr.Load(self_f);
|
||||||
|
|
||||||
// Read ELF program headers.
|
// Read ELF program headers.
|
||||||
if (isElf32)
|
if (isElf32)
|
||||||
|
@ -905,11 +921,11 @@ bool SELFDecrypter::LoadHeaders()
|
||||||
LOG_ERROR(LOADER, "SELF: ELF program header offset is null!");
|
LOG_ERROR(LOADER, "SELF: ELF program header offset is null!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
sce_f.seek(self_hdr.se_phdroff);
|
self_f.seek(self_hdr.se_phdroff);
|
||||||
for(u32 i = 0; i < elf32_hdr.e_phnum; ++i)
|
for(u32 i = 0; i < elf32_hdr.e_phnum; ++i)
|
||||||
{
|
{
|
||||||
phdr32_arr.emplace_back();
|
phdr32_arr.emplace_back();
|
||||||
phdr32_arr.back().Load(sce_f);
|
phdr32_arr.back().Load(self_f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -922,40 +938,40 @@ bool SELFDecrypter::LoadHeaders()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sce_f.seek(self_hdr.se_phdroff);
|
self_f.seek(self_hdr.se_phdroff);
|
||||||
|
|
||||||
for (u32 i = 0; i < elf64_hdr.e_phnum; ++i)
|
for (u32 i = 0; i < elf64_hdr.e_phnum; ++i)
|
||||||
{
|
{
|
||||||
phdr64_arr.emplace_back();
|
phdr64_arr.emplace_back();
|
||||||
phdr64_arr.back().Load(sce_f);
|
phdr64_arr.back().Load(self_f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Read section info.
|
// Read section info.
|
||||||
secinfo_arr.clear();
|
secinfo_arr.clear();
|
||||||
sce_f.seek(self_hdr.se_secinfoff);
|
self_f.seek(self_hdr.se_secinfoff);
|
||||||
|
|
||||||
for(u32 i = 0; i < ((isElf32) ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i)
|
for(u32 i = 0; i < ((isElf32) ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i)
|
||||||
{
|
{
|
||||||
secinfo_arr.emplace_back();
|
secinfo_arr.emplace_back();
|
||||||
secinfo_arr.back().Load(sce_f);
|
secinfo_arr.back().Load(self_f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read SCE version info.
|
// Read SCE version info.
|
||||||
sce_f.seek(self_hdr.se_sceveroff);
|
self_f.seek(self_hdr.se_sceveroff);
|
||||||
scev_info.Load(sce_f);
|
scev_info.Load(self_f);
|
||||||
|
|
||||||
// Read control info.
|
// Read control info.
|
||||||
ctrlinfo_arr.clear();
|
ctrlinfo_arr.clear();
|
||||||
sce_f.seek(self_hdr.se_controloff);
|
self_f.seek(self_hdr.se_controloff);
|
||||||
|
|
||||||
u32 i = 0;
|
u32 i = 0;
|
||||||
while(i < self_hdr.se_controlsize)
|
while(i < self_hdr.se_controlsize)
|
||||||
{
|
{
|
||||||
ctrlinfo_arr.emplace_back();
|
ctrlinfo_arr.emplace_back();
|
||||||
ControlInfo &cinfo = ctrlinfo_arr.back();
|
ControlInfo &cinfo = ctrlinfo_arr.back();
|
||||||
cinfo.Load(sce_f);
|
cinfo.Load(self_f);
|
||||||
i += cinfo.size;
|
i += cinfo.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -970,12 +986,12 @@ bool SELFDecrypter::LoadHeaders()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
sce_f.seek(self_hdr.se_shdroff);
|
self_f.seek(self_hdr.se_shdroff);
|
||||||
|
|
||||||
for(u32 i = 0; i < elf32_hdr.e_shnum; ++i)
|
for(u32 i = 0; i < elf32_hdr.e_shnum; ++i)
|
||||||
{
|
{
|
||||||
shdr32_arr.emplace_back();
|
shdr32_arr.emplace_back();
|
||||||
shdr32_arr.back().Load(sce_f);
|
shdr32_arr.back().Load(self_f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -987,19 +1003,19 @@ bool SELFDecrypter::LoadHeaders()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
sce_f.seek(self_hdr.se_shdroff);
|
self_f.seek(self_hdr.se_shdroff);
|
||||||
|
|
||||||
for(u32 i = 0; i < elf64_hdr.e_shnum; ++i)
|
for(u32 i = 0; i < elf64_hdr.e_shnum; ++i)
|
||||||
{
|
{
|
||||||
shdr64_arr.emplace_back();
|
shdr64_arr.emplace_back();
|
||||||
shdr64_arr.back().Load(sce_f);
|
shdr64_arr.back().Load(self_f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SELFDecrypter::ShowHeaders()
|
void SELFDecrypter::ShowHeaders(bool isElf32)
|
||||||
{
|
{
|
||||||
LOG_NOTICE(LOADER, "SCE header");
|
LOG_NOTICE(LOADER, "SCE header");
|
||||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||||
|
@ -1116,8 +1132,76 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||||
|
|
||||||
bool SELFDecrypter::LoadMetadata()
|
bool SELFDecrypter::LoadMetadata()
|
||||||
{
|
{
|
||||||
|
aes_context aes;
|
||||||
|
u32 metadata_info_size = SIZE_32(meta_info);
|
||||||
|
auto metadata_info = std::make_unique<u8[]>(metadata_info_size);
|
||||||
|
u32 metadata_headers_size = sce_hdr.se_hsize - (SIZE_32(sce_hdr) + sce_hdr.se_meta + SIZE_32(meta_info));
|
||||||
|
auto metadata_headers = std::make_unique<u8[]>(metadata_headers_size);
|
||||||
|
|
||||||
|
// Locate and read the encrypted metadata info.
|
||||||
|
self_f.seek(sce_hdr.se_meta + sizeof(sce_hdr));
|
||||||
|
self_f.read(metadata_info.get(), metadata_info_size);
|
||||||
|
|
||||||
|
// Locate and read the encrypted metadata header and section header.
|
||||||
|
self_f.seek(sce_hdr.se_meta + sizeof(sce_hdr) + metadata_info_size);
|
||||||
|
self_f.read(metadata_headers.get(), metadata_headers_size);
|
||||||
|
|
||||||
|
// Find the right keyset from the key vault.
|
||||||
SELF_KEY keyset = key_v.FindSelfKey(app_info.self_type, sce_hdr.se_flags, app_info.version);
|
SELF_KEY keyset = key_v.FindSelfKey(app_info.self_type, sce_hdr.se_flags, app_info.version);
|
||||||
return SCEDecrypter::LoadMetadata(keyset.erk,keyset.riv);
|
|
||||||
|
// Copy the necessary parameters.
|
||||||
|
u8 metadata_key[0x20];
|
||||||
|
u8 metadata_iv[0x10];
|
||||||
|
memcpy(metadata_key, keyset.erk, 0x20);
|
||||||
|
memcpy(metadata_iv, keyset.riv, 0x10);
|
||||||
|
|
||||||
|
// Check DEBUG flag.
|
||||||
|
if ((sce_hdr.se_flags & 0x8000) != 0x8000)
|
||||||
|
{
|
||||||
|
// Decrypt the NPDRM layer.
|
||||||
|
if (!DecryptNPDRM(metadata_info.get(), metadata_info_size))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Decrypt the metadata info.
|
||||||
|
aes_setkey_dec(&aes, metadata_key, 256); // AES-256
|
||||||
|
aes_crypt_cbc(&aes, AES_DECRYPT, metadata_info_size, metadata_iv, metadata_info.get(), metadata_info.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the metadata info.
|
||||||
|
meta_info.Load(metadata_info.get());
|
||||||
|
|
||||||
|
// If the padding is not NULL for the key or iv fields, the metadata info
|
||||||
|
// is not properly decrypted.
|
||||||
|
if ((meta_info.key_pad[0] != 0x00) ||
|
||||||
|
(meta_info.iv_pad[0] != 0x00))
|
||||||
|
{
|
||||||
|
LOG_ERROR(LOADER, "SELF: Failed to decrypt metadata info!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform AES-CTR encryption on the metadata headers.
|
||||||
|
size_t ctr_nc_off = 0;
|
||||||
|
u8 ctr_stream_block[0x10];
|
||||||
|
aes_setkey_enc(&aes, meta_info.key, 128);
|
||||||
|
aes_crypt_ctr(&aes, metadata_headers_size, &ctr_nc_off, meta_info.iv, ctr_stream_block, metadata_headers.get(), metadata_headers.get());
|
||||||
|
|
||||||
|
// Load the metadata header.
|
||||||
|
meta_hdr.Load(metadata_headers.get());
|
||||||
|
|
||||||
|
// Load the metadata section headers.
|
||||||
|
meta_shdr.clear();
|
||||||
|
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
|
||||||
|
{
|
||||||
|
meta_shdr.emplace_back();
|
||||||
|
meta_shdr.back().Load(metadata_headers.get() + sizeof(meta_hdr) + sizeof(MetadataSectionHeader) * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the decrypted data keys.
|
||||||
|
data_keys_length = meta_hdr.key_count * 0x10;
|
||||||
|
data_keys = std::make_unique<u8[]>(data_keys_length);
|
||||||
|
memcpy(data_keys.get(), metadata_headers.get() + sizeof(meta_hdr) + meta_hdr.section_count * sizeof(MetadataSectionHeader), data_keys_length);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SELFDecrypter::DecryptData()
|
bool SELFDecrypter::DecryptData()
|
||||||
|
@ -1162,8 +1246,8 @@ bool SELFDecrypter::DecryptData()
|
||||||
auto buf = std::make_unique<u8[]>(meta_shdr[i].data_size);
|
auto buf = std::make_unique<u8[]>(meta_shdr[i].data_size);
|
||||||
|
|
||||||
// Seek to the section data offset and read the encrypted data.
|
// Seek to the section data offset and read the encrypted data.
|
||||||
sce_f.seek(meta_shdr[i].data_offset);
|
self_f.seek(meta_shdr[i].data_offset);
|
||||||
sce_f.read(buf.get(), meta_shdr[i].data_size);
|
self_f.read(buf.get(), meta_shdr[i].data_size);
|
||||||
|
|
||||||
// Zero out our ctr nonce.
|
// Zero out our ctr nonce.
|
||||||
memset(ctr_stream_block, 0, sizeof(ctr_stream_block));
|
memset(ctr_stream_block, 0, sizeof(ctr_stream_block));
|
||||||
|
@ -1184,7 +1268,7 @@ bool SELFDecrypter::DecryptData()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::file SELFDecrypter::MakeFile()
|
fs::file SELFDecrypter::MakeElf(bool isElf32)
|
||||||
{
|
{
|
||||||
// Create a new ELF file.
|
// Create a new ELF file.
|
||||||
fs::file e = fs::make_stream<std::vector<u8>>();
|
fs::file e = fs::make_stream<std::vector<u8>>();
|
||||||
|
@ -1419,10 +1503,10 @@ extern fs::file decrypt_self(fs::file elf_or_self)
|
||||||
bool isElf32 = IsSelfElf32(elf_or_self);
|
bool isElf32 = IsSelfElf32(elf_or_self);
|
||||||
|
|
||||||
// Start the decrypter on this SELF file.
|
// Start the decrypter on this SELF file.
|
||||||
SELFDecrypter self_dec(elf_or_self, isElf32);
|
SELFDecrypter self_dec(elf_or_self);
|
||||||
|
|
||||||
// Load the SELF file headers.
|
// Load the SELF file headers.
|
||||||
if (!self_dec.LoadHeaders())
|
if (!self_dec.LoadHeaders(isElf32))
|
||||||
{
|
{
|
||||||
LOG_ERROR(LOADER, "SELF: Failed to load SELF file headers!");
|
LOG_ERROR(LOADER, "SELF: Failed to load SELF file headers!");
|
||||||
return fs::file{};
|
return fs::file{};
|
||||||
|
@ -1443,7 +1527,7 @@ extern fs::file decrypt_self(fs::file elf_or_self)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a new ELF file from this SELF.
|
// Make a new ELF file from this SELF.
|
||||||
return self_dec.MakeFile();
|
return self_dec.MakeElf(isElf32);
|
||||||
}
|
}
|
||||||
|
|
||||||
return elf_or_self;
|
return elf_or_self;
|
||||||
|
|
|
@ -366,14 +366,16 @@ public:
|
||||||
bool DecryptData();
|
bool DecryptData();
|
||||||
};
|
};
|
||||||
|
|
||||||
class SELFDecrypter : private SCEDecrypter
|
class SELFDecrypter
|
||||||
{
|
{
|
||||||
// SELF, APP headers.
|
// Main SELF file stream.
|
||||||
|
const fs::file& self_f;
|
||||||
|
|
||||||
|
// SCE, SELF and APP headers.
|
||||||
|
SceHeader sce_hdr;
|
||||||
SelfHeader self_hdr;
|
SelfHeader self_hdr;
|
||||||
AppInfo app_info;
|
AppInfo app_info;
|
||||||
|
|
||||||
bool isElf32;
|
|
||||||
|
|
||||||
// ELF64 header and program header/section header arrays.
|
// ELF64 header and program header/section header arrays.
|
||||||
Elf64_Ehdr elf64_hdr;
|
Elf64_Ehdr elf64_hdr;
|
||||||
std::vector<Elf64_Shdr> shdr64_arr;
|
std::vector<Elf64_Shdr> shdr64_arr;
|
||||||
|
@ -389,14 +391,25 @@ class SELFDecrypter : private SCEDecrypter
|
||||||
SCEVersionInfo scev_info;
|
SCEVersionInfo scev_info;
|
||||||
std::vector<ControlInfo> ctrlinfo_arr;
|
std::vector<ControlInfo> ctrlinfo_arr;
|
||||||
|
|
||||||
|
// Metadata structs.
|
||||||
|
MetadataInfo meta_info;
|
||||||
|
MetadataHeader meta_hdr;
|
||||||
|
std::vector<MetadataSectionHeader> meta_shdr;
|
||||||
|
|
||||||
|
// Internal data buffers.
|
||||||
|
std::unique_ptr<u8[]> data_keys;
|
||||||
|
u32 data_keys_length;
|
||||||
|
std::unique_ptr<u8[]> data_buf;
|
||||||
|
u32 data_buf_length;
|
||||||
|
|
||||||
// Main key vault instance.
|
// Main key vault instance.
|
||||||
KeyVault key_v;
|
KeyVault key_v;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SELFDecrypter(const fs::file& s, bool isElf32) : SCEDecrypter(s), key_v(), isElf32(isElf32) {};
|
SELFDecrypter(const fs::file& s);
|
||||||
fs::file MakeFile();
|
fs::file MakeElf(bool isElf32);
|
||||||
bool LoadHeaders();
|
bool LoadHeaders(bool isElf32);
|
||||||
void ShowHeaders();
|
void ShowHeaders(bool isElf32);
|
||||||
bool LoadMetadata();
|
bool LoadMetadata();
|
||||||
bool DecryptData();
|
bool DecryptData();
|
||||||
bool DecryptNPDRM(u8 *metadata, u32 metadata_size);
|
bool DecryptNPDRM(u8 *metadata, u32 metadata_size);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue