From d46ca5a0157a5267b4c2ebf0515f1a492434071a Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sun, 29 Nov 2020 10:54:09 -0500 Subject: [PATCH] pl_u, applets/web: Decrypt shared fonts to TTF files --- .../hle/service/am/applets/web_browser.cpp | 86 +++++++++++++++++++ src/core/hle/service/ns/pl_u.cpp | 30 +++---- src/core/hle/service/ns/pl_u.h | 19 ++++ 3 files changed, 117 insertions(+), 18 deletions(-) diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index c0c98ad30..02ce9f387 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -16,12 +16,14 @@ #include "core/file_sys/romfs.h" #include "core/file_sys/system_archive/system_archive.h" #include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs_vector.h" #include "core/frontend/applets/web_browser.h" #include "core/hle/kernel/process.h" #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/web_browser.h" #include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/ns/pl_u.h" namespace Service::AM::Applets { @@ -123,6 +125,88 @@ FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id, } } +void ExtractSharedFonts(Core::System& system) { + static constexpr std::array DECRYPTED_SHARED_FONTS{ + "FontStandard.ttf", + "FontChineseSimplified.ttf", + "FontExtendedChineseSimplified.ttf", + "FontChineseTraditional.ttf", + "FontKorean.ttf", + "FontNintendoExtended.ttf", + "FontNintendoExtended2.ttf", + }; + + for (std::size_t i = 0; i < NS::SHARED_FONTS.size(); ++i) { + const auto fonts_dir = Common::FS::SanitizePath( + fmt::format("{}/fonts", Common::FS::GetUserPath(Common::FS::UserPath::CacheDir)), + Common::FS::DirectorySeparator::PlatformDefault); + + const auto font_file_path = + Common::FS::SanitizePath(fmt::format("{}/{}", fonts_dir, DECRYPTED_SHARED_FONTS[i]), + Common::FS::DirectorySeparator::PlatformDefault); + + if (Common::FS::Exists(font_file_path)) { + continue; + } + + const auto font = NS::SHARED_FONTS[i]; + const auto font_title_id = static_cast(font.first); + + const auto nca = system.GetFileSystemController().GetSystemNANDContents()->GetEntry( + font_title_id, FileSys::ContentRecordType::Data); + + FileSys::VirtualFile romfs; + + if (!nca) { + romfs = FileSys::SystemArchive::SynthesizeSystemArchive(font_title_id); + } else { + romfs = nca->GetRomFS(); + } + + if (!romfs) { + LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} cannot be extracted!", + font_title_id); + continue; + } + + const auto extracted_romfs = FileSys::ExtractRomFS(romfs); + + if (!extracted_romfs) { + LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} failed to extract!", + font_title_id); + continue; + } + + const auto font_file = extracted_romfs->GetFile(font.second); + + if (!font_file) { + LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} has no font file \"{}\"!", + font_title_id, font.second); + continue; + } + + std::vector font_data_u32(font_file->GetSize() / sizeof(u32)); + font_file->ReadBytes(font_data_u32.data(), font_file->GetSize()); + + std::transform(font_data_u32.begin(), font_data_u32.end(), font_data_u32.begin(), + Common::swap32); + + std::vector decrypted_data(font_file->GetSize() - 8); + + NS::DecryptSharedFontToTTF(font_data_u32, decrypted_data); + + FileSys::VirtualFile decrypted_font = std::make_shared( + std::move(decrypted_data), DECRYPTED_SHARED_FONTS[i]); + + const auto temp_dir = + system.GetFilesystem()->CreateDirectory(fonts_dir, FileSys::Mode::ReadWrite); + + const auto out_file = temp_dir->CreateFile(DECRYPTED_SHARED_FONTS[i]); + + FileSys::VfsRawCopy(decrypted_font, out_file); + } +} + } // namespace WebBrowser::WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_) @@ -155,6 +239,8 @@ void WebBrowser::Initialize() { LOG_DEBUG(Service_AM, "WebArgHeader: total_tlv_entries={}, shim_kind={}", web_arg_header.total_tlv_entries, web_arg_header.shim_kind); + ExtractSharedFonts(system); + switch (web_arg_header.shim_kind) { case ShimKind::Shop: InitializeShop(); diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index c8a215845..71c7587db 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -27,29 +27,11 @@ namespace Service::NS { -enum class FontArchives : u64 { - Extension = 0x0100000000000810, - Standard = 0x0100000000000811, - Korean = 0x0100000000000812, - ChineseTraditional = 0x0100000000000813, - ChineseSimple = 0x0100000000000814, -}; - struct FontRegion { u32 offset; u32 size; }; -constexpr std::array, 7> SHARED_FONTS{ - std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"), - std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"), - std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_ext_zh-cn_003.bfttf"), - std::make_pair(FontArchives::ChineseTraditional, "nintendo_udjxh-db_zh-tw_003.bfttf"), - std::make_pair(FontArchives::Korean, "nintendo_udsg-r_ko_003.bfttf"), - std::make_pair(FontArchives::Extension, "nintendo_ext_003.bfttf"), - std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf"), -}; - // The below data is specific to shared font data dumped from Switch on f/w 2.2 // Virtual address and offsets/sizes likely will vary by dump [[maybe_unused]] constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL}; @@ -80,6 +62,18 @@ static void DecryptSharedFont(const std::vector& input, Kernel::PhysicalMem offset += transformed_font.size() * sizeof(u32); } +void DecryptSharedFontToTTF(const std::vector& input, std::vector& output) { + ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number"); + + const u32 KEY = input[0] ^ EXPECTED_RESULT; // Derive key using an inverse xor + std::vector transformed_font(input.size()); + // TODO(ogniK): Figure out a better way to do this + std::transform(input.begin(), input.end(), transformed_font.begin(), + [&KEY](u32 font_data) { return Common::swap32(font_data ^ KEY); }); + transformed_font[1] = Common::swap32(transformed_font[1]) ^ KEY; // "re-encrypt" the size + std::memcpy(output.data(), transformed_font.data() + 2, transformed_font.size() * sizeof(u32)); +} + void EncryptSharedFont(const std::vector& input, std::vector& output, std::size_t& offset) { ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h index 224dcb997..f920c7f69 100644 --- a/src/core/hle/service/ns/pl_u.h +++ b/src/core/hle/service/ns/pl_u.h @@ -16,6 +16,25 @@ class FileSystemController; namespace NS { +enum class FontArchives : u64 { + Extension = 0x0100000000000810, + Standard = 0x0100000000000811, + Korean = 0x0100000000000812, + ChineseTraditional = 0x0100000000000813, + ChineseSimple = 0x0100000000000814, +}; + +constexpr std::array, 7> SHARED_FONTS{ + std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"), + std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"), + std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_ext_zh-cn_003.bfttf"), + std::make_pair(FontArchives::ChineseTraditional, "nintendo_udjxh-db_zh-tw_003.bfttf"), + std::make_pair(FontArchives::Korean, "nintendo_udsg-r_ko_003.bfttf"), + std::make_pair(FontArchives::Extension, "nintendo_ext_003.bfttf"), + std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf"), +}; + +void DecryptSharedFontToTTF(const std::vector& input, std::vector& output); void EncryptSharedFont(const std::vector& input, std::vector& output, std::size_t& offset); class PL_U final : public ServiceFramework {