diff --git a/rpcs3/Crypto/unself.cpp b/rpcs3/Crypto/unself.cpp index 91dd579c3f..75675d3577 100644 --- a/rpcs3/Crypto/unself.cpp +++ b/rpcs3/Crypto/unself.cpp @@ -867,7 +867,7 @@ std::vector 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 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(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(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(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(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>(); @@ -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; diff --git a/rpcs3/Crypto/unself.h b/rpcs3/Crypto/unself.h index ee9933de64..a219b3c6ef 100644 --- a/rpcs3/Crypto/unself.h +++ b/rpcs3/Crypto/unself.h @@ -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 shdr64_arr; @@ -389,14 +391,25 @@ class SELFDecrypter : private SCEDecrypter SCEVersionInfo scev_info; std::vector ctrlinfo_arr; + // Metadata structs. + MetadataInfo meta_info; + MetadataHeader meta_hdr; + std::vector meta_shdr; + + // Internal data buffers. + std::unique_ptr data_keys; + u32 data_keys_length; + std::unique_ptr 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);