From a6e75cd45b75a202eed1a68692e33e7732789dd2 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Tue, 28 Aug 2018 22:37:42 -0400 Subject: bktr: Implement IVFC offset shifting Fixes base game read errors --- src/core/file_sys/content_archive.cpp | 13 +++++++++---- src/core/file_sys/content_archive.h | 7 ++++++- src/core/file_sys/nca_patch.cpp | 2 +- src/core/file_sys/romfs_factory.cpp | 5 +++-- src/core/file_sys/romfs_factory.h | 1 + src/core/loader/loader.h | 9 +++++++++ src/core/loader/nca.cpp | 6 ++++++ src/core/loader/nca.h | 1 + 8 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index f0d376bf5..26e1daf55 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(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(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 104226f3a..00eca52da 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> 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 22fbba573..e293af452 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 fc9cf1eca..33ec62491 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 RomFSFactory::OpenCurrentProcess() { if (!updatable) return MakeResult(file); - const PatchManager patch_manager(Core::CurrentProcess()->process_id); - return MakeResult(patch_manager.PatchRomFS(file)); + const PatchManager patch_manager(Core::CurrentProcess()->program_id); + return MakeResult(patch_manager.PatchRomFS(file, ivfc_offset)); } ResultVal 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 168db1c46..26b8f46cc 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 225c05127..843c4bb91 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 6b1c27b47..6aaffae59 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 326f84857..10be197c4 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h @@ -37,6 +37,7 @@ public: ResultStatus Load(Kernel::SharedPtr& process) override; ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; + u64 ReadRomFSIVFCOffset() const override; ResultStatus ReadProgramId(u64& out_program_id) override; private: -- cgit v1.2.3