diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index f0d376bf52e248bc099e511f0b63f98559488c6e..26e1daf554661a12acab2c53b94ab78dbb65b31e 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -215,7 +215,7 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting } } -NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_) +NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset) : file(std::move(file_)), bktr_base_romfs(bktr_base_romfs_ ? std::move(bktr_base_romfs_) : nullptr) { status = Loader::ResultStatus::Success; @@ -292,6 +292,7 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_) is_update = std::find_if(sections.begin(), sections.end(), [](const NCASectionHeader& header) { return header.raw.header.crypto_type == NCASectionCryptoType::BKTR; }) != sections.end(); + ivfc_offset = 0; for (std::ptrdiff_t i = 0; i < number_sections; ++i) { auto section = sections[i]; @@ -299,8 +300,8 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_) if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) { const size_t base_offset = header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER; - const size_t romfs_offset = - base_offset + section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset; + ivfc_offset = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset; + const size_t romfs_offset = base_offset + ivfc_offset; const size_t romfs_size = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].size; auto raw = std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset); auto dec = Decrypt(section, raw, romfs_offset); @@ -414,7 +415,7 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_) bktr_base_romfs, std::make_shared<OffsetVfsFile>(file, romfs_size, base_offset), relocation_block, relocation_buckets, subsection_block, subsection_buckets, encrypted, encrypted ? key.get() : Core::Crypto::Key128{}, base_offset, - romfs_offset - base_offset, section.raw.section_ctr); + bktr_base_ivfc_offset, section.raw.section_ctr); // BKTR applies to entire IVFC, so make an offset version to level 6 @@ -511,6 +512,10 @@ VirtualFile NCA::GetBaseFile() const { return file; } +u64 NCA::GetBaseIVFCOffset() const { + return ivfc_offset; +} + bool NCA::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { return false; } diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index 104226f3a14623f6472b6921b1044dcd0b0cdc9b..00eca52da5107cd4581c41967bab0f79ad71783c 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h @@ -79,7 +79,8 @@ bool IsValidNCA(const NCAHeader& header); // After construction, use GetStatus to determine if the file is valid and ready to be used. class NCA : public ReadOnlyVfsDirectory { public: - explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr); + explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr, + u64 bktr_base_ivfc_offset = 0); Loader::ResultStatus GetStatus() const; std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; @@ -96,6 +97,9 @@ public: VirtualFile GetBaseFile() const; + // Returns the base ivfc offset used in BKTR patching. + u64 GetBaseIVFCOffset() const; + protected: bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; @@ -112,6 +116,7 @@ private: VirtualDir exefs = nullptr; VirtualFile file; VirtualFile bktr_base_romfs; + u64 ivfc_offset; NCAHeader header{}; bool has_rights_id{}; diff --git a/src/core/file_sys/nca_patch.cpp b/src/core/file_sys/nca_patch.cpp index 22fbba5732f720c681b312ced5d303494c0b5cda..e293af45249f53bc0e55b0b2e5d8d016154dfba0 100644 --- a/src/core/file_sys/nca_patch.cpp +++ b/src/core/file_sys/nca_patch.cpp @@ -51,7 +51,7 @@ size_t BKTR::Read(u8* data, size_t length, size_t offset) const { if (!bktr_read) { ASSERT_MSG(section_offset > ivfc_offset, "Offset calculation negative."); - return base_romfs->Read(data, length, section_offset); + return base_romfs->Read(data, length, section_offset - ivfc_offset); } if (!encrypted) { diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index fc9cf1eca731ae6965820604e05e07ca0502ea26..33ec62491a3bd0d1a5039fcf98ee44feed713f9c 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp @@ -24,14 +24,15 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) { } updatable = app_loader.IsRomFSUpdatable(); + ivfc_offset = app_loader.ReadRomFSIVFCOffset(); } ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() { if (!updatable) return MakeResult<VirtualFile>(file); - const PatchManager patch_manager(Core::CurrentProcess()->process_id); - return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file)); + const PatchManager patch_manager(Core::CurrentProcess()->program_id); + return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset)); } ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) { diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h index 168db1c465b9634e600fc8e45b26ba4d2f90ee2f..26b8f46cc2565525074ab5a9318d94e12257535b 100644 --- a/src/core/file_sys/romfs_factory.h +++ b/src/core/file_sys/romfs_factory.h @@ -37,6 +37,7 @@ public: private: VirtualFile file; bool updatable; + u64 ivfc_offset; }; } // namespace FileSys diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 225c05127d14a323454d277a29edcc5e6c980fc3..843c4bb912ae3e4d26de0064e872a82c2fd7ee9e 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -214,6 +214,15 @@ public: return true; } + /** + * Gets the difference between the start of the IVFC header and the start of level 6 (RomFS) + * data. Needed for bktr patching. + * @return IVFC offset for romfs. + */ + virtual u64 ReadRomFSIVFCOffset() const { + return 0; + } + /** * Get the title of the application * @param title Reference to store the application title into diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index 6b1c27b47fd2d721c1a519971d4ff3bee241b2e9..6aaffae5951831b0c3e5ad5f4bd7aaf3c280b959 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -71,6 +71,12 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { return ResultStatus::Success; } +u64 AppLoader_NCA::ReadRomFSIVFCOffset() const { + if (nca == nullptr) + return 0; + return nca->GetBaseIVFCOffset(); +} + ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) return ResultStatus::ErrorNotInitialized; diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index 326f84857971539a5dd8f4e4083fbea87d7b3e5d..10be197c4ba53ffdb4f44a2b39a540dd1d8bfd99 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h @@ -37,6 +37,7 @@ public: ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; + u64 ReadRomFSIVFCOffset() const override; ResultStatus ReadProgramId(u64& out_program_id) override; private: