bktr: Implement IVFC offset shifting
Fixes base game read errors
This commit is contained in:
parent
9664ce255d
commit
a6e75cd45b
8 changed files with 36 additions and 8 deletions
|
@ -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_)),
|
: file(std::move(file_)),
|
||||||
bktr_base_romfs(bktr_base_romfs_ ? std::move(bktr_base_romfs_) : nullptr) {
|
bktr_base_romfs(bktr_base_romfs_ ? std::move(bktr_base_romfs_) : nullptr) {
|
||||||
status = Loader::ResultStatus::Success;
|
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) {
|
is_update = std::find_if(sections.begin(), sections.end(), [](const NCASectionHeader& header) {
|
||||||
return header.raw.header.crypto_type == NCASectionCryptoType::BKTR;
|
return header.raw.header.crypto_type == NCASectionCryptoType::BKTR;
|
||||||
}) != sections.end();
|
}) != sections.end();
|
||||||
|
ivfc_offset = 0;
|
||||||
|
|
||||||
for (std::ptrdiff_t i = 0; i < number_sections; ++i) {
|
for (std::ptrdiff_t i = 0; i < number_sections; ++i) {
|
||||||
auto section = 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) {
|
if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) {
|
||||||
const size_t base_offset =
|
const size_t base_offset =
|
||||||
header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER;
|
header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER;
|
||||||
const size_t romfs_offset =
|
ivfc_offset = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset;
|
||||||
base_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;
|
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 raw = std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset);
|
||||||
auto dec = Decrypt(section, raw, 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),
|
bktr_base_romfs, std::make_shared<OffsetVfsFile>(file, romfs_size, base_offset),
|
||||||
relocation_block, relocation_buckets, subsection_block, subsection_buckets,
|
relocation_block, relocation_buckets, subsection_block, subsection_buckets,
|
||||||
encrypted, encrypted ? key.get() : Core::Crypto::Key128{}, base_offset,
|
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
|
// BKTR applies to entire IVFC, so make an offset version to level 6
|
||||||
|
|
||||||
|
@ -511,6 +512,10 @@ VirtualFile NCA::GetBaseFile() const {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 NCA::GetBaseIVFCOffset() const {
|
||||||
|
return ivfc_offset;
|
||||||
|
}
|
||||||
|
|
||||||
bool NCA::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
|
bool NCA::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
|
||||||
return false;
|
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.
|
// After construction, use GetStatus to determine if the file is valid and ready to be used.
|
||||||
class NCA : public ReadOnlyVfsDirectory {
|
class NCA : public ReadOnlyVfsDirectory {
|
||||||
public:
|
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;
|
Loader::ResultStatus GetStatus() const;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
|
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
|
||||||
|
@ -96,6 +97,9 @@ public:
|
||||||
|
|
||||||
VirtualFile GetBaseFile() const;
|
VirtualFile GetBaseFile() const;
|
||||||
|
|
||||||
|
// Returns the base ivfc offset used in BKTR patching.
|
||||||
|
u64 GetBaseIVFCOffset() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
|
bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
|
||||||
|
|
||||||
|
@ -112,6 +116,7 @@ private:
|
||||||
VirtualDir exefs = nullptr;
|
VirtualDir exefs = nullptr;
|
||||||
VirtualFile file;
|
VirtualFile file;
|
||||||
VirtualFile bktr_base_romfs;
|
VirtualFile bktr_base_romfs;
|
||||||
|
u64 ivfc_offset;
|
||||||
|
|
||||||
NCAHeader header{};
|
NCAHeader header{};
|
||||||
bool has_rights_id{};
|
bool has_rights_id{};
|
||||||
|
|
|
@ -51,7 +51,7 @@ size_t BKTR::Read(u8* data, size_t length, size_t offset) const {
|
||||||
|
|
||||||
if (!bktr_read) {
|
if (!bktr_read) {
|
||||||
ASSERT_MSG(section_offset > ivfc_offset, "Offset calculation negative.");
|
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) {
|
if (!encrypted) {
|
||||||
|
|
|
@ -24,14 +24,15 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
updatable = app_loader.IsRomFSUpdatable();
|
updatable = app_loader.IsRomFSUpdatable();
|
||||||
|
ivfc_offset = app_loader.ReadRomFSIVFCOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
|
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
|
||||||
if (!updatable)
|
if (!updatable)
|
||||||
return MakeResult<VirtualFile>(file);
|
return MakeResult<VirtualFile>(file);
|
||||||
|
|
||||||
const PatchManager patch_manager(Core::CurrentProcess()->process_id);
|
const PatchManager patch_manager(Core::CurrentProcess()->program_id);
|
||||||
return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file));
|
return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) {
|
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) {
|
||||||
|
|
|
@ -37,6 +37,7 @@ public:
|
||||||
private:
|
private:
|
||||||
VirtualFile file;
|
VirtualFile file;
|
||||||
bool updatable;
|
bool updatable;
|
||||||
|
u64 ivfc_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -214,6 +214,15 @@ public:
|
||||||
return true;
|
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
|
* Get the title of the application
|
||||||
* @param title Reference to store the application title into
|
* @param title Reference to store the application title into
|
||||||
|
|
|
@ -71,6 +71,12 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 AppLoader_NCA::ReadRomFSIVFCOffset() const {
|
||||||
|
if (nca == nullptr)
|
||||||
|
return 0;
|
||||||
|
return nca->GetBaseIVFCOffset();
|
||||||
|
}
|
||||||
|
|
||||||
ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
|
ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
|
||||||
if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
|
if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
|
||||||
return ResultStatus::ErrorNotInitialized;
|
return ResultStatus::ErrorNotInitialized;
|
||||||
|
|
|
@ -37,6 +37,7 @@ public:
|
||||||
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
||||||
|
|
||||||
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
|
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
|
||||||
|
u64 ReadRomFSIVFCOffset() const override;
|
||||||
ResultStatus ReadProgramId(u64& out_program_id) override;
|
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in a new issue