mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +00: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.
|
||||
data_buf_offset += meta_shdr[i].data_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());
|
||||
|
||||
|
@ -877,24 +877,40 @@ std::vector<fs::file> SCEDecrypter::MakeFile()
|
|||
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.
|
||||
self_hdr.Load(sce_f);
|
||||
self_hdr.Load(self_f);
|
||||
|
||||
// Read the APP INFO.
|
||||
sce_f.seek(self_hdr.se_appinfooff);
|
||||
app_info.Load(sce_f);
|
||||
self_f.seek(self_hdr.se_appinfooff);
|
||||
app_info.Load(self_f);
|
||||
|
||||
// Read ELF header.
|
||||
sce_f.seek(self_hdr.se_elfoff);
|
||||
self_f.seek(self_hdr.se_elfoff);
|
||||
|
||||
if (isElf32)
|
||||
elf32_hdr.Load(sce_f);
|
||||
elf32_hdr.Load(self_f);
|
||||
else
|
||||
elf64_hdr.Load(sce_f);
|
||||
elf64_hdr.Load(self_f);
|
||||
|
||||
// Read ELF program headers.
|
||||
if (isElf32)
|
||||
|
@ -905,11 +921,11 @@ bool SELFDecrypter::LoadHeaders()
|
|||
LOG_ERROR(LOADER, "SELF: ELF program header offset is null!");
|
||||
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)
|
||||
{
|
||||
phdr32_arr.emplace_back();
|
||||
phdr32_arr.back().Load(sce_f);
|
||||
phdr32_arr.back().Load(self_f);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -922,40 +938,40 @@ bool SELFDecrypter::LoadHeaders()
|
|||
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)
|
||||
{
|
||||
phdr64_arr.emplace_back();
|
||||
phdr64_arr.back().Load(sce_f);
|
||||
phdr64_arr.back().Load(self_f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Read section info.
|
||||
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)
|
||||
{
|
||||
secinfo_arr.emplace_back();
|
||||
secinfo_arr.back().Load(sce_f);
|
||||
secinfo_arr.back().Load(self_f);
|
||||
}
|
||||
|
||||
// Read SCE version info.
|
||||
sce_f.seek(self_hdr.se_sceveroff);
|
||||
scev_info.Load(sce_f);
|
||||
self_f.seek(self_hdr.se_sceveroff);
|
||||
scev_info.Load(self_f);
|
||||
|
||||
// Read control info.
|
||||
ctrlinfo_arr.clear();
|
||||
sce_f.seek(self_hdr.se_controloff);
|
||||
self_f.seek(self_hdr.se_controloff);
|
||||
|
||||
u32 i = 0;
|
||||
while(i < self_hdr.se_controlsize)
|
||||
{
|
||||
ctrlinfo_arr.emplace_back();
|
||||
ControlInfo &cinfo = ctrlinfo_arr.back();
|
||||
cinfo.Load(sce_f);
|
||||
cinfo.Load(self_f);
|
||||
i += cinfo.size;
|
||||
}
|
||||
|
||||
|
@ -970,12 +986,12 @@ bool SELFDecrypter::LoadHeaders()
|
|||
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)
|
||||
{
|
||||
shdr32_arr.emplace_back();
|
||||
shdr32_arr.back().Load(sce_f);
|
||||
shdr32_arr.back().Load(self_f);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -987,19 +1003,19 @@ bool SELFDecrypter::LoadHeaders()
|
|||
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)
|
||||
{
|
||||
shdr64_arr.emplace_back();
|
||||
shdr64_arr.back().Load(sce_f);
|
||||
shdr64_arr.back().Load(self_f);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SELFDecrypter::ShowHeaders()
|
||||
void SELFDecrypter::ShowHeaders(bool isElf32)
|
||||
{
|
||||
LOG_NOTICE(LOADER, "SCE header");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
|
@ -1116,8 +1132,76 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
|||
|
||||
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);
|
||||
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()
|
||||
|
@ -1162,8 +1246,8 @@ bool SELFDecrypter::DecryptData()
|
|||
auto buf = std::make_unique<u8[]>(meta_shdr[i].data_size);
|
||||
|
||||
// Seek to the section data offset and read the encrypted data.
|
||||
sce_f.seek(meta_shdr[i].data_offset);
|
||||
sce_f.read(buf.get(), meta_shdr[i].data_size);
|
||||
self_f.seek(meta_shdr[i].data_offset);
|
||||
self_f.read(buf.get(), meta_shdr[i].data_size);
|
||||
|
||||
// Zero out our ctr nonce.
|
||||
memset(ctr_stream_block, 0, sizeof(ctr_stream_block));
|
||||
|
@ -1184,7 +1268,7 @@ bool SELFDecrypter::DecryptData()
|
|||
return true;
|
||||
}
|
||||
|
||||
fs::file SELFDecrypter::MakeFile()
|
||||
fs::file SELFDecrypter::MakeElf(bool isElf32)
|
||||
{
|
||||
// Create a new ELF file.
|
||||
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);
|
||||
|
||||
// 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.
|
||||
if (!self_dec.LoadHeaders())
|
||||
if (!self_dec.LoadHeaders(isElf32))
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Failed to load SELF file headers!");
|
||||
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.
|
||||
return self_dec.MakeFile();
|
||||
return self_dec.MakeElf(isElf32);
|
||||
}
|
||||
|
||||
return elf_or_self;
|
||||
|
|
|
@ -366,14 +366,16 @@ public:
|
|||
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;
|
||||
AppInfo app_info;
|
||||
|
||||
bool isElf32;
|
||||
|
||||
|
||||
// ELF64 header and program header/section header arrays.
|
||||
Elf64_Ehdr elf64_hdr;
|
||||
std::vector<Elf64_Shdr> shdr64_arr;
|
||||
|
@ -389,14 +391,25 @@ class SELFDecrypter : private SCEDecrypter
|
|||
SCEVersionInfo scev_info;
|
||||
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.
|
||||
KeyVault key_v;
|
||||
|
||||
public:
|
||||
SELFDecrypter(const fs::file& s, bool isElf32) : SCEDecrypter(s), key_v(), isElf32(isElf32) {};
|
||||
fs::file MakeFile();
|
||||
bool LoadHeaders();
|
||||
void ShowHeaders();
|
||||
SELFDecrypter(const fs::file& s);
|
||||
fs::file MakeElf(bool isElf32);
|
||||
bool LoadHeaders(bool isElf32);
|
||||
void ShowHeaders(bool isElf32);
|
||||
bool LoadMetadata();
|
||||
bool DecryptData();
|
||||
bool DecryptNPDRM(u8 *metadata, u32 metadata_size);
|
||||
|
|
Loading…
Add table
Reference in a new issue