bktr: Implement IVFC offset shifting
Fixes base game read errors
This commit is contained in:
		| @@ -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; | ||||
| } | ||||
|   | ||||
| @@ -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{}; | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -37,6 +37,7 @@ public: | ||||
| private: | ||||
|     VirtualFile file; | ||||
|     bool updatable; | ||||
|     u64 ivfc_offset; | ||||
| }; | ||||
|  | ||||
| } // namespace FileSys | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user