From 60acda6615762aecec2c8fe52df5e62c2519549f Mon Sep 17 00:00:00 2001 From: jakcron Date: Tue, 28 Sep 2021 19:15:54 +0800 Subject: [PATCH] Begin migration from libfnd to libtoolchain --- build/visualstudio/nstool.sln | 280 +++-- build/visualstudio/nstool/nstool.vcxproj | 86 +- .../nstool/nstool.vcxproj.filters | 202 +-- deps/libfnd | 2 +- deps/liblz4 | 2 +- deps/libmbedtls | 2 +- deps/libnintendo-es | 2 +- deps/libnintendo-hac | 2 +- deps/libnintendo-hac-hb | 2 +- deps/libnintendo-pki | 2 +- deps/libtoolchain | 2 +- makefile | 22 +- src/AssetProcess.cpp | 90 +- src/AssetProcess.h | 22 +- src/CnmtProcess.cpp | 31 +- src/CnmtProcess.h | 16 +- src/CompressedArchiveIFile.cpp | 195 --- src/CompressedArchiveIFile.h | 51 - src/ElfSymbolParser.cpp | 16 +- src/ElfSymbolParser.h | 15 +- src/EsTikProcess.cpp | 50 +- src/EsTikProcess.h | 28 +- src/GameCardProcess.cpp | 58 +- src/GameCardProcess.h | 27 +- src/IniProcess.cpp | 42 +- src/IniProcess.h | 20 +- src/KeyBag.cpp | 568 +++++++++ src/KeyBag.h | 76 ++ src/KeyConfiguration.cpp | 413 ------- src/KeyConfiguration.h | 217 ---- src/KipProcess.cpp | 48 +- src/KipProcess.h | 19 +- src/MetaProcess.cpp | 48 +- src/MetaProcess.h | 24 +- src/NacpProcess.cpp | 134 +- src/NacpProcess.h | 16 +- src/NcaProcess.cpp | 108 +- src/NcaProcess.h | 34 +- src/NroProcess.cpp | 48 +- src/NroProcess.h | 25 +- src/NsoProcess.cpp | 60 +- src/NsoProcess.h | 21 +- src/PfsProcess.cpp | 52 +- src/PfsProcess.h | 18 +- src/PkiCertProcess.cpp | 46 +- src/PkiCertProcess.h | 27 +- src/PkiValidator.cpp | 48 +- src/PkiValidator.h | 25 +- src/RoMetadataProcess.cpp | 52 +- src/RoMetadataProcess.h | 21 +- src/RomfsProcess.cpp | 64 +- src/RomfsProcess.h | 33 +- src/SdkApiString.cpp | 20 +- src/SdkApiString.h | 8 +- src/Settings.cpp | 819 +++++++++++++ src/Settings.h | 155 +++ src/UserSettings.cpp | 1086 ----------------- src/UserSettings.h | 138 --- src/common.h | 62 - src/elf.h | 458 +++++++ src/main.cpp | 256 ++-- src/types.h | 26 + src/util.cpp | 100 ++ src/util.h | 13 + src/version.h | 4 +- 65 files changed, 3311 insertions(+), 3346 deletions(-) delete mode 100644 src/CompressedArchiveIFile.cpp delete mode 100644 src/CompressedArchiveIFile.h create mode 100644 src/KeyBag.cpp create mode 100644 src/KeyBag.h delete mode 100644 src/KeyConfiguration.cpp delete mode 100644 src/KeyConfiguration.h create mode 100644 src/Settings.cpp create mode 100644 src/Settings.h delete mode 100644 src/UserSettings.cpp delete mode 100644 src/UserSettings.h delete mode 100644 src/common.h create mode 100644 src/elf.h create mode 100644 src/types.h create mode 100644 src/util.cpp create mode 100644 src/util.h diff --git a/build/visualstudio/nstool.sln b/build/visualstudio/nstool.sln index ad181a1..202b2b9 100644 --- a/build/visualstudio/nstool.sln +++ b/build/visualstudio/nstool.sln @@ -1,129 +1,151 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28010.2036 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nstool", "nstool\nstool.vcxproj", "{775EF5EB-CA49-4994-8AC4-47B4A5385266}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deps", "deps", "{05929EAE-4471-4E8E-A6F3-793A81623D7F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfnd", "..\..\deps\libfnd\build\visualstudio\libfnd\libfnd.vcxproj", "{4E578016-34BA-4A1E-B8EC-37A48780B6CA}" - ProjectSection(ProjectDependencies) = postProject - {E741ADED-7900-4E07-8DB0-D008C336C3FB} = {E741ADED-7900-4E07-8DB0-D008C336C3FB} - {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C} = {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblz4", "..\..\deps\liblz4\build\visualstudio\liblz4\liblz4.vcxproj", "{E741ADED-7900-4E07-8DB0-D008C336C3FB}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-es", "..\..\deps\libnintendo-es\build\visualstudio\libnintendo-es\libnintendo-es.vcxproj", "{8616D6C9-C8DE-4C3F-AFC2-625636664C2B}" - ProjectSection(ProjectDependencies) = postProject - {4E578016-34BA-4A1E-B8EC-37A48780B6CA} = {4E578016-34BA-4A1E-B8EC-37A48780B6CA} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-hac", "..\..\deps\libnintendo-hac\build\visualstudio\libnintendo-hac\libnintendo-hac.vcxproj", "{8885C125-83FB-4F73-A93A-C712B1434D54}" - ProjectSection(ProjectDependencies) = postProject - {4E578016-34BA-4A1E-B8EC-37A48780B6CA} = {4E578016-34BA-4A1E-B8EC-37A48780B6CA} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-hac-hb", "..\..\deps\libnintendo-hac-hb\build\visualstudio\libnintendo-hac-hb\libnintendo-hac-hb.vcxproj", "{24D001B4-D439-4967-9371-DC3E0523EB19}" - ProjectSection(ProjectDependencies) = postProject - {4E578016-34BA-4A1E-B8EC-37A48780B6CA} = {4E578016-34BA-4A1E-B8EC-37A48780B6CA} - {8885C125-83FB-4F73-A93A-C712B1434D54} = {8885C125-83FB-4F73-A93A-C712B1434D54} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-pki", "..\..\deps\libnintendo-pki\build\visualstudio\libnintendo-pki\libnintendo-pki.vcxproj", "{0BEF63A0-2801-4563-AB65-1E2FD881C3AF}" - ProjectSection(ProjectDependencies) = postProject - {4E578016-34BA-4A1E-B8EC-37A48780B6CA} = {4E578016-34BA-4A1E-B8EC-37A48780B6CA} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmbedtls", "..\..\deps\libmbedtls\build\visualstudio\libmbedtls\libmbedtls.vcxproj", "{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Debug|x64.ActiveCfg = Debug|x64 - {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Debug|x64.Build.0 = Debug|x64 - {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Debug|x86.ActiveCfg = Debug|Win32 - {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Debug|x86.Build.0 = Debug|Win32 - {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Release|x64.ActiveCfg = Release|x64 - {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Release|x64.Build.0 = Release|x64 - {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Release|x86.ActiveCfg = Release|Win32 - {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Release|x86.Build.0 = Release|Win32 - {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Debug|x64.ActiveCfg = Debug|x64 - {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Debug|x64.Build.0 = Debug|x64 - {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Debug|x86.ActiveCfg = Debug|Win32 - {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Debug|x86.Build.0 = Debug|Win32 - {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Release|x64.ActiveCfg = Release|x64 - {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Release|x64.Build.0 = Release|x64 - {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Release|x86.ActiveCfg = Release|Win32 - {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Release|x86.Build.0 = Release|Win32 - {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Debug|x64.ActiveCfg = Debug|x64 - {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Debug|x64.Build.0 = Debug|x64 - {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Debug|x86.ActiveCfg = Debug|Win32 - {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Debug|x86.Build.0 = Debug|Win32 - {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Release|x64.ActiveCfg = Release|x64 - {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Release|x64.Build.0 = Release|x64 - {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Release|x86.ActiveCfg = Release|Win32 - {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Release|x86.Build.0 = Release|Win32 - {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Debug|x64.ActiveCfg = Debug|x64 - {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Debug|x64.Build.0 = Debug|x64 - {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Debug|x86.ActiveCfg = Debug|Win32 - {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Debug|x86.Build.0 = Debug|Win32 - {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Release|x64.ActiveCfg = Release|x64 - {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Release|x64.Build.0 = Release|x64 - {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Release|x86.ActiveCfg = Release|Win32 - {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Release|x86.Build.0 = Release|Win32 - {8885C125-83FB-4F73-A93A-C712B1434D54}.Debug|x64.ActiveCfg = Debug|x64 - {8885C125-83FB-4F73-A93A-C712B1434D54}.Debug|x64.Build.0 = Debug|x64 - {8885C125-83FB-4F73-A93A-C712B1434D54}.Debug|x86.ActiveCfg = Debug|Win32 - {8885C125-83FB-4F73-A93A-C712B1434D54}.Debug|x86.Build.0 = Debug|Win32 - {8885C125-83FB-4F73-A93A-C712B1434D54}.Release|x64.ActiveCfg = Release|x64 - {8885C125-83FB-4F73-A93A-C712B1434D54}.Release|x64.Build.0 = Release|x64 - {8885C125-83FB-4F73-A93A-C712B1434D54}.Release|x86.ActiveCfg = Release|Win32 - {8885C125-83FB-4F73-A93A-C712B1434D54}.Release|x86.Build.0 = Release|Win32 - {24D001B4-D439-4967-9371-DC3E0523EB19}.Debug|x64.ActiveCfg = Debug|x64 - {24D001B4-D439-4967-9371-DC3E0523EB19}.Debug|x64.Build.0 = Debug|x64 - {24D001B4-D439-4967-9371-DC3E0523EB19}.Debug|x86.ActiveCfg = Debug|Win32 - {24D001B4-D439-4967-9371-DC3E0523EB19}.Debug|x86.Build.0 = Debug|Win32 - {24D001B4-D439-4967-9371-DC3E0523EB19}.Release|x64.ActiveCfg = Release|x64 - {24D001B4-D439-4967-9371-DC3E0523EB19}.Release|x64.Build.0 = Release|x64 - {24D001B4-D439-4967-9371-DC3E0523EB19}.Release|x86.ActiveCfg = Release|Win32 - {24D001B4-D439-4967-9371-DC3E0523EB19}.Release|x86.Build.0 = Release|Win32 - {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Debug|x64.ActiveCfg = Debug|x64 - {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Debug|x64.Build.0 = Debug|x64 - {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Debug|x86.ActiveCfg = Debug|Win32 - {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Debug|x86.Build.0 = Debug|Win32 - {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Release|x64.ActiveCfg = Release|x64 - {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Release|x64.Build.0 = Release|x64 - {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Release|x86.ActiveCfg = Release|Win32 - {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Release|x86.Build.0 = Release|Win32 - {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.ActiveCfg = Debug|x64 - {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.Build.0 = Debug|x64 - {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.ActiveCfg = Debug|Win32 - {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.Build.0 = Debug|Win32 - {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.ActiveCfg = Release|x64 - {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.Build.0 = Release|x64 - {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.ActiveCfg = Release|Win32 - {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {4E578016-34BA-4A1E-B8EC-37A48780B6CA} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} - {E741ADED-7900-4E07-8DB0-D008C336C3FB} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} - {8616D6C9-C8DE-4C3F-AFC2-625636664C2B} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} - {8885C125-83FB-4F73-A93A-C712B1434D54} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} - {24D001B4-D439-4967-9371-DC3E0523EB19} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} - {0BEF63A0-2801-4563-AB65-1E2FD881C3AF} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} - {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {ABDCFB40-D6B3-44A9-92B5-0D7AB38D9FB8} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31229.75 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nstool", "nstool\nstool.vcxproj", "{775EF5EB-CA49-4994-8AC4-47B4A5385266}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deps", "deps", "{05929EAE-4471-4E8E-A6F3-793A81623D7F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfnd", "..\..\deps\libfnd\build\visualstudio\libfnd\libfnd.vcxproj", "{4E578016-34BA-4A1E-B8EC-37A48780B6CA}" + ProjectSection(ProjectDependencies) = postProject + {E741ADED-7900-4E07-8DB0-D008C336C3FB} = {E741ADED-7900-4E07-8DB0-D008C336C3FB} + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C} = {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblz4", "..\..\deps\liblz4\build\visualstudio\liblz4\liblz4.vcxproj", "{E741ADED-7900-4E07-8DB0-D008C336C3FB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-es", "..\..\deps\libnintendo-es\build\visualstudio\libnintendo-es\libnintendo-es.vcxproj", "{8616D6C9-C8DE-4C3F-AFC2-625636664C2B}" + ProjectSection(ProjectDependencies) = postProject + {4E578016-34BA-4A1E-B8EC-37A48780B6CA} = {4E578016-34BA-4A1E-B8EC-37A48780B6CA} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-hac", "..\..\deps\libnintendo-hac\build\visualstudio\libnintendo-hac\libnintendo-hac.vcxproj", "{8885C125-83FB-4F73-A93A-C712B1434D54}" + ProjectSection(ProjectDependencies) = postProject + {4E578016-34BA-4A1E-B8EC-37A48780B6CA} = {4E578016-34BA-4A1E-B8EC-37A48780B6CA} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-hac-hb", "..\..\deps\libnintendo-hac-hb\build\visualstudio\libnintendo-hac-hb\libnintendo-hac-hb.vcxproj", "{24D001B4-D439-4967-9371-DC3E0523EB19}" + ProjectSection(ProjectDependencies) = postProject + {4E578016-34BA-4A1E-B8EC-37A48780B6CA} = {4E578016-34BA-4A1E-B8EC-37A48780B6CA} + {8885C125-83FB-4F73-A93A-C712B1434D54} = {8885C125-83FB-4F73-A93A-C712B1434D54} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-pki", "..\..\deps\libnintendo-pki\build\visualstudio\libnintendo-pki\libnintendo-pki.vcxproj", "{0BEF63A0-2801-4563-AB65-1E2FD881C3AF}" + ProjectSection(ProjectDependencies) = postProject + {4E578016-34BA-4A1E-B8EC-37A48780B6CA} = {4E578016-34BA-4A1E-B8EC-37A48780B6CA} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmbedtls", "..\..\deps\libmbedtls\build\visualstudio\libmbedtls\libmbedtls.vcxproj", "{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtoolchain", "..\..\deps\libtoolchain\build\visualstudio\libtoolchain\libtoolchain.vcxproj", "{E194E4B8-1482-40A2-901B-75D4387822E9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfmt", "..\..\deps\libfmt\build\visualstudio\libfmt\libfmt.vcxproj", "{F4B0540E-0AAE-4006-944B-356944EF61FA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Debug|x64.ActiveCfg = Debug|x64 + {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Debug|x64.Build.0 = Debug|x64 + {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Debug|x86.ActiveCfg = Debug|Win32 + {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Debug|x86.Build.0 = Debug|Win32 + {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Release|x64.ActiveCfg = Release|x64 + {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Release|x64.Build.0 = Release|x64 + {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Release|x86.ActiveCfg = Release|Win32 + {775EF5EB-CA49-4994-8AC4-47B4A5385266}.Release|x86.Build.0 = Release|Win32 + {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Debug|x64.ActiveCfg = Debug|x64 + {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Debug|x64.Build.0 = Debug|x64 + {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Debug|x86.ActiveCfg = Debug|Win32 + {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Debug|x86.Build.0 = Debug|Win32 + {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Release|x64.ActiveCfg = Release|x64 + {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Release|x64.Build.0 = Release|x64 + {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Release|x86.ActiveCfg = Release|Win32 + {4E578016-34BA-4A1E-B8EC-37A48780B6CA}.Release|x86.Build.0 = Release|Win32 + {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Debug|x64.ActiveCfg = Debug|x64 + {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Debug|x64.Build.0 = Debug|x64 + {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Debug|x86.ActiveCfg = Debug|Win32 + {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Debug|x86.Build.0 = Debug|Win32 + {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Release|x64.ActiveCfg = Release|x64 + {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Release|x64.Build.0 = Release|x64 + {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Release|x86.ActiveCfg = Release|Win32 + {E741ADED-7900-4E07-8DB0-D008C336C3FB}.Release|x86.Build.0 = Release|Win32 + {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Debug|x64.ActiveCfg = Debug|x64 + {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Debug|x64.Build.0 = Debug|x64 + {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Debug|x86.ActiveCfg = Debug|Win32 + {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Debug|x86.Build.0 = Debug|Win32 + {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Release|x64.ActiveCfg = Release|x64 + {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Release|x64.Build.0 = Release|x64 + {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Release|x86.ActiveCfg = Release|Win32 + {8616D6C9-C8DE-4C3F-AFC2-625636664C2B}.Release|x86.Build.0 = Release|Win32 + {8885C125-83FB-4F73-A93A-C712B1434D54}.Debug|x64.ActiveCfg = Debug|x64 + {8885C125-83FB-4F73-A93A-C712B1434D54}.Debug|x64.Build.0 = Debug|x64 + {8885C125-83FB-4F73-A93A-C712B1434D54}.Debug|x86.ActiveCfg = Debug|Win32 + {8885C125-83FB-4F73-A93A-C712B1434D54}.Debug|x86.Build.0 = Debug|Win32 + {8885C125-83FB-4F73-A93A-C712B1434D54}.Release|x64.ActiveCfg = Release|x64 + {8885C125-83FB-4F73-A93A-C712B1434D54}.Release|x64.Build.0 = Release|x64 + {8885C125-83FB-4F73-A93A-C712B1434D54}.Release|x86.ActiveCfg = Release|Win32 + {8885C125-83FB-4F73-A93A-C712B1434D54}.Release|x86.Build.0 = Release|Win32 + {24D001B4-D439-4967-9371-DC3E0523EB19}.Debug|x64.ActiveCfg = Debug|x64 + {24D001B4-D439-4967-9371-DC3E0523EB19}.Debug|x64.Build.0 = Debug|x64 + {24D001B4-D439-4967-9371-DC3E0523EB19}.Debug|x86.ActiveCfg = Debug|Win32 + {24D001B4-D439-4967-9371-DC3E0523EB19}.Debug|x86.Build.0 = Debug|Win32 + {24D001B4-D439-4967-9371-DC3E0523EB19}.Release|x64.ActiveCfg = Release|x64 + {24D001B4-D439-4967-9371-DC3E0523EB19}.Release|x64.Build.0 = Release|x64 + {24D001B4-D439-4967-9371-DC3E0523EB19}.Release|x86.ActiveCfg = Release|Win32 + {24D001B4-D439-4967-9371-DC3E0523EB19}.Release|x86.Build.0 = Release|Win32 + {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Debug|x64.ActiveCfg = Debug|x64 + {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Debug|x64.Build.0 = Debug|x64 + {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Debug|x86.ActiveCfg = Debug|Win32 + {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Debug|x86.Build.0 = Debug|Win32 + {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Release|x64.ActiveCfg = Release|x64 + {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Release|x64.Build.0 = Release|x64 + {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Release|x86.ActiveCfg = Release|Win32 + {0BEF63A0-2801-4563-AB65-1E2FD881C3AF}.Release|x86.Build.0 = Release|Win32 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.ActiveCfg = Debug|x64 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.Build.0 = Debug|x64 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.ActiveCfg = Debug|Win32 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.Build.0 = Debug|Win32 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.ActiveCfg = Release|x64 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.Build.0 = Release|x64 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.ActiveCfg = Release|Win32 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.Build.0 = Release|Win32 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x64.ActiveCfg = Debug|x64 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x64.Build.0 = Debug|x64 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x86.ActiveCfg = Debug|Win32 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x86.Build.0 = Debug|Win32 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x64.ActiveCfg = Release|x64 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x64.Build.0 = Release|x64 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x86.ActiveCfg = Release|Win32 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x86.Build.0 = Release|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.ActiveCfg = Debug|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.Build.0 = Debug|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.ActiveCfg = Debug|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.Build.0 = Debug|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.ActiveCfg = Release|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.Build.0 = Release|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.ActiveCfg = Release|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {4E578016-34BA-4A1E-B8EC-37A48780B6CA} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} + {E741ADED-7900-4E07-8DB0-D008C336C3FB} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} + {8616D6C9-C8DE-4C3F-AFC2-625636664C2B} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} + {8885C125-83FB-4F73-A93A-C712B1434D54} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} + {24D001B4-D439-4967-9371-DC3E0523EB19} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} + {0BEF63A0-2801-4563-AB65-1E2FD881C3AF} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} + {E194E4B8-1482-40A2-901B-75D4387822E9} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} + {F4B0540E-0AAE-4006-944B-356944EF61FA} = {05929EAE-4471-4E8E-A6F3-793A81623D7F} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {ABDCFB40-D6B3-44A9-92B5-0D7AB38D9FB8} + EndGlobalSection +EndGlobal diff --git a/build/visualstudio/nstool/nstool.vcxproj b/build/visualstudio/nstool/nstool.vcxproj index e07dcf0..e4db0c3 100644 --- a/build/visualstudio/nstool/nstool.vcxproj +++ b/build/visualstudio/nstool/nstool.vcxproj @@ -76,7 +76,8 @@ Disabled true true - $(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\libfnd\include;$(SolutionDir)..\..\deps\libnintendo-es\include;$(SolutionDir)..\..\deps\libnintendo-pki\include;$(SolutionDir)..\..\deps\libnintendo-hac\include;$(SolutionDir)..\..\deps\libnintendo-hac-hb\include + $(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\libfnd\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libnintendo-es\include;$(SolutionDir)..\..\deps\libnintendo-pki\include;$(SolutionDir)..\..\deps\libnintendo-hac\include;$(SolutionDir)..\..\deps\libnintendo-hac-hb\include + MultiThreadedDebug @@ -85,7 +86,8 @@ Disabled true true - $(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\libfnd\include;$(SolutionDir)..\..\deps\libnintendo-es\include;$(SolutionDir)..\..\deps\libnintendo-pki\include;$(SolutionDir)..\..\deps\libnintendo-hac\include;$(SolutionDir)..\..\deps\libnintendo-hac-hb\include + $(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\libfnd\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libnintendo-es\include;$(SolutionDir)..\..\deps\libnintendo-pki\include;$(SolutionDir)..\..\deps\libnintendo-hac\include;$(SolutionDir)..\..\deps\libnintendo-hac-hb\include + MultiThreadedDebug @@ -96,7 +98,8 @@ true true true - $(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\libfnd\include;$(SolutionDir)..\..\deps\libnintendo-es\include;$(SolutionDir)..\..\deps\libnintendo-pki\include;$(SolutionDir)..\..\deps\libnintendo-hac\include;$(SolutionDir)..\..\deps\libnintendo-hac-hb\include + $(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\libfnd\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libnintendo-es\include;$(SolutionDir)..\..\deps\libnintendo-pki\include;$(SolutionDir)..\..\deps\libnintendo-hac\include;$(SolutionDir)..\..\deps\libnintendo-hac-hb\include + MultiThreaded true @@ -111,7 +114,8 @@ true true true - $(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\libfnd\include;$(SolutionDir)..\..\deps\libnintendo-es\include;$(SolutionDir)..\..\deps\libnintendo-pki\include;$(SolutionDir)..\..\deps\libnintendo-hac\include;$(SolutionDir)..\..\deps\libnintendo-hac-hb\include + $(ProjectDir)..\..\..\include;$(SolutionDir)..\..\deps\libfnd\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libnintendo-es\include;$(SolutionDir)..\..\deps\libnintendo-pki\include;$(SolutionDir)..\..\deps\libnintendo-hac\include;$(SolutionDir)..\..\deps\libnintendo-hac-hb\include + MultiThreaded true @@ -119,76 +123,46 @@ - + + {f4b0540e-0aae-4006-944b-356944ef61fa} + + {4e578016-34ba-4a1e-b8ec-37a48780b6ca} - + {e741aded-7900-4e07-8db0-d008c336c3fb} - + {8616d6c9-c8de-4c3f-afc2-625636664c2b} - + {24d001b4-d439-4967-9371-dc3e0523eb19} - + {8885c125-83fb-4f73-a93a-c712b1434d54} - + {0bef63a0-2801-4563-ab65-1e2fd881c3af} - + {7a7c66f3-2b5b-4e23-85d8-2a74fedad92c} + + {e194e4b8-1482-40a2-901b-75d4387822e9} + - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + diff --git a/build/visualstudio/nstool/nstool.vcxproj.filters b/build/visualstudio/nstool/nstool.vcxproj.filters index 82a1d26..44261e8 100644 --- a/build/visualstudio/nstool/nstool.vcxproj.filters +++ b/build/visualstudio/nstool/nstool.vcxproj.filters @@ -1,156 +1,48 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + \ No newline at end of file diff --git a/deps/libfnd b/deps/libfnd index b6a74e0..27705ae 160000 --- a/deps/libfnd +++ b/deps/libfnd @@ -1 +1 @@ -Subproject commit b6a74e03d2c3fb272e900f32554b2cc0d18e7d26 +Subproject commit 27705aeb2394dbe21f580cc742792537e3a0cbed diff --git a/deps/liblz4 b/deps/liblz4 index 298f2ec..555e430 160000 --- a/deps/liblz4 +++ b/deps/liblz4 @@ -1 +1 @@ -Subproject commit 298f2ecfa6c966472eda9a4f2b93121a060d1867 +Subproject commit 555e43086b348a640179ddf2ecd86d8503c12b85 diff --git a/deps/libmbedtls b/deps/libmbedtls index 30ef43f..597bb57 160000 --- a/deps/libmbedtls +++ b/deps/libmbedtls @@ -1 +1 @@ -Subproject commit 30ef43f1d6ef00d9d94e19270ae8b646e821ecc7 +Subproject commit 597bb57271177d776682104dc7c8ea8b62670d1d diff --git a/deps/libnintendo-es b/deps/libnintendo-es index f96b4f9..7572682 160000 --- a/deps/libnintendo-es +++ b/deps/libnintendo-es @@ -1 +1 @@ -Subproject commit f96b4f96552da4258f4212427137d6ff40c45392 +Subproject commit 7572682f1fa819fd7ef1a4b639cb14fa67128f0d diff --git a/deps/libnintendo-hac b/deps/libnintendo-hac index 33cfca7..02c6703 160000 --- a/deps/libnintendo-hac +++ b/deps/libnintendo-hac @@ -1 +1 @@ -Subproject commit 33cfca799ccdcc4c34f73696da9fe31f104dd23f +Subproject commit 02c6703c9720d98197b3bb697fdab12008a9829e diff --git a/deps/libnintendo-hac-hb b/deps/libnintendo-hac-hb index db9af77..e52fb0e 160000 --- a/deps/libnintendo-hac-hb +++ b/deps/libnintendo-hac-hb @@ -1 +1 @@ -Subproject commit db9af77ec23d170ec703a13cd5cd9b67cd47d3a3 +Subproject commit e52fb0e1ebc558f68bb438bd278b05704c5aaeb3 diff --git a/deps/libnintendo-pki b/deps/libnintendo-pki index 040405b..b8a1066 160000 --- a/deps/libnintendo-pki +++ b/deps/libnintendo-pki @@ -1 +1 @@ -Subproject commit 040405bc6f9936e4e61c80b5ab384b3d95c395cd +Subproject commit b8a10663a99f7b5fedf11139549e8bf1b289c0e0 diff --git a/deps/libtoolchain b/deps/libtoolchain index 0be82cf..7948f58 160000 --- a/deps/libtoolchain +++ b/deps/libtoolchain @@ -1 +1 @@ -Subproject commit 0be82cf582b4af7539f57a261e17e5769f4f8cfa +Subproject commit 7948f581d32ebbfdf5a872b96c37938690f665e7 diff --git a/makefile b/makefile index 4f4ca61..f8c302a 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,6 @@ # C++/C Recursive Project Makefile # (c) Jack -# Version 3 +# Version 4 # Project Name PROJECT_NAME = nstool @@ -13,7 +13,7 @@ PROJECT_SRC_SUBDIRS = $(PROJECT_SRC_PATH) #PROJECT_TESTSRC_PATH = test #PROJECT_TESTSRC_SUBDIRS = $(PROJECT_TESTSRC_PATH) PROJECT_BIN_PATH = bin -#PROJECT_DOCS_PATH = docs +#PROJECT_DOCS_PATH = docs #PROJECT_DOXYFILE_PATH = Doxyfile # Determine if the root makefile has been established, and if not establish this makefile as the root makefile @@ -31,8 +31,8 @@ PROJECT_SONAME = $(PROJECT_NAME).so.$(PROJECT_SO_VER_MAJOR) PROJECT_SO_FILENAME = $(PROJECT_SONAME).$(PROJECT_SO_VER_MINOR).$(PROJECT_SO_VER_PATCH) # Project Dependencies -PROJECT_DEPEND_LOCAL = nintendo-hac-hb nintendo-hac nintendo-es nintendo-pki fnd mbedtls lz4 -PROJECT_DEPEND_EXTERNAL = +PROJECT_DEPEND = mbedtls lz4 toolchain fmt nintendo-hac nintendo-hac-hb nintendo-es nintendo-pki +PROJECT_DEPEND_LOCAL_DIR = libmbedtls liblz4 libtoolchain libfmt libnintendo-hac libnintendo-hac-hb libnintendo-es libnintendo-pki # Generate compiler flags for including project include path ifneq ($(PROJECT_INCLUDE_PATH),) @@ -40,14 +40,14 @@ ifneq ($(PROJECT_INCLUDE_PATH),) endif # Generate compiler flags for local included dependencies -ifneq ($(PROJECT_DEPEND_LOCAL),) - LIB += $(foreach dep,$(PROJECT_DEPEND_LOCAL), -L"$(ROOT_PROJECT_DEPENDENCY_PATH)/lib$(dep)/bin" -l$(dep)) - INC += $(foreach dep,$(PROJECT_DEPEND_LOCAL), -I"$(ROOT_PROJECT_DEPENDENCY_PATH)/lib$(dep)/include") +ifneq ($(PROJECT_DEPEND_LOCAL_DIR),) + LIB += $(foreach dep,$(PROJECT_DEPEND_LOCAL_DIR), -L"$(ROOT_PROJECT_DEPENDENCY_PATH)/$(dep)/bin") + INC += $(foreach dep,$(PROJECT_DEPEND_LOCAL_DIR), -I"$(ROOT_PROJECT_DEPENDENCY_PATH)/$(dep)/include") endif # Generate compiler flags for external dependencies -ifneq ($(PROJECT_DEPEND_EXTERNAL),) - LIB += $(foreach dep,$(PROJECT_DEPEND_EXTERNAL), -l$(dep)) +ifneq ($(PROJECT_DEPEND),) + LIB += $(foreach dep,$(PROJECT_DEPEND), -l$(dep)) endif # Detect Platform @@ -170,8 +170,8 @@ endif # Dependencies .PHONY: deps deps: - @$(foreach lib,$(PROJECT_DEPEND_LOCAL), cd "$(ROOT_PROJECT_DEPENDENCY_PATH)/lib$(lib)" && $(MAKE) static_lib && cd "$(PROJECT_PATH)";) + @$(foreach lib,$(PROJECT_DEPEND_LOCAL_DIR), cd "$(ROOT_PROJECT_DEPENDENCY_PATH)/$(lib)" && $(MAKE) static_lib && cd "$(PROJECT_PATH)";) .PHONY: clean_deps clean_deps: - @$(foreach lib,$(PROJECT_DEPEND_LOCAL), cd "$(ROOT_PROJECT_DEPENDENCY_PATH)/lib$(lib)" && $(MAKE) clean && cd "$(PROJECT_PATH)";) \ No newline at end of file + @$(foreach lib,$(PROJECT_DEPEND_LOCAL_DIR), cd "$(ROOT_PROJECT_DEPENDENCY_PATH)/$(lib)" && $(MAKE) clean && cd "$(PROJECT_PATH)";) \ No newline at end of file diff --git a/src/AssetProcess.cpp b/src/AssetProcess.cpp index fcca0ce..1a9bf53 100644 --- a/src/AssetProcess.cpp +++ b/src/AssetProcess.cpp @@ -1,115 +1,103 @@ -#include -#include -#include -#include -#include #include "AssetProcess.h" +#include "utils.h" -AssetProcess::AssetProcess() : +nstool::AssetProcess::AssetProcess() : mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false) { } -void AssetProcess::process() +void nstool::AssetProcess::process() { importHeader(); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) displayHeader(); processSections(); -} +} -void AssetProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::AssetProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void AssetProcess::setCliOutputMode(CliOutputMode type) +void nstool::AssetProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void AssetProcess::setVerifyMode(bool verify) +void nstool::AssetProcess::setVerifyMode(bool verify) { mVerify = verify; } -void AssetProcess::setListFs(bool list) +void nstool::AssetProcess::setListFs(bool list) { mRomfs.setListFs(list); } -void AssetProcess::setIconExtractPath(const std::string& path) +void nstool::AssetProcess::setIconExtractPath(const std::string& path) { mIconExtractPath = path; } -void AssetProcess::setNacpExtractPath(const std::string& path) +void nstool::AssetProcess::setNacpExtractPath(const std::string& path) { mNacpExtractPath = path; } -void AssetProcess::setRomfsExtractPath(const std::string& path) +void nstool::AssetProcess::setRomfsExtractPath(const std::string& path) { mRomfs.setExtractPath(path); } -void AssetProcess::importHeader() +void nstool::AssetProcess::importHeader() { - fnd::Vec scratch; + tc::ByteData scratch; - if (*mFile == nullptr) + if (mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } - if ((*mFile)->size() < sizeof(nn::hac::sAssetHeader)) + size_t file_size = tc::io::IOUtil::castInt64ToSize(mFile->length()); + + if (file_size < sizeof(nn::hac::sAssetHeader)) { - throw fnd::Exception(kModuleName, "Corrupt ASET: file too small"); + throw tc::Exception(kModuleName, "Corrupt ASET: file too small"); } scratch.alloc(sizeof(nn::hac::sAssetHeader)); - (*mFile)->read(scratch.data(), 0, scratch.size()); + mFile->read(scratch.data(), 0, scratch.size()); mHdr.fromBytes(scratch.data(), scratch.size()); } -void AssetProcess::processSections() +void nstool::AssetProcess::processSections() { - if (mHdr.getIconInfo().size > 0 && mIconExtractPath.isSet) + size_t file_size = tc::io::IOUtil::castInt64ToSize(mFile->length()); + + if (mHdr.getIconInfo().size > 0 && mIconExtractPath.isSet()) { - if ((mHdr.getIconInfo().size + mHdr.getIconInfo().offset) > (*mFile)->size()) - throw fnd::Exception(kModuleName, "ASET geometry for icon beyond file size"); + if ((mHdr.getIconInfo().size + mHdr.getIconInfo().offset) > file_size) + throw tc::Exception(kModuleName, "ASET geometry for icon beyond file size"); - fnd::SimpleFile outfile(mIconExtractPath.var, fnd::SimpleFile::Create); - fnd::Vec cache; - - cache.alloc(mHdr.getIconInfo().size); - (*mFile)->read(cache.data(), mHdr.getIconInfo().offset, cache.size()); - outfile.write(cache.data(), cache.size()); - outfile.close(); + writeSubStreamToFile(mFile, tc::io::IOUtil::castSizeToInt64(mHdr.getIconInfo().offset), tc::io::IOUtil::castSizeToInt64(mHdr.getIconInfo().size), mIconExtractPath.get()); } if (mHdr.getNacpInfo().size > 0) { - if ((mHdr.getNacpInfo().size + mHdr.getNacpInfo().offset) > (*mFile)->size()) - throw fnd::Exception(kModuleName, "ASET geometry for nacp beyond file size"); + if ((mHdr.getNacpInfo().size + mHdr.getNacpInfo().offset) > file_size) + throw tc::Exception(kModuleName, "ASET geometry for nacp beyond file size"); - if (mNacpExtractPath.isSet) + if (mNacpExtractPath.isSet()) { - fnd::SimpleFile outfile(mNacpExtractPath.var, fnd::SimpleFile::Create); - fnd::Vec cache; - - cache.alloc(mHdr.getNacpInfo().size); - (*mFile)->read(cache.data(), mHdr.getNacpInfo().offset, cache.size()); - outfile.write(cache.data(), cache.size()); - outfile.close(); + writeSubStreamToFile(mFile, tc::io::IOUtil::castSizeToInt64(mHdr.getNacpInfo().offset), tc::io::IOUtil::castSizeToInt64(mHdr.getNacpInfo().size), mNacpExtractPath.get()); } - mNacp.setInputFile(new fnd::OffsetAdjustedIFile(mFile, mHdr.getNacpInfo().offset, mHdr.getNacpInfo().size)); + mNacp.setInputFile(std::make_shared(mFile, tc::io::IOUtil::castSizeToInt64(mHdr.getNacpInfo().offset), tc::io::IOUtil::castSizeToInt64(mHdr.getNacpInfo().size))); mNacp.setCliOutputMode(mCliOutputMode); mNacp.setVerifyMode(mVerify); @@ -118,10 +106,10 @@ void AssetProcess::processSections() if (mHdr.getRomfsInfo().size > 0) { - if ((mHdr.getRomfsInfo().size + mHdr.getRomfsInfo().offset) > (*mFile)->size()) - throw fnd::Exception(kModuleName, "ASET geometry for romfs beyond file size"); + if ((mHdr.getRomfsInfo().size + mHdr.getRomfsInfo().offset) > file_size) + throw tc::Exception(kModuleName, "ASET geometry for romfs beyond file size"); - mRomfs.setInputFile(new fnd::OffsetAdjustedIFile(mFile, mHdr.getRomfsInfo().offset, mHdr.getRomfsInfo().size)); + mRomfs.setInputFile(std::make_shared(mFile, tc::io::IOUtil::castSizeToInt64(mHdr.getRomfsInfo().offset), tc::io::IOUtil::castSizeToInt64(mHdr.getRomfsInfo().size))); mRomfs.setCliOutputMode(mCliOutputMode); mRomfs.setVerifyMode(mVerify); @@ -129,9 +117,9 @@ void AssetProcess::processSections() } } -void AssetProcess::displayHeader() +void nstool::AssetProcess::displayHeader() { - if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + if (mCliOutputMode.show_layout) { std::cout << "[ASET Header]" << std::endl; std::cout << " Icon:" << std::endl; diff --git a/src/AssetProcess.h b/src/AssetProcess.h index 7364d15..262de5a 100644 --- a/src/AssetProcess.h +++ b/src/AssetProcess.h @@ -1,13 +1,11 @@ #pragma once -#include -#include -#include -#include -#include +#include "types.h" #include "NacpProcess.h" #include "RomfsProcess.h" -#include "common.h" +#include + +namespace nstool { class AssetProcess { @@ -16,7 +14,7 @@ public: void process(); - void setInputFile(const fnd::SharedPtr& file); + void setInputFile(const std::shared_ptr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -30,12 +28,12 @@ public: private: const std::string kModuleName = "AssetProcess"; - fnd::SharedPtr mFile; + std::shared_ptr mFile; CliOutputMode mCliOutputMode; bool mVerify; - sOptional mIconExtractPath; - sOptional mNacpExtractPath; + tc::Optional mIconExtractPath; + tc::Optional mNacpExtractPath; nn::hac::AssetHeader mHdr; NacpProcess mNacp; @@ -44,4 +42,6 @@ private: void importHeader(); void processSections(); void displayHeader(); -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/CnmtProcess.cpp b/src/CnmtProcess.cpp index 8e8c4ed..5849c16 100644 --- a/src/CnmtProcess.cpp +++ b/src/CnmtProcess.cpp @@ -3,53 +3,50 @@ #include #include -#include -#include - #include -CnmtProcess::CnmtProcess() : +nstool::CnmtProcess::CnmtProcess() : mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false) { } -void CnmtProcess::process() +void nstool::CnmtProcess::process() { importCnmt(); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) displayCnmt(); } -void CnmtProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::CnmtProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void CnmtProcess::setCliOutputMode(CliOutputMode type) +void nstool::CnmtProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void CnmtProcess::setVerifyMode(bool verify) +void nstool::CnmtProcess::setVerifyMode(bool verify) { mVerify = verify; } -const nn::hac::ContentMeta& CnmtProcess::getContentMeta() const +const nn::hac::ContentMeta& nstool::CnmtProcess::getContentMeta() const { return mCnmt; } -void CnmtProcess::importCnmt() +void nstool::CnmtProcess::importCnmt() { - fnd::Vec scratch; + tc::ByteData scratch; if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } scratch.alloc((*mFile)->size()); @@ -58,7 +55,7 @@ void CnmtProcess::importCnmt() mCnmt.fromBytes(scratch.data(), scratch.size()); } -void CnmtProcess::displayCnmt() +void nstool::CnmtProcess::displayCnmt() { std::cout << "[ContentMeta]" << std::endl; std::cout << " TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getTitleId() << std::endl; @@ -178,7 +175,7 @@ void CnmtProcess::displayCnmt() std::cout << " Digest: " << fnd::SimpleTextOutput::arrayToString(mCnmt.getDigest().data(), mCnmt.getDigest().size(), false, "") << std::endl; } -void CnmtProcess::displayContentMetaInfo(const nn::hac::ContentMetaInfo& content_meta_info, const std::string& prefix) +void nstool::CnmtProcess::displayContentMetaInfo(const nn::hac::ContentMetaInfo& content_meta_info, const std::string& prefix) { std::cout << prefix << "Id: 0x" << std::hex << std::setw(16) << std::setfill('0') << content_meta_info.getTitleId() << std::endl; std::cout << prefix << "Version: " << nn::hac::ContentMetaUtil::getVersionAsString(content_meta_info.getTitleVersion()) << " (v" << std::dec << content_meta_info.getTitleVersion() << ")"<< std::endl; @@ -210,7 +207,7 @@ void CnmtProcess::displayContentMetaInfo(const nn::hac::ContentMetaInfo& content } } -void CnmtProcess::displayContentMetaInfoList(const std::vector& content_meta_info_list, const std::string& prefix) +void nstool::CnmtProcess::displayContentMetaInfoList(const std::vector& content_meta_info_list, const std::string& prefix) { for (size_t i = 0; i < content_meta_info_list.size(); i++) { diff --git a/src/CnmtProcess.h b/src/CnmtProcess.h index 2353f68..99c9462 100644 --- a/src/CnmtProcess.h +++ b/src/CnmtProcess.h @@ -1,11 +1,9 @@ #pragma once -#include -#include -#include -#include +#include "types.h" + #include -#include "common.h" +namespace nstool { class CnmtProcess { @@ -14,7 +12,7 @@ public: void process(); - void setInputFile(const fnd::SharedPtr& file); + void setInputFile(const std::shared_ptr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -23,7 +21,7 @@ public: private: const std::string kModuleName = "CnmtProcess"; - fnd::SharedPtr mFile; + std::shared_ptr mFile; CliOutputMode mCliOutputMode; bool mVerify; @@ -34,4 +32,6 @@ private: void displayContentMetaInfo(const nn::hac::ContentMetaInfo& content_meta_info, const std::string& prefix); void displayContentMetaInfoList(const std::vector& content_meta_info_list, const std::string& prefix); -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/CompressedArchiveIFile.cpp b/src/CompressedArchiveIFile.cpp deleted file mode 100644 index 4467bfc..0000000 --- a/src/CompressedArchiveIFile.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "CompressedArchiveIFile.h" -#include - -#include - -CompressedArchiveIFile::CompressedArchiveIFile(const fnd::SharedPtr& base_file, size_t compression_meta_offset) : - mFile(base_file), - mCompEntries(), - mLogicalFileSize(0), - mCacheCapacity(nn::hac::compression::kRomfsBlockSize), - mCurrentCacheDataSize(0), - mCache(std::shared_ptr(new byte_t[mCacheCapacity])), - mScratch(std::shared_ptr(new byte_t[mCacheCapacity])) -{ - // determine and check the compression metadata size - size_t compression_meta_size = (*mFile)->size() - compression_meta_offset; - if (compression_meta_size % sizeof(nn::hac::sCompressionEntry)) - { - fnd::Exception(kModuleName, "Invalid compression meta size"); - } - - // import raw metadata - std::shared_ptr entries_raw = std::shared_ptr(new byte_t[compression_meta_size]); - (*mFile)->read(entries_raw.get(), compression_meta_offset, compression_meta_size); - - // process metadata entries - nn::hac::sCompressionEntry* entries = (nn::hac::sCompressionEntry*)entries_raw.get(); - for (size_t idx = 0, num = compression_meta_size / sizeof(nn::hac::sCompressionEntry); idx < num; idx++) - { - if (idx == 0) - { - if (entries[idx].physical_offset.get() != 0x0) - throw fnd::Exception(kModuleName, "Entry 0 had a non-zero physical offset"); - if (entries[idx].virtual_offset.get() != 0x0) - throw fnd::Exception(kModuleName, "Entry 0 had a non-zero virtual offset"); - } - else - { - if (entries[idx].physical_offset.get() != align(entries[idx - 1].physical_offset.get() + entries[idx - 1].physical_size.get(), nn::hac::compression::kRomfsBlockAlign)) - throw fnd::Exception(kModuleName, "Entry was not physically aligned with previous entry"); - if (entries[idx].virtual_offset.get() <= entries[idx - 1].virtual_offset.get()) - throw fnd::Exception(kModuleName, "Entry was not virtually aligned with previous entry"); - - // set previous entry virtual_size = this->virtual_offset - prev->virtual_offset; - mCompEntries[mCompEntries.size() - 1].virtual_size = uint32_t(entries[idx].virtual_offset.get() - mCompEntries[mCompEntries.size() - 1].virtual_offset); - } - - if (entries[idx].physical_size.get() > nn::hac::compression::kRomfsBlockSize) - throw fnd::Exception(kModuleName, "Entry physical size was too large"); - - switch ((nn::hac::compression::CompressionType)entries[idx].compression_type) - { - case (nn::hac::compression::CompressionType::None): - case (nn::hac::compression::CompressionType::Lz4): - break; - default: - throw fnd::Exception(kModuleName, "Unsupported CompressionType"); - } - - mCompEntries.push_back({(nn::hac::compression::CompressionType)entries[idx].compression_type, entries[idx].virtual_offset.get(), 0, entries[idx].physical_offset.get(), entries[idx].physical_size.get()}); - } - - // determine logical file size and final entry size - importEntryDataToCache(mCompEntries.size() - 1); - mCompEntries[mCurrentEntryIndex].virtual_size = mCurrentCacheDataSize; - mLogicalFileSize = mCompEntries[mCurrentEntryIndex].virtual_offset + mCompEntries[mCurrentEntryIndex].virtual_size; - - /* - for (auto itr = mCompEntries.begin(); itr != mCompEntries.end(); itr++) - { - std::cout << "entry " << std::endl; - std::cout << " type: " << (uint32_t)itr->compression_type << std::endl; - std::cout << " phys_addr: 0x" << std::hex << itr->physical_offset << std::endl; - std::cout << " phys_size: 0x" << std::hex << itr->physical_size << std::endl; - std::cout << " virt_addr: 0x" << std::hex << itr->virtual_offset << std::endl; - std::cout << " virt_size: 0x" << std::hex << itr->virtual_size << std::endl; - } - - std::cout << "logical size: 0x" << std::hex << mLogicalFileSize << std::endl; - */ -} - -size_t CompressedArchiveIFile::size() -{ - return mLogicalFileSize; -} - -void CompressedArchiveIFile::seek(size_t offset) -{ - mLogicalOffset = std::min(offset, mLogicalFileSize); -} - -void CompressedArchiveIFile::read(byte_t* out, size_t len) -{ - // limit len to the end of the logical file - len = std::min(len, mLogicalFileSize - mLogicalOffset); - - for (size_t pos = 0, entry_index = getEntryIndexForLogicalOffset(mLogicalOffset); pos < len; entry_index++) - { - // importing entry into cache (this does nothing if the entry is already imported) - importEntryDataToCache(entry_index); - - // write padding if required - if (mCompEntries[entry_index].virtual_size > mCurrentCacheDataSize) - { - memset(mCache.get() + mCurrentCacheDataSize, 0, mCompEntries[entry_index].virtual_size - mCurrentCacheDataSize); - } - - // determine subset of cache to copy out - size_t read_offset = mLogicalOffset - (size_t)mCompEntries[entry_index].virtual_offset; - size_t read_size = std::min(len, (size_t)mCompEntries[entry_index].virtual_size - read_offset); - - memcpy(out + pos, mCache.get() + read_offset, read_size); - - // update position/logical offset - pos += read_size; - mLogicalOffset += read_size; - } -} - -void CompressedArchiveIFile::read(byte_t* out, size_t offset, size_t len) -{ - seek(offset); - read(out, len); -} - -void CompressedArchiveIFile::write(const byte_t* out, size_t len) -{ - throw fnd::Exception(kModuleName, "write() not supported"); -} - -void CompressedArchiveIFile::write(const byte_t* out, size_t offset, size_t len) -{ - throw fnd::Exception(kModuleName, "write() not supported"); -} - -void CompressedArchiveIFile::importEntryDataToCache(size_t entry_index) -{ - // return if entry already imported - if (mCurrentEntryIndex == entry_index && mCurrentCacheDataSize != 0) - return; - - // save index - mCurrentEntryIndex = entry_index; - - // reference entry - CompressionEntry& entry = mCompEntries[mCurrentEntryIndex]; - - if (entry.compression_type == nn::hac::compression::CompressionType::None) - { - (*mFile)->read(mCache.get(), entry.physical_offset, entry.physical_size); - mCurrentCacheDataSize = entry.physical_size; - } - else if (entry.compression_type == nn::hac::compression::CompressionType::Lz4) - { - (*mFile)->read(mScratch.get(), entry.physical_offset, entry.physical_size); - - mCurrentCacheDataSize = 0; - fnd::lz4::decompressData(mScratch.get(), entry.physical_size, mCache.get(), uint32_t(mCacheCapacity), mCurrentCacheDataSize); - - if (mCurrentCacheDataSize == 0) - { - throw fnd::Exception(kModuleName, "Decompression of final block failed"); - } - } -} - -size_t CompressedArchiveIFile::getEntryIndexForLogicalOffset(size_t logical_offset) -{ - // rule out bad offset - if (logical_offset > mLogicalFileSize) - throw fnd::Exception(kModuleName, "illegal logical offset"); - - size_t entry_index = 0; - - // try the current comp entry - if (mCompEntries[mCurrentEntryIndex].virtual_offset <= logical_offset && \ - mCompEntries[mCurrentEntryIndex].virtual_offset + mCompEntries[mCurrentEntryIndex].virtual_size >= logical_offset) - { - entry_index = mCurrentEntryIndex; - } - else - { - for (size_t index = 0; index < mCompEntries.size(); index++) - { - if (mCompEntries[index].virtual_offset <= logical_offset && \ - mCompEntries[index].virtual_offset + mCompEntries[index].virtual_size >= logical_offset) - { - entry_index = index; - } - } - } - - return entry_index; -} \ No newline at end of file diff --git a/src/CompressedArchiveIFile.h b/src/CompressedArchiveIFile.h deleted file mode 100644 index 795bb49..0000000 --- a/src/CompressedArchiveIFile.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -class CompressedArchiveIFile : public fnd::IFile -{ -public: - CompressedArchiveIFile(const fnd::SharedPtr& file, size_t compression_meta_offset); - - size_t size(); - void seek(size_t offset); - void read(byte_t* out, size_t len); - void read(byte_t* out, size_t offset, size_t len); - void write(const byte_t* out, size_t len); - void write(const byte_t* out, size_t offset, size_t len); -private: - const std::string kModuleName = "CompressedArchiveIFile"; - std::stringstream mErrorSs; - - struct CompressionEntry - { - nn::hac::compression::CompressionType compression_type; - uint64_t virtual_offset; - uint32_t virtual_size; - uint64_t physical_offset; - uint32_t physical_size; - }; - - // raw data - fnd::SharedPtr mFile; - - // compression metadata - std::vector mCompEntries; - size_t mLogicalFileSize; - size_t mLogicalOffset; - - // cached decompressed entry - size_t mCacheCapacity; // capacity - size_t mCurrentEntryIndex; // index of entry currently associated with the cache - uint32_t mCurrentCacheDataSize; // size of data currently in cache - std::shared_ptr mCache; // where decompressed data resides - std::shared_ptr mScratch; // same size as cache, but is used for storing data pre-compression - - // this will import entry to cache - void importEntryDataToCache(size_t entry_index); - size_t getEntryIndexForLogicalOffset(size_t logical_offset); -}; \ No newline at end of file diff --git a/src/ElfSymbolParser.cpp b/src/ElfSymbolParser.cpp index b57c9f2..8bb66dd 100644 --- a/src/ElfSymbolParser.cpp +++ b/src/ElfSymbolParser.cpp @@ -1,26 +1,26 @@ #include "ElfSymbolParser.h" -ElfSymbolParser::ElfSymbolParser() +nstool::ElfSymbolParser::ElfSymbolParser() { mSymbolList.clear(); } -void ElfSymbolParser::operator=(const ElfSymbolParser& other) +void nstool::ElfSymbolParser::operator=(const ElfSymbolParser& other) { mSymbolList = other.mSymbolList; } -bool ElfSymbolParser::operator==(const ElfSymbolParser& other) const +bool nstool::ElfSymbolParser::operator==(const ElfSymbolParser& other) const { return mSymbolList == other.mSymbolList; } -bool ElfSymbolParser::operator!=(const ElfSymbolParser& other) const +bool nstool::ElfSymbolParser::operator!=(const ElfSymbolParser& other) const { return !(*this == other); } -void ElfSymbolParser::parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit) +void nstool::ElfSymbolParser::parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit) { size_t dynSymSize = is64Bit ? sizeof(fnd::Elf64_Sym) : sizeof(fnd::Elf32_Sym); @@ -46,17 +46,17 @@ void ElfSymbolParser::parseData(const byte_t *dyn_sym, size_t dyn_sym_size, cons if (name_pos >= dyn_str_size) { - throw fnd::Exception(kModuleName, "Out of bounds symbol name offset"); + throw tc::Exception(kModuleName, "Out of bounds symbol name offset"); } //for (; dyn_str[name_pos] == 0x00 && name_pos < dyn_str_size; name_pos++); symbol.name = std::string((char*)&dyn_str[name_pos]); - mSymbolList.addElement(symbol); + mSymbolList.push_back(symbol); } } -const fnd::List& ElfSymbolParser::getSymbolList() const +const std::vector& nstool::ElfSymbolParser::getSymbolList() const { return mSymbolList; } \ No newline at end of file diff --git a/src/ElfSymbolParser.h b/src/ElfSymbolParser.h index e06bdf3..ea8bedb 100644 --- a/src/ElfSymbolParser.h +++ b/src/ElfSymbolParser.h @@ -1,7 +1,8 @@ #pragma once -#include -#include -#include +#include "types.h" +#include "elf.h" + +namespace nstool { class ElfSymbolParser { @@ -40,10 +41,12 @@ public: void parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit); - const fnd::List& getSymbolList() const; + const std::vector& getSymbolList() const; private: const std::string kModuleName = "ElfSymbolParser"; // data - fnd::List mSymbolList; -}; \ No newline at end of file + std::vector mSymbolList; +}; + +} \ No newline at end of file diff --git a/src/EsTikProcess.cpp b/src/EsTikProcess.cpp index 41da96c..561b6fb 100644 --- a/src/EsTikProcess.cpp +++ b/src/EsTikProcess.cpp @@ -8,57 +8,57 @@ -EsTikProcess::EsTikProcess() : +nstool::EsTikProcess::EsTikProcess() : mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false) { } -void EsTikProcess::process() +void nstool::EsTikProcess::process() { importTicket(); if (mVerify) verifyTicket(); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) displayTicket(); } -void EsTikProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::EsTikProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void EsTikProcess::setKeyCfg(const KeyConfiguration& keycfg) +void nstool::EsTikProcess::setKeyCfg(const KeyBag& keycfg) { mKeyCfg = keycfg; } -void EsTikProcess::setCertificateChain(const fnd::List>& certs) +void nstool::EsTikProcess::setCertificateChain(const std::vector>& certs) { mCerts = certs; } -void EsTikProcess::setCliOutputMode(CliOutputMode mode) +void nstool::EsTikProcess::setCliOutputMode(CliOutputMode mode) { mCliOutputMode = mode; } -void EsTikProcess::setVerifyMode(bool verify) +void nstool::EsTikProcess::setVerifyMode(bool verify) { mVerify = verify; } -void EsTikProcess::importTicket() +void nstool::EsTikProcess::importTicket() { - fnd::Vec scratch; + tc::ByteData scratch; if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } scratch.alloc((*mFile)->size()); @@ -66,10 +66,10 @@ void EsTikProcess::importTicket() mTik.fromBytes(scratch.data(), scratch.size()); } -void EsTikProcess::verifyTicket() +void nstool::EsTikProcess::verifyTicket() { PkiValidator pki_validator; - fnd::Vec tik_hash; + tc::ByteData tik_hash; switch (nn::pki::sign::getHashAlgo(mTik.getSignature().getSignType())) { @@ -89,13 +89,13 @@ void EsTikProcess::verifyTicket() pki_validator.addCertificates(mCerts); pki_validator.validateSignature(mTik.getBody().getIssuer(), mTik.getSignature().getSignType(), mTik.getSignature().getSignature(), tik_hash); } - catch (const fnd::Exception& e) + catch (const tc::Exception& e) { std::cout << "[WARNING] Ticket signature could not be validated (" << e.error() << ")" << std::endl; } } -void EsTikProcess::displayTicket() +void nstool::EsTikProcess::displayTicket() { #define _SPLIT_VER(ver) (uint32_t)((ver>>10) & 0x3f) << "." << (uint32_t)((ver>>4) & 0x3f) << "." << (uint32_t)((ver>>0) & 0xf) @@ -104,7 +104,7 @@ void EsTikProcess::displayTicket() std::cout << "[ES Ticket]" << std::endl; std::cout << " SignType: " << getSignTypeStr(mTik.getSignature().getSignType()); - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) std::cout << " (0x" << std::hex << mTik.getSignature().getSignType() << ")"; std::cout << std::endl; @@ -129,7 +129,7 @@ void EsTikProcess::displayTicket() } std::cout << " Version: v" << _SPLIT_VER(body.getTicketVersion()); - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) std::cout << " (" << (uint32_t)body.getTicketVersion() << ")"; std::cout << std::endl; @@ -144,16 +144,16 @@ void EsTikProcess::displayTicket() } } - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) { std::cout << " Reserved Region:" << std::endl; fnd::SimpleTextOutput::hexDump(body.getReservedRegion(), 8, 0x10, 4); } - if (body.getTicketId() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (body.getTicketId() != 0 || mCliOutputMode.show_extended_info) std::cout << " TicketId: 0x" << std::hex << std::setw(16) << std::setfill('0') << body.getTicketId() << std::endl; - if (body.getDeviceId() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (body.getDeviceId() != 0 || mCliOutputMode.show_extended_info) std::cout << " DeviceId: 0x" << std::hex << std::setw(16) << std::setfill('0') << body.getDeviceId() << std::endl; std::cout << " RightsId: " << std::endl << " "; @@ -167,7 +167,7 @@ void EsTikProcess::displayTicket() #undef _SPLIT_VER } -const char* EsTikProcess::getSignTypeStr(uint32_t type) const +const char* nstool::EsTikProcess::getSignTypeStr(uint32_t type) const { const char* str = nullptr; switch(type) @@ -197,7 +197,7 @@ const char* EsTikProcess::getSignTypeStr(uint32_t type) const return str; } -const char* EsTikProcess::getTitleKeyPersonalisationStr(byte_t flag) const +const char* nstool::EsTikProcess::getTitleKeyPersonalisationStr(byte_t flag) const { const char* str = nullptr; switch(flag) @@ -215,7 +215,7 @@ const char* EsTikProcess::getTitleKeyPersonalisationStr(byte_t flag) const return str; } -const char* EsTikProcess::getLicenseTypeStr(byte_t flag) const +const char* nstool::EsTikProcess::getLicenseTypeStr(byte_t flag) const { const char* str = nullptr; switch(flag) @@ -245,7 +245,7 @@ const char* EsTikProcess::getLicenseTypeStr(byte_t flag) const return str; } -const char* EsTikProcess::getPropertyFlagStr(byte_t flag) const +const char* nstool::EsTikProcess::getPropertyFlagStr(byte_t flag) const { const char* str = nullptr; switch(flag) diff --git a/src/EsTikProcess.h b/src/EsTikProcess.h index cf3e36e..075759c 100644 --- a/src/EsTikProcess.h +++ b/src/EsTikProcess.h @@ -1,14 +1,12 @@ #pragma once -#include -#include -#include -#include -#include +#include "types.h" +#include "KeyBag.h" + #include #include #include -#include "KeyConfiguration.h" -#include "common.h" + +namespace nstool { class EsTikProcess { @@ -17,21 +15,21 @@ public: void process(); - void setInputFile(const fnd::SharedPtr& file); - void setKeyCfg(const KeyConfiguration& keycfg); - void setCertificateChain(const fnd::List>& certs); + void setInputFile(const std::shared_ptr& file); + void setKeyCfg(const KeyBag& keycfg); + void setCertificateChain(const std::vector>& certs); void setCliOutputMode(CliOutputMode mode); void setVerifyMode(bool verify); private: const std::string kModuleName = "EsTikProcess"; - fnd::SharedPtr mFile; - KeyConfiguration mKeyCfg; + std::shared_ptr mFile; + KeyBag mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; - fnd::List> mCerts; + std::vector> mCerts; nn::pki::SignedData mTik; @@ -42,4 +40,6 @@ private: const char* getTitleKeyPersonalisationStr(byte_t flag) const; const char* getLicenseTypeStr(byte_t flag) const; const char* getPropertyFlagStr(byte_t flag) const; -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/GameCardProcess.cpp b/src/GameCardProcess.cpp index b0cfb4a..d06a6ce 100644 --- a/src/GameCardProcess.cpp +++ b/src/GameCardProcess.cpp @@ -7,9 +7,9 @@ #include #include "GameCardProcess.h" -GameCardProcess::GameCardProcess() : +nstool::GameCardProcess::GameCardProcess() : mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false), mListFs(false), mProccessExtendedHeader(false), @@ -18,7 +18,7 @@ GameCardProcess::GameCardProcess() : { } -void GameCardProcess::process() +void nstool::GameCardProcess::process() { importHeader(); @@ -27,7 +27,7 @@ void GameCardProcess::process() validateXciSignature(); // display header - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) displayHeader(); // process root partition @@ -37,43 +37,43 @@ void GameCardProcess::process() processPartitionPfs(); } -void GameCardProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::GameCardProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void GameCardProcess::setKeyCfg(const KeyConfiguration& keycfg) +void nstool::GameCardProcess::setKeyCfg(const KeyBag& keycfg) { mKeyCfg = keycfg; } -void GameCardProcess::setCliOutputMode(CliOutputMode type) +void nstool::GameCardProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void GameCardProcess::setVerifyMode(bool verify) +void nstool::GameCardProcess::setVerifyMode(bool verify) { mVerify = verify; } -void GameCardProcess::setPartitionForExtract(const std::string& partition_name, const std::string& extract_path) +void nstool::GameCardProcess::setPartitionForExtract(const std::string& partition_name, const std::string& extract_path) { - mExtractInfo.addElement({partition_name, extract_path}); + mExtractInfo.push_back({partition_name, extract_path}); } -void GameCardProcess::setListFs(bool list_fs) +void nstool::GameCardProcess::setListFs(bool list_fs) { mListFs = list_fs; } -void GameCardProcess::importHeader() +void nstool::GameCardProcess::importHeader() { - fnd::Vec scratch; + tc::ByteData scratch; if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } // allocate memory for header @@ -95,7 +95,7 @@ void GameCardProcess::importHeader() } else { - throw fnd::Exception(kModuleName, "GameCard image did not have expected magic bytes"); + throw tc::Exception(kModuleName, "GameCard image did not have expected magic bytes"); } nn::hac::sGcHeader_Rsa2048Signed* hdr_ptr = (nn::hac::sGcHeader_Rsa2048Signed*)(scratch.data() + mGcHeaderOffset); @@ -107,7 +107,7 @@ void GameCardProcess::importHeader() memcpy(mHdrSignature, hdr_ptr->signature, fnd::rsa::kRsa2048Size); // decrypt extended header - fnd::aes::sAes128Key header_key; + KeyBag::aes128_key_t header_key; if (mKeyCfg.getXciHeaderKey(header_key)) { nn::hac::GameCardUtil::decryptXciHeader(&hdr_ptr->header, header_key.key); @@ -118,12 +118,12 @@ void GameCardProcess::importHeader() mHdr.fromBytes((byte_t*)&hdr_ptr->header, sizeof(nn::hac::sGcHeader)); } -void GameCardProcess::displayHeader() +void nstool::GameCardProcess::displayHeader() { std::cout << "[GameCard Header]" << std::endl; std::cout << " CardHeaderVersion: " << std::dec << (uint32_t)mHdr.getCardHeaderVersion() << std::endl; std::cout << " RomSize: " << nn::hac::GameCardUtil::getRomSizeAsString((nn::hac::gc::RomSize)mHdr.getRomSizeType()); - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) std::cout << " (0x" << std::hex << (uint32_t)mHdr.getRomSizeType() << ")"; std::cout << std::endl; std::cout << " PackageId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getPackageId() << std::endl; @@ -138,7 +138,7 @@ void GameCardProcess::displayHeader() } } } - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) { std::cout << " KekIndex: " << nn::hac::GameCardUtil::getKekIndexAsString((nn::hac::gc::KekIndex)mHdr.getKekIndex()) << " (" << std::dec << (uint32_t)mHdr.getKekIndex() << ")" << std::endl; std::cout << " TitleKeyDecIndex: " << std::dec << (uint32_t)mHdr.getTitleKeyDecIndex() << std::endl; @@ -147,7 +147,7 @@ void GameCardProcess::displayHeader() std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes, 0x10, true, ":") << std::endl; std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes+0x10, 0x10, true, ":") << std::endl; } - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) { std::cout << " Extended Header AesCbc IV:" << std::endl; std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), true, ":") << std::endl; @@ -155,7 +155,7 @@ void GameCardProcess::displayHeader() std::cout << " SelSec: 0x" << std::hex << mHdr.getSelSec() << std::endl; std::cout << " SelT1Key: 0x" << std::hex << mHdr.getSelT1Key() << std::endl; std::cout << " SelKey: 0x" << std::hex << mHdr.getSelKey() << std::endl; - if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + if (mCliOutputMode.show_layout) { std::cout << " RomAreaStartPage: 0x" << std::hex << mHdr.getRomAreaStartPage(); if (mHdr.getRomAreaStartPage() != (uint32_t)(-1)) @@ -180,7 +180,7 @@ void GameCardProcess::displayHeader() std::cout << " PartitionFs Header:" << std::endl; std::cout << " Offset: 0x" << std::hex << mHdr.getPartitionFsAddress() << std::endl; std::cout << " Size: 0x" << std::hex << mHdr.getPartitionFsSize() << std::endl; - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) { std::cout << " Hash:" << std::endl; std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes, 0x10, true, ":") << std::endl; @@ -208,9 +208,9 @@ void GameCardProcess::displayHeader() } } -bool GameCardProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash, bool use_salt, byte_t salt) +bool nstool::GameCardProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash, bool use_salt, byte_t salt) { - fnd::Vec scratch; + tc::ByteData scratch; fnd::sha::sSha256Hash calc_hash; if (use_salt) { @@ -228,12 +228,12 @@ bool GameCardProcess::validateRegionOfFile(size_t offset, size_t len, const byte return calc_hash.compare(test_hash); } -bool GameCardProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash) +bool nstool::GameCardProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash) { return validateRegionOfFile(offset, len, test_hash, false, 0); } -void GameCardProcess::validateXciSignature() +void nstool::GameCardProcess::validateXciSignature() { fnd::rsa::sRsa2048Key header_sign_key; @@ -244,7 +244,7 @@ void GameCardProcess::validateXciSignature() } } -void GameCardProcess::processRootPfs() +void nstool::GameCardProcess::processRootPfs() { if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize(), mHdr.getPartitionFsHash().bytes, mHdr.getCompatibilityType() != nn::hac::gc::COMPAT_GLOBAL, mHdr.getCompatibilityType()) == false) { @@ -258,9 +258,9 @@ void GameCardProcess::processRootPfs() mRootPfs.process(); } -void GameCardProcess::processPartitionPfs() +void nstool::GameCardProcess::processPartitionPfs() { - const fnd::List& rootPartitions = mRootPfs.getPfsHeader().getFileList(); + const std::vector& rootPartitions = mRootPfs.getPfsHeader().getFileList(); for (size_t i = 0; i < rootPartitions.size(); i++) { // this must be validated here because only the size of the root partiton header is known at verification time diff --git a/src/GameCardProcess.h b/src/GameCardProcess.h index b32ec0f..61243b7 100644 --- a/src/GameCardProcess.h +++ b/src/GameCardProcess.h @@ -1,14 +1,11 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include "KeyConfiguration.h" +#include "types.h" +#include "KeyBag.h" #include "PfsProcess.h" -#include "common.h" +#include + +namespace nstool { class GameCardProcess { @@ -18,8 +15,8 @@ public: void process(); // generic - void setInputFile(const fnd::SharedPtr& file); - void setKeyCfg(const KeyConfiguration& keycfg); + void setInputFile(const std::shared_ptr& file); + void setKeyCfg(const KeyBag& keycfg); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -31,8 +28,8 @@ private: const std::string kModuleName = "GameCardProcess"; const std::string kXciMountPointName = "gamecard:/"; - fnd::SharedPtr mFile; - KeyConfiguration mKeyCfg; + std::shared_ptr mFile; + KeyBag mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; bool mListFs; @@ -65,7 +62,7 @@ private: nn::hac::GameCardHeader mHdr; PfsProcess mRootPfs; - fnd::List mExtractInfo; + std::vector mExtractInfo; void importHeader(); void displayHeader(); @@ -74,4 +71,6 @@ private: void validateXciSignature(); void processRootPfs(); void processPartitionPfs(); -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/IniProcess.cpp b/src/IniProcess.cpp index d6b6af1..d976309 100644 --- a/src/IniProcess.cpp +++ b/src/IniProcess.cpp @@ -9,20 +9,20 @@ #include "KipProcess.h" -IniProcess::IniProcess() : +nstool::IniProcess::IniProcess() : mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false), mDoExtractKip(false), mKipExtractPath() { } -void IniProcess::process() +void nstool::IniProcess::process() { importHeader(); importKipList(); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) { displayHeader(); displayKipList(); @@ -33,39 +33,39 @@ void IniProcess::process() } } -void IniProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::IniProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void IniProcess::setCliOutputMode(CliOutputMode type) +void nstool::IniProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void IniProcess::setVerifyMode(bool verify) +void nstool::IniProcess::setVerifyMode(bool verify) { mVerify = verify; } -void IniProcess::setKipExtractPath(const std::string& path) +void nstool::IniProcess::setKipExtractPath(const std::string& path) { mDoExtractKip = true; mKipExtractPath = path; } -void IniProcess::importHeader() +void nstool::IniProcess::importHeader() { - fnd::Vec scratch; + tc::ByteData scratch; if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } if ((*mFile)->size() < sizeof(nn::hac::sIniHeader)) { - throw fnd::Exception(kModuleName, "Corrupt INI: file too small"); + throw tc::Exception(kModuleName, "Corrupt INI: file too small"); } scratch.alloc(sizeof(nn::hac::sIniHeader)); @@ -74,14 +74,14 @@ void IniProcess::importHeader() mHdr.fromBytes(scratch.data(), scratch.size()); } -void IniProcess::importKipList() +void nstool::IniProcess::importKipList() { // kip pos info size_t kip_pos = sizeof(nn::hac::sIniHeader); size_t kip_size = 0; // tmp data to determine size - fnd::Vec hdr_raw; + tc::ByteData hdr_raw; nn::hac::KernelInitialProcessHeader hdr; hdr_raw.alloc(sizeof(nn::hac::sKipHeader)); @@ -90,19 +90,19 @@ void IniProcess::importKipList() (*mFile)->read(hdr_raw.data(), kip_pos, hdr_raw.size()); hdr.fromBytes(hdr_raw.data(), hdr_raw.size()); kip_size = getKipSizeFromHeader(hdr); - mKipList.addElement(new fnd::OffsetAdjustedIFile(mFile, kip_pos, kip_size)); + mKipList.push_back(new fnd::OffsetAdjustedIFile(mFile, kip_pos, kip_size)); kip_pos += kip_size; } } -void IniProcess::displayHeader() +void nstool::IniProcess::displayHeader() { std::cout << "[INI Header]" << std::endl; std::cout << " Size: 0x" << std::hex << mHdr.getSize() << std::endl; std::cout << " KIP Num: " << std::dec << (uint32_t)mHdr.getKipNum() << std::endl; } -void IniProcess::displayKipList() +void nstool::IniProcess::displayKipList() { for (size_t i = 0; i < mKipList.size(); i++) { @@ -116,9 +116,9 @@ void IniProcess::displayKipList() } } -void IniProcess::extractKipList() +void nstool::IniProcess::extractKipList() { - fnd::Vec cache; + tc::ByteData cache; nn::hac::KernelInitialProcessHeader hdr; @@ -151,7 +151,7 @@ void IniProcess::extractKipList() // get kip file size out_size = (*mKipList[i])->size(); // extract kip - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) printf("extract=[%s]\n", out_path.c_str()); (*mKipList[i])->seek(0); @@ -164,7 +164,7 @@ void IniProcess::extractKipList() } } -size_t IniProcess::getKipSizeFromHeader(const nn::hac::KernelInitialProcessHeader& hdr) const +size_t nstool::IniProcess::getKipSizeFromHeader(const nn::hac::KernelInitialProcessHeader& hdr) const { return sizeof(nn::hac::sKipHeader) + hdr.getTextSegmentInfo().file_layout.size + hdr.getRoSegmentInfo().file_layout.size + hdr.getDataSegmentInfo().file_layout.size; } \ No newline at end of file diff --git a/src/IniProcess.h b/src/IniProcess.h index dbfad5e..365f715 100644 --- a/src/IniProcess.h +++ b/src/IniProcess.h @@ -1,14 +1,10 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include "types.h" + #include #include -#include "common.h" +namespace nstool { class IniProcess { @@ -17,7 +13,7 @@ public: void process(); - void setInputFile(const fnd::SharedPtr& file); + void setInputFile(const std::shared_ptr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -27,7 +23,7 @@ private: const std::string kKipExtention = ".kip"; const size_t kCacheSize = 0x10000; - fnd::SharedPtr mFile; + std::shared_ptr mFile; CliOutputMode mCliOutputMode; bool mVerify; @@ -35,7 +31,7 @@ private: std::string mKipExtractPath; nn::hac::IniHeader mHdr; - fnd::List> mKipList; + std::vector> mKipList; void importHeader(); void importKipList(); @@ -44,4 +40,6 @@ private: void extractKipList(); size_t getKipSizeFromHeader(const nn::hac::KernelInitialProcessHeader& hdr) const; -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/KeyBag.cpp b/src/KeyBag.cpp new file mode 100644 index 0000000..6e00cf0 --- /dev/null +++ b/src/KeyBag.cpp @@ -0,0 +1,568 @@ +#include "KeyBag.h" + +#include "util.h" +#include + +#include +#include + +#include +#include +#include +#include + +nstool::KeyBagInitializer::KeyBagInitializer(bool isDev, const tc::Optional& keyfile_path, const tc::Optional& tik_path, const tc::Optional& cert_path) +{ + if (keyfile_path.isSet()) + { + importBaseKeyFile(keyfile_path.get(), isDev); + } + if (cert_path.isSet()) + { + importCertificateChain(cert_path.get()); + } + if (tik_path.isSet()) + { + importTicket(tik_path.get()); + } +} + +void nstool::KeyBagInitializer::importBaseKeyFile(const tc::io::Path& keyfile_path, bool isDev) +{ + std::shared_ptr keyfile_stream = std::make_shared(tc::io::FileStream(keyfile_path, tc::io::FileMode::Open, tc::io::FileAccess::Read)); + + // import keyfile into a dictionary + std::map keyfile_dict; + processResFile(keyfile_stream, keyfile_dict); + + // sources for key derivation + std::map master_key; + tc::Optional package2_key_source; + tc::Optional ticket_titlekek_source; + std::array, 3> key_area_key_source; + tc::Optional aes_kek_generation_source; + tc::Optional aes_key_generation_source; + tc::Optional nca_header_kek_source; + tc::Optional nca_header_key_source; + tc::Optional pki_root_sign_key; + + // macros for importing + +#define _SAVE_AES128KEY(key_name, dst) \ + { \ + std::string key,val; \ + tc::ByteData dec_val; \ + aes128_key_t tmp_aes128_key; \ + key = (key_name); \ + val = keyfile_dict[key]; \ + if (val.empty() == false) { \ + dec_val = tc::cli::FormatUtil::hexStringToBytes(val); \ + if (dec_val.size() != tmp_aes128_key.size()) \ + throw tc::ArgumentException("nstool::KeyBagInitializer", "Key: \"" + key_name + "\" has incorrect length"); \ + memcpy(tmp_aes128_key.data(), dec_val.data(), tmp_aes128_key.size()); \ + (dst) = tmp_aes128_key; \ + } \ + } + +#define _SAVE_AES128XTSKEY(key_name, dst) \ + { \ + std::string key,val; \ + tc::ByteData dec_val; \ + aes128_xtskey_t tmp_aes128_xtskey; \ + key = (key_name); \ + val = keyfile_dict[key]; \ + if (val.empty() == false) { \ + dec_val = tc::cli::FormatUtil::hexStringToBytes(val); \ + if (dec_val.size() != sizeof(tmp_aes128_xtskey)) \ + throw tc::ArgumentException("nstool::KeyBagInitializer", "Key: \"" + key_name + "\" has incorrect length"); \ + memcpy(tmp_aes128_xtskey[0].data(), dec_val.data(), tmp_aes128_xtskey[0].size()); \ + memcpy(tmp_aes128_xtskey[1].data(), dec_val.data()+tmp_aes128_xtskey[0].size(), tmp_aes128_xtskey[1].size()); \ + (dst) = tmp_aes128_xtskey; \ + } \ + } + +#define _SAVE_RSAKEY(key_name, dst, bitsize) \ + { \ + std::string key_mod,key_prv,val_mod,val_prv; \ + tc::ByteData dec_val; \ + rsa_key_t tmp_rsa_key; \ + key_mod = fmt::format("{:s}_modulus", (key_name)); \ + key_prv = fmt::format("{:s}_private", (key_name)); \ + val_mod = keyfile_dict[key_mod]; \ + val_prv = keyfile_dict[key_prv]; \ + if (val_mod.empty() == false) { \ + dec_val = tc::cli::FormatUtil::hexStringToBytes(val_mod); \ + if (dec_val.size() == (bitsize) >> 3) { \ + tmp_rsa_key.n = dec_val; \ + if (val_prv.empty() == false) { \ + dec_val = tc::cli::FormatUtil::hexStringToBytes(val_prv); \ + if (dec_val.size() == (bitsize) >> 3) { \ + tmp_rsa_key.d = dec_val; \ + (dst) = tc::crypto::RsaPrivateKey(tmp_rsa_key.n.data(), tmp_rsa_key.n.size(), tmp_rsa_key.d.data(), tmp_rsa_key.d.size()); \ + } \ + else { \ + fmt::print("[WARNING] Key: \"{:s}\" has incorrect length (was: {:d}, expected {:d})\n", key_prv, val_prv.size(), ((bitsize) >> 3)*2); \ + } \ + } \ + else { \ + (dst) = tc::crypto::RsaPublicKey(tmp_rsa_key.n.data(), tmp_rsa_key.n.size()); \ + } \ + } \ + else {\ + fmt::print("[WARNING] Key: \"{:s}\" has incorrect length (was: {:d}, expected {:d})\n", key_mod, val_mod.size(), ((bitsize) >> 3)*2); \ + } \ + } \ + } + + // keynames + enum NameVariantIndex + { + NNTOOLS, + LEGACY_HACTOOL, + LEGACY_0 + }; + + static const size_t kNameVariantNum = 3; + + std::vector kMasterBase = { "master" }; + std::vector kPkg1Base = { "package1" }; + std::vector kPkg2Base = { "package2" }; + std::vector kXciHeaderBase = { "xci_header" }; + std::vector kContentArchiveHeaderBase = { "nca_header", "header" }; + std::vector kAcidBase = { "acid" }; + std::vector kNrrCertBase = { "nrr_certificate" }; + std::vector kPkiRootBase = { "pki_root" }; + std::vector kTicketCommonKeyBase = { "ticket_commonkey", "titlekek" }; + std::vector kNcaKeyAreaEncKeyBase = { "nca_key_area_key", "key_area_key", "nca_body_keak" }; + std::vector kNcaKeyAreaEncKeyHwBase = { "nca_key_area_key_hw", "key_area_hw_key" }; + std::vector kKekGenBase = { "aes_kek_generation" }; + std::vector kKeyGenBase = { "aes_key_generation" }; + + // misc str + const std::string kKeyStr = "key"; + const std::string kKekStr = "kek"; + const std::string kSourceStr = "source"; + const std::string kSignKey = "sign_key"; + const std::string kModulusStr = "modulus"; + const std::string kPrivateStr = "private"; + std::vector kNcaKeyAreaKeyIndexStr = { "application", "ocean", "system" }; + + static const size_t kMasterKeyMax = 0x20; + /**/ + + // import key data + for (size_t name_idx = 0; name_idx < kNameVariantNum; name_idx++) + { + /* internal key sources */ + if (name_idx < kMasterBase.size()) + { + for (size_t mkey_rev = 0; mkey_rev < kMasterKeyMax; mkey_rev++) + { + // std::map master_key; + //fmt::print("{:s}_key_{:02x}\n", kMasterBase[name_idx], mkey_rev); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kMasterBase[name_idx], kKeyStr, mkey_rev), master_key[mkey_rev]); + } + } + + if (name_idx < kPkg2Base.size()) + { + // tc::Optional package2_key_source; + //fmt::print("{:s}_key_source\n", kPkg2Base[name_idx]); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:s}", kPkg2Base[name_idx], kKeyStr, kSourceStr), package2_key_source); + } + + if (name_idx < kTicketCommonKeyBase.size()) + { + // tc::Optional ticket_titlekek_source; + //fmt::print("{:s}_source\n", kTicketCommonKeyBase[name_idx]); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}", kTicketCommonKeyBase[name_idx], kSourceStr), ticket_titlekek_source); + } + + if (name_idx < kNcaKeyAreaEncKeyBase.size()) + { + // std::array, 3> key_area_key_source; + + for (size_t keak_idx = 0; keak_idx < kNcaKeyAreaKeyIndexStr.size(); keak_idx++) + { + //fmt::print("{:s}_{:s}_source\n", kNcaKeyAreaEncKeyBase[name_idx], kNcaKeyAreaKeyIndexStr[keak_idx]); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:s}", kNcaKeyAreaEncKeyBase[name_idx], kNcaKeyAreaKeyIndexStr[keak_idx], kSourceStr), key_area_key_source[keak_idx]); + } + } + + if (name_idx < kKekGenBase.size()) + { + // tc::Optional aes_kek_generation_source; + //fmt::print("{:s}_source\n", kKekGenBase[name_idx]); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}", kKekGenBase[name_idx], kSourceStr), aes_kek_generation_source); + } + + if (name_idx < kKeyGenBase.size()) + { + // tc::Optional aes_key_generation_source; + //fmt::print("{:s}_source\n", kKeyGenBase[name_idx]); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}", kKeyGenBase[name_idx], kSourceStr), aes_key_generation_source); + } + + if (name_idx < kContentArchiveHeaderBase.size()) + { + // tc::Optional nca_header_kek_source; + //fmt::print("{:s}_kek_source\n", kContentArchiveHeaderBase[name_idx]); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:s}", kContentArchiveHeaderBase[name_idx], kKekStr, kSourceStr), nca_header_kek_source); + } + + if (name_idx < kContentArchiveHeaderBase.size()) + { + // tc::Optional nca_header_key_source; + //fmt::print("{:s}_key_source\n", kContentArchiveHeaderBase[name_idx]); + _SAVE_AES128XTSKEY(fmt::format("{:s}_{:s}_{:s}", kContentArchiveHeaderBase[name_idx], kKeyStr, kSourceStr), nca_header_key_source); + } + + /* package1 */ + // package1_key_xx + if (name_idx < kPkg1Base.size()) + { + for (size_t mkey_rev = 0; mkey_rev < kMasterKeyMax; mkey_rev++) + { + //fmt::print("{:s}_key_{:02x}\n", kPkg1Base[name_idx], mkey_rev); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kPkg1Base[name_idx], kKeyStr, mkey_rev), pkg1_key[mkey_rev]); + } + } + + /* package2 */ + if (name_idx < kPkg2Base.size()) + { + // package2_key_xx + for (size_t mkey_rev = 0; mkey_rev < kMasterKeyMax; mkey_rev++) + { + //fmt::print("{:s}_key_{:02x}\n", kPkg2Base[name_idx], mkey_rev); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kPkg2Base[name_idx], kKeyStr, mkey_rev), pkg2_key[mkey_rev]); + } + + // package2_sign_key + //fmt::print("{:s}_{:s}_{:s}\n", kPkg2Base[name_idx], kSignKey, kPrivateStr); + //fmt::print("{:s}_{:s}_{:s}\n", kPkg2Base[name_idx], kSignKey, kModulusStr); + _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kPkg2Base[name_idx], kSignKey), pkg2_sign_key, 2048); + } + + /* eticket */ + // ticket common key + if (name_idx < kTicketCommonKeyBase.size()) + { + for (size_t mkey_rev = 0; mkey_rev < kMasterKeyMax; mkey_rev++) + { + //fmt::print("{:s}_{:02x}\n", kTicketCommonKeyBase[name_idx], mkey_rev); + _SAVE_AES128KEY(fmt::format("{:s}_{:02x}", kTicketCommonKeyBase[name_idx], mkey_rev), etik_common_key[mkey_rev]); + } + } + + /* NCA keys */ + if (name_idx < kContentArchiveHeaderBase.size()) + { + // nca header key + //fmt::print("{:s}_{:s}\n", kContentArchiveHeaderBase[name_idx], kKeyStr); + //_SAVE_AES128XTSKEY(fmt::format("{:s}_{:s}", kContentArchiveHeaderBase[name_idx], kKeyStr), nca_header_key); + + // nca header sign0 key (generations) + for (size_t mkey_rev = 0; mkey_rev < kMasterKeyMax; mkey_rev++) + { + //fmt::print("{:s}_{:s}_{:02x}_{:s}\n", kContentArchiveHeaderBase[name_idx], kSignKey, mkey_rev, kPrivateStr); + //fmt::print("{:s}_{:s}_{:02x}_{:s}\n", kContentArchiveHeaderBase[name_idx], kSignKey, mkey_rev, kModulusStr); + _SAVE_RSAKEY(fmt::format("{:s}_{:s}_{:02x}", kContentArchiveHeaderBase[name_idx], kSignKey, mkey_rev), nca_header_sign0_key[mkey_rev], 2048); + } + // nca header sign0 key (generation 0) + //fmt::print("{:s}_{:s}_{:s}\n", kContentArchiveHeaderBase[name_idx], kSignKey, kPrivateStr); + //fmt::print("{:s}_{:s}_{:s}\n", kContentArchiveHeaderBase[name_idx], kSignKey, kModulusStr); + _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kContentArchiveHeaderBase[name_idx], kSignKey), nca_header_sign0_key[0], 2048); + + } + + // nca body key (unused since prototype format) + + // nca key area encryption keys + if (name_idx < kNcaKeyAreaEncKeyBase.size()) + { + for (size_t mkey_rev = 0; mkey_rev < kMasterKeyMax; mkey_rev++) + { + for (size_t keak_idx = 0; keak_idx < kNcaKeyAreaKeyIndexStr.size(); keak_idx++) + { + //fmt::print("{:s}_{:s}_{:02x}\n", kNcaKeyAreaEncKeyBase[name_idx], kNcaKeyAreaKeyIndexStr[keak_idx], mkey_rev); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kNcaKeyAreaEncKeyBase[name_idx], kNcaKeyAreaKeyIndexStr[keak_idx], mkey_rev), nca_key_area_encryption_key[keak_idx][mkey_rev]); + } + } + } + // nca key area "hw" encryption keys + if (name_idx < kNcaKeyAreaEncKeyHwBase.size()) + { + for (size_t mkey_rev = 0; mkey_rev < kMasterKeyMax; mkey_rev++) + { + for (size_t keak_idx = 0; keak_idx < kNcaKeyAreaKeyIndexStr.size(); keak_idx++) + { + //fmt::print("{:s}_{:s}_{:02x}\n", kNcaKeyAreaEncKeyHwBase[name_idx], kNcaKeyAreaKeyIndexStr[keak_idx], mkey_rev); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kNcaKeyAreaEncKeyHwBase[name_idx], kNcaKeyAreaKeyIndexStr[keak_idx], mkey_rev), nca_key_area_encryption_key_hw[keak_idx][mkey_rev]); + } + } + } + + /* ACID */ + if (name_idx < kAcidBase.size()) + { + // acid sign key (generations) + for (size_t mkey_rev = 0; mkey_rev < kMasterKeyMax; mkey_rev++) + { + //fmt::print("{:s}_{:s}_{:02x}_{:s}\n", kAcidBase[name_idx], kSignKey, mkey_rev, kPrivateStr); + //fmt::print("{:s}_{:s}_{:02x}_{:s}\n", kAcidBase[name_idx], kSignKey, mkey_rev, kModulusStr); + _SAVE_RSAKEY(fmt::format("{:s}_{:s}_{:02x}", kAcidBase[name_idx], kSignKey, mkey_rev), acid_sign_key[mkey_rev], 2048); + } + // acid sign key (generation 0) + //fmt::print("{:s}_{:s}_{:s}\n", kAcidBase[name_idx], kSignKey, kPrivateStr); + //fmt::print("{:s}_{:s}_{:s}\n", kAcidBase[name_idx], kSignKey, kModulusStr); + _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kAcidBase[name_idx], kSignKey), acid_sign_key[0], 2048); + } + + /* NRR certificate */ + if (name_idx < kNrrCertBase.size()) + { + // nrr certificate sign key (generations) + for (size_t mkey_rev = 0; mkey_rev < kMasterKeyMax; mkey_rev++) + { + //fmt::print("{:s}_{:s}_{:02x}_{:s}\n", kNrrCertBase[name_idx], kSignKey, mkey_rev, kPrivateStr); + //fmt::print("{:s}_{:s}_{:02x}_{:s}\n", kNrrCertBase[name_idx], kSignKey, mkey_rev, kModulusStr); + _SAVE_RSAKEY(fmt::format("{:s}_{:s}_{:02x}", kNrrCertBase[name_idx], kSignKey, mkey_rev), nrr_certificate_sign_key[mkey_rev], 2048); + } + // nrr certificate sign key (generation 0) + //fmt::print("{:s}_{:s}_{:s}\n", kNrrCertBase[name_idx], kSignKey, kPrivateStr); + //fmt::print("{:s}_{:s}_{:s}\n", kNrrCertBase[name_idx], kSignKey, kModulusStr); + _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kNrrCertBase[name_idx], kSignKey), nrr_certificate_sign_key[0], 2048); + } + + /* XCI header */ + if (name_idx < kXciHeaderBase.size()) + { + // xci header key (based on index) + for (size_t kek_index = 0; kek_index < 8; kek_index++) + { + //fmt::print("{:s}_{:s}_{:02x}\n", kXciHeaderBase[name_idx], kKeyStr, kek_index); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kXciHeaderBase[name_idx], kKeyStr, kek_index), xci_header_key[kek_index]); + } + // xci header key (old lable) + //fmt::print("{:s}_{:s}\n", kXciHeaderBase[name_idx], kKeyStr); + _SAVE_AES128KEY(fmt::format("{:s}_{:s}", kXciHeaderBase[name_idx], kKeyStr), xci_header_key[isDev ? nn::hac::gc::KEK_DEV : nn::hac::gc::KEK_PROD]); + + // xci header sign key + //fmt::print("{:s}_{:s}_{:s}\n", kXciHeaderBase[name_idx], kSignKey, kPrivateStr); + //fmt::print("{:s}_{:s}_{:s}\n", kXciHeaderBase[name_idx], kSignKey, kModulusStr); + _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kXciHeaderBase[name_idx], kSignKey), xci_header_sign_key, 2048); + } + + /* PKI */ + if (name_idx < kPkiRootBase.size()) + { + // tc::Optional pki_root_sign_key; + //fmt::print("{:s}_{:s}_{:s}\n", kPkiRootBase[name_idx], kSignKey, kPrivateStr); + //fmt::print("{:s}_{:s}_{:s}\n", kPkiRootBase[name_idx], kSignKey, kModulusStr); + _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kPkiRootBase[name_idx], kSignKey), pki_root_sign_key, 4096); + } + + + } + +#undef _SAVE_RSAKEY +#undef _SAVE_AES128XTSKEY +#undef _SAVE_AES128KEY + + // Derive Keys + for (auto itr = master_key.begin(); itr != master_key.end(); itr++) + { + if (aes_kek_generation_source.isSet() && aes_key_generation_source.isSet()) + { + if (itr->first == 0 && nca_header_kek_source.isSet() && nca_header_key_source.isSet()) + { + if (nca_header_key.isNull()) + { + aes128_key_t nca_header_kek_tmp; + nn::hac::AesKeygen::generateKey(nca_header_kek_tmp.data(), aes_kek_generation_source.get().data(), nca_header_kek_source.get().data(), aes_key_generation_source.get().data(), itr->second.data()); + + aes128_xtskey_t nca_header_key_tmp; + nn::hac::AesKeygen::generateKey(nca_header_key_tmp[0].data(), nca_header_key_source.get()[0].data(), nca_header_kek_tmp.data()); + nn::hac::AesKeygen::generateKey(nca_header_key_tmp[1].data(), nca_header_key_source.get()[1].data(), nca_header_kek_tmp.data()); + + nca_header_key = nca_header_key_tmp; + } + } + + for (size_t keak_idx = 0; keak_idx < nn::hac::nca::kKeyAreaEncryptionKeyNum; keak_idx++) + { + if (key_area_key_source[keak_idx].isSet() && nca_key_area_encryption_key[keak_idx].find(itr->first) != nca_key_area_encryption_key[keak_idx].end()) + { + aes128_key_t nca_key_area_encryption_key_tmp; + nn::hac::AesKeygen::generateKey(nca_key_area_encryption_key_tmp.data(), aes_kek_generation_source.get().data(), key_area_key_source[keak_idx].get().data(), aes_key_generation_source.get().data(), itr->second.data()); + nca_key_area_encryption_key[keak_idx][itr->first] = nca_key_area_encryption_key_tmp; + } + } + } + if (ticket_titlekek_source.isSet() && etik_common_key.find(itr->first) == etik_common_key.end()) + { + aes128_key_t etik_common_key_tmp; + nn::hac::AesKeygen::generateKey(etik_common_key_tmp.data(), ticket_titlekek_source.get().data(), itr->second.data()); + etik_common_key[itr->first] = etik_common_key_tmp; + } + if (package2_key_source.isSet() && pkg2_key.find(itr->first) == pkg2_key.end()) + { + aes128_key_t pkg2_key_tmp; + nn::hac::AesKeygen::generateKey(pkg2_key_tmp.data(), package2_key_source.get().data(), itr->second.data()); + pkg2_key[itr->first] = pkg2_key_tmp; + } + } + + // Save PKI Root Key + if (pki_root_sign_key.isSet()) + { + broadon_rsa_signer["Root"] = { tc::ByteData(), pki_root_sign_key.get() }; + } +} + +void nstool::KeyBagInitializer::importTitleKeyFile(const tc::io::Path& keyfile_path) +{ + +} + +void nstool::KeyBagInitializer::importCertificateChain(const tc::io::Path& cert_path) +{ + // save file path string for error messages + std::string cert_path_str; + tc::io::PathUtil::pathToUnixUTF8(cert_path, cert_path_str); + + // open cert file + std::shared_ptr certfile_stream; + try { + certfile_stream = std::make_shared(tc::io::FileStream(cert_path, tc::io::FileMode::Open, tc::io::FileAccess::Read)); + } + catch (tc::io::FileNotFoundException& e) { + fmt::print("[WARNING] Failed to open certificate file \"{:s}\" ({:s}).\n", cert_path_str, e.error()); + return; + } + + // check size + size_t cert_raw_size = tc::io::IOUtil::castInt64ToSize(certfile_stream->length()); + if (cert_raw_size > 0x10000) + { + fmt::print("[WARNING] Certificate file \"{:s}\" was too large.\n", cert_path_str); + return; + } + + // import cert data + tc::ByteData cert_raw = tc::ByteData(cert_raw_size); + certfile_stream->seek(0, tc::io::SeekOrigin::Begin); + certfile_stream->read(cert_raw.data(), cert_raw.size()); + + nn::pki::SignedData cert; + try { + for (size_t f_pos = 0; f_pos < cert_raw.size(); f_pos += cert.getBytes().size()) + { + cert.fromBytes(cert_raw.data() + f_pos, cert_raw.size() - f_pos); + + std::string cert_identity = fmt::format("{:s}-{:s}", cert.getBody().getIssuer(), cert.getBody().getSubject()); + + switch (cert.getBody().getPublicKeyType()) { + case nn::pki::cert::PublicKeyType::RSA2048: + broadon_rsa_signer[cert_identity] = { cert.getBytes(), cert.getBody().getRsa2048PublicKey() }; + break; + case nn::pki::cert::PublicKeyType::RSA4096: + broadon_rsa_signer[cert_identity] = { cert.getBytes(), cert.getBody().getRsa4096PublicKey() }; + break; + case nn::pki::cert::PublicKeyType::ECDSA240: + fmt::print("[WARNING] Certificate {:s} will not be imported. ecc233 public keys are not supported yet.\n", cert_identity); + break; + default: + fmt::print("[WARNING] Certificate {:s} will not be imported. Unknown public key type.\n", cert_identity); + } + } + } + catch (tc::Exception& e) { + fmt::print("[WARNING] Certificate file \"{:s}\" is corrupted ({:s}).\n", cert_path_str, e.error()); + return; + } +} + +void nstool::KeyBagInitializer::importTicket(const tc::io::Path& tik_path) +{ + // save file path string for error messages + std::string tik_path_str; + tc::io::PathUtil::pathToUnixUTF8(tik_path, tik_path_str); + + // open cert file + std::shared_ptr tik_stream; + try { + tik_stream = std::make_shared(tc::io::FileStream(tik_path, tc::io::FileMode::Open, tc::io::FileAccess::Read)); + } + catch (tc::io::FileNotFoundException& e) { + fmt::print("[WARNING] Failed to open ticket \"{:s}\" ({:s}).\n", tik_path_str, e.error()); + return; + } + + // check size + size_t tik_raw_size = tc::io::IOUtil::castInt64ToSize(tik_stream->length()); + if (tik_raw_size > 0x10000) + { + fmt::print("[WARNING] Ticket \"{:s}\" was too large.\n", tik_path_str); + return; + } + + // import cert data + tc::ByteData tik_raw = tc::ByteData(tik_raw_size); + tik_stream->seek(0, tc::io::SeekOrigin::Begin); + tik_stream->read(tik_raw.data(), tik_raw.size()); + + nn::pki::SignedData tik; + try { + // de serialise ticket + tik.fromBytes(tik_raw.data(), tik_raw.size()); + + // save rights id + rights_id_t rights_id; + memcpy(rights_id.data(), tik.getBody().getRightsId(), rights_id.size()); + + // check ticket is not personalised + if (tik.getBody().getTitleKeyEncType() != nn::es::ticket::AES128_CBC) + { + fmt::print("[WARNING] Ticket \"{:s}\" will not be imported. Personalised tickets are not supported.\n", tc::cli::FormatUtil::formatBytesAsString(rights_id.data(), rights_id.size(), true, "")); + return; + } + + // save enc title key + aes128_key_t enc_title_key; + memcpy(enc_title_key.data(), tik.getBody().getEncTitleKey(), enc_title_key.size()); + + // save the encrypted title key as the fallback enc content key incase the ticket was malformed and workarounds to decrypt it in isolation fail + if (fallback_enc_content_key.isNull()) + { + fallback_enc_content_key = enc_title_key; + } + + // determine key to decrypt title key + byte_t common_key_index = tik.getBody().getCommonKeyId(); + + // work around for bad scene tickets where they don't set the commonkey id field (detect scene ticket with ffff.... signature) + if (common_key_index != rights_id[15] && tik.getSignature().getBytes()[0x00] == 0xff && tik.getSignature().getBytes()[0x01] == 0xff) + { + common_key_index = rights_id[15]; + } + if (etik_common_key.find(tik.getBody().getCommonKeyId()) == etik_common_key.end()) + { + fmt::print("[WARNING] Ticket \"{:s}\" will not be imported. Could not decrypt title key.\n", tc::cli::FormatUtil::formatBytesAsString(rights_id.data(), rights_id.size(), true, "")); + return; + } + + // decrypt title key + aes128_key_t dec_title_key; + tc::crypto::DecryptAes128Ecb(dec_title_key.data(), enc_title_key.data(), sizeof(aes128_key_t), etik_common_key[common_key_index].data(), sizeof(aes128_key_t)); + + // add to key dict + external_content_keys[rights_id] = dec_title_key; + + } + catch (tc::Exception& e) { + fmt::print("[WARNING] Ticket \"{:s}\" is corrupted ({:s}).\n", tik_path_str, e.error()); + return; + } +} \ No newline at end of file diff --git a/src/KeyBag.h b/src/KeyBag.h new file mode 100644 index 0000000..e319fb6 --- /dev/null +++ b/src/KeyBag.h @@ -0,0 +1,76 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nstool { + +struct KeyBag +{ + using aes128_key_t = nn::hac::detail::aes128_key_t; + using aes128_xtskey_t = nn::hac::detail::aes128_xtskey_t; + using rsa_key_t = tc::crypto::RsaKey; + using rights_id_t = nn::hac::detail::rights_id_t; + using key_generation_t = byte_t; + using broadon_issuer_t = std::string; + static const size_t kNcaKeakNum = nn::hac::nca::kKeyAreaEncryptionKeyNum; + + + // acid + std::map acid_sign_key; + + // pkg1 and pkg2 + std::map pkg1_key; + std::map pkg2_key; + tc::Optional pkg2_sign_key; + + // nca + tc::Optional nca_header_key; + std::map nca_header_sign0_key; + std::array, kNcaKeakNum> nca_key_area_encryption_key; + std::array, kNcaKeakNum> nca_key_area_encryption_key_hw; + + // external content keys (nca<->ticket) + std::map external_content_keys; + tc::Optional fallback_enc_content_key; // encrypted content key to be used when external_content_keys does not have the required content key (usually taken raw from ticket) + tc::Optional fallback_content_key; // content key to be used when external_content_keys does not have the required content key (usually already decrypted from ticket) + + // nrr + std::map nrr_certificate_sign_key; + + // xci + tc::Optional xci_header_sign_key; + std::map xci_header_key; + + // ticket + std::map etik_common_key; + + // BroadOn signer profiles (for es cert and es tik) + // BroadOn RSA Keys + struct BroadOnRsaSignerProfile + { + tc::ByteData certificate; + rsa_key_t key; + }; + std::map broadon_rsa_signer; +}; + +class KeyBagInitializer : public KeyBag +{ +public: + KeyBagInitializer(bool isDev, const tc::Optional& keyfile_path, const tc::Optional& tik_path, const tc::Optional& cert_path); +private: + KeyBagInitializer(); + + void importBaseKeyFile(const tc::io::Path& keyfile_path, bool isDev); + void importTitleKeyFile(const tc::io::Path& keyfile_path); + void importCertificateChain(const tc::io::Path& cert_path); + void importTicket(const tc::io::Path& tik_path); +}; + +} \ No newline at end of file diff --git a/src/KeyConfiguration.cpp b/src/KeyConfiguration.cpp deleted file mode 100644 index 8164091..0000000 --- a/src/KeyConfiguration.cpp +++ /dev/null @@ -1,413 +0,0 @@ -#include "KeyConfiguration.h" -#include -#include -#include - -KeyConfiguration::KeyConfiguration() -{ - clearGeneralKeyConfiguration(); - clearNcaExternalKeys(); -} - -KeyConfiguration::KeyConfiguration(const KeyConfiguration& other) -{ - *this = other; -} - -void KeyConfiguration::operator=(const KeyConfiguration& other) -{ - mPkg2SignKey = other.mPkg2SignKey; - mXciHeaderSignKey = other.mXciHeaderSignKey; - - mContentArchiveHeaderKey = other.mContentArchiveHeaderKey; - mXciHeaderKey = other.mXciHeaderKey; - - for (size_t i = 0; i < kMasterKeyNum; i++) - { - mAcidSignKey[i] = other.mAcidSignKey[i]; - mContentArchiveHeader0SignKey[i] = other.mContentArchiveHeader0SignKey[i]; - mNrrCertificateSignKey[i] = other.mNrrCertificateSignKey[i]; - mPkg2Key[i] = other.mPkg2Key[i]; - mPkg1Key[i] = other.mPkg1Key[i]; - mNcaKeyAreaEncryptionKey[0][i] = other.mNcaKeyAreaEncryptionKey[0][i]; - mNcaKeyAreaEncryptionKey[1][i] = other.mNcaKeyAreaEncryptionKey[1][i]; - mNcaKeyAreaEncryptionKey[2][i] = other.mNcaKeyAreaEncryptionKey[2][i]; - mNcaKeyAreaEncryptionKeyHw[0][i] = other.mNcaKeyAreaEncryptionKeyHw[0][i]; - mNcaKeyAreaEncryptionKeyHw[1][i] = other.mNcaKeyAreaEncryptionKeyHw[1][i]; - mNcaKeyAreaEncryptionKeyHw[2][i] = other.mNcaKeyAreaEncryptionKeyHw[2][i]; - mETicketCommonKey[i] = other.mETicketCommonKey[i]; - } - - mPkiRootKeyList = other.mPkiRootKeyList; - - mNcaExternalContentKeyList = other.mNcaExternalContentKeyList; -} - -void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path) -{ - clearGeneralKeyConfiguration(); - - fnd::ResourceFileReader res; - try - { - res.processFile(path); - } - catch (const fnd::Exception&) - { - throw fnd::Exception(kModuleName, "Failed to open key file: " + path); - } - - // internally used sources - fnd::aes::sAes128Key master_key[kMasterKeyNum] = { kNullAesKey }; - fnd::aes::sAes128Key package2_key_source = kNullAesKey; - fnd::aes::sAes128Key ticket_titlekek_source = kNullAesKey; - fnd::aes::sAes128Key key_area_key_source[kNcaKeakNum] = { kNullAesKey, kNullAesKey, kNullAesKey }; - fnd::aes::sAes128Key aes_kek_generation_source = kNullAesKey; - fnd::aes::sAes128Key aes_key_generation_source = kNullAesKey; - fnd::aes::sAes128Key nca_header_kek_source = kNullAesKey; - fnd::aes::sAesXts128Key nca_header_key_source = kNullAesXtsKey; - fnd::rsa::sRsa4096Key pki_root_sign_key = kNullRsa4096Key; - -#define _CONCAT_2_STRINGS(str1, str2) ((str1) + "_" + (str2)) -#define _CONCAT_3_STRINGS(str1, str2, str3) _CONCAT_2_STRINGS(_CONCAT_2_STRINGS(str1, str2), str3) -#define _CONCAT_4_STRINGS(str1, str2, str3, str4) _CONCAT_2_STRINGS(_CONCAT_2_STRINGS(_CONCAT_2_STRINGS(str1, str2), str3), str4) - - std::string key,val; - fnd::Vec dec_array; - -#define _SAVE_KEYDATA(key_name, array, len) \ - key = (key_name); \ - val = res[key]; \ - if (val.empty() == false) { \ - fnd::SimpleTextOutput::stringToArray(val, dec_array); \ - if (dec_array.size() != len) \ - throw fnd::Exception(kModuleName, "Key: \"" + key_name + "\" has incorrect length"); \ - memcpy(array, dec_array.data(), len); \ - } - - for (size_t nameidx = 0; nameidx < kNameVariantNum; nameidx++) - { - // import sources - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg2Base[nameidx], kKeyStr, kSourceStr), package2_key_source.key, 0x10); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[nameidx], kSourceStr), ticket_titlekek_source.key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[0], kSourceStr), key_area_key_source[0].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[1], kSourceStr), key_area_key_source[1].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[2], kSourceStr), key_area_key_source[2].key, 0x10); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kKekGenBase[nameidx], kSourceStr), aes_kek_generation_source.key, 0x10); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kKeyGenBase[nameidx], kSourceStr), aes_key_generation_source.key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kContentArchiveHeaderBase[nameidx], kKekStr, kSourceStr), nca_header_kek_source.key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kContentArchiveHeaderBase[nameidx], kKeyStr, kSourceStr), nca_header_key_source.key, 0x20); - - // Store Key Variants/Derivatives - for (size_t mkeyidx = 0; mkeyidx < kMasterKeyNum; mkeyidx++) - { - - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kMasterBase[nameidx], kKeyStr, kKeyIndex[mkeyidx]), master_key[mkeyidx].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg1Base[nameidx], kKeyStr, kKeyIndex[mkeyidx]), mPkg1Key[mkeyidx].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg2Base[nameidx], kKeyStr, kKeyIndex[mkeyidx]), mPkg2Key[mkeyidx].key, 0x10); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[nameidx], kKeyIndex[mkeyidx]), mETicketCommonKey[mkeyidx].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[0], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKey[0][mkeyidx].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[1], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKey[1][mkeyidx].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[2], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKey[2][mkeyidx].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[0], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[0][mkeyidx].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[1], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[1][mkeyidx].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[2], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[2][mkeyidx].key, 0x10); - - _SAVE_KEYDATA(_CONCAT_4_STRINGS(kContentArchiveHeaderBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kPrivateStr), mContentArchiveHeader0SignKey[mkeyidx].priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_4_STRINGS(kContentArchiveHeaderBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kModulusStr), mContentArchiveHeader0SignKey[mkeyidx].modulus, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_4_STRINGS(kAcidBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kPrivateStr), mAcidSignKey[mkeyidx].priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_4_STRINGS(kAcidBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kModulusStr), mAcidSignKey[mkeyidx].modulus, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_4_STRINGS(kNrrCertBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kPrivateStr), mNrrCertificateSignKey[mkeyidx].priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_4_STRINGS(kNrrCertBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kModulusStr), mNrrCertificateSignKey[mkeyidx].modulus, fnd::rsa::kRsa2048Size); - } - - // store nca header key - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kContentArchiveHeaderBase[nameidx], kKeyStr), mContentArchiveHeaderKey.key[0], 0x20); - - // store xci header key - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kKeyStr), mXciHeaderKey.key, 0x10); - - // store rsa keys - - // legacy header nca key name - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kContentArchiveHeaderBase[nameidx], kSignKey, kPrivateStr), mContentArchiveHeader0SignKey[0].priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kContentArchiveHeaderBase[nameidx], kSignKey, kModulusStr), mContentArchiveHeader0SignKey[0].modulus, fnd::rsa::kRsa2048Size); - - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kXciHeaderBase[nameidx], kSignKey, kPrivateStr), mXciHeaderSignKey.priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kXciHeaderBase[nameidx], kSignKey, kModulusStr), mXciHeaderSignKey.modulus, fnd::rsa::kRsa2048Size); - - // legacy acid header key name - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kAcidBase[nameidx], kSignKey, kPrivateStr), mAcidSignKey[0].priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kAcidBase[nameidx], kSignKey, kModulusStr), mAcidSignKey[0].modulus, fnd::rsa::kRsa2048Size); - - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg2Base[nameidx], kSignKey, kPrivateStr), mPkg2SignKey.priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg2Base[nameidx], kSignKey, kModulusStr), mPkg2SignKey.modulus, fnd::rsa::kRsa2048Size); - - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkiRootBase[nameidx], kSignKey, kPrivateStr), pki_root_sign_key.priv_exponent, fnd::rsa::kRsa4096Size); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkiRootBase[nameidx], kSignKey, kModulusStr), pki_root_sign_key.modulus, fnd::rsa::kRsa4096Size); - } - -#undef _SAVE_KEYDATA -#undef _CONCAT_3_STRINGS -#undef _CONCAT_2_STRINGS - - // Derive keys - for (size_t i = 0; i < kMasterKeyNum; i++) - { - if (master_key[i] != kNullAesKey) - { - if (aes_kek_generation_source != kNullAesKey && aes_key_generation_source != kNullAesKey) - { - if (i == 0 && nca_header_kek_source != kNullAesKey && nca_header_key_source != kNullAesXtsKey) - { - if (mContentArchiveHeaderKey == kNullAesXtsKey) - { - fnd::aes::sAes128Key nca_header_kek; - nn::hac::AesKeygen::generateKey(nca_header_kek.key, aes_kek_generation_source.key, nca_header_kek_source.key, aes_key_generation_source.key, master_key[i].key); - nn::hac::AesKeygen::generateKey(mContentArchiveHeaderKey.key[0], nca_header_key_source.key[0], nca_header_kek.key); - nn::hac::AesKeygen::generateKey(mContentArchiveHeaderKey.key[1], nca_header_key_source.key[1], nca_header_kek.key); - } - } - - for (size_t j = 0; j < nn::hac::nca::kKeyAreaEncryptionKeyNum; j++) - { - if (key_area_key_source[j] != kNullAesKey && mNcaKeyAreaEncryptionKey[j][i] == kNullAesKey) - { - nn::hac::AesKeygen::generateKey(mNcaKeyAreaEncryptionKey[j][i].key, aes_kek_generation_source.key, key_area_key_source[j].key, aes_key_generation_source.key, master_key[i].key); - } - } - } - - if (ticket_titlekek_source != kNullAesKey && mETicketCommonKey[i] == kNullAesKey) - { - nn::hac::AesKeygen::generateKey(mETicketCommonKey[i].key, ticket_titlekek_source.key, master_key[i].key); - } - if (package2_key_source != kNullAesKey && mPkg2Key[i] == kNullAesKey) - { - nn::hac::AesKeygen::generateKey(mPkg2Key[i].key, package2_key_source.key, master_key[i].key); - } - } - } - - // populate pki root keys - if (pki_root_sign_key != kNullRsa4096Key) - { - sPkiRootKey tmp; - - tmp.name = nn::pki::sign::kRootIssuerStr; - tmp.key_type = nn::pki::sign::SIGN_ALGO_RSA4096; - tmp.rsa4096_key = pki_root_sign_key; - - mPkiRootKeyList.addElement(tmp); - } -} - - -void KeyConfiguration::clearGeneralKeyConfiguration() -{ - - mPkg2SignKey = kNullRsa2048Key; - - mXciHeaderSignKey = kNullRsa2048Key; - mPkiRootKeyList.clear(); - - mContentArchiveHeaderKey = kNullAesXtsKey; - mXciHeaderKey = kNullAesKey; - - for (size_t i = 0; i < kMasterKeyNum; i++) - { - mAcidSignKey[i] = kNullRsa2048Key; - mContentArchiveHeader0SignKey[i] = kNullRsa2048Key; - mNrrCertificateSignKey[i] = kNullRsa2048Key; - mPkg1Key[i] = kNullAesKey; - mPkg2Key[i] = kNullAesKey; - mETicketCommonKey[i] = kNullAesKey; - for (size_t j = 0; j < kNcaKeakNum; j++) - { - mNcaKeyAreaEncryptionKey[j][i] = kNullAesKey; - mNcaKeyAreaEncryptionKeyHw[j][i] = kNullAesKey; - } - } -} - -void KeyConfiguration::clearNcaExternalKeys() -{ - mNcaExternalContentKeyList.clear(); -} - -bool KeyConfiguration::getContentArchiveHeaderKey(fnd::aes::sAesXts128Key& key) const -{ - return copyOutKeyResourceIfExists(mContentArchiveHeaderKey, key, kNullAesXtsKey); -} - -bool KeyConfiguration::getContentArchiveHeader0SignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const -{ - // TODO: This needs to be changed to support multiple keys - if (key_generation >= kMasterKeyNum) - { - return false; - } - - return copyOutKeyResourceIfExists(mContentArchiveHeader0SignKey[key_generation], key, kNullRsa2048Key); -} - -bool KeyConfiguration::getAcidSignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const -{ - // TODO: This needs to be changed to support multiple keys - if (key_generation >= kMasterKeyNum) - { - return false; - } - - return copyOutKeyResourceIfExists(mAcidSignKey[key_generation], key, kNullRsa2048Key); -} - -bool KeyConfiguration::getNcaKeyAreaEncryptionKey(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const -{ - if (keak_type >= kNcaKeakNum || masterkey_index >= kMasterKeyNum) - { - return false; - } - return copyOutKeyResourceIfExists(mNcaKeyAreaEncryptionKey[keak_type][masterkey_index], key, kNullAesKey); -} - -bool KeyConfiguration::getNcaKeyAreaEncryptionKeyHw(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const -{ - if (keak_type >= kNcaKeakNum || masterkey_index >= kMasterKeyNum) - { - return false; - } - return copyOutKeyResourceIfExists(mNcaKeyAreaEncryptionKeyHw[keak_type][masterkey_index], key, kNullAesKey); -} - -void KeyConfiguration::addNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], const fnd::aes::sAes128Key& key) -{ - sNcaExternalContentKey tmp; - memcpy(tmp.rights_id.data, rights_id, nn::hac::nca::kRightsIdLen); - tmp.key = key; - - if (mNcaExternalContentKeyList.hasElement(tmp)) - return; - - mNcaExternalContentKeyList.addElement(tmp); -} - -bool KeyConfiguration::getNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], fnd::aes::sAes128Key& key) const -{ - sRightsId id; - bool res_exists = false; - - memcpy(id.data, rights_id, nn::hac::nca::kRightsIdLen); - for (size_t i = 0; i < mNcaExternalContentKeyList.size(); i++) - { - if (mNcaExternalContentKeyList[i].rights_id == id) - { - res_exists = true; - key = mNcaExternalContentKeyList[i].key; - break; - } - } - - return res_exists; -} - -bool KeyConfiguration::getNrrCertificateSignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const -{ - // TODO: This needs to be changed to support multiple keys - if (key_generation >= kMasterKeyNum) - { - return false; - } - - return copyOutKeyResourceIfExists(mNrrCertificateSignKey[key_generation], key, kNullRsa2048Key); -} - -bool KeyConfiguration::getPkg1Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const -{ - if (masterkey_index >= kMasterKeyNum) - { - return false; - } - return copyOutKeyResourceIfExists(mPkg1Key[masterkey_index], key, kNullAesKey); -} - -bool KeyConfiguration::getPkg2Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const -{ - if (masterkey_index >= kMasterKeyNum) - { - return false; - } - return copyOutKeyResourceIfExists(mPkg2Key[masterkey_index], key, kNullAesKey); -} - -bool KeyConfiguration::getPkg2SignKey(fnd::rsa::sRsa2048Key& key) const -{ - return copyOutKeyResourceIfExists(mPkg2SignKey, key, kNullRsa2048Key); -} - -bool KeyConfiguration::getXciHeaderSignKey(fnd::rsa::sRsa2048Key& key) const -{ - return copyOutKeyResourceIfExists(mXciHeaderSignKey, key, kNullRsa2048Key); -} - -bool KeyConfiguration::getXciHeaderKey(fnd::aes::sAes128Key& key) const -{ - return copyOutKeyResourceIfExists(mXciHeaderKey, key, kNullAesKey); -} - -bool KeyConfiguration::getETicketCommonKey(byte_t masterkey_index, fnd::aes::sAes128Key& key) const -{ - if (masterkey_index >= kMasterKeyNum) - { - return false; - } - return copyOutKeyResourceIfExists(mETicketCommonKey[masterkey_index], key, kNullAesKey); -} - -bool KeyConfiguration::getPkiRootSignKey(const std::string& root_name, fnd::rsa::sRsa4096Key& key) const -{ - bool res_exists = false; - for (size_t i = 0; i < mPkiRootKeyList.size(); i++) - { - if (root_name == mPkiRootKeyList[i].name && mPkiRootKeyList[i].key_type == nn::pki::sign::SIGN_ALGO_RSA4096) - { - res_exists = true; - key = mPkiRootKeyList[i].rsa4096_key; - break; - } - } - - return res_exists; -} - -bool KeyConfiguration::getPkiRootSignKey(const std::string& root_name, fnd::rsa::sRsa2048Key& key) const -{ - bool res_exists = false; - for (size_t i = 0; i < mPkiRootKeyList.size(); i++) - { - if (root_name == mPkiRootKeyList[i].name && mPkiRootKeyList[i].key_type == nn::pki::sign::SIGN_ALGO_RSA2048) - { - res_exists = true; - key = mPkiRootKeyList[i].rsa2048_key; - break; - } - } - - return res_exists; -} - -bool KeyConfiguration::getPkiRootSignKey(const std::string& root_name, fnd::ecdsa::sEcdsa240Key& key) const -{ - bool res_exists = false; - for (size_t i = 0; i < mPkiRootKeyList.size(); i++) - { - if (root_name == mPkiRootKeyList[i].name && mPkiRootKeyList[i].key_type == nn::pki::sign::SIGN_ALGO_ECDSA240) - { - res_exists = true; - key = mPkiRootKeyList[i].ecdsa240_key; - break; - } - } - - return res_exists; -} \ No newline at end of file diff --git a/src/KeyConfiguration.h b/src/KeyConfiguration.h deleted file mode 100644 index 4a112c6..0000000 --- a/src/KeyConfiguration.h +++ /dev/null @@ -1,217 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class KeyConfiguration -{ -public: - KeyConfiguration(); - KeyConfiguration(const KeyConfiguration& other); - - void operator=(const KeyConfiguration& other); - - void importHactoolGenericKeyfile(const std::string& path); - //void importHactoolTitleKeyfile(const std::string& path); - - void clearGeneralKeyConfiguration(); - void clearNcaExternalKeys(); - - // nca keys - bool getContentArchiveHeaderKey(fnd::aes::sAesXts128Key& key) const; - bool getContentArchiveHeader0SignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const; - bool getAcidSignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const; - bool getNcaKeyAreaEncryptionKey(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const; - bool getNcaKeyAreaEncryptionKeyHw(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const; - - // external content keys - void addNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], const fnd::aes::sAes128Key& key); - bool getNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], fnd::aes::sAes128Key& key) const; - - // nrr key - bool getNrrCertificateSignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const; - - // pkg1/pkg2 - bool getPkg1Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const; - bool getPkg2Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const; - bool getPkg2SignKey(fnd::rsa::sRsa2048Key& key) const; - - // xci keys - bool getXciHeaderSignKey(fnd::rsa::sRsa2048Key& key) const; - bool getXciHeaderKey(fnd::aes::sAes128Key& key) const; - - // ticket - bool getETicketCommonKey(byte_t masterkey_index, fnd::aes::sAes128Key& key) const; - - // pki - bool getPkiRootSignKey(const std::string& root_name, fnd::rsa::sRsa4096Key& key) const; - bool getPkiRootSignKey(const std::string& root_name, fnd::rsa::sRsa2048Key& key) const; - bool getPkiRootSignKey(const std::string& root_name, fnd::ecdsa::sEcdsa240Key& key) const; -private: - const std::string kModuleName = "KeyConfiguration"; - const fnd::aes::sAes128Key kNullAesKey = {{0}}; - const fnd::aes::sAesXts128Key kNullAesXtsKey = {{{0}}}; - const fnd::rsa::sRsa4096Key kNullRsa4096Key = {{0}, {0}, {0}}; - const fnd::rsa::sRsa2048Key kNullRsa2048Key = {{0}, {0}, {0}}; - static const size_t kMasterKeyNum = 0x20; - static const size_t kNcaKeakNum = nn::hac::nca::kKeyAreaEncryptionKeyNum; - - // keynames - enum NameVariantIndex - { - NNTOOLS, - LEGACY_HACTOOL, - LEGACY_0 - }; - static const size_t kNameVariantNum = 3; - const std::string kMasterBase[kNameVariantNum] = { "master", "master", "master" }; - const std::string kPkg1Base[kNameVariantNum] = { "package1", "package1", "package1" }; - const std::string kPkg2Base[kNameVariantNum] = { "package2", "package2", "package2" }; - const std::string kXciHeaderBase[kNameVariantNum] = { "xci_header", "xci_header", "xci_header" }; - const std::string kContentArchiveHeaderBase[kNameVariantNum] = { "nca_header", "header", "nca_header" }; - const std::string kAcidBase[kNameVariantNum] = { "acid", "acid", "acid" }; - const std::string kNrrCertBase[kNameVariantNum] = { "nrr_certificate", "nrr_certificate", "nrr_certificate" }; - const std::string kPkiRootBase[kNameVariantNum] = { "pki_root", "pki_root", "pki_root" }; - const std::string kTicketCommonKeyBase[kNameVariantNum] = { "ticket_commonkey", "titlekek", "ticket_commonkey" }; - const std::string kNcaKeyAreaEncKeyBase[kNameVariantNum] = { "nca_key_area_key", "key_area_key", "nca_body_keak" }; - const std::string kNcaKeyAreaEncKeyHwBase[kNameVariantNum] = { "nca_key_area_key_hw", "key_area_hw_key", "nca_key_area_key_hw" }; - const std::string kKekGenBase[kNameVariantNum] = { "aes_kek_generation", "aes_kek_generation", "aes_kek_generation" }; - const std::string kKeyGenBase[kNameVariantNum] = { "aes_key_generation", "aes_key_generation", "aes_key_generation" }; - - // misc str - const std::string kKeyStr = "key"; - const std::string kKekStr = "kek"; - const std::string kSourceStr = "source"; - const std::string kSignKey = "sign_key"; - const std::string kModulusStr = "modulus"; - const std::string kPrivateStr = "private"; - const std::string kNcaKeyAreaKeyIndexStr[kNcaKeakNum] = { "application", "ocean", "system" }; - const std::string kKeyIndex[kMasterKeyNum] = {"00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f","10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f"}; - - struct sRightsId - { - byte_t data[nn::hac::nca::kRightsIdLen]; - - void operator=(const sRightsId& other) - { - memcpy(this->data, other.data, nn::hac::nca::kRightsIdLen); - } - - bool operator==(const sRightsId& other) const - { - return memcmp(this->data, other.data, nn::hac::nca::kRightsIdLen) == 0; - } - - bool operator!=(const sRightsId& other) const - { - return !(operator==(other)); - } - }; - - struct sNcaExternalContentKey - { - sRightsId rights_id; - fnd::aes::sAes128Key key; - - void operator=(const sNcaExternalContentKey& other) - { - rights_id = other.rights_id; - key = other.key; - } - - bool operator==(const sNcaExternalContentKey& other) const - { - return (rights_id == other.rights_id) \ - && (key == other.key); - } - - bool operator!=(const sNcaExternalContentKey& other) const - { - return !(operator==(other)); - } - }; - - struct sPkiRootKey - { - std::string name; - nn::pki::sign::SignatureAlgo key_type; - fnd::rsa::sRsa4096Key rsa4096_key; - fnd::rsa::sRsa2048Key rsa2048_key; - fnd::ecdsa::sEcdsa240Key ecdsa240_key; - - void operator=(const sPkiRootKey& other) - { - name = other.name; - key_type = other.key_type; - rsa4096_key = other.rsa4096_key; - rsa2048_key = other.rsa2048_key; - ecdsa240_key = other.ecdsa240_key; - } - - bool operator==(const sPkiRootKey& other) const - { - return (name == other.name) \ - && (key_type == other.key_type) \ - && (rsa4096_key == other.rsa4096_key) \ - && (rsa2048_key == other.rsa2048_key) \ - && (ecdsa240_key == other.ecdsa240_key); - } - - bool operator!=(const sPkiRootKey& other) const - { - return !(operator==(other)); - } - }; - - - /* general key config */ - // acid - fnd::rsa::sRsa2048Key mAcidSignKey[kMasterKeyNum]; - - // pkg1 and pkg2 - fnd::aes::sAes128Key mPkg1Key[kMasterKeyNum]; - fnd::rsa::sRsa2048Key mPkg2SignKey; - fnd::aes::sAes128Key mPkg2Key[kMasterKeyNum]; - - // nca - fnd::rsa::sRsa2048Key mContentArchiveHeader0SignKey[kMasterKeyNum]; - fnd::aes::sAesXts128Key mContentArchiveHeaderKey; - fnd::aes::sAes128Key mNcaKeyAreaEncryptionKey[kNcaKeakNum][kMasterKeyNum]; - fnd::aes::sAes128Key mNcaKeyAreaEncryptionKeyHw[kNcaKeakNum][kMasterKeyNum]; - - // nrr - fnd::rsa::sRsa2048Key mNrrCertificateSignKey[kMasterKeyNum]; - - // xci - fnd::rsa::sRsa2048Key mXciHeaderSignKey; - fnd::aes::sAes128Key mXciHeaderKey; - - // ticket - fnd::aes::sAes128Key mETicketCommonKey[kMasterKeyNum]; - - // pki - fnd::List mPkiRootKeyList; - - /* Nca External Keys */ - fnd::List mNcaExternalContentKeyList; - - template - bool copyOutKeyResourceIfExists(const T& src, T& dst, const T& null_sample) const - { - bool resource_exists = false; - - if (src != null_sample) - { - resource_exists = true; - dst = src; - } - - return resource_exists; - } -}; \ No newline at end of file diff --git a/src/KipProcess.cpp b/src/KipProcess.cpp index 2c787e2..dbaae88 100644 --- a/src/KipProcess.cpp +++ b/src/KipProcess.cpp @@ -9,51 +9,51 @@ #include -KipProcess::KipProcess(): +nstool::KipProcess::KipProcess(): mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false) { } -void KipProcess::process() +void nstool::KipProcess::process() { importHeader(); //importCodeSegments(); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) { displayHeader(); displayKernelCap(mHdr.getKernelCapabilities()); } } -void KipProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::KipProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void KipProcess::setCliOutputMode(CliOutputMode type) +void nstool::KipProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void KipProcess::setVerifyMode(bool verify) +void nstool::KipProcess::setVerifyMode(bool verify) { mVerify = verify; } -void KipProcess::importHeader() +void nstool::KipProcess::importHeader() { - fnd::Vec scratch; + tc::ByteData scratch; if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } if ((*mFile)->size() < sizeof(nn::hac::sKipHeader)) { - throw fnd::Exception(kModuleName, "Corrupt KIP: file too small"); + throw tc::Exception(kModuleName, "Corrupt KIP: file too small"); } scratch.alloc(sizeof(nn::hac::sKipHeader)); @@ -62,10 +62,10 @@ void KipProcess::importHeader() mHdr.fromBytes(scratch.data(), scratch.size()); } -void KipProcess::importCodeSegments() +void nstool::KipProcess::importCodeSegments() { #ifdef _KIP_COMPRESSION_IMPLEMENTED - fnd::Vec scratch; + tc::ByteData scratch; uint32_t decompressed_len; #endif @@ -79,7 +79,7 @@ void KipProcess::importCodeSegments() fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mTextBlob.data(), (uint32_t)mTextBlob.size(), decompressed_len); if (decompressed_len != mTextBlob.size()) { - throw fnd::Exception(kModuleName, "KIP text segment failed to decompress"); + throw tc::Exception(kModuleName, "KIP text segment failed to decompress"); } } else @@ -102,7 +102,7 @@ void KipProcess::importCodeSegments() fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mRoBlob.data(), (uint32_t)mRoBlob.size(), decompressed_len); if (decompressed_len != mRoBlob.size()) { - throw fnd::Exception(kModuleName, "KIP ro segment failed to decompress"); + throw tc::Exception(kModuleName, "KIP ro segment failed to decompress"); } } else @@ -125,7 +125,7 @@ void KipProcess::importCodeSegments() fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mDataBlob.data(), (uint32_t)mDataBlob.size(), decompressed_len); if (decompressed_len != mDataBlob.size()) { - throw fnd::Exception(kModuleName, "KIP data segment failed to decompress"); + throw tc::Exception(kModuleName, "KIP data segment failed to decompress"); } } else @@ -139,7 +139,7 @@ void KipProcess::importCodeSegments() #endif } -void KipProcess::displayHeader() +void nstool::KipProcess::displayHeader() { std::cout << "[KIP Header]" << std::endl; std::cout << " Meta:" << std::endl; @@ -151,7 +151,7 @@ void KipProcess::displayHeader() std::cout << " UseSecureMemory: " << std::boolalpha << mHdr.getUseSecureMemoryFlag() << std::endl; std::cout << " Program Sections:" << std::endl; std::cout << " .text:" << std::endl; - if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + if (mCliOutputMode.show_layout) { std::cout << " FileOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().file_layout.offset << std::endl; std::cout << " FileSize: 0x" << std::hex << mHdr.getTextSegmentInfo().file_layout.size << (mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl; @@ -159,7 +159,7 @@ void KipProcess::displayHeader() std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.offset << std::endl; std::cout << " MemorySize: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.size << std::endl; std::cout << " .ro:" << std::endl; - if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + if (mCliOutputMode.show_layout) { std::cout << " FileOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().file_layout.offset << std::endl; std::cout << " FileSize: 0x" << std::hex << mHdr.getRoSegmentInfo().file_layout.size << (mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl; @@ -167,7 +167,7 @@ void KipProcess::displayHeader() std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.offset << std::endl; std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.size << std::endl; std::cout << " .data:" << std::endl; - if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + if (mCliOutputMode.show_layout) { std::cout << " FileOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().file_layout.offset << std::endl; std::cout << " FileSize: 0x" << std::hex << mHdr.getDataSegmentInfo().file_layout.size << (mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl; @@ -179,7 +179,7 @@ void KipProcess::displayHeader() } -void KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern) +void nstool::KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern) { std::cout << "[Kernel Capabilities]" << std::endl; if (kern.getThreadInfo().isSet()) @@ -207,8 +207,8 @@ void KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern) } if (kern.getMemoryMaps().isSet()) { - fnd::List maps = kern.getMemoryMaps().getMemoryMaps(); - fnd::List ioMaps = kern.getMemoryMaps().getIoMemoryMaps(); + std::vector maps = kern.getMemoryMaps().getMemoryMaps(); + std::vector ioMaps = kern.getMemoryMaps().getIoMemoryMaps(); std::cout << " MemoryMaps:" << std::endl; for (size_t i = 0; i < maps.size(); i++) @@ -223,7 +223,7 @@ void KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern) } if (kern.getInterupts().isSet()) { - fnd::List interupts = kern.getInterupts().getInteruptList(); + std::vector interupts = kern.getInterupts().getInteruptList(); std::cout << " Interupts Flags:" << std::endl; for (uint32_t i = 0; i < interupts.size(); i++) { diff --git a/src/KipProcess.h b/src/KipProcess.h index 09580e1..cd844c9 100644 --- a/src/KipProcess.h +++ b/src/KipProcess.h @@ -1,12 +1,9 @@ #pragma once -#include -#include -#include -#include -#include +#include "types.h" + #include -#include "common.h" +namespace nstool { class KipProcess { @@ -15,21 +12,23 @@ public: void process(); - void setInputFile(const fnd::SharedPtr& file); + void setInputFile(const std::shared_ptr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); private: const std::string kModuleName = "KipProcess"; - fnd::SharedPtr mFile; + std::shared_ptr mFile; CliOutputMode mCliOutputMode; bool mVerify; nn::hac::KernelInitialProcessHeader mHdr; - fnd::Vec mTextBlob, mRoBlob, mDataBlob; + tc::ByteData mTextBlob, mRoBlob, mDataBlob; void importHeader(); void importCodeSegments(); void displayHeader(); void displayKernelCap(const nn::hac::KernelCapabilityControl& kern); -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/MetaProcess.cpp b/src/MetaProcess.cpp index 40877bb..a906125 100644 --- a/src/MetaProcess.cpp +++ b/src/MetaProcess.cpp @@ -10,14 +10,14 @@ #include -MetaProcess::MetaProcess() : +nstool::MetaProcess::MetaProcess() : mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false) { } -void MetaProcess::process() +void nstool::MetaProcess::process() { importMeta(); @@ -27,7 +27,7 @@ void MetaProcess::process() validateAciFromAcid(mMeta.getAccessControlInfo(), mMeta.getAccessControlInfoDesc()); } - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) { // npdm binary displayMetaHeader(mMeta); @@ -39,7 +39,7 @@ void MetaProcess::process() displayKernelCap(mMeta.getAccessControlInfo().getKernelCapabilities()); // acid binary - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) { displayAciDescHdr(mMeta.getAccessControlInfoDesc()); displayFac(mMeta.getAccessControlInfoDesc().getFileSystemAccessControl()); @@ -49,38 +49,38 @@ void MetaProcess::process() } } -void MetaProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::MetaProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void MetaProcess::setKeyCfg(const KeyConfiguration& keycfg) +void nstool::MetaProcess::setKeyCfg(const KeyBag& keycfg) { mKeyCfg = keycfg; } -void MetaProcess::setCliOutputMode(CliOutputMode type) +void nstool::MetaProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void MetaProcess::setVerifyMode(bool verify) +void nstool::MetaProcess::setVerifyMode(bool verify) { mVerify = verify; } -const nn::hac::Meta& MetaProcess::getMeta() const +const nn::hac::Meta& nstool::MetaProcess::getMeta() const { return mMeta; } -void MetaProcess::importMeta() +void nstool::MetaProcess::importMeta() { - fnd::Vec scratch; + tc::ByteData scratch; if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } scratch.alloc((*mFile)->size()); @@ -89,12 +89,12 @@ void MetaProcess::importMeta() mMeta.fromBytes(scratch.data(), scratch.size()); } -void MetaProcess::validateAcidSignature(const nn::hac::AccessControlInfoDesc& acid, byte_t key_generation) +void nstool::MetaProcess::validateAcidSignature(const nn::hac::AccessControlInfoDesc& acid, byte_t key_generation) { try { fnd::rsa::sRsa2048Key acid_sign_key; if (mKeyCfg.getAcidSignKey(acid_sign_key, key_generation) != true) - throw fnd::Exception(); + throw tc::Exception(); acid.validateSignature(acid_sign_key); } @@ -104,7 +104,7 @@ void MetaProcess::validateAcidSignature(const nn::hac::AccessControlInfoDesc& ac } -void MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo& aci, const nn::hac::AccessControlInfoDesc& acid) +void nstool::MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo& aci, const nn::hac::AccessControlInfoDesc& acid) { // check Program ID if (acid.getProgramIdRestrict().min > 0 && aci.getProgramId() < acid.getProgramIdRestrict().min) @@ -279,7 +279,7 @@ void MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo& aci, con } } -void MetaProcess::displayMetaHeader(const nn::hac::Meta& hdr) +void nstool::MetaProcess::displayMetaHeader(const nn::hac::Meta& hdr) { std::cout << "[Meta Header]" << std::endl; std::cout << " ACID KeyGeneration: " << std::dec << (uint32_t)hdr.getAccessControlInfoDescKeyGeneration() << std::endl; @@ -301,13 +301,13 @@ void MetaProcess::displayMetaHeader(const nn::hac::Meta& hdr) } } -void MetaProcess::displayAciHdr(const nn::hac::AccessControlInfo& aci) +void nstool::MetaProcess::displayAciHdr(const nn::hac::AccessControlInfo& aci) { std::cout << "[Access Control Info]" << std::endl; std::cout << " ProgramID: 0x" << std::hex << std::setw(16) << std::setfill('0') << aci.getProgramId() << std::endl; } -void MetaProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDesc& acid) +void nstool::MetaProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDesc& acid) { std::cout << "[Access Control Info Desc]" << std::endl; std::cout << " Flags: " << std::endl; @@ -319,7 +319,7 @@ void MetaProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDesc& acid) std::cout << " Max: 0x" << std::hex << std::setw(16) << std::setfill('0') << acid.getProgramIdRestrict().max << std::endl; } -void MetaProcess::displayFac(const nn::hac::FileSystemAccessControl& fac) +void nstool::MetaProcess::displayFac(const nn::hac::FileSystemAccessControl& fac) { std::cout << "[FS Access Control]" << std::endl; std::cout << " Format Version: " << std::dec << (uint32_t)fac.getFormatVersion() << std::endl; @@ -353,7 +353,7 @@ void MetaProcess::displayFac(const nn::hac::FileSystemAccessControl& fac) // output string info std::cout << nn::hac::FileSystemAccessUtil::getFsAccessFlagAsString(nn::hac::fac::FsAccessFlag(flag)); - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) std::cout << " (bit " << std::dec << (uint32_t)flag << ")"; } std::cout << std::endl; @@ -379,7 +379,7 @@ void MetaProcess::displayFac(const nn::hac::FileSystemAccessControl& fac) } -void MetaProcess::displaySac(const nn::hac::ServiceAccessControl& sac) +void nstool::MetaProcess::displaySac(const nn::hac::ServiceAccessControl& sac) { std::cout << "[Service Access Control]" << std::endl; std::cout << " Service List:" << std::endl; @@ -391,7 +391,7 @@ void MetaProcess::displaySac(const nn::hac::ServiceAccessControl& sac) fnd::SimpleTextOutput::dumpStringList(service_name_list, 60, 4); } -void MetaProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern) +void nstool::MetaProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern) { std::cout << "[Kernel Capabilities]" << std::endl; if (kern.getThreadInfo().isSet()) @@ -435,7 +435,7 @@ void MetaProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern) } if (kern.getInterupts().isSet()) { - fnd::List interupts = kern.getInterupts().getInteruptList(); + std::vector interupts = kern.getInterupts().getInteruptList(); std::cout << " Interupts Flags:" << std::endl; for (uint32_t i = 0; i < interupts.size(); i++) { diff --git a/src/MetaProcess.h b/src/MetaProcess.h index 85618a5..56155a9 100644 --- a/src/MetaProcess.h +++ b/src/MetaProcess.h @@ -1,12 +1,10 @@ #pragma once -#include -#include -#include -#include -#include -#include "KeyConfiguration.h" +#include "types.h" +#include "KeyBag.h" -#include "common.h" +#include + +namespace nstool { class MetaProcess { @@ -15,8 +13,8 @@ public: void process(); - void setInputFile(const fnd::SharedPtr& file); - void setKeyCfg(const KeyConfiguration& keycfg); + void setInputFile(const std::shared_ptr& file); + void setKeyCfg(const KeyBag& keycfg); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -25,8 +23,8 @@ public: private: const std::string kModuleName = "MetaProcess"; - fnd::SharedPtr mFile; - KeyConfiguration mKeyCfg; + std::shared_ptr mFile; + KeyBag mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; @@ -43,4 +41,6 @@ private: void displayFac(const nn::hac::FileSystemAccessControl& fac); void displaySac(const nn::hac::ServiceAccessControl& sac); void displayKernelCap(const nn::hac::KernelCapabilityControl& kern); -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/NacpProcess.cpp b/src/NacpProcess.cpp index 1dbe44e..e454709 100644 --- a/src/NacpProcess.cpp +++ b/src/NacpProcess.cpp @@ -9,48 +9,48 @@ #include -NacpProcess::NacpProcess() : +nstool::NacpProcess::NacpProcess() : mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode((1 << OUTPUT_BASIC)), mVerify(false) { } -void NacpProcess::process() +void nstool::NacpProcess::process() { importNacp(); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) displayNacp(); } -void NacpProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::NacpProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void NacpProcess::setCliOutputMode(CliOutputMode type) +void nstool::NacpProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void NacpProcess::setVerifyMode(bool verify) +void nstool::NacpProcess::setVerifyMode(bool verify) { mVerify = verify; } -const nn::hac::ApplicationControlProperty& NacpProcess::getApplicationControlProperty() const +const nn::hac::ApplicationControlProperty& nstool::NacpProcess::getApplicationControlProperty() const { return mNacp; } -void NacpProcess::importNacp() +void nstool::NacpProcess::importNacp() { - fnd::Vec scratch; + tc::ByteData scratch; if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } scratch.alloc((*mFile)->size()); @@ -59,7 +59,7 @@ void NacpProcess::importNacp() mNacp.fromBytes(scratch.data(), scratch.size()); } -void NacpProcess::displayNacp() +void nstool::NacpProcess::displayNacp() { std::cout << "[ApplicationControlProperty]" << std::endl; @@ -74,7 +74,7 @@ void NacpProcess::displayNacp() std::cout << " Publisher: " << itr->publisher << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " Title: None" << std::endl; } @@ -84,25 +84,25 @@ void NacpProcess::displayNacp() { std::cout << " ISBN: " << mNacp.getIsbn() << std::endl; } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " ISBN: (NotSet)" << std::endl; } // StartupUserAccount - if (mNacp.getStartupUserAccount() != nn::hac::nacp::StartupUserAccount::None || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getStartupUserAccount() != nn::hac::nacp::StartupUserAccount::None || mCliOutputMode.show_extended_info) { std::cout << " StartupUserAccount: " << nn::hac::ApplicationControlPropertyUtil::getStartupUserAccountAsString(mNacp.getStartupUserAccount()) << std::endl; } // UserAccountSwitchLock - if (mNacp.getUserAccountSwitchLock() != nn::hac::nacp::UserAccountSwitchLock::Disable || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getUserAccountSwitchLock() != nn::hac::nacp::UserAccountSwitchLock::Disable || mCliOutputMode.show_extended_info) { std::cout << " UserAccountSwitchLock: " << nn::hac::ApplicationControlPropertyUtil::getUserAccountSwitchLockAsString(mNacp.getUserAccountSwitchLock()) << std::endl; } // AddOnContentRegistrationType - if (mNacp.getAddOnContentRegistrationType() != nn::hac::nacp::AddOnContentRegistrationType::AllOnLaunch || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getAddOnContentRegistrationType() != nn::hac::nacp::AddOnContentRegistrationType::AllOnLaunch || mCliOutputMode.show_extended_info) { std::cout << " AddOnContentRegistrationType: " << nn::hac::ApplicationControlPropertyUtil::getAddOnContentRegistrationTypeAsString(mNacp.getAddOnContentRegistrationType()) << std::endl; } @@ -116,7 +116,7 @@ void NacpProcess::displayNacp() std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getAttributeFlagAsString(*itr) << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " Attribute: None" << std::endl; } @@ -130,7 +130,7 @@ void NacpProcess::displayNacp() std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getLanguageAsString(*itr) << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " SupportedLanguage: None" << std::endl; } @@ -144,37 +144,37 @@ void NacpProcess::displayNacp() std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getParentalControlFlagAsString(*itr) << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " ParentalControl: None" << std::endl; } // Screenshot - if (mNacp.getScreenshot() != nn::hac::nacp::Screenshot::Allow || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getScreenshot() != nn::hac::nacp::Screenshot::Allow || mCliOutputMode.show_extended_info) { std::cout << " Screenshot: " << nn::hac::ApplicationControlPropertyUtil::getScreenshotAsString(mNacp.getScreenshot()) << std::endl; } // VideoCapture - if (mNacp.getVideoCapture() != nn::hac::nacp::VideoCapture::Disable || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getVideoCapture() != nn::hac::nacp::VideoCapture::Disable || mCliOutputMode.show_extended_info) { std::cout << " VideoCapture: " << nn::hac::ApplicationControlPropertyUtil::getVideoCaptureAsString(mNacp.getVideoCapture()) << std::endl; } // DataLossConfirmation - if (mNacp.getDataLossConfirmation() != nn::hac::nacp::DataLossConfirmation::None || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getDataLossConfirmation() != nn::hac::nacp::DataLossConfirmation::None || mCliOutputMode.show_extended_info) { std::cout << " DataLossConfirmation: " << nn::hac::ApplicationControlPropertyUtil::getDataLossConfirmationAsString(mNacp.getDataLossConfirmation()) << std::endl; } // PlayLogPolicy - if (mNacp.getPlayLogPolicy() != nn::hac::nacp::PlayLogPolicy::All || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getPlayLogPolicy() != nn::hac::nacp::PlayLogPolicy::All || mCliOutputMode.show_extended_info) { std::cout << " PlayLogPolicy: " << nn::hac::ApplicationControlPropertyUtil::getPlayLogPolicyAsString(mNacp.getPlayLogPolicy()) << std::endl; } // PresenceGroupId - if (mNacp.getPresenceGroupId() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getPresenceGroupId() != 0 || mCliOutputMode.show_extended_info) { std::cout << " PresenceGroupId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getPresenceGroupId() << std::endl; } @@ -190,7 +190,7 @@ void NacpProcess::displayNacp() std::cout << " Age: " << std::dec << (uint32_t)itr->age << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " RatingAge: None" << std::endl; } @@ -200,49 +200,49 @@ void NacpProcess::displayNacp() { std::cout << " DisplayVersion: " << mNacp.getDisplayVersion() << std::endl; } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " DisplayVersion: (NotSet)" << std::endl; } // AddOnContentBaseId - if (mNacp.getAddOnContentBaseId() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getAddOnContentBaseId() != 0 || mCliOutputMode.show_extended_info) { std::cout << " AddOnContentBaseId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getAddOnContentBaseId() << std::endl; } // SaveDataOwnerId - if (mNacp.getSaveDataOwnerId() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getSaveDataOwnerId() != 0 || mCliOutputMode.show_extended_info) { std::cout << " SaveDataOwnerId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getSaveDataOwnerId() << std::endl; } // UserAccountSaveDataSize - if (mNacp.getUserAccountSaveDataSize().size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getUserAccountSaveDataSize().size != 0 || mCliOutputMode.show_extended_info) { std::cout << " UserAccountSaveDataSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().size) << std::endl; } // UserAccountSaveDataJournalSize - if (mNacp.getUserAccountSaveDataSize().journal_size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getUserAccountSaveDataSize().journal_size != 0 || mCliOutputMode.show_extended_info) { std::cout << " UserAccountSaveDataJournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().journal_size) << std::endl; } // DeviceSaveDataSize - if (mNacp.getDeviceSaveDataSize().size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getDeviceSaveDataSize().size != 0 || mCliOutputMode.show_extended_info) { std::cout << " DeviceSaveDataSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().size) << std::endl; } // DeviceSaveDataJournalSize - if (mNacp.getDeviceSaveDataSize().journal_size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getDeviceSaveDataSize().journal_size != 0 || mCliOutputMode.show_extended_info) { std::cout << " DeviceSaveDataJournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().journal_size) << std::endl; } // BcatDeliveryCacheStorageSize - if (mNacp.getBcatDeliveryCacheStorageSize() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getBcatDeliveryCacheStorageSize() != 0 || mCliOutputMode.show_extended_info) { std::cout << " BcatDeliveryCacheStorageSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getBcatDeliveryCacheStorageSize()) << std::endl; } @@ -252,7 +252,7 @@ void NacpProcess::displayNacp() { std::cout << " ApplicationErrorCodeCategory: " << mNacp.getApplicationErrorCodeCategory() << std::endl; } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " ApplicationErrorCodeCategory: (NotSet)" << std::endl; } @@ -266,49 +266,49 @@ void NacpProcess::displayNacp() std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << *itr << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " LocalCommunicationId: None" << std::endl; } // LogoType - //if (mNacp.getLogoType() != nn::hac::nacp::LogoType::Nintendo || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + //if (mNacp.getLogoType() != nn::hac::nacp::LogoType::Nintendo || mCliOutputMode.show_extended_info) //{ std::cout << " LogoType: " << nn::hac::ApplicationControlPropertyUtil::getLogoTypeAsString(mNacp.getLogoType()) << std::endl; //} // LogoHandling - if (mNacp.getLogoHandling() != nn::hac::nacp::LogoHandling::Auto || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getLogoHandling() != nn::hac::nacp::LogoHandling::Auto || mCliOutputMode.show_extended_info) { std::cout << " LogoHandling: " << nn::hac::ApplicationControlPropertyUtil::getLogoHandlingAsString(mNacp.getLogoHandling()) << std::endl; } // RuntimeAddOnContentInstall - if (mNacp.getRuntimeAddOnContentInstall() != nn::hac::nacp::RuntimeAddOnContentInstall::Deny || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getRuntimeAddOnContentInstall() != nn::hac::nacp::RuntimeAddOnContentInstall::Deny || mCliOutputMode.show_extended_info) { std::cout << " RuntimeAddOnContentInstall: " << nn::hac::ApplicationControlPropertyUtil::getRuntimeAddOnContentInstallAsString(mNacp.getRuntimeAddOnContentInstall()) << std::endl; } // RuntimeParameterDelivery - if (mNacp.getRuntimeParameterDelivery() != nn::hac::nacp::RuntimeParameterDelivery::Always || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getRuntimeParameterDelivery() != nn::hac::nacp::RuntimeParameterDelivery::Always || mCliOutputMode.show_extended_info) { std::cout << " RuntimeParameterDelivery: " << nn::hac::ApplicationControlPropertyUtil::getRuntimeParameterDeliveryAsString(mNacp.getRuntimeParameterDelivery()) << std::endl; } // CrashReport - if (mNacp.getCrashReport() != nn::hac::nacp::CrashReport::Deny || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getCrashReport() != nn::hac::nacp::CrashReport::Deny || mCliOutputMode.show_extended_info) { std::cout << " CrashReport: " << nn::hac::ApplicationControlPropertyUtil::getCrashReportAsString(mNacp.getCrashReport()) << std::endl; } // Hdcp - if (mNacp.getHdcp() != nn::hac::nacp::Hdcp::None || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getHdcp() != nn::hac::nacp::Hdcp::None || mCliOutputMode.show_extended_info) { std::cout << " Hdcp: " << nn::hac::ApplicationControlPropertyUtil::getHdcpAsString(mNacp.getHdcp()) << std::endl; } // SeedForPsuedoDeviceId - if (mNacp.getSeedForPsuedoDeviceId() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getSeedForPsuedoDeviceId() != 0 || mCliOutputMode.show_extended_info) { std::cout << " SeedForPsuedoDeviceId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getSeedForPsuedoDeviceId() << std::endl; } @@ -318,7 +318,7 @@ void NacpProcess::displayNacp() { std::cout << " BcatPassphase: " << mNacp.getBcatPassphase() << std::endl; } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " BcatPassphase: (NotSet)" << std::endl; } @@ -332,61 +332,61 @@ void NacpProcess::displayNacp() std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getStartupUserAccountOptionFlagAsString(*itr) << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " StartupUserAccountOption: None" << std::endl; } // UserAccountSaveDataSizeMax - if (mNacp.getUserAccountSaveDataMax().size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getUserAccountSaveDataMax().size != 0 || mCliOutputMode.show_extended_info) { std::cout << " UserAccountSaveDataSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().size) << std::endl; } // UserAccountSaveDataJournalSizeMax - if (mNacp.getUserAccountSaveDataMax().journal_size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getUserAccountSaveDataMax().journal_size != 0 || mCliOutputMode.show_extended_info) { std::cout << " UserAccountSaveDataJournalSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().journal_size) << std::endl; } // DeviceSaveDataSizeMax - if (mNacp.getDeviceSaveDataMax().size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getDeviceSaveDataMax().size != 0 || mCliOutputMode.show_extended_info) { std::cout << " DeviceSaveDataSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().size) << std::endl; } // DeviceSaveDataJournalSizeMax - if (mNacp.getDeviceSaveDataMax().journal_size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getDeviceSaveDataMax().journal_size != 0 || mCliOutputMode.show_extended_info) { std::cout << " DeviceSaveDataJournalSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().journal_size) << std::endl; } // TemporaryStorageSize - if (mNacp.getTemporaryStorageSize() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getTemporaryStorageSize() != 0 || mCliOutputMode.show_extended_info) { std::cout << " TemporaryStorageSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getTemporaryStorageSize()) << std::endl; } // CacheStorageSize - if (mNacp.getCacheStorageSize().size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getCacheStorageSize().size != 0 || mCliOutputMode.show_extended_info) { std::cout << " CacheStorageSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().size) << std::endl; } // CacheStorageJournalSize - if (mNacp.getCacheStorageSize().journal_size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getCacheStorageSize().journal_size != 0 || mCliOutputMode.show_extended_info) { std::cout << " CacheStorageJournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().journal_size) << std::endl; } // CacheStorageDataAndJournalSizeMax - if (mNacp.getCacheStorageDataAndJournalSizeMax() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getCacheStorageDataAndJournalSizeMax() != 0 || mCliOutputMode.show_extended_info) { std::cout << " CacheStorageDataAndJournalSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageDataAndJournalSizeMax()) << std::endl; } // CacheStorageIndexMax - if (mNacp.getCacheStorageIndexMax() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getCacheStorageIndexMax() != 0 || mCliOutputMode.show_extended_info) { std::cout << " CacheStorageIndexMax: 0x" << std::hex << std::setw(4) << std::setfill('0') << mNacp.getCacheStorageIndexMax() << std::endl; } @@ -400,13 +400,13 @@ void NacpProcess::displayNacp() std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << *itr << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " PlayLogQueryableApplicationId: None" << std::endl; } // PlayLogQueryCapability - if (mNacp.getPlayLogQueryCapability() != nn::hac::nacp::PlayLogQueryCapability::None || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getPlayLogQueryCapability() != nn::hac::nacp::PlayLogQueryCapability::None || mCliOutputMode.show_extended_info) { std::cout << " PlayLogQueryCapability: " << nn::hac::ApplicationControlPropertyUtil::getPlayLogQueryCapabilityAsString(mNacp.getPlayLogQueryCapability()) << std::endl; } @@ -420,13 +420,13 @@ void NacpProcess::displayNacp() std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getRepairFlagAsString(*itr) << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " Repair: None" << std::endl; } // ProgramIndex - if (mNacp.getProgramIndex() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getProgramIndex() != 0 || mCliOutputMode.show_extended_info) { std::cout << " ProgramIndex: 0x" << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)mNacp.getProgramIndex() << std::endl; } @@ -440,7 +440,7 @@ void NacpProcess::displayNacp() std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getRequiredNetworkServiceLicenseOnLaunchFlagAsString(*itr) << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " RequiredNetworkServiceLicenseOnLaunch: None" << std::endl; } @@ -456,7 +456,7 @@ void NacpProcess::displayNacp() std::cout << " GroupId: 0x" << std::hex << std::setw(16) << std::setfill('0') << detect_config.send_data_configuration.group_id << std::endl; std::cout << " Key: " << fnd::SimpleTextOutput::arrayToString(detect_config.send_data_configuration.key, nn::hac::nacp::kNeighborDetectionGroupConfigurationKeyLength, false, "") << std::endl; } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " SendGroupConfig: None" << std::endl; } @@ -472,18 +472,18 @@ void NacpProcess::displayNacp() std::cout << " Key: " << fnd::SimpleTextOutput::arrayToString(detect_config.receivable_data_configuration[i].key, nn::hac::nacp::kNeighborDetectionGroupConfigurationKeyLength, false, "") << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " ReceivableGroupConfig: None" << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " NeighborDetectionClientConfiguration: None" << std::endl; } // JitConfiguration - if (mNacp.getJitConfiguration().is_enabled || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getJitConfiguration().is_enabled || mCliOutputMode.show_extended_info) { std::cout << " JitConfiguration:" << std::endl; std::cout << " IsEnabled: " << std::boolalpha << mNacp.getJitConfiguration().is_enabled << std::endl; @@ -491,19 +491,19 @@ void NacpProcess::displayNacp() } // PlayReportPermission - if (mNacp.getPlayReportPermission() != nn::hac::nacp::PlayReportPermission::None || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getPlayReportPermission() != nn::hac::nacp::PlayReportPermission::None || mCliOutputMode.show_extended_info) { std::cout << " PlayReportPermission: " << nn::hac::ApplicationControlPropertyUtil::getPlayReportPermissionAsString(mNacp.getPlayReportPermission()) << std::endl; } // CrashScreenshotForProd - if (mNacp.getCrashScreenshotForProd() != nn::hac::nacp::CrashScreenshotForProd::Deny || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getCrashScreenshotForProd() != nn::hac::nacp::CrashScreenshotForProd::Deny || mCliOutputMode.show_extended_info) { std::cout << " CrashScreenshotForProd: " << nn::hac::ApplicationControlPropertyUtil::getCrashScreenshotForProdAsString(mNacp.getCrashScreenshotForProd()) << std::endl; } // CrashScreenshotForDev - if (mNacp.getCrashScreenshotForDev() != nn::hac::nacp::CrashScreenshotForDev::Deny || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mNacp.getCrashScreenshotForDev() != nn::hac::nacp::CrashScreenshotForDev::Deny || mCliOutputMode.show_extended_info) { std::cout << " CrashScreenshotForDev: " << nn::hac::ApplicationControlPropertyUtil::getCrashScreenshotForDevAsString(mNacp.getCrashScreenshotForDev()) << std::endl; } @@ -518,7 +518,7 @@ void NacpProcess::displayNacp() std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << *itr << std::endl; } } - else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + else if (mCliOutputMode.show_extended_info) { std::cout << " AccessibleLaunchRequiredVersion: None" << std::endl; } diff --git a/src/NacpProcess.h b/src/NacpProcess.h index 7084d81..e458124 100644 --- a/src/NacpProcess.h +++ b/src/NacpProcess.h @@ -1,11 +1,9 @@ #pragma once -#include -#include -#include -#include +#include "types.h" + #include -#include "common.h" +namespace nstool { class NacpProcess { @@ -14,7 +12,7 @@ public: void process(); - void setInputFile(const fnd::SharedPtr& file); + void setInputFile(const std::shared_ptr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -23,7 +21,7 @@ public: private: const std::string kModuleName = "NacpProcess"; - fnd::SharedPtr mFile; + std::shared_ptr mFile; CliOutputMode mCliOutputMode; bool mVerify; @@ -31,4 +29,6 @@ private: void importNacp(); void displayNacp(); -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/NcaProcess.cpp b/src/NcaProcess.cpp index 6ed73d3..e0019e3 100644 --- a/src/NcaProcess.cpp +++ b/src/NcaProcess.cpp @@ -18,9 +18,9 @@ #include #include -NcaProcess::NcaProcess() : +nstool::NcaProcess::NcaProcess() : mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false), mListFs(false) { @@ -30,7 +30,7 @@ NcaProcess::NcaProcess() : } } -void NcaProcess::process() +void nstool::NcaProcess::process() { // import header importHeader(); @@ -46,67 +46,67 @@ void NcaProcess::process() validateNcaSignatures(); // display header - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) displayHeader(); // process partition processPartitions(); } -void NcaProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::NcaProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void NcaProcess::setKeyCfg(const KeyConfiguration& keycfg) +void nstool::NcaProcess::setKeyCfg(const KeyBag& keycfg) { mKeyCfg = keycfg; } -void NcaProcess::setCliOutputMode(CliOutputMode type) +void nstool::NcaProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void NcaProcess::setVerifyMode(bool verify) +void nstool::NcaProcess::setVerifyMode(bool verify) { mVerify = verify; } -void NcaProcess::setPartition0ExtractPath(const std::string& path) +void nstool::NcaProcess::setPartition0ExtractPath(const std::string& path) { mPartitionPath[0].path = path; mPartitionPath[0].doExtract = true; } -void NcaProcess::setPartition1ExtractPath(const std::string& path) +void nstool::NcaProcess::setPartition1ExtractPath(const std::string& path) { mPartitionPath[1].path = path; mPartitionPath[1].doExtract = true; } -void NcaProcess::setPartition2ExtractPath(const std::string& path) +void nstool::NcaProcess::setPartition2ExtractPath(const std::string& path) { mPartitionPath[2].path = path; mPartitionPath[2].doExtract = true; } -void NcaProcess::setPartition3ExtractPath(const std::string& path) +void nstool::NcaProcess::setPartition3ExtractPath(const std::string& path) { mPartitionPath[3].path = path; mPartitionPath[3].doExtract = true; } -void NcaProcess::setListFs(bool list_fs) +void nstool::NcaProcess::setListFs(bool list_fs) { mListFs = list_fs; } -void NcaProcess::importHeader() +void nstool::NcaProcess::importHeader() { if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } // read header block @@ -124,10 +124,10 @@ void NcaProcess::importHeader() mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sContentArchiveHeader)); } -void NcaProcess::generateNcaBodyEncryptionKeys() +void nstool::NcaProcess::generateNcaBodyEncryptionKeys() { // create zeros key - fnd::aes::sAes128Key zero_aesctr_key; + KeyBag::aes128_key_t zero_aesctr_key; memset(zero_aesctr_key.key, 0, sizeof(zero_aesctr_key)); // get key data from header @@ -136,8 +136,8 @@ void NcaProcess::generateNcaBodyEncryptionKeys() // process key area sKeys::sKeyAreaKey kak; - fnd::aes::sAes128Key key_area_enc_key; - const fnd::aes::sAes128Key* key_area = (const fnd::aes::sAes128Key*) mHdr.getKeyArea(); + KeyBag::aes128_key_t key_area_enc_key; + const KeyBag::aes128_key_t* key_area = (const KeyBag::aes128_key_t*) mHdr.getKeyArea(); for (size_t i = 0; i < nn::hac::nca::kKeyAreaKeyNum; i++) { @@ -161,7 +161,7 @@ void NcaProcess::generateNcaBodyEncryptionKeys() { kak.decrypted = false; } - mContentKey.kak_list.addElement(kak); + mContentKey.kak_list.push_back(kak); } } @@ -171,14 +171,14 @@ void NcaProcess::generateNcaBodyEncryptionKeys() // if this has a rights id, the key needs to be sourced from a ticket if (mHdr.hasRightsId() == true) { - fnd::aes::sAes128Key tmp_key; + KeyBag::aes128_key_t tmp_key; if (mKeyCfg.getNcaExternalContentKey(mHdr.getRightsId(), tmp_key) == true) { mContentKey.aes_ctr = tmp_key; } else if (mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserTitleKey, tmp_key) == true) { - fnd::aes::sAes128Key common_key; + KeyBag::aes128_key_t common_key; if (mKeyCfg.getETicketCommonKey(masterkey_rev, common_key) == true) { nn::hac::AesKeygen::generateKey(tmp_key.key, tmp_key.key, common_key.key); @@ -189,7 +189,7 @@ void NcaProcess::generateNcaBodyEncryptionKeys() // otherwise decrypt key area else { - fnd::aes::sAes128Key kak_aes_ctr = zero_aesctr_key; + KeyBag::aes128_key_t kak_aes_ctr = zero_aesctr_key; for (size_t i = 0; i < mContentKey.kak_list.size(); i++) { if (mContentKey.kak_list[i].index == nn::hac::nca::KEY_AESCTR && mContentKey.kak_list[i].decrypted) @@ -205,26 +205,26 @@ void NcaProcess::generateNcaBodyEncryptionKeys() } // if the keys weren't generated, check if the keys were supplied by the user - if (mContentKey.aes_ctr.isSet == false) + if (mContentKey.aes_ctr.isNull()) { - if (mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserBodyKey, mContentKey.aes_ctr.var) == true) + if (mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserBodyKey, mContentKey.aes_ctr.get()) == true) mContentKey.aes_ctr.isSet = true; } - if (_HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) + if (mCliOutputMode.show_keydata) { - if (mContentKey.aes_ctr.isSet) + if (mContentKey.aes_ctr.isSet()) { std::cout << "[NCA Content Key]" << std::endl; - std::cout << " AES-CTR Key: " << fnd::SimpleTextOutput::arrayToString(mContentKey.aes_ctr.var.key, sizeof(mContentKey.aes_ctr.var), true, ":") << std::endl; + std::cout << " AES-CTR Key: " << fnd::SimpleTextOutput::arrayToString(mContentKey.aes_ctr.get().key, sizeof(mContentKey.aes_ctr.get()), true, ":") << std::endl; } } } -void NcaProcess::generatePartitionConfiguration() +void nstool::NcaProcess::generatePartitionConfiguration() { std::stringstream error; @@ -244,7 +244,7 @@ void NcaProcess::generatePartitionConfiguration() { error.clear(); error << "NCA FS Header [" << partition.header_index << "] Hash: FAIL \n"; - throw fnd::Exception(kModuleName, error.str()); + throw tc::Exception(kModuleName, error.str()); } @@ -252,7 +252,7 @@ void NcaProcess::generatePartitionConfiguration() { error.clear(); error << "NCA FS Header [" << partition.header_index << "] Version(" << fs_header.version.get() << "): UNSUPPORTED"; - throw fnd::Exception(kModuleName, error.str()); + throw tc::Exception(kModuleName, error.str()); } // setup AES-CTR @@ -269,9 +269,9 @@ void NcaProcess::generatePartitionConfiguration() { // info.hash_tree_meta.importData(fs_header.hash_info, nn::hac::nca::kHashInfoLen, LayeredIntegrityMetadata::HASH_TYPE_SHA256); nn::hac::HierarchicalSha256Header hdr; - fnd::List hash_layers; + std::vector hash_layers; fnd::LayeredIntegrityMetadata::sLayer data_layer; - fnd::List master_hash_list; + std::vector master_hash_list; // import raw data hdr.fromBytes(fs_header.hash_info, nn::hac::nca::kHashInfoLen); @@ -287,10 +287,10 @@ void NcaProcess::generatePartitionConfiguration() } else { - hash_layers.addElement(layer); + hash_layers.push_back(layer); } } - master_hash_list.addElement(hdr.getMasterHash()); + master_hash_list.push_back(hdr.getMasterHash()); // write data into metadata info.layered_intergrity_metadata.setAlignHashToBlock(false); @@ -302,9 +302,9 @@ void NcaProcess::generatePartitionConfiguration() { // info.hash_tree_meta.importData(fs_header.hash_info, nn::hac::nca::kHashInfoLen, LayeredIntegrityMetadata::HASH_TYPE_INTEGRITY); nn::hac::HierarchicalIntegrityHeader hdr; - fnd::List hash_layers; + std::vector hash_layers; fnd::LayeredIntegrityMetadata::sLayer data_layer; - fnd::List master_hash_list; + std::vector master_hash_list; hdr.fromBytes(fs_header.hash_info, nn::hac::nca::kHashInfoLen); for (size_t i = 0; i < hdr.getLayerInfo().size(); i++) @@ -312,14 +312,14 @@ void NcaProcess::generatePartitionConfiguration() fnd::LayeredIntegrityMetadata::sLayer layer; layer.offset = hdr.getLayerInfo()[i].offset; layer.size = hdr.getLayerInfo()[i].size; - layer.block_size = _BIT(hdr.getLayerInfo()[i].block_size); + layer.block_size = (1 << hdr.getLayerInfo()[i].block_size); if (i + 1 == hdr.getLayerInfo().size()) { data_layer = layer; } else { - hash_layers.addElement(layer); + hash_layers.push_back(layer); } } @@ -342,7 +342,7 @@ void NcaProcess::generatePartitionConfiguration() default: error.clear(); error << "FormatType(" << nn::hac::ContentArchiveUtil::getFormatTypeAsString(info.format_type) << "): UNKNOWN"; - throw fnd::Exception(kModuleName, error.str()); + throw tc::Exception(kModuleName, error.str()); } // create reader based on encryption type0 @@ -352,21 +352,21 @@ void NcaProcess::generatePartitionConfiguration() } else if (info.enc_type == nn::hac::nca::EncryptionType::AesCtr) { - if (mContentKey.aes_ctr.isSet == false) - throw fnd::Exception(kModuleName, "AES-CTR Key was not determined"); - info.reader = new fnd::OffsetAdjustedIFile(new fnd::AesCtrWrappedIFile(mFile, mContentKey.aes_ctr.var, info.aes_ctr), info.offset, info.size); + if (mContentKey.aes_ctr.isNull()) + throw tc::Exception(kModuleName, "AES-CTR Key was not determined"); + info.reader = new fnd::OffsetAdjustedIFile(new fnd::AesCtrWrappedIFile(mFile, mContentKey.aes_ctr.get(), info.aes_ctr), info.offset, info.size); } else if (info.enc_type == nn::hac::nca::EncryptionType::AesXts || info.enc_type == nn::hac::nca::EncryptionType::AesCtrEx) { error.clear(); error << "EncryptionType(" << nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type) << "): UNSUPPORTED"; - throw fnd::Exception(kModuleName, error.str()); + throw tc::Exception(kModuleName, error.str()); } else { error.clear(); error << "EncryptionType(" << nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type) << "): UNKNOWN"; - throw fnd::Exception(kModuleName, error.str()); + throw tc::Exception(kModuleName, error.str()); } // filter out unrecognised hash types, and hash based readers @@ -378,17 +378,17 @@ void NcaProcess::generatePartitionConfiguration() { error.clear(); error << "HashType(" << nn::hac::ContentArchiveUtil::getHashTypeAsString(info.hash_type) << "): UNKNOWN"; - throw fnd::Exception(kModuleName, error.str()); + throw tc::Exception(kModuleName, error.str()); } } - catch (const fnd::Exception& e) + catch (const tc::Exception& e) { info.fail_reason = std::string(e.error()); } } } -void NcaProcess::validateNcaSignatures() +void nstool::NcaProcess::validateNcaSignatures() { // validate signature[0] fnd::rsa::sRsa2048Key sign0_key; @@ -445,7 +445,7 @@ void NcaProcess::validateNcaSignatures() } } -void NcaProcess::displayHeader() +void nstool::NcaProcess::displayHeader() { std::cout << "[NCA Header]" << std::endl; std::cout << " Format Type: " << nn::hac::ContentArchiveUtil::getFormatHeaderVersionAsString((nn::hac::nca::HeaderFormatVersion)mHdr.getFormatVersion()) << std::endl; @@ -463,7 +463,7 @@ void NcaProcess::displayHeader() std::cout << " RightsId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen, true, "") << std::endl; } - if (mContentKey.kak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) + if (mContentKey.kak_list.size() > 0 && mCliOutputMode.show_keydata) { std::cout << " Key Area:" << std::endl; std::cout << " <--------------------------------------------------------------------------------------------------------->" << std::endl; @@ -486,7 +486,7 @@ void NcaProcess::displayHeader() std::cout << " <--------------------------------------------------------------------------------------------------------->" << std::endl; } - if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + if (mCliOutputMode.show_layout) { std::cout << " Partitions:" << std::endl; for (size_t i = 0; i < mHdr.getPartitionEntryList().size(); i++) @@ -551,7 +551,7 @@ void NcaProcess::displayHeader() } -void NcaProcess::processPartitions() +void nstool::NcaProcess::processPartitions() { for (size_t i = 0; i < mHdr.getPartitionEntryList().size(); i++) { @@ -609,13 +609,13 @@ void NcaProcess::processPartitions() romfs.setExtractPath(mPartitionPath[index].path); romfs.process(); } - } catch (const fnd::Exception& e) { + } catch (const tc::Exception& e) { std::cout << "[WARNING] NCA Partition " << std::dec << index << " not readable (" << e.error() << ")." << std::endl; } } } -const char* NcaProcess::getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const +const char* nstool::NcaProcess::getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const { const char* str = nullptr; diff --git a/src/NcaProcess.h b/src/NcaProcess.h index d467077..0f7538b 100644 --- a/src/NcaProcess.h +++ b/src/NcaProcess.h @@ -1,14 +1,10 @@ #pragma once -#include -#include -#include -#include -#include +#include "types.h" +#include "KeyBag.h" + #include -#include "KeyConfiguration.h" - -#include "common.h" +namespace nstool { class NcaProcess { @@ -18,8 +14,8 @@ public: void process(); // generic - void setInputFile(const fnd::SharedPtr& file); - void setKeyCfg(const KeyConfiguration& keycfg); + void setInputFile(const std::shared_ptr& file); + void setKeyCfg(const KeyBag& keycfg); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -35,8 +31,8 @@ private: const std::string kNpdmExefsPath = "main.npdm"; // user options - fnd::SharedPtr mFile; - KeyConfiguration mKeyCfg; + std::shared_ptr mFile; + KeyBag mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; @@ -60,8 +56,8 @@ private: { byte_t index; bool decrypted; - fnd::aes::sAes128Key enc; - fnd::aes::sAes128Key dec; + KeyBag::aes128_key_t enc; + KeyBag::aes128_key_t dec; void operator=(const sKeyAreaKey& other) { @@ -84,14 +80,14 @@ private: return !(*this == other); } }; - fnd::List kak_list; + std::vector kak_list; - sOptional aes_ctr; + tc::Optional aes_ctr; } mContentKey; struct sPartitionInfo { - fnd::SharedPtr reader; + std::shared_ptr reader; std::string fail_reason; size_t offset; size_t size; @@ -112,4 +108,6 @@ private: void processPartitions(); const char* getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const; -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/NroProcess.cpp b/src/NroProcess.cpp index 465c1cc..c76d845 100644 --- a/src/NroProcess.cpp +++ b/src/NroProcess.cpp @@ -7,19 +7,19 @@ #include #include "NroProcess.h" -NroProcess::NroProcess(): +nstool::NroProcess::NroProcess(): mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false) { } -void NroProcess::process() +void nstool::NroProcess::process() { importHeader(); importCodeSegments(); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) displayHeader(); processRoMeta(); @@ -28,73 +28,73 @@ void NroProcess::process() mAssetProc.process(); } -void NroProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::NroProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void NroProcess::setCliOutputMode(CliOutputMode type) +void nstool::NroProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void NroProcess::setVerifyMode(bool verify) +void nstool::NroProcess::setVerifyMode(bool verify) { mVerify = verify; } -void NroProcess::setIs64BitInstruction(bool flag) +void nstool::NroProcess::setIs64BitInstruction(bool flag) { mRoMeta.setIs64BitInstruction(flag); } -void NroProcess::setListApi(bool listApi) +void nstool::NroProcess::setListApi(bool listApi) { mRoMeta.setListApi(listApi); } -void NroProcess::setListSymbols(bool listSymbols) +void nstool::NroProcess::setListSymbols(bool listSymbols) { mRoMeta.setListSymbols(listSymbols); } -void NroProcess::setAssetListFs(bool list) +void nstool::NroProcess::setAssetListFs(bool list) { mAssetProc.setListFs(list); } -void NroProcess::setAssetIconExtractPath(const std::string& path) +void nstool::NroProcess::setAssetIconExtractPath(const std::string& path) { mAssetProc.setIconExtractPath(path); } -void NroProcess::setAssetNacpExtractPath(const std::string& path) +void nstool::NroProcess::setAssetNacpExtractPath(const std::string& path) { mAssetProc.setNacpExtractPath(path); } -void NroProcess::setAssetRomfsExtractPath(const std::string& path) +void nstool::NroProcess::setAssetRomfsExtractPath(const std::string& path) { mAssetProc.setRomfsExtractPath(path); } -const RoMetadataProcess& NroProcess::getRoMetadataProcess() const +const RoMetadataProcess& nstool::NroProcess::getRoMetadataProcess() const { return mRoMeta; } -void NroProcess::importHeader() +void nstool::NroProcess::importHeader() { - fnd::Vec scratch; + tc::ByteData scratch; if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } if ((*mFile)->size() < sizeof(nn::hac::sNroHeader)) { - throw fnd::Exception(kModuleName, "Corrupt NRO: file too small"); + throw tc::Exception(kModuleName, "Corrupt NRO: file too small"); } scratch.alloc(sizeof(nn::hac::sNroHeader)); @@ -104,7 +104,7 @@ void NroProcess::importHeader() // setup homebrew extension nn::hac::sNroHeader* raw_hdr = (nn::hac::sNroHeader*)scratch.data(); - if (((le_uint64_t*)raw_hdr->reserved_0)->get() == nn::hac::nro::kNroHomebrewStructMagic && (*mFile)->size() > mHdr.getNroSize()) + if (((tc::bn::le64*)raw_hdr->reserved_0)->get() == nn::hac::nro::kNroHomebrewStructMagic && (*mFile)->size() > mHdr.getNroSize()) { mIsHomebrewNro = true; mAssetProc.setInputFile(new fnd::OffsetAdjustedIFile(mFile, mHdr.getNroSize(), (*mFile)->size() - mHdr.getNroSize())); @@ -115,7 +115,7 @@ void NroProcess::importHeader() mIsHomebrewNro = false; } -void NroProcess::importCodeSegments() +void nstool::NroProcess::importCodeSegments() { mTextBlob.alloc(mHdr.getTextInfo().size); (*mFile)->read(mTextBlob.data(), mHdr.getTextInfo().memory_offset, mTextBlob.size()); @@ -125,7 +125,7 @@ void NroProcess::importCodeSegments() (*mFile)->read(mDataBlob.data(), mHdr.getDataInfo().memory_offset, mDataBlob.size()); } -void NroProcess::displayHeader() +void nstool::NroProcess::displayHeader() { std::cout << "[NRO Header]" << std::endl; std::cout << " RoCrt: " << std::endl; @@ -140,7 +140,7 @@ void NroProcess::displayHeader() std::cout << " .ro:" << std::endl; std::cout << " Offset: 0x" << std::hex << mHdr.getRoInfo().memory_offset << std::endl; std::cout << " Size: 0x" << std::hex << mHdr.getRoInfo().size << std::endl; - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) { std::cout << " .api_info:" << std::endl; std::cout << " Offset: 0x" << std::hex << mHdr.getRoEmbeddedInfo().memory_offset << std::endl; @@ -159,7 +159,7 @@ void NroProcess::displayHeader() std::cout << " Size: 0x" << std::hex << mHdr.getBssSize() << std::endl; } -void NroProcess::processRoMeta() +void nstool::NroProcess::processRoMeta() { if (mRoBlob.size()) { diff --git a/src/NroProcess.h b/src/NroProcess.h index 2ef222f..420b58d 100644 --- a/src/NroProcess.h +++ b/src/NroProcess.h @@ -1,15 +1,12 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include +#include "types.h" +#include "RoMetadataProcess.h" #include "AssetProcess.h" -#include "common.h" -#include "RoMetadataProcess.h" +#include +#include + +namespace nstool { class NroProcess { @@ -18,7 +15,7 @@ public: void process(); - void setInputFile(const fnd::SharedPtr& file); + void setInputFile(const std::shared_ptr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -36,12 +33,12 @@ public: private: const std::string kModuleName = "NroProcess"; - fnd::SharedPtr mFile; + std::shared_ptr mFile; CliOutputMode mCliOutputMode; bool mVerify; nn::hac::NroHeader mHdr; - fnd::Vec mTextBlob, mRoBlob, mDataBlob; + tc::ByteData mTextBlob, mRoBlob, mDataBlob; RoMetadataProcess mRoMeta; bool mIsHomebrewNro; AssetProcess mAssetProc; @@ -50,4 +47,6 @@ private: void importCodeSegments(); void displayHeader(); void processRoMeta(); -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/NsoProcess.cpp b/src/NsoProcess.cpp index 7b8db33..dbdc11f 100644 --- a/src/NsoProcess.cpp +++ b/src/NsoProcess.cpp @@ -6,9 +6,9 @@ #include #include "NsoProcess.h" -NsoProcess::NsoProcess(): +nstool::NsoProcess::NsoProcess(): mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false), mIs64BitInstruction(true), mListApi(false), @@ -16,63 +16,63 @@ NsoProcess::NsoProcess(): { } -void NsoProcess::process() +void nstool::NsoProcess::process() { importHeader(); importCodeSegments(); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) displayNsoHeader(); processRoMeta(); } -void NsoProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::NsoProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void NsoProcess::setCliOutputMode(CliOutputMode type) +void nstool::NsoProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void NsoProcess::setVerifyMode(bool verify) +void nstool::NsoProcess::setVerifyMode(bool verify) { mVerify = verify; } -void NsoProcess::setIs64BitInstruction(bool flag) +void nstool::NsoProcess::setIs64BitInstruction(bool flag) { mRoMeta.setIs64BitInstruction(flag); } -void NsoProcess::setListApi(bool listApi) +void nstool::NsoProcess::setListApi(bool listApi) { mRoMeta.setListApi(listApi); } -void NsoProcess::setListSymbols(bool listSymbols) +void nstool::NsoProcess::setListSymbols(bool listSymbols) { mRoMeta.setListSymbols(listSymbols); } -const RoMetadataProcess& NsoProcess::getRoMetadataProcess() const +const RoMetadataProcess& nstool::NsoProcess::getRoMetadataProcess() const { return mRoMeta; } -void NsoProcess::importHeader() +void nstool::NsoProcess::importHeader() { - fnd::Vec scratch; + tc::ByteData scratch; if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } if ((*mFile)->size() < sizeof(nn::hac::sNsoHeader)) { - throw fnd::Exception(kModuleName, "Corrupt NSO: file too small"); + throw tc::Exception(kModuleName, "Corrupt NSO: file too small"); } scratch.alloc(sizeof(nn::hac::sNsoHeader)); @@ -81,9 +81,9 @@ void NsoProcess::importHeader() mHdr.fromBytes(scratch.data(), scratch.size()); } -void NsoProcess::importCodeSegments() +void nstool::NsoProcess::importCodeSegments() { - fnd::Vec scratch; + tc::ByteData scratch; uint32_t decompressed_len; fnd::sha::sSha256Hash calc_hash; @@ -96,7 +96,7 @@ void NsoProcess::importCodeSegments() fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mTextBlob.data(), (uint32_t)mTextBlob.size(), decompressed_len); if (decompressed_len != mTextBlob.size()) { - throw fnd::Exception(kModuleName, "NSO text segment failed to decompress"); + throw tc::Exception(kModuleName, "NSO text segment failed to decompress"); } } else @@ -109,7 +109,7 @@ void NsoProcess::importCodeSegments() fnd::sha::Sha256(mTextBlob.data(), mTextBlob.size(), calc_hash.bytes); if (calc_hash != mHdr.getTextSegmentInfo().hash) { - throw fnd::Exception(kModuleName, "NSO text segment failed SHA256 verification"); + throw tc::Exception(kModuleName, "NSO text segment failed SHA256 verification"); } } @@ -122,7 +122,7 @@ void NsoProcess::importCodeSegments() fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mRoBlob.data(), (uint32_t)mRoBlob.size(), decompressed_len); if (decompressed_len != mRoBlob.size()) { - throw fnd::Exception(kModuleName, "NSO ro segment failed to decompress"); + throw tc::Exception(kModuleName, "NSO ro segment failed to decompress"); } } else @@ -135,7 +135,7 @@ void NsoProcess::importCodeSegments() fnd::sha::Sha256(mRoBlob.data(), mRoBlob.size(), calc_hash.bytes); if (calc_hash != mHdr.getRoSegmentInfo().hash) { - throw fnd::Exception(kModuleName, "NSO ro segment failed SHA256 verification"); + throw tc::Exception(kModuleName, "NSO ro segment failed SHA256 verification"); } } @@ -148,7 +148,7 @@ void NsoProcess::importCodeSegments() fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mDataBlob.data(), (uint32_t)mDataBlob.size(), decompressed_len); if (decompressed_len != mDataBlob.size()) { - throw fnd::Exception(kModuleName, "NSO data segment failed to decompress"); + throw tc::Exception(kModuleName, "NSO data segment failed to decompress"); } } else @@ -161,16 +161,16 @@ void NsoProcess::importCodeSegments() fnd::sha::Sha256(mDataBlob.data(), mDataBlob.size(), calc_hash.bytes); if (calc_hash != mHdr.getDataSegmentInfo().hash) { - throw fnd::Exception(kModuleName, "NSO data segment failed SHA256 verification"); + throw tc::Exception(kModuleName, "NSO data segment failed SHA256 verification"); } } } -void NsoProcess::displayNsoHeader() +void nstool::NsoProcess::displayNsoHeader() { std::cout << "[NSO Header]" << std::endl; std::cout << " ModuleId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize, false, "") << std::endl; - if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + if (mCliOutputMode.show_layout) { std::cout << " Program Segments:" << std::endl; std::cout << " .module_name:" << std::endl; @@ -190,18 +190,18 @@ void NsoProcess::displayNsoHeader() std::cout << " .text:" << std::endl; std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.offset << std::endl; std::cout << " MemorySize: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.size << std::endl; - if (mHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mHdr.getTextSegmentInfo().is_hashed && mCliOutputMode.show_extended_info) { std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getTextSegmentInfo().hash.bytes, 32, false, "") << std::endl; } std::cout << " .ro:" << std::endl; std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.offset << std::endl; std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.size << std::endl; - if (mHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mHdr.getRoSegmentInfo().is_hashed && mCliOutputMode.show_extended_info) { std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRoSegmentInfo().hash.bytes, 32, false, "") << std::endl; } - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) { std::cout << " .api_info:" << std::endl; std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoEmbeddedInfo().offset << std::endl; @@ -217,7 +217,7 @@ void NsoProcess::displayNsoHeader() std::cout << " .data:" << std::endl; std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.offset << std::endl; std::cout << " MemorySize: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.size << std::endl; - if (mHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mHdr.getDataSegmentInfo().is_hashed && mCliOutputMode.show_extended_info) { std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getDataSegmentInfo().hash.bytes, 32, false, "") << std::endl; } @@ -225,7 +225,7 @@ void NsoProcess::displayNsoHeader() std::cout << " MemorySize: 0x" << std::hex << mHdr.getBssSize() << std::endl; } -void NsoProcess::processRoMeta() +void nstool::NsoProcess::processRoMeta() { if (mRoBlob.size()) { diff --git a/src/NsoProcess.h b/src/NsoProcess.h index 2d29784..2f4fbb2 100644 --- a/src/NsoProcess.h +++ b/src/NsoProcess.h @@ -1,14 +1,11 @@ #pragma once -#include -#include -#include -#include -#include +#include "types.h" +#include "RoMetadataProcess.h" + #include #include -#include "common.h" -#include "RoMetadataProcess.h" +namespace nstool { class NsoProcess { @@ -17,7 +14,7 @@ public: void process(); - void setInputFile(const fnd::SharedPtr& file); + void setInputFile(const std::shared_ptr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -29,7 +26,7 @@ public: private: const std::string kModuleName = "NsoProcess"; - fnd::SharedPtr mFile; + std::shared_ptr mFile; CliOutputMode mCliOutputMode; bool mVerify; bool mIs64BitInstruction; @@ -37,11 +34,13 @@ private: bool mListSymbols; nn::hac::NsoHeader mHdr; - fnd::Vec mTextBlob, mRoBlob, mDataBlob; + tc::ByteData mTextBlob, mRoBlob, mDataBlob; RoMetadataProcess mRoMeta; void importHeader(); void importCodeSegments(); void displayNsoHeader(); void processRoMeta(); -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/PfsProcess.cpp b/src/PfsProcess.cpp index 36287e5..425df18 100644 --- a/src/PfsProcess.cpp +++ b/src/PfsProcess.cpp @@ -9,9 +9,9 @@ #include -PfsProcess::PfsProcess() : +nstool::PfsProcess::PfsProcess() : mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false), mExtractPath(), mExtract(false), @@ -21,14 +21,14 @@ PfsProcess::PfsProcess() : { } -void PfsProcess::process() +void nstool::PfsProcess::process() { importHeader(); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) { displayHeader(); - if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mListFs || mCliOutputMode.show_extended_info) displayFs(); } if (mPfs.getFsType() == mPfs.TYPE_HFS0 && mVerify) @@ -37,49 +37,49 @@ void PfsProcess::process() extractFs(); } -void PfsProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::PfsProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void PfsProcess::setCliOutputMode(CliOutputMode type) +void nstool::PfsProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void PfsProcess::setVerifyMode(bool verify) +void nstool::PfsProcess::setVerifyMode(bool verify) { mVerify = verify; } -void PfsProcess::setMountPointName(const std::string& mount_name) +void nstool::PfsProcess::setMountPointName(const std::string& mount_name) { mMountName = mount_name; } -void PfsProcess::setExtractPath(const std::string& path) +void nstool::PfsProcess::setExtractPath(const std::string& path) { mExtract = true; mExtractPath = path; } -void PfsProcess::setListFs(bool list_fs) +void nstool::PfsProcess::setListFs(bool list_fs) { mListFs = list_fs; } -const nn::hac::PartitionFsHeader& PfsProcess::getPfsHeader() const +const nn::hac::PartitionFsHeader& nstool::PfsProcess::getPfsHeader() const { return mPfs; } -void PfsProcess::importHeader() +void nstool::PfsProcess::importHeader() { - fnd::Vec scratch; + tc::ByteData scratch; if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } // open minimum header to get full header size @@ -87,7 +87,7 @@ void PfsProcess::importHeader() (*mFile)->read(scratch.data(), 0, scratch.size()); if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false) { - throw fnd::Exception(kModuleName, "Corrupt Header"); + throw tc::Exception(kModuleName, "Corrupt Header"); } size_t pfsHeaderSize = determineHeaderSize(((nn::hac::sPfsHeader*)scratch.data())); @@ -97,7 +97,7 @@ void PfsProcess::importHeader() mPfs.fromBytes(scratch.data(), scratch.size()); } -void PfsProcess::displayHeader() +void nstool::PfsProcess::displayHeader() { std::cout << "[PartitionFS]" << std::endl; std::cout << " Type: " << nn::hac::PartitionFsUtil::getFsTypeAsString(mPfs.getFsType()) << std::endl; @@ -111,13 +111,13 @@ void PfsProcess::displayHeader() } } -void PfsProcess::displayFs() +void nstool::PfsProcess::displayFs() { for (size_t i = 0; i < mPfs.getFileList().size(); i++) { const nn::hac::PartitionFsHeader::sFile& file = mPfs.getFileList()[i]; std::cout << " " << file.name; - if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + if (mCliOutputMode.show_layout) { switch (mPfs.getFsType()) { @@ -134,7 +134,7 @@ void PfsProcess::displayFs() } } -size_t PfsProcess::determineHeaderSize(const nn::hac::sPfsHeader* hdr) +size_t nstool::PfsProcess::determineHeaderSize(const nn::hac::sPfsHeader* hdr) { size_t fileEntrySize = 0; if (hdr->st_magic.get() == nn::hac::pfs::kPfsStructMagic) @@ -145,15 +145,15 @@ size_t PfsProcess::determineHeaderSize(const nn::hac::sPfsHeader* hdr) return sizeof(nn::hac::sPfsHeader) + hdr->file_num.get() * fileEntrySize + hdr->name_table_size.get(); } -bool PfsProcess::validateHeaderMagic(const nn::hac::sPfsHeader* hdr) +bool nstool::PfsProcess::validateHeaderMagic(const nn::hac::sPfsHeader* hdr) { return hdr->st_magic.get() == nn::hac::pfs::kPfsStructMagic || hdr->st_magic.get() == nn::hac::pfs::kHashedPfsStructMagic; } -void PfsProcess::validateHfs() +void nstool::PfsProcess::validateHfs() { fnd::sha::sSha256Hash hash; - const fnd::List& file = mPfs.getFileList(); + const std::vector& file = mPfs.getFileList(); for (size_t i = 0; i < file.size(); i++) { mCache.alloc(file[i].hash_protected_size); @@ -166,7 +166,7 @@ void PfsProcess::validateHfs() } } -void PfsProcess::extractFs() +void nstool::PfsProcess::extractFs() { // allocate only when extractDir is invoked mCache.alloc(kCacheSize); @@ -175,7 +175,7 @@ void PfsProcess::extractFs() fnd::io::makeDirectory(mExtractPath); fnd::SimpleFile outFile; - const fnd::List& file = mPfs.getFileList(); + const std::vector& file = mPfs.getFileList(); std::string file_path; for (size_t i = 0; i < file.size(); i++) @@ -184,7 +184,7 @@ void PfsProcess::extractFs() fnd::io::appendToPath(file_path, mExtractPath); fnd::io::appendToPath(file_path, file[i].name); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) printf("extract=[%s]\n", file_path.c_str()); outFile.open(file_path, outFile.Create); diff --git a/src/PfsProcess.h b/src/PfsProcess.h index 8ae6fd7..2736809 100644 --- a/src/PfsProcess.h +++ b/src/PfsProcess.h @@ -1,11 +1,9 @@ #pragma once -#include -#include -#include -#include +#include "types.h" + #include -#include "common.h" +namespace nstool { class PfsProcess { @@ -15,7 +13,7 @@ public: void process(); // generic - void setInputFile(const fnd::SharedPtr& file); + void setInputFile(const std::shared_ptr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -30,7 +28,7 @@ private: const std::string kModuleName = "PfsProcess"; static const size_t kCacheSize = 0x10000; - fnd::SharedPtr mFile; + std::shared_ptr mFile; CliOutputMode mCliOutputMode; bool mVerify; @@ -39,7 +37,7 @@ private: std::string mMountName; bool mListFs; - fnd::Vec mCache; + tc::ByteData mCache; nn::hac::PartitionFsHeader mPfs; @@ -50,4 +48,6 @@ private: bool validateHeaderMagic(const nn::hac::sPfsHeader* hdr); void validateHfs(); void extractFs(); -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/PkiCertProcess.cpp b/src/PkiCertProcess.cpp index 4433ae7..45ce6b7 100644 --- a/src/PkiCertProcess.cpp +++ b/src/PkiCertProcess.cpp @@ -6,51 +6,51 @@ #include "PkiCertProcess.h" #include "PkiValidator.h" -PkiCertProcess::PkiCertProcess() : +nstool::PkiCertProcess::PkiCertProcess() : mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false) { } -void PkiCertProcess::process() +void nstool::PkiCertProcess::process() { importCerts(); if (mVerify) validateCerts(); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) displayCerts(); } -void PkiCertProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::PkiCertProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void PkiCertProcess::setKeyCfg(const KeyConfiguration& keycfg) +void nstool::PkiCertProcess::setKeyCfg(const KeyBag& keycfg) { mKeyCfg = keycfg; } -void PkiCertProcess::setCliOutputMode(CliOutputMode mode) +void nstool::PkiCertProcess::setCliOutputMode(CliOutputMode mode) { mCliOutputMode = mode; } -void PkiCertProcess::setVerifyMode(bool verify) +void nstool::PkiCertProcess::setVerifyMode(bool verify) { mVerify = verify; } -void PkiCertProcess::importCerts() +void nstool::PkiCertProcess::importCerts() { - fnd::Vec scratch; + tc::ByteData scratch; if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } scratch.alloc((*mFile)->size()); @@ -60,11 +60,11 @@ void PkiCertProcess::importCerts() for (size_t f_pos = 0; f_pos < scratch.size(); f_pos += cert.getBytes().size()) { cert.fromBytes(scratch.data() + f_pos, scratch.size() - f_pos); - mCert.addElement(cert); + mCert.push_back(cert); } } -void PkiCertProcess::validateCerts() +void nstool::PkiCertProcess::validateCerts() { PkiValidator pki; @@ -73,14 +73,14 @@ void PkiCertProcess::validateCerts() pki.setKeyCfg(mKeyCfg); pki.addCertificates(mCert); } - catch (const fnd::Exception& e) + catch (const tc::Exception& e) { std::cout << "[WARNING] " << e.error() << std::endl; return; } } -void PkiCertProcess::displayCerts() +void nstool::PkiCertProcess::displayCerts() { for (size_t i = 0; i < mCert.size(); i++) { @@ -88,19 +88,19 @@ void PkiCertProcess::displayCerts() } } -void PkiCertProcess::displayCert(const nn::pki::SignedData& cert) +void nstool::PkiCertProcess::displayCert(const nn::pki::SignedData& cert) { std::cout << "[NNPKI Certificate]" << std::endl; std::cout << " SignType " << getSignTypeStr(cert.getSignature().getSignType()); - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) std::cout << " (0x" << std::hex << cert.getSignature().getSignType() << ") (" << getEndiannessStr(cert.getSignature().isLittleEndian()) << ")"; std::cout << std::endl; std::cout << " Issuer: " << cert.getBody().getIssuer() << std::endl; std::cout << " Subject: " << cert.getBody().getSubject() << std::endl; std::cout << " PublicKeyType: " << getPublicKeyTypeStr(cert.getBody().getPublicKeyType()); - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mCliOutputMode.show_extended_info) std::cout << " (" << std::dec << cert.getBody().getPublicKeyType() << ")"; std::cout << std::endl; std::cout << " CertID: 0x" << std::hex << cert.getBody().getCertId() << std::endl; @@ -131,12 +131,12 @@ void PkiCertProcess::displayCert(const nn::pki::SignedData -#include -#include -#include -#include -#include +#include "types.h" +#include "KeyBag.h" + #include #include -#include "KeyConfiguration.h" -#include "common.h" + +namespace nstool { class PkiCertProcess { @@ -17,8 +14,8 @@ public: void process(); - void setInputFile(const fnd::SharedPtr& file); - void setKeyCfg(const KeyConfiguration& keycfg); + void setInputFile(const std::shared_ptr& file); + void setKeyCfg(const KeyBag& keycfg); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -26,12 +23,12 @@ private: const std::string kModuleName = "PkiCertProcess"; static const size_t kSmallHexDumpLen = 0x10; - fnd::SharedPtr mFile; - KeyConfiguration mKeyCfg; + std::shared_ptr mFile; + KeyBag mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; - fnd::List> mCert; + std::vector> mCert; void importCerts(); void validateCerts(); @@ -42,4 +39,6 @@ private: const char* getSignTypeStr(nn::pki::sign::SignatureId type) const; const char* getEndiannessStr(bool isLittleEndian) const; const char* getPublicKeyTypeStr(nn::pki::cert::PublicKeyType type) const; -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/PkiValidator.cpp b/src/PkiValidator.cpp index 37bb9b5..d608e90 100644 --- a/src/PkiValidator.cpp +++ b/src/PkiValidator.cpp @@ -4,15 +4,15 @@ #include #include "PkiValidator.h" -PkiValidator::PkiValidator() +nstool::PkiValidator::PkiValidator() { clearCertificates(); } -void PkiValidator::setKeyCfg(const KeyConfiguration& keycfg) +void nstool::PkiValidator::setKeyCfg(const KeyBag& keycfg) { // save a copy of the certificate bank - fnd::List> old_certs = mCertificateBank; + std::vector> old_certs = mCertificateBank; // clear the certificate bank mCertificateBank.clear(); @@ -27,7 +27,7 @@ void PkiValidator::setKeyCfg(const KeyConfiguration& keycfg) } } -void PkiValidator::addCertificates(const fnd::List>& certs) +void nstool::PkiValidator::addCertificates(const std::vector>& certs) { for (size_t i = 0; i < certs.size(); i++) { @@ -35,12 +35,12 @@ void PkiValidator::addCertificates(const fnd::List& cert) +void nstool::PkiValidator::addCertificate(const nn::pki::SignedData& cert) { std::string cert_ident; nn::pki::sign::SignatureAlgo cert_sign_algo; nn::pki::sign::HashAlgo cert_hash_algo; - fnd::Vec cert_hash; + tc::ByteData cert_hash; try { @@ -48,7 +48,7 @@ void PkiValidator::addCertificate(const nn::pki::SignedData& signature, const fnd::Vec& hash) const +void nstool::PkiValidator::validateSignature(const std::string& issuer, nn::pki::sign::SignatureId signature_id, const tc::ByteData& signature, const tc::ByteData& hash) const { nn::pki::sign::SignatureAlgo sign_algo = nn::pki::sign::getSignatureAlgo(signature_id); nn::pki::sign::HashAlgo hash_algo = nn::pki::sign::getHashAlgo(signature_id); @@ -112,11 +112,11 @@ void PkiValidator::validateSignature(const std::string& issuer, nn::pki::sign::S } else if (mKeyCfg.getPkiRootSignKey(issuer, ecdsa_pub) == true && sign_algo == nn::pki::sign::SIGN_ALGO_ECDSA240) { - throw fnd::Exception(kModuleName, "ECDSA signatures are not supported"); + throw tc::Exception(kModuleName, "ECDSA signatures are not supported"); } else { - throw fnd::Exception(kModuleName, "Public key for issuer \"" + issuer + "\" does not exist."); + throw tc::Exception(kModuleName, "Public key for issuer \"" + issuer + "\" does not exist."); } } else @@ -135,34 +135,34 @@ void PkiValidator::validateSignature(const std::string& issuer, nn::pki::sign::S } else if (issuer_pubk_type == nn::pki::cert::ECDSA240 && sign_algo == nn::pki::sign::SIGN_ALGO_ECDSA240) { - throw fnd::Exception(kModuleName, "ECDSA signatures are not supported"); + throw tc::Exception(kModuleName, "ECDSA signatures are not supported"); } else { - throw fnd::Exception(kModuleName, "Mismatch between issuer public key and signature type"); + throw tc::Exception(kModuleName, "Mismatch between issuer public key and signature type"); } } if (sig_validate_res != 0) { - throw fnd::Exception(kModuleName, "Incorrect signature"); + throw tc::Exception(kModuleName, "Incorrect signature"); } } -void PkiValidator::makeCertIdent(const nn::pki::SignedData& cert, std::string& ident) const +void nstool::PkiValidator::makeCertIdent(const nn::pki::SignedData& cert, std::string& ident) const { makeCertIdent(cert.getBody().getIssuer(), cert.getBody().getSubject(), ident); } -void PkiValidator::makeCertIdent(const std::string& issuer, const std::string& subject, std::string& ident) const +void nstool::PkiValidator::makeCertIdent(const std::string& issuer, const std::string& subject, std::string& ident) const { ident = issuer + nn::pki::sign::kIdentDelimiter + subject; ident = ident.substr(0, _MIN(ident.length(),64)); } -bool PkiValidator::doesCertExist(const std::string& ident) const +bool nstool::PkiValidator::doesCertExist(const std::string& ident) const { bool exists = false; std::string full_cert_name; @@ -179,7 +179,7 @@ bool PkiValidator::doesCertExist(const std::string& ident) const return exists; } -const nn::pki::SignedData& PkiValidator::getCert(const std::string& ident) const +const nn::pki::SignedData& nstool::PkiValidator::getCert(const std::string& ident) const { std::string full_cert_name; for (size_t i = 0; i < mCertificateBank.size(); i++) @@ -191,10 +191,10 @@ const nn::pki::SignedData& PkiValidator::getCert(const } } - throw fnd::Exception(kModuleName, "Issuer certificate does not exist"); + throw tc::Exception(kModuleName, "Issuer certificate does not exist"); } -fnd::sha::HashType PkiValidator::getCryptoHashAlgoFromEsSignHashAlgo(nn::pki::sign::HashAlgo hash_algo) const +fnd::sha::HashType nstool::PkiValidator::getCryptoHashAlgoFromEsSignHashAlgo(nn::pki::sign::HashAlgo hash_algo) const { fnd::sha::HashType hash_type = fnd::sha::HASH_SHA1; diff --git a/src/PkiValidator.h b/src/PkiValidator.h index 7b7a0ab..6cc2006 100644 --- a/src/PkiValidator.h +++ b/src/PkiValidator.h @@ -1,34 +1,35 @@ #pragma once -#include -#include -#include -#include +#include "types.h" +#include "KeyBag.h" + #include #include -#include -#include "KeyConfiguration.h" + +namespace nstool { class PkiValidator { public: PkiValidator(); - void setKeyCfg(const KeyConfiguration& keycfg); - void addCertificates(const fnd::List>& certs); + void setKeyCfg(const KeyBag& keycfg); + void addCertificates(const std::vector>& certs); void addCertificate(const nn::pki::SignedData& cert); void clearCertificates(); - void validateSignature(const std::string& issuer, nn::pki::sign::SignatureId signature_id, const fnd::Vec& signature, const fnd::Vec& hash) const; + void validateSignature(const std::string& issuer, nn::pki::sign::SignatureId signature_id, const tc::ByteData& signature, const tc::ByteData& hash) const; private: const std::string kModuleName = "NNPkiValidator"; - KeyConfiguration mKeyCfg; - fnd::List> mCertificateBank; + KeyBag mKeyCfg; + std::vector> mCertificateBank; void makeCertIdent(const nn::pki::SignedData& cert, std::string& ident) const; void makeCertIdent(const std::string& issuer, const std::string& subject, std::string& ident) const; bool doesCertExist(const std::string& ident) const; const nn::pki::SignedData& getCert(const std::string& ident) const; fnd::sha::HashType getCryptoHashAlgoFromEsSignHashAlgo(nn::pki::sign::HashAlgo hash_algo) const; -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/RoMetadataProcess.cpp b/src/RoMetadataProcess.cpp index 81e9b47..019c4ef 100644 --- a/src/RoMetadataProcess.cpp +++ b/src/RoMetadataProcess.cpp @@ -5,8 +5,8 @@ #include "RoMetadataProcess.h" -RoMetadataProcess::RoMetadataProcess() : - mCliOutputMode(_BIT(OUTPUT_BASIC)), +nstool::RoMetadataProcess::RoMetadataProcess() : + mCliOutputMode(true, false, false, false), mIs64BitInstruction(true), mListApi(false), mListSymbols(false), @@ -23,90 +23,90 @@ RoMetadataProcess::RoMetadataProcess() : } -void RoMetadataProcess::process() +void nstool::RoMetadataProcess::process() { importApiList(); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) displayRoMetaData(); } -void RoMetadataProcess::setRoBinary(const fnd::Vec& bin) +void nstool::RoMetadataProcess::setRoBinary(const tc::ByteData& bin) { mRoBlob = bin; } -void RoMetadataProcess::setApiInfo(size_t offset, size_t size) +void nstool::RoMetadataProcess::setApiInfo(size_t offset, size_t size) { mApiInfo.offset = offset; mApiInfo.size = size; } -void RoMetadataProcess::setDynSym(size_t offset, size_t size) +void nstool::RoMetadataProcess::setDynSym(size_t offset, size_t size) { mDynSym.offset = offset; mDynSym.size = size; } -void RoMetadataProcess::setDynStr(size_t offset, size_t size) +void nstool::RoMetadataProcess::setDynStr(size_t offset, size_t size) { mDynStr.offset = offset; mDynStr.size = size; } -void RoMetadataProcess::setCliOutputMode(CliOutputMode type) +void nstool::RoMetadataProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void RoMetadataProcess::setIs64BitInstruction(bool flag) +void nstool::RoMetadataProcess::setIs64BitInstruction(bool flag) { mIs64BitInstruction = flag; } -void RoMetadataProcess::setListApi(bool listApi) +void nstool::RoMetadataProcess::setListApi(bool listApi) { mListApi = listApi; } -void RoMetadataProcess::setListSymbols(bool listSymbols) +void nstool::RoMetadataProcess::setListSymbols(bool listSymbols) { mListSymbols = listSymbols; } -const std::vector& RoMetadataProcess::getSdkVerApiList() const +const std::vector& nstool::RoMetadataProcess::getSdkVerApiList() const { return mSdkVerApiList; } -const std::vector& RoMetadataProcess::getPublicApiList() const +const std::vector& nstool::RoMetadataProcess::getPublicApiList() const { return mPublicApiList; } -const std::vector& RoMetadataProcess::getDebugApiList() const +const std::vector& nstool::RoMetadataProcess::getDebugApiList() const { return mDebugApiList; } -const std::vector& RoMetadataProcess::getPrivateApiList() const +const std::vector& nstool::RoMetadataProcess::getPrivateApiList() const { return mPrivateApiList; } -const std::vector& RoMetadataProcess::getGuidelineApiList() const +const std::vector& nstool::RoMetadataProcess::getGuidelineApiList() const { return mGuidelineApiList; } -const fnd::List& RoMetadataProcess::getSymbolList() const +const std::vector& nstool::RoMetadataProcess::getSymbolList() const { return mSymbolList.getSymbolList(); } -void RoMetadataProcess::importApiList() +void nstool::RoMetadataProcess::importApiList() { if (mRoBlob.size() == 0) { - throw fnd::Exception(kModuleName, "No ro binary set."); + throw tc::Exception(kModuleName, "No ro binary set."); } if (mApiInfo.size > 0) @@ -147,11 +147,11 @@ void RoMetadataProcess::importApiList() } } -void RoMetadataProcess::displayRoMetaData() +void nstool::RoMetadataProcess::displayRoMetaData() { size_t api_num = mSdkVerApiList.size() + mPublicApiList.size() + mDebugApiList.size() + mPrivateApiList.size(); - if (api_num > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) + if (api_num > 0 && (mListApi || mCliOutputMode.show_extended_info)) { std::cout << "[SDK API List]" << std::endl; if (mSdkVerApiList.size() > 0) @@ -191,7 +191,7 @@ void RoMetadataProcess::displayRoMetaData() } } } - if (mSymbolList.getSymbolList().size() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) + if (mSymbolList.getSymbolList().size() > 0 && (mListSymbols || mCliOutputMode.show_extended_info)) { std::cout << "[Symbol List]" << std::endl; for (size_t i = 0; i < mSymbolList.getSymbolList().size(); i++) @@ -202,7 +202,7 @@ void RoMetadataProcess::displayRoMetaData() } } -const char* RoMetadataProcess::getSectionIndexStr(uint16_t shn_index) const +const char* nstool::RoMetadataProcess::getSectionIndexStr(uint16_t shn_index) const { const char* str; switch (shn_index) @@ -235,7 +235,7 @@ const char* RoMetadataProcess::getSectionIndexStr(uint16_t shn_index) const return str; } -const char* RoMetadataProcess::getSymbolTypeStr(byte_t symbol_type) const +const char* nstool::RoMetadataProcess::getSymbolTypeStr(byte_t symbol_type) const { const char* str; switch (symbol_type) @@ -274,7 +274,7 @@ const char* RoMetadataProcess::getSymbolTypeStr(byte_t symbol_type) const return str; } -const char* RoMetadataProcess::getSymbolBindingStr(byte_t symbol_binding) const +const char* nstool::RoMetadataProcess::getSymbolBindingStr(byte_t symbol_binding) const { const char* str; switch (symbol_binding) diff --git a/src/RoMetadataProcess.h b/src/RoMetadataProcess.h index df854c1..4a13cc9 100644 --- a/src/RoMetadataProcess.h +++ b/src/RoMetadataProcess.h @@ -1,14 +1,11 @@ #pragma once -#include -#include -#include -#include +#include "types.h" +#include "SdkApiString.h" +#include "ElfSymbolParser.h" #include -#include "common.h" -#include "SdkApiString.h" -#include "ElfSymbolParser.h" +namespace nstool { class RoMetadataProcess { @@ -17,7 +14,7 @@ public: void process(); - void setRoBinary(const fnd::Vec& bin); + void setRoBinary(const tc::ByteData& bin); void setApiInfo(size_t offset, size_t size); void setDynSym(size_t offset, size_t size); void setDynStr(size_t offset, size_t size); @@ -33,7 +30,7 @@ public: const std::vector& getDebugApiList() const; const std::vector& getPrivateApiList() const; const std::vector& getGuidelineApiList() const; - const fnd::List& getSymbolList() const; + const std::vector& getSymbolList() const; private: const std::string kModuleName = "RoMetadataProcess"; @@ -52,7 +49,7 @@ private: sLayout mApiInfo; sLayout mDynSym; sLayout mDynStr; - fnd::Vec mRoBlob; + tc::ByteData mRoBlob; std::vector mSdkVerApiList; std::vector mPublicApiList; std::vector mDebugApiList; @@ -67,4 +64,6 @@ private: const char* getSectionIndexStr(uint16_t shn_index) const; const char* getSymbolTypeStr(byte_t symbol_type) const; const char* getSymbolBindingStr(byte_t symbol_binding) const; -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/RomfsProcess.cpp b/src/RomfsProcess.cpp index f03e0be..93207e6 100644 --- a/src/RomfsProcess.cpp +++ b/src/RomfsProcess.cpp @@ -6,9 +6,9 @@ #include "CompressedArchiveIFile.h" #include "RomfsProcess.h" -RomfsProcess::RomfsProcess() : +nstool::RomfsProcess::RomfsProcess() : mFile(), - mCliOutputMode(_BIT(OUTPUT_BASIC)), + mCliOutputMode(true, false, false, false), mVerify(false), mExtractPath(), mExtract(false), @@ -22,14 +22,14 @@ RomfsProcess::RomfsProcess() : mRootDir.file_list.clear(); } -void RomfsProcess::process() +void nstool::RomfsProcess::process() { resolveRomfs(); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) { displayHeader(); - if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + if (mListFs || mCliOutputMode.show_extended_info) displayFs(); } @@ -37,43 +37,43 @@ void RomfsProcess::process() extractFs(); } -void RomfsProcess::setInputFile(const fnd::SharedPtr& file) +void nstool::RomfsProcess::setInputFile(const std::shared_ptr& file) { mFile = file; } -void RomfsProcess::setCliOutputMode(CliOutputMode type) +void nstool::RomfsProcess::setCliOutputMode(CliOutputMode type) { mCliOutputMode = type; } -void RomfsProcess::setVerifyMode(bool verify) +void nstool::RomfsProcess::setVerifyMode(bool verify) { mVerify = verify; } -void RomfsProcess::setMountPointName(const std::string& mount_name) +void nstool::RomfsProcess::setMountPointName(const std::string& mount_name) { mMountName = mount_name; } -void RomfsProcess::setExtractPath(const std::string& path) +void nstool::RomfsProcess::setExtractPath(const std::string& path) { mExtract = true; mExtractPath = path; } -void RomfsProcess::setListFs(bool list_fs) +void nstool::RomfsProcess::setListFs(bool list_fs) { mListFs = list_fs; } -const RomfsProcess::sDirectory& RomfsProcess::getRootDir() const +const nstool::RomfsProcess::sDirectory& nstool::RomfsProcess::getRootDir() const { return mRootDir; } -void RomfsProcess::printTab(size_t tab) const +void nstool::RomfsProcess::printTab(size_t tab) const { for (size_t i = 0; i < tab; i++) { @@ -81,18 +81,18 @@ void RomfsProcess::printTab(size_t tab) const } } -void RomfsProcess::displayFile(const sFile& file, size_t tab) const +void nstool::RomfsProcess::displayFile(const sFile& file, size_t tab) const { printTab(tab); std::cout << file.name; - if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + if (mCliOutputMode.show_layout) { std::cout << std::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ")"; } std::cout << std::endl; } -void RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const +void nstool::RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const { if (dir.name.empty() == false) { @@ -110,7 +110,7 @@ void RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const } } -void RomfsProcess::displayHeader() +void nstool::RomfsProcess::displayHeader() { std::cout << "[RomFS]" << std::endl; std::cout << " DirNum: " << std::dec << mDirNum << std::endl; @@ -124,12 +124,12 @@ void RomfsProcess::displayHeader() } } -void RomfsProcess::displayFs() +void nstool::RomfsProcess::displayFs() { displayDir(mRootDir, 1); } -void RomfsProcess::extractDir(const std::string& path, const sDirectory& dir) +void nstool::RomfsProcess::extractDir(const std::string& path, const sDirectory& dir) { std::string dir_path; std::string file_path; @@ -150,7 +150,7 @@ void RomfsProcess::extractDir(const std::string& path, const sDirectory& dir) fnd::io::appendToPath(file_path, dir_path); fnd::io::appendToPath(file_path, dir.file_list[i].name); - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + if (mCliOutputMode.show_basic_info) std::cout << "extract=[" << file_path << "]" << std::endl; outFile.open(file_path, outFile.Create); @@ -170,14 +170,14 @@ void RomfsProcess::extractDir(const std::string& path, const sDirectory& dir) } -void RomfsProcess::extractFs() +void nstool::RomfsProcess::extractFs() { // allocate only when extractDir is invoked mCache.alloc(kCacheSize); extractDir(mExtractPath, mRootDir); } -bool RomfsProcess::validateHeaderLayout(const nn::hac::sRomfsHeader* hdr) const +bool nstool::RomfsProcess::validateHeaderLayout(const nn::hac::sRomfsHeader* hdr) const { bool validLayout = true; @@ -199,7 +199,7 @@ bool RomfsProcess::validateHeaderLayout(const nn::hac::sRomfsHeader* hdr) const return validLayout; } -void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir) +void nstool::RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir) { nn::hac::sRomfsDirEntry* d_node = get_dir_node(dir_offset); @@ -229,7 +229,7 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir) printf(" name=%s\n", f_node->name); */ - dir.file_list.addElement({std::string(f_node->name(), f_node->name_size.get()), mHdr.data_offset.get() + f_node->offset.get(), f_node->size.get()}); + dir.file_list.push_back({std::string(f_node->name(), f_node->name_size.get()), mHdr.data_offset.get() + f_node->offset.get(), f_node->size.get()}); file_addr = f_node->sibling.get(); mFileNum++; @@ -239,7 +239,7 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir) { nn::hac::sRomfsDirEntry* c_node = get_dir_node(child_addr); - dir.dir_list.addElement({std::string(c_node->name(), c_node->name_size.get())}); + dir.dir_list.push_back({std::string(c_node->name(), c_node->name_size.get())}); importDirectory(child_addr, dir.dir_list.atBack()); child_addr = c_node->sibling.get(); @@ -247,11 +247,11 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir) } } -void RomfsProcess::resolveRomfs() +void nstool::RomfsProcess::resolveRomfs() { if (*mFile == nullptr) { - throw fnd::Exception(kModuleName, "No file reader set."); + throw tc::Exception(kModuleName, "No file reader set."); } // read header @@ -260,7 +260,7 @@ void RomfsProcess::resolveRomfs() // logic check on the header layout if (validateHeaderLayout(&mHdr) == false) { - throw fnd::Exception(kModuleName, "Invalid ROMFS Header"); + throw tc::Exception(kModuleName, "Invalid ROMFS Header"); } // check for romfs compression @@ -284,7 +284,7 @@ void RomfsProcess::resolveRomfs() if ((entry[1].virtual_offset.get() >= romfs_metadata_begin_offset && entry[1].virtual_offset.get() < romfs_metadata_end_offset) == false || \ entry[1].compression_type != (byte_t)nn::hac::compression::CompressionType::Lz4) { - throw fnd::Exception(kModuleName, "RomFs appears corrupted (bad final compression entry virtual offset/compression type)"); + throw tc::Exception(kModuleName, "RomFs appears corrupted (bad final compression entry virtual offset/compression type)"); } // the first compression entry follows the physical placement of the final data chunk (specified in the final compression entry) @@ -293,7 +293,7 @@ void RomfsProcess::resolveRomfs() // quick check to make sure the offset at least before the last entry offset if (first_entry_offset >= (physical_size - sizeof(nn::hac::sCompressionEntry))) { - throw fnd::Exception(kModuleName, "RomFs appears corrupted (bad final compression entry physical offset/size)"); + throw tc::Exception(kModuleName, "RomFs appears corrupted (bad final compression entry physical offset/size)"); } // read first compression entry @@ -306,7 +306,7 @@ void RomfsProcess::resolveRomfs() entry[0].physical_size.get() != 0x200 || \ entry[0].compression_type != (byte_t)nn::hac::compression::CompressionType::None) { - throw fnd::Exception(kModuleName, "RomFs appears corrupted (bad first compression entry)"); + throw tc::Exception(kModuleName, "RomFs appears corrupted (bad first compression entry)"); } // wrap mFile in a class to transparantly decompress the image. @@ -331,7 +331,7 @@ void RomfsProcess::resolveRomfs() || get_dir_node(0)->hash.get() != nn::hac::romfs::kInvalidAddr \ || get_dir_node(0)->name_size.get() != 0) { - throw fnd::Exception(kModuleName, "Invalid root directory node"); + throw tc::Exception(kModuleName, "Invalid root directory node"); } // import directory into internal structure diff --git a/src/RomfsProcess.h b/src/RomfsProcess.h index d6cee47..dc39ff4 100644 --- a/src/RomfsProcess.h +++ b/src/RomfsProcess.h @@ -1,13 +1,9 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include "types.h" + #include -#include "common.h" +namespace nstool { class RomfsProcess { @@ -18,8 +14,8 @@ public: struct sDirectory { std::string name; - fnd::List dir_list; - fnd::List file_list; + std::vector dir_list; + std::vector file_list; void operator=(const sDirectory& other) { @@ -82,7 +78,7 @@ public: void process(); // generic - void setInputFile(const fnd::SharedPtr& file); + void setInputFile(const std::shared_ptr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -96,8 +92,13 @@ private: const std::string kModuleName = "RomfsProcess"; static const size_t kCacheSize = 0x10000; - fnd::SharedPtr mFile; + std::shared_ptr mFile; CliOutputMode mCliOutputMode; + bool mShowBasicInfo; + bool mShowExtendedInfo; + bool mShowLayoutInfo; + bool mShowKeydata; + bool mVerbose; bool mVerify; std::string mExtractPath; @@ -105,13 +106,13 @@ private: std::string mMountName; bool mListFs; - fnd::Vec mCache; + tc::ByteData mCache; size_t mDirNum; size_t mFileNum; nn::hac::sRomfsHeader mHdr; - fnd::Vec mDirNodes; - fnd::Vec mFileNodes; + tc::ByteData mDirNodes; + tc::ByteData mFileNodes; sDirectory mRootDir; inline nn::hac::sRomfsDirEntry* get_dir_node(uint32_t offset) { return (nn::hac::sRomfsDirEntry*)(mDirNodes.data() + offset); } @@ -131,4 +132,6 @@ private: bool validateHeaderLayout(const nn::hac::sRomfsHeader* hdr) const; void importDirectory(uint32_t dir_offset, sDirectory& dir); void resolveRomfs(); -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/SdkApiString.cpp b/src/SdkApiString.cpp index 1f3c9e6..6714772 100644 --- a/src/SdkApiString.cpp +++ b/src/SdkApiString.cpp @@ -1,13 +1,13 @@ #include #include "SdkApiString.h" -SdkApiString::SdkApiString(const std::string& full_str) : +nstool::SdkApiString::SdkApiString(const std::string& full_str) : SdkApiString(API_MIDDLEWARE, "", "") { resolveApiString(full_str); } -SdkApiString::SdkApiString(ApiType type, const std::string& vender_name, const std::string& module_name) : +nstool::SdkApiString::SdkApiString(ApiType type, const std::string& vender_name, const std::string& module_name) : mApiType(type), mVenderName(vender_name), mModuleName(module_name) @@ -15,44 +15,44 @@ SdkApiString::SdkApiString(ApiType type, const std::string& vender_name, const s } -void SdkApiString::operator=(const SdkApiString& other) +void nstool::SdkApiString::operator=(const SdkApiString& other) { mApiType = other.mApiType; mVenderName = other.mVenderName; mModuleName = other.mModuleName; } -SdkApiString::ApiType SdkApiString::getApiType() const +nstool::SdkApiString::ApiType nstool::SdkApiString::getApiType() const { return mApiType; } -void SdkApiString::setApiType(ApiType type) +void nstool::SdkApiString::setApiType(ApiType type) { mApiType = type; } -const std::string& SdkApiString::getVenderName() const +const std::string& nstool::SdkApiString::getVenderName() const { return mVenderName; } -void SdkApiString::setVenderName(const std::string& name) +void nstool::SdkApiString::setVenderName(const std::string& name) { mVenderName = name; } -const std::string& SdkApiString::getModuleName() const +const std::string& nstool::SdkApiString::getModuleName() const { return mModuleName; } -void SdkApiString::setModuleName(const std::string& name) +void nstool::SdkApiString::setModuleName(const std::string& name) { mModuleName = name; } -void SdkApiString::resolveApiString(const std::string& full_str) +void nstool::SdkApiString::resolveApiString(const std::string& full_str) { std::stringstream list_stream(full_str); std::string api_type, vender, module; diff --git a/src/SdkApiString.h b/src/SdkApiString.h index c1a8ffa..7e3a396 100644 --- a/src/SdkApiString.h +++ b/src/SdkApiString.h @@ -1,5 +1,7 @@ #pragma once -#include +#include "types.h" + +namespace nstool { class SdkApiString { @@ -42,4 +44,6 @@ private: std::string mModuleName; void resolveApiString(const std::string& full_str); -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/src/Settings.cpp b/src/Settings.cpp new file mode 100644 index 0000000..a9a6bce --- /dev/null +++ b/src/Settings.cpp @@ -0,0 +1,819 @@ +#include +#include +#include +#include +#include +#include "types.h" +#include "version.h" +#include "Settings.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class UnkOptionHandler : public tc::cli::OptionParser::IOptionHandler +{ +public: + UnkOptionHandler(const std::string& module_label) : mModuleLabel(module_label) + {} + + const std::vector& getOptionStrings() const + { + throw tc::InvalidOperationException("getOptionStrings() not defined for UnkOptionHandler."); + } + + void processOption(const std::string& option, const std::vector& params) + { + throw tc::Exception(mModuleLabel, "Unrecognized option: \"" + option + "\""); + } +private: + std::string mModuleLabel; +}; + +class DeprecatedOptionHandler : public tc::cli::OptionParser::IOptionHandler +{ +public: + DeprecatedOptionHandler(const std::string& warn_message, const std::vector& opts) : + mWarnMessage(warn_message), + mOptStrings(opts) + {} + + const std::vector& getOptionStrings() const + { + return mOptStrings; + } + + void processOption(const std::string& option, const std::vector& params) + { + fmt::print("[WARNING] Option \"{}\" is deprecated.{}{}\n", option, (mWarnMessage.empty() ? "" : " "), mWarnMessage); + } +private: + std::string mWarnMessage; + std::vector mOptStrings; +}; + +class FlagOptionHandler : public tc::cli::OptionParser::IOptionHandler +{ +public: + FlagOptionHandler(bool& flag, const std::vector& opts) : + mFlag(flag), + mOptStrings(opts) + {} + + const std::vector& getOptionStrings() const + { + return mOptStrings; + } + + void processOption(const std::string& option, const std::vector& params) + { + if (params.size() != 0) + { + throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" is a flag, that takes no parameters.", option)); + } + + mFlag = true; + } +private: + bool& mFlag; + std::vector mOptStrings; +}; + +class SingleParamStringOptionHandler : public tc::cli::OptionParser::IOptionHandler +{ +public: + SingleParamStringOptionHandler(tc::Optional& param, const std::vector& opts) : + mParam(param), + mOptStrings(opts) + {} + + const std::vector& getOptionStrings() const + { + return mOptStrings; + } + + void processOption(const std::string& option, const std::vector& params) + { + if (params.size() != 1) + { + throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires a parameter.", option)); + } + + mParam = params[0]; + } +private: + tc::Optional& mParam; + std::vector mOptStrings; +}; + +class SingleParamPathOptionHandler : public tc::cli::OptionParser::IOptionHandler +{ +public: + SingleParamPathOptionHandler(tc::Optional& param, const std::vector& opts) : + mParam(param), + mOptStrings(opts) + {} + + const std::vector& getOptionStrings() const + { + return mOptStrings; + } + + void processOption(const std::string& option, const std::vector& params) + { + if (params.size() != 1) + { + throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires a parameter.", option)); + } + + mParam = params[0]; + } +private: + tc::Optional& mParam; + std::vector mOptStrings; +}; + +class SingleParamSizetOptionHandler : public tc::cli::OptionParser::IOptionHandler +{ +public: + SingleParamSizetOptionHandler(size_t& param, const std::vector& opts) : + mParam(param), + mOptStrings(opts) + {} + + const std::vector& getOptionStrings() const + { + return mOptStrings; + } + + void processOption(const std::string& option, const std::vector& params) + { + if (params.size() != 1) + { + throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires a parameter.", option)); + } + + mParam = strtoul(params[0].c_str(), nullptr, 0); + } +private: + size_t& mParam; + std::vector mOptStrings; +}; + +class SingleParamAesKeyOptionHandler : public tc::cli::OptionParser::IOptionHandler +{ +public: + SingleParamAesKeyOptionHandler(tc::Optional& param, const std::vector& opts) : + mParam(param), + mOptStrings(opts) + {} + + const std::vector& getOptionStrings() const + { + return mOptStrings; + } + + void processOption(const std::string& option, const std::vector& params) + { + if (params.size() != 1) + { + throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires a parameter.", option)); + } + + tc::ByteData key_raw = tc::cli::FormatUtil::hexStringToBytes(params[0]); + if (key_raw.size() != sizeof(nstool::KeyBag::aes128_key_t)) + { + throw tc::ArgumentOutOfRangeException(fmt::format("Option: \"{:s}\", requires an AES128 key as the parameter (must be 32 hex chars).", option)); + } + + nstool::KeyBag::aes128_key_t key_tmp; + memcpy(key_tmp.data(), key_raw.data(), key_tmp.size()); + + mParam = key_tmp; + } +private: + tc::Optional& mParam; + std::vector mOptStrings; +}; + +class FileTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler +{ +public: + FileTypeOptionHandler(nstool::Settings::FileType& param, const std::vector& opts) : + mParam(param), + mOptStrings(opts) + {} + + const std::vector& getOptionStrings() const + { + return mOptStrings; + } + + void processOption(const std::string& option, const std::vector& params) + { + if (params.size() != 1) + { + throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires a parameter.", option)); + } + + if (params[0] == "gc" \ + || params[0] == "gamecard" \ + || params[0] == "xci" \ + || params[0] == "xcie" \ + || params[0] == "xcir") + { + mParam = nstool::Settings::FILE_TYPE_GAMECARD; + } + else if (params[0] == "nsp") + { + mParam = nstool::Settings::FILE_TYPE_NSP; + } + else if (params[0] == "partitionfs" || params[0] == "hashedpartitionfs" \ + || params[0] == "pfs" || params[0] == "pfs0" \ + || params[0] == "hfs" || params[0] == "hfs0") + { + mParam = nstool::Settings::FILE_TYPE_PARTITIONFS; + } + else if (params[0] == "romfs") + { + mParam = nstool::Settings::FILE_TYPE_ROMFS; + } + else if (params[0] == "nca" || params[0] == "contentarchive") + { + mParam = nstool::Settings::FILE_TYPE_NCA; + } + else if (params[0] == "meta" || params[0] == "npdm") + { + mParam = nstool::Settings::FILE_TYPE_META; + } + else if (params[0] == "cnmt") + { + mParam = nstool::Settings::FILE_TYPE_CNMT; + } + else if (params[0] == "nso") + { + mParam = nstool::Settings::FILE_TYPE_NSO; + } + else if (params[0] == "nro") + { + mParam = nstool::Settings::FILE_TYPE_NRO; + } + else if (params[0] == "ini") + { + mParam = nstool::Settings::FILE_TYPE_INI; + } + else if (params[0] == "kip") + { + mParam = nstool::Settings::FILE_TYPE_KIP; + } + else if (params[0] == "nacp") + { + mParam = nstool::Settings::FILE_TYPE_NACP; + } + else if (params[0] == "cert") + { + mParam = nstool::Settings::FILE_TYPE_PKI_CERT; + } + else if (params[0] == "tik") + { + mParam = nstool::Settings::FILE_TYPE_ES_TIK; + } + else if (params[0] == "aset" || params[0] == "asset") + { + mParam = nstool::Settings::FILE_TYPE_HB_ASSET; + } + else + { + throw tc::ArgumentException(fmt::format("File type \"{}\" unrecognised.", params[0])); + } + } +private: + nstool::Settings::FileType& mParam; + std::vector mOptStrings; +}; + +class InstructionTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler +{ +public: + InstructionTypeOptionHandler(bool& param, const std::vector& opts) : + mParam(param), + mOptStrings(opts) + {} + + const std::vector& getOptionStrings() const + { + return mOptStrings; + } + + void processOption(const std::string& option, const std::vector& params) + { + if (params.size() != 1) + { + throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires a parameter.", option)); + } + + if (params[0] == "32bit") + { + mParam = false; + } + else if (params[0] == "64bit") + { + mParam = true; + } + else + { + throw tc::ArgumentException(fmt::format("Instruction type \"{}\" unrecognised. Try \"32bit\" or \"64bit\"", params[0])); + } + } +private: + bool& mParam; + std::vector mOptStrings; +}; + +nstool::SettingsInitializer::SettingsInitializer(const std::vector& args) : + Settings(), + mModuleLabel("nstool::SettingsInitializer"), + mTitleKey(), + mBodyKey(), + mTikPath(), + mCertPath() +{ + // parse input arguments + parse_args(args); + if (infile.path.isNull()) + throw tc::ArgumentException(mModuleLabel, "No input file was specified."); + + // locate key file, if not specfied + if (mKeysetPath.isNull()) + { + std::string home_path_str; + if (tc::os::getEnvVar("HOME", home_path_str) || tc::os::getEnvVar("USERPROFILE", home_path_str)) + { + tc::io::Path keyfile_path = tc::io::Path(home_path_str); + keyfile_path.push_back(".switch"); + keyfile_path.push_back(opt.is_dev ? "dev.keys" : "prod.keys"); + + try { + tc::io::FileStream test = tc::io::FileStream(keyfile_path, tc::io::FileMode::Open, tc::io::FileAccess::Read); + + mKeysetPath = keyfile_path; + } + catch (tc::io::FileNotFoundException&) { + fmt::print("[WARNING] Failed to load \"{}\" keyfile. Maybe specify it with \"-k \"?\n", opt.is_dev ? "dev.keys" : "prod.keys"); + } + } + else { + fmt::print("[WARNING] Failed to located \"{}\" keyfile. Maybe specify it with \"-k \"?\n", opt.is_dev ? "dev.keys" : "prod.keys"); + } + } + + // generate keybag + opt.keybag = KeyBagInitializer(opt.is_dev, mKeysetPath, mTikPath, mCertPath); + opt.keybag.fallback_enc_content_key = mTitleKey; + opt.keybag.fallback_content_key = mBodyKey; + + // determine filetype if not manually specified + if (infile.filetype == FILE_TYPE_ERROR) + { + determine_filetype(); + if (infile.filetype == FILE_TYPE_ERROR) + { + throw tc::ArgumentException(mModuleLabel, "Input file type was undetermined."); + } + } +} + +void nstool::SettingsInitializer::parse_args(const std::vector& args) +{ + // check for minimum arguments + if (args.size() < 2) + { + usage_text(); + throw tc::ArgumentException(mModuleLabel, "Not enough arguments."); + } + + // detect request for help + for (auto itr = ++(args.begin()); itr != args.end(); itr++) + { + if (*itr == "-h" || *itr == "--help" || *itr == "-help") + { + usage_text(); + throw tc::ArgumentException(mModuleLabel, "Help required."); + } + } + + // save input file + infile.path = tc::io::Path(args.back()); + + // test new option parser + tc::cli::OptionParser opts; + + // register unk option handler + opts.registerUnrecognisedOptionHandler(std::shared_ptr(new UnkOptionHandler(mModuleLabel))); + + // register handler for deprecated options DeprecatedOptionHandler + // none just yet + + // get option flags + opts.registerOptionHandler(std::shared_ptr(new FlagOptionHandler(opt.show_layout, {"--showlayout"}))); + opts.registerOptionHandler(std::shared_ptr(new FlagOptionHandler(opt.show_keydata, { "--showkeys" }))); + opts.registerOptionHandler(std::shared_ptr(new FlagOptionHandler(opt.verbose, {"-v", "--verbose"}))); + opts.registerOptionHandler(std::shared_ptr(new FlagOptionHandler(opt.verify, {"-y", "--verify"}))); + opts.registerOptionHandler(std::shared_ptr(new FlagOptionHandler(opt.is_dev, {"-d", "--dev"}))); + + // process input file type + opts.registerOptionHandler(std::shared_ptr(new FileTypeOptionHandler(infile.filetype, { "-t", "--intype" }))); + + // get user-provided keydata + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(mKeysetPath, {"-k", "--keyset"}))); + opts.registerOptionHandler(std::shared_ptr(new SingleParamAesKeyOptionHandler(mTitleKey, {"--titlekey"}))); + opts.registerOptionHandler(std::shared_ptr(new SingleParamAesKeyOptionHandler(mBodyKey, {"--bodykey"}))); + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(mTikPath, {"--tik"}))); + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(mCertPath, {"--cert"}))); + + // code options + opts.registerOptionHandler(std::shared_ptr(new FlagOptionHandler(code.list_api, { "--listapi" }))); + opts.registerOptionHandler(std::shared_ptr(new FlagOptionHandler(code.list_symbols, { "--listsym" }))); + opts.registerOptionHandler(std::shared_ptr(new InstructionTypeOptionHandler(code.is_64bit_instruction, { "--insttype" }))); + + // fs options + opts.registerOptionHandler(std::shared_ptr(new FlagOptionHandler(fs.show_fs_tree, { "--listfs" }))); + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(fs.extract_path, { "--fsdir" }))); + + // xci options + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(xci.update_extract_path, { "--update" }))); + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(xci.normal_extract_path, { "--normal" }))); + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(xci.secure_extract_path, { "--secure" }))); + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(xci.logo_extract_path, { "--logo" }))); + + // nca options + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(nca.part0_extract_path, { "--part0" }))); + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(nca.part1_extract_path, { "--part1" }))); + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(nca.part2_extract_path, { "--part2" }))); + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(nca.part3_extract_path, { "--part3" }))); + + // kip options + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(kip.extract_path, { "--kipdir" }))); + + // aset options + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(aset.icon_extract_path, { "--icon" }))); + opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(aset.nacp_extract_path, { "--nacp" }))); + + + // process option + opts.processOptions(args, 1, args.size() - 2); +} + +void nstool::SettingsInitializer::determine_filetype() +{ + //std::string infile_path_str; + //tc::io::PathUtil::pathToUnixUTF8(infile.path.get(), infile_path_str); + //fmt::print("infile path = \"{}\"\n", infile_path_str); + + auto file = tc::io::StreamSource(std::make_shared(tc::io::FileStream(infile.path.get(), tc::io::FileMode::Open, tc::io::FileAccess::Read))); + + auto raw_data = file.pullData(0, 0x5000); + +#define _TYPE_PTR(st) ((st*)(raw_data.data())) +#define _ASSERT_FILE_SIZE(sz) (file.length() >= (sz)) + + // do easy tests + + // detect "scene" XCI + if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sGcHeader_Rsa2048Signed)) + && _TYPE_PTR(nn::hac::sGcHeader_Rsa2048Signed)->header.st_magic.unwrap() == nn::hac::gc::kGcHeaderStructMagic) + { + infile.filetype = FILE_TYPE_GAMECARD; + } + // detect "SDK" XCI + else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sSdkGcHeader)) + && _TYPE_PTR(nn::hac::sSdkGcHeader)->signed_header.header.st_magic.unwrap() == nn::hac::gc::kGcHeaderStructMagic) + { + infile.filetype = FILE_TYPE_GAMECARD; + } + // detect PFS0 + else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sPfsHeader)) + && _TYPE_PTR(nn::hac::sPfsHeader)->st_magic.unwrap() == nn::hac::pfs::kPfsStructMagic) + { + infile.filetype = FILE_TYPE_PARTITIONFS; + } + // detect HFS0 + else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sPfsHeader)) + && _TYPE_PTR(nn::hac::sPfsHeader)->st_magic.unwrap() == nn::hac::pfs::kHashedPfsStructMagic) + { + infile.filetype = FILE_TYPE_PARTITIONFS; + } + // detect ROMFS + else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sRomfsHeader)) + && _TYPE_PTR(nn::hac::sRomfsHeader)->header_size.unwrap() == sizeof(nn::hac::sRomfsHeader) + && _TYPE_PTR(nn::hac::sRomfsHeader)->sections[1].offset.unwrap() == (_TYPE_PTR(nn::hac::sRomfsHeader)->sections[0].offset.unwrap() + _TYPE_PTR(nn::hac::sRomfsHeader)->sections[0].size.unwrap())) + { + infile.filetype = FILE_TYPE_ROMFS; + } + // detect NPDM + else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sMetaHeader)) + && _TYPE_PTR(nn::hac::sMetaHeader)->st_magic.unwrap() == nn::hac::meta::kMetaStructMagic) + { + infile.filetype = FILE_TYPE_META; + } + // detect NSO + else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sNsoHeader)) + && _TYPE_PTR(nn::hac::sNsoHeader)->st_magic.unwrap() == nn::hac::nso::kNsoStructMagic) + { + infile.filetype = FILE_TYPE_NSO; + } + // detect NRO + else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sNroHeader)) + && _TYPE_PTR(nn::hac::sNroHeader)->st_magic.unwrap() == nn::hac::nro::kNroStructMagic) + { + infile.filetype = FILE_TYPE_NRO; + } + // detect INI + else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sIniHeader)) + && _TYPE_PTR(nn::hac::sIniHeader)->st_magic.unwrap() == nn::hac::ini::kIniStructMagic) + { + infile.filetype = FILE_TYPE_INI; + } + // detect KIP + else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sKipHeader)) + && _TYPE_PTR(nn::hac::sKipHeader)->st_magic.unwrap() == nn::hac::kip::kKipStructMagic) + { + infile.filetype = FILE_TYPE_KIP; + } + // detect HB ASET + else if (_ASSERT_FILE_SIZE(sizeof(nn::hac::sAssetHeader)) + && _TYPE_PTR(nn::hac::sAssetHeader)->st_magic.unwrap() == nn::hac::aset::kAssetStructMagic) + { + infile.filetype = FILE_TYPE_KIP; + } + + // more complicated tests + + // detect NCA + else if (determineValidNcaFromSample(raw_data)) + { + infile.filetype = FILE_TYPE_NCA; + } + // detect Certificate + else if (determineValidEsCertFromSample(raw_data)) + { + infile.filetype = FILE_TYPE_PKI_CERT; + } + // detect Ticket + else if (determineValidEsTikFromSample(raw_data)) + { + infile.filetype = FILE_TYPE_ES_TIK; + } + // detect Ticket + else if (determineValidCnmtFromSample(raw_data)) + { + infile.filetype = FILE_TYPE_CNMT; + } + // detect Ticket + else if (determineValidNacpFromSample(raw_data)) + { + infile.filetype = FILE_TYPE_NACP; + } +#undef _TYPE_PTR +#undef _ASSERT_FILE_SIZE +} + +void nstool::SettingsInitializer::usage_text() +{ + fmt::print("{:s} v{:d}.{:d}.{:d} (C) {:s}\n", APP_NAME, VER_MAJOR, VER_MINOR, VER_PATCH, AUTHORS); + fmt::print("Built: {:s} {:s}\n\n", __TIME__, __DATE__); + fmt::print("Usage: {:s} [options... ] \n", BIN_NAME); + fmt::print("\n General Options:\n"); + fmt::print(" -d, --dev Use devkit keyset.\n"); + fmt::print(" -k, --keyset Specify keyset file.\n"); + fmt::print(" -t, --type Specify input file type. [xci, pfs, romfs, nca, meta, cnmt, nso, nro, ini, kip, nacp, aset, cert, tik]\n"); + fmt::print(" -y, --verify Verify file.\n"); + fmt::print("\n Output Options:\n"); + fmt::print(" --showkeys Show keys generated.\n"); + fmt::print(" --showlayout Show layout metadata.\n"); + fmt::print(" -v, --verbose Verbose output.\n"); + fmt::print("\n XCI (GameCard Image)\n"); + fmt::print(" {:s} [--listfs] [--update --logo --normal --secure ] <.xci file>\n", BIN_NAME); + fmt::print(" --listfs Print file system in embedded partitions.\n"); + fmt::print(" --update Extract \"update\" partition to directory.\n"); + fmt::print(" --logo Extract \"logo\" partition to directory.\n"); + fmt::print(" --normal Extract \"normal\" partition to directory.\n"); + fmt::print(" --secure Extract \"secure\" partition to directory.\n"); + fmt::print("\n PFS0/HFS0 (PartitionFs), RomFs, NSP (Ninendo Submission Package)\n"); + fmt::print(" {:s} [--listfs] [--fsdir ] \n", BIN_NAME); + fmt::print(" --listfs Print file system.\n"); + fmt::print(" --fsdir Extract file system to directory.\n"); + fmt::print("\n NCA (Nintendo Content Archive)\n"); + fmt::print(" {:s} [--listfs] [--bodykey --titlekey ] [--part0 ...] <.nca file>\n", BIN_NAME); + fmt::print(" --listfs Print file system in embedded partitions.\n"); + fmt::print(" --titlekey Specify title key extracted from ticket.\n"); + fmt::print(" --bodykey Specify body encryption key.\n"); + fmt::print(" --tik Specify ticket to source title key.\n"); + fmt::print(" --cert Specify certificate chain to verify ticket.\n"); + fmt::print(" --part0 Extract \"partition 0\" to directory.\n"); + fmt::print(" --part1 Extract \"partition 1\" to directory.\n"); + fmt::print(" --part2 Extract \"partition 2\" to directory.\n"); + fmt::print(" --part3 Extract \"partition 3\" to directory.\n"); + fmt::print("\n NSO (Nintendo Software Object), NRO (Nintendo Relocatable Object)\n"); + fmt::print(" {:s} [--listapi --listsym] [--insttype ] \n", BIN_NAME); + fmt::print(" --listapi Print SDK API List.\n"); + fmt::print(" --listsym Print Code Symbols.\n"); + fmt::print(" --insttype Specify instruction type [64bit|32bit] (64bit is assumed).\n"); + fmt::print("\n INI (Initial Process List Blob)\n"); + fmt::print(" {:s} [--kipdir ] \n", BIN_NAME); + fmt::print(" --kipdir Extract embedded KIPs to directory.\n"); + fmt::print("\n ASET (Homebrew Asset Blob)\n"); + fmt::print(" {:s} [--listfs] [--icon --nacp --fsdir ] \n", BIN_NAME); + fmt::print(" --listfs Print filesystem in embedded RomFS partition.\n"); + fmt::print(" --icon Extract icon partition to file.\n"); + fmt::print(" --nacp Extract NACP partition to file.\n"); + fmt::print(" --fsdir Extract RomFS partition to directory.\n"); +} + +bool nstool::SettingsInitializer::determineValidNcaFromSample(const tc::ByteData& sample) const +{ + if (sample.size() < nn::hac::nca::kHeaderSize) + { + return false; + } + + if (opt.keybag.nca_header_key.isNull()) + { + fmt::print("[WARNING] Failed to load NCA Header Key.\n"); + return false; + } + + nn::hac::detail::aes128_xtskey_t key = opt.keybag.nca_header_key.get(); + + //fmt::print("NCA header key: {} {}\n", tc::cli::FormatUtil::formatBytesAsString(opt.keybag.nca_header_key.get()[0].data(), opt.keybag.nca_header_key.get()[0].size(), true, ""), tc::cli::FormatUtil::formatBytesAsString(opt.keybag.nca_header_key.get()[1].data(), opt.keybag.nca_header_key.get()[1].size(), true, "")); + + // init aes-xts + tc::crypto::Aes128XtsEncryptor enc; + enc.initialize(key[0].data(), key[0].size(), key[1].data(), key[1].size(), nn::hac::nca::kSectorSize, false); + + // decrypt main header + byte_t raw_hdr[nn::hac::nca::kSectorSize]; + enc.decrypt(raw_hdr, sample.data() + nn::hac::ContentArchiveUtil::sectorToOffset(1), nn::hac::nca::kSectorSize, 1); + nn::hac::sContentArchiveHeader* hdr = (nn::hac::sContentArchiveHeader*)(raw_hdr); + + /* + fmt::print("NCA Header Raw:\n"); + fmt::print("{:s}\n", tc::cli::FormatUtil::formatBytesAsHxdHexString(sample.data() + nn::hac::ContentArchiveUtil::sectorToOffset(1), nn::hac::nca::kSectorSize)); + fmt::print("{:s}\n", tc::cli::FormatUtil::formatBytesAsHxdHexString(raw_hdr, nn::hac::nca::kSectorSize)); + */ + + if (hdr->st_magic.unwrap() != nn::hac::nca::kNca2StructMagic && hdr->st_magic.unwrap() != nn::hac::nca::kNca3StructMagic) + { + return false; + } + + return true; +} + +bool nstool::SettingsInitializer::determineValidCnmtFromSample(const tc::ByteData& sample) const +{ + if (sample.size() < sizeof(nn::hac::sContentMetaHeader)) + return false; + + const nn::hac::sContentMetaHeader* data = (const nn::hac::sContentMetaHeader*)sample.data(); + + size_t minimum_size = sizeof(nn::hac::sContentMetaHeader) + data->exhdr_size.unwrap() + data->content_count.unwrap() * sizeof(nn::hac::sContentInfo) + data->content_meta_count.unwrap() * sizeof(nn::hac::sContentMetaInfo) + nn::hac::cnmt::kDigestLen; + + if (sample.size() < minimum_size) + return false; + + // include exthdr/data check if applicable + if (data->exhdr_size.unwrap() > 0) + { + if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Application) + { + const nn::hac::sApplicationMetaExtendedHeader* meta = (const nn::hac::sApplicationMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader)); + if ((meta->patch_id.unwrap() & data->id.unwrap()) != data->id.unwrap()) + return false; + } + else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Patch) + { + const nn::hac::sPatchMetaExtendedHeader* meta = (const nn::hac::sPatchMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader)); + if ((meta->application_id.unwrap() & data->id.unwrap()) != meta->application_id.unwrap()) + return false; + + minimum_size += meta->extended_data_size.unwrap(); + } + else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::AddOnContent) + { + const nn::hac::sAddOnContentMetaExtendedHeader* meta = (const nn::hac::sAddOnContentMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader)); + if ((meta->application_id.unwrap() & data->id.unwrap()) != meta->application_id.unwrap()) + return false; + } + else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Delta) + { + const nn::hac::sDeltaMetaExtendedHeader* meta = (const nn::hac::sDeltaMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader)); + if ((meta->application_id.unwrap() & data->id.unwrap()) != meta->application_id.unwrap()) + return false; + + minimum_size += meta->extended_data_size.unwrap(); + } + else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::SystemUpdate) + { + const nn::hac::sSystemUpdateMetaExtendedHeader* meta = (const nn::hac::sSystemUpdateMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader)); + + minimum_size += meta->extended_data_size.unwrap(); + } + } + + if (sample.size() != minimum_size) + return false; + + return true; +} + +bool nstool::SettingsInitializer::determineValidNacpFromSample(const tc::ByteData& sample) const +{ + if (sample.size() != sizeof(nn::hac::sApplicationControlProperty)) + return false; + + const nn::hac::sApplicationControlProperty* data = (const nn::hac::sApplicationControlProperty*)sample.data(); + + if (data->logo_type > (byte_t)nn::hac::nacp::LogoType::Nintendo) + return false; + + if (data->display_version[0] == 0) + return false; + + if (data->user_account_save_data_size.unwrap() == 0 && data->user_account_save_data_journal_size.unwrap() != 0) + return false; + + if (data->user_account_save_data_journal_size.unwrap() == 0 && data->user_account_save_data_size.unwrap() != 0) + return false; + + if (*((uint32_t*)(&data->supported_language_flag)) == 0) + return false; + + return true; +} + +bool nstool::SettingsInitializer::determineValidEsCertFromSample(const tc::ByteData& sample) const +{ + nn::pki::SignatureBlock sign; + + try + { + sign.fromBytes(sample.data(), sample.size()); + } + catch (...) + { + return false; + } + + if (sign.isLittleEndian() == true) + return false; + + if (sign.getSignType() != nn::pki::sign::SIGN_ID_RSA4096_SHA256 && sign.getSignType() != nn::pki::sign::SIGN_ID_RSA2048_SHA256 && sign.getSignType() != nn::pki::sign::SIGN_ID_ECDSA240_SHA256) + return false; + + return true; +} + +bool nstool::SettingsInitializer::determineValidEsTikFromSample(const tc::ByteData& sample) const +{ + nn::pki::SignatureBlock sign; + + try + { + sign.fromBytes(sample.data(), sample.size()); + } + catch (...) + { + return false; + } + + if (sign.isLittleEndian() == false) + return false; + + if (sign.getSignType() != nn::pki::sign::SIGN_ID_RSA2048_SHA256) + return false; + + const nn::es::sTicketBody_v2* body = (const nn::es::sTicketBody_v2*)(sample.data() + sign.getBytes().size()); + + if ((body->issuer.str().substr(0, 5) == "Root-" + && body->issuer.str().substr(16, 2) == "XS") == false) + return false; + + return true; +} \ No newline at end of file diff --git a/src/Settings.h b/src/Settings.h new file mode 100644 index 0000000..75564c1 --- /dev/null +++ b/src/Settings.h @@ -0,0 +1,155 @@ +#pragma once +#include "types.h" +#include +#include +#include +#include + +#include "KeyBag.h" + +namespace nstool { + +struct Settings +{ + enum FileType + { + FILE_TYPE_ERROR, + FILE_TYPE_GAMECARD, + FILE_TYPE_NSP, + FILE_TYPE_PARTITIONFS, + FILE_TYPE_ROMFS, + FILE_TYPE_NCA, + FILE_TYPE_META, + FILE_TYPE_CNMT, + FILE_TYPE_NSO, + FILE_TYPE_NRO, + FILE_TYPE_NACP, + FILE_TYPE_INI, + FILE_TYPE_KIP, + FILE_TYPE_PKI_CERT, + FILE_TYPE_ES_TIK, + FILE_TYPE_HB_ASSET, + }; + + struct InputFileOptions + { + FileType filetype; + tc::Optional path; + } infile; + + struct Options + { + CliOutputMode cli_output_mode; + bool verify; + bool is_dev; + KeyBag keybag; + } opt; + + // code options + struct CodeOptions + { + bool list_api; + bool list_symbols; + bool is_64bit_instruction; // true=64bit, false=32bit + } code; + + // Generic FS options + struct FsOptions + { + bool show_fs_tree; + tc::Optional extract_path; + } fs; + + // XCI options + struct XciOptions + { + tc::Optional update_extract_path; + tc::Optional logo_extract_path; + tc::Optional normal_extract_path; + tc::Optional secure_extract_path; + } xci; + + // NCA options + struct NcaOptions + { + tc::Optional part0_extract_path; + tc::Optional part1_extract_path; + tc::Optional part2_extract_path; + tc::Optional part3_extract_path; + } nca; + + // KIP options + struct KipOptions + { + tc::Optional extract_path; + } kip; + + // ASET Options + struct AsetOptions + { + tc::Optional icon_extract_path; + tc::Optional nacp_extract_path; + } aset; + + Settings() + { + infile.filetype = FILE_TYPE_ERROR; + infile.path = tc::Optional(); + + opt.cli_output_mode = CliOutputMode(); + opt.verify = false; + opt.is_dev = false; + opt.keybag = KeyBag(); + + code.list_api = false; + code.list_symbols = false; + code.is_64bit_instruction = true; + + xci.update_extract_path = tc::Optional(); + xci.logo_extract_path = tc::Optional(); + xci.normal_extract_path = tc::Optional(); + xci.secure_extract_path = tc::Optional(); + + fs.show_fs_tree = false; + fs.extract_path = tc::Optional(); + + nca.part0_extract_path = tc::Optional(); + nca.part1_extract_path = tc::Optional(); + nca.part2_extract_path = tc::Optional(); + nca.part3_extract_path = tc::Optional(); + + kip.extract_path = tc::Optional(); + + aset.icon_extract_path = tc::Optional(); + aset.nacp_extract_path = tc::Optional(); + } +}; + +class SettingsInitializer : public Settings +{ +public: + SettingsInitializer(const std::vector& args); +private: + void parse_args(const std::vector& args); + void determine_filetype(); + void usage_text(); + + std::string mModuleLabel; + + bool mShowLayout; + bool mShowKeydata; + + tc::Optional mKeysetPath; + tc::Optional mTitleKey; + tc::Optional mBodyKey; + tc::Optional mTikPath; + tc::Optional mCertPath; + + bool determineValidNcaFromSample(const tc::ByteData& raw_data) const; + bool determineValidEsCertFromSample(const tc::ByteData& raw_data) const; + bool determineValidEsTikFromSample(const tc::ByteData& raw_data) const; + bool determineValidCnmtFromSample(const tc::ByteData& raw_data) const; + bool determineValidNacpFromSample(const tc::ByteData& raw_data) const; +}; + +} \ No newline at end of file diff --git a/src/UserSettings.cpp b/src/UserSettings.cpp deleted file mode 100644 index 3356974..0000000 --- a/src/UserSettings.cpp +++ /dev/null @@ -1,1086 +0,0 @@ -#include "UserSettings.h" -#include "version.h" -#include "PkiValidator.h" -#include "KeyConfiguration.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -UserSettings::UserSettings() -{} - -void UserSettings::parseCmdArgs(const std::vector& arg_list) -{ - sCmdArgs args; - populateCmdArgs(arg_list, args); - populateKeyset(args); - populateUserSettings(args); - if (_HAS_BIT(mOutputMode, OUTPUT_KEY_DATA)) - dumpKeyConfig(); -} - -void UserSettings::showHelp() -{ - printf("%s v%d.%d.%d (C) %s\n", APP_NAME, VER_MAJOR, VER_MINOR, VER_PATCH, AUTHORS); - printf("Built: %s %s\n\n", __TIME__, __DATE__); - - printf("Usage: %s [options... ] \n", BIN_NAME); - printf("\n General Options:\n"); - printf(" -d, --dev Use devkit keyset.\n"); - printf(" -k, --keyset Specify keyset file.\n"); - printf(" -t, --type Specify input file type. [xci, pfs, romfs, nca, meta, cnmt, nso, nro, ini, kip, nacp, aset, cert, tik]\n"); - printf(" -y, --verify Verify file.\n"); - printf("\n Output Options:\n"); - printf(" --showkeys Show keys generated.\n"); - printf(" --showlayout Show layout metadata.\n"); - printf(" -v, --verbose Verbose output.\n"); - printf("\n XCI (GameCard Image)\n"); - printf(" %s [--listfs] [--update --logo --normal --secure ] <.xci file>\n", BIN_NAME); - printf(" --listfs Print file system in embedded partitions.\n"); - printf(" --update Extract \"update\" partition to directory.\n"); - printf(" --logo Extract \"logo\" partition to directory.\n"); - printf(" --normal Extract \"normal\" partition to directory.\n"); - printf(" --secure Extract \"secure\" partition to directory.\n"); - printf("\n PFS0/HFS0 (PartitionFs), RomFs, NSP (Ninendo Submission Package)\n"); - printf(" %s [--listfs] [--fsdir ] \n", BIN_NAME); - printf(" --listfs Print file system.\n"); - printf(" --fsdir Extract file system to directory.\n"); - printf("\n NCA (Nintendo Content Archive)\n"); - printf(" %s [--listfs] [--bodykey --titlekey ] [--part0 ...] <.nca file>\n", BIN_NAME); - printf(" --listfs Print file system in embedded partitions.\n"); - printf(" --titlekey Specify title key extracted from ticket.\n"); - printf(" --bodykey Specify body encryption key.\n"); - printf(" --tik Specify ticket to source title key.\n"); - printf(" --cert Specify certificate chain to verify ticket.\n"); - printf(" --part0 Extract \"partition 0\" to directory.\n"); - printf(" --part1 Extract \"partition 1\" to directory.\n"); - printf(" --part2 Extract \"partition 2\" to directory.\n"); - printf(" --part3 Extract \"partition 3\" to directory.\n"); - printf("\n NSO (Nintendo Software Object), NRO (Nintendo Relocatable Object)\n"); - printf(" %s [--listapi --listsym] [--insttype ] \n", BIN_NAME); - printf(" --listapi Print SDK API List.\n"); - printf(" --listsym Print Code Symbols.\n"); - printf(" --insttype Specify instruction type [64bit|32bit] (64bit is assumed).\n"); - printf("\n INI (Initial Process List Blob)\n"); - printf(" %s [--kipdir ] \n", BIN_NAME); - printf(" --kipdir Extract embedded KIPs to directory.\n"); - printf("\n ASET (Homebrew Asset Blob)\n"); - printf(" %s [--listfs] [--icon --nacp --fsdir ] \n", BIN_NAME); - printf(" --listfs Print filesystem in embedded RomFS partition.\n"); - printf(" --icon Extract icon partition to file.\n"); - printf(" --nacp Extract NACP partition to file.\n"); - printf(" --fsdir Extract RomFS partition to directory.\n"); - -} - -const std::string UserSettings::getInputPath() const -{ - return mInputPath; -} - -const KeyConfiguration& UserSettings::getKeyCfg() const -{ - return mKeyCfg; -} - -FileType UserSettings::getFileType() const -{ - return mFileType; -} - -bool UserSettings::isVerifyFile() const -{ - return mVerifyFile; -} - -CliOutputMode UserSettings::getCliOutputMode() const -{ - return mOutputMode; -} - -bool UserSettings::isListFs() const -{ - return mListFs; -} - -bool UserSettings::isListApi() const -{ - return mListApi; -} -bool UserSettings::isListSymbols() const -{ - return mListSymbols; -} - -bool UserSettings::getIs64BitInstruction() const -{ - return mIs64BitInstruction; -} - -const sOptional& UserSettings::getXciUpdatePath() const -{ - return mXciUpdatePath; -} - -const sOptional& UserSettings::getXciLogoPath() const -{ - return mXciLogoPath; -} - -const sOptional& UserSettings::getXciNormalPath() const -{ - return mXciNormalPath; -} - -const sOptional& UserSettings::getXciSecurePath() const -{ - return mXciSecurePath; -} - -const sOptional& UserSettings::getFsPath() const -{ - return mFsPath; -} - -const sOptional& UserSettings::getNcaPart0Path() const -{ - return mNcaPart0Path; -} - -const sOptional& UserSettings::getNcaPart1Path() const -{ - return mNcaPart1Path; -} - -const sOptional& UserSettings::getNcaPart2Path() const -{ - return mNcaPart2Path; -} - -const sOptional& UserSettings::getNcaPart3Path() const -{ - return mNcaPart3Path; -} - -const sOptional& UserSettings::getKipExtractPath() const -{ - return mKipExtractPath; -} - -const sOptional& UserSettings::getAssetIconPath() const -{ - return mAssetIconPath; -} - -const sOptional& UserSettings::getAssetNacpPath() const -{ - return mAssetNacpPath; -} - -const fnd::List>& UserSettings::getCertificateChain() const -{ - return mCertChain; -} - -void UserSettings::populateCmdArgs(const std::vector& arg_list, sCmdArgs& cmd_args) -{ - // show help text - if (arg_list.size() < 2) - { - showHelp(); - throw fnd::Exception(kModuleName, "Not enough arguments."); - } - - cmd_args.input_path = arg_list.back(); - - for (size_t i = 1; i < arg_list.size(); i++) - { - if (arg_list[i] == "-h" || arg_list[i] == "--help") - { - showHelp(); - throw fnd::Exception(kModuleName, "Nothing to do."); - } - } - - for (size_t i = 1; i+1 < arg_list.size(); i++) - { - bool hasParamter = arg_list[i+1][0] != '-' && i+2 < arg_list.size(); - - if (arg_list[i] == "-d" || arg_list[i] == "--dev") - { - if (hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " does not take a parameter."); - cmd_args.devkit_keys = true; - } - - else if (arg_list[i] == "-y" || arg_list[i] == "--verify") - { - if (hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " does not take a parameter."); - cmd_args.verify_file = true; - } - - else if (arg_list[i] == "--showkeys") - { - if (hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " does not take a parameter."); - cmd_args.show_keys = true; - } - - else if (arg_list[i] == "--showlayout") - { - if (hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " does not take a parameter."); - cmd_args.show_layout = true; - } - - else if (arg_list[i] == "-v" || arg_list[i] == "--verbose") - { - if (hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " does not take a parameter."); - cmd_args.verbose_output = true; - } - - else if (arg_list[i] == "-k" || arg_list[i] == "--keyset") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.keyset_path = arg_list[i+1]; - } - - else if (arg_list[i] == "-t" || arg_list[i] == "--type") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.file_type = arg_list[i+1]; - } - - else if (arg_list[i] == "--listfs") - { - if (hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " does not take a parameter."); - cmd_args.list_fs = true; - } - - else if (arg_list[i] == "--update") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.update_path = arg_list[i+1]; - } - - else if (arg_list[i] == "--normal") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.normal_path = arg_list[i+1]; - } - - else if (arg_list[i] == "--secure") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.secure_path = arg_list[i+1]; - } - - else if (arg_list[i] == "--logo") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.logo_path = arg_list[i+1]; - } - - else if (arg_list[i] == "--fsdir") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.fs_path = arg_list[i+1]; - } - - else if (arg_list[i] == "--titlekey") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.nca_titlekey = arg_list[i+1]; - } - - else if (arg_list[i] == "--bodykey") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.nca_bodykey = arg_list[i+1]; - } - - else if (arg_list[i] == "--tik") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.ticket_path = arg_list[i+1]; - } - - else if (arg_list[i] == "--cert") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.cert_path = arg_list[i+1]; - } - - else if (arg_list[i] == "--part0") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.part0_path = arg_list[i+1]; - } - - else if (arg_list[i] == "--part1") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.part1_path = arg_list[i+1]; - } - - else if (arg_list[i] == "--part2") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.part2_path = arg_list[i+1]; - } - - else if (arg_list[i] == "--part3") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.part3_path = arg_list[i+1]; - } - - else if (arg_list[i] == "--listapi") - { - if (hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " does not take a parameter."); - cmd_args.list_api = true; - } - - else if (arg_list[i] == "--listsym") - { - if (hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " does not take a parameter."); - cmd_args.list_sym = true; - } - - else if (arg_list[i] == "--insttype") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.inst_type = arg_list[i + 1]; - } - - else if (arg_list[i] == "--kipdir") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.kip_extract_path = arg_list[i + 1]; - } - - else if (arg_list[i] == "--icon") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.asset_icon_path = arg_list[i + 1]; - } - - else if (arg_list[i] == "--nacp") - { - if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); - cmd_args.asset_nacp_path = arg_list[i + 1]; - } - - else - { - throw fnd::Exception(kModuleName, arg_list[i] + " is not recognised."); - } - - i += hasParamter; - } -} - -void UserSettings::populateKeyset(sCmdArgs& args) -{ - if (args.keyset_path.isSet) - { - mKeyCfg.importHactoolGenericKeyfile(*args.keyset_path); - } - else - { - // open other resource files in $HOME/.switch/prod.keys (or $HOME/.switch/dev.keys if -d/--dev is set). - std::string keyset_path; - getSwitchPath(keyset_path); - if (keyset_path.empty()) - return; - - fnd::io::appendToPath(keyset_path, kGeneralKeyfileName[args.devkit_keys.isSet]); - - try - { - mKeyCfg.importHactoolGenericKeyfile(keyset_path); - } - catch (const fnd::Exception&) - { - return; - } - - } - - - - if (args.nca_bodykey.isSet) - { - fnd::aes::sAes128Key tmp_key; - fnd::Vec tmp_raw; - fnd::SimpleTextOutput::stringToArray(args.nca_bodykey.var, tmp_raw); - if (tmp_raw.size() != sizeof(fnd::aes::sAes128Key)) - throw fnd::Exception(kModuleName, "Key: \"--bodykey\" has incorrect length"); - memcpy(tmp_key.key, tmp_raw.data(), 16); - mKeyCfg.addNcaExternalContentKey(kDummyRightsIdForUserBodyKey, tmp_key); - } - - if (args.nca_titlekey.isSet) - { - fnd::aes::sAes128Key tmp_key; - fnd::Vec tmp_raw; - fnd::SimpleTextOutput::stringToArray(args.nca_titlekey.var, tmp_raw); - if (tmp_raw.size() != sizeof(fnd::aes::sAes128Key)) - throw fnd::Exception(kModuleName, "Key: \"--titlekey\" has incorrect length"); - memcpy(tmp_key.key, tmp_raw.data(), 16); - mKeyCfg.addNcaExternalContentKey(kDummyRightsIdForUserTitleKey, tmp_key); - } - - // import certificate chain - if (args.cert_path.isSet) - { - fnd::SimpleFile cert_file; - fnd::Vec cert_raw; - nn::pki::SignedData cert; - - cert_file.open(args.cert_path.var, fnd::SimpleFile::Read); - cert_raw.alloc(cert_file.size()); - cert_file.read(cert_raw.data(), cert_raw.size()); - - for (size_t i = 0; i < cert_raw.size(); i+= cert.getBytes().size()) - { - cert.fromBytes(cert_raw.data() + i, cert_raw.size() - i); - mCertChain.addElement(cert); - } - } - - // get titlekey from ticket - if (args.ticket_path.isSet) - { - fnd::SimpleFile tik_file; - fnd::Vec tik_raw; - nn::pki::SignedData tik; - - // open and import ticket - tik_file.open(args.ticket_path.var, fnd::SimpleFile::Read); - tik_raw.alloc(tik_file.size()); - tik_file.read(tik_raw.data(), tik_raw.size()); - tik.fromBytes(tik_raw.data(), tik_raw.size()); - - // validate ticket signature - if (mCertChain.size() > 0) - { - PkiValidator pki_validator; - fnd::Vec tik_hash; - - switch (nn::pki::sign::getHashAlgo(tik.getSignature().getSignType())) - { - case (nn::pki::sign::HASH_ALGO_SHA1): - tik_hash.alloc(fnd::sha::kSha1HashLen); - fnd::sha::Sha1(tik.getBody().getBytes().data(), tik.getBody().getBytes().size(), tik_hash.data()); - break; - case (nn::pki::sign::HASH_ALGO_SHA256): - tik_hash.alloc(fnd::sha::kSha256HashLen); - fnd::sha::Sha256(tik.getBody().getBytes().data(), tik.getBody().getBytes().size(), tik_hash.data()); - break; - } - - try - { - pki_validator.setKeyCfg(mKeyCfg); - pki_validator.addCertificates(mCertChain); - pki_validator.validateSignature(tik.getBody().getIssuer(), tik.getSignature().getSignType(), tik.getSignature().getSignature(), tik_hash); - } - catch (const fnd::Exception& e) - { - std::cout << "[WARNING] Ticket signature could not be validated (" << e.error() << ")" << std::endl; - } - - } - - // extract title key - if (tik.getBody().getTitleKeyEncType() == nn::es::ticket::AES128_CBC) - { - fnd::aes::sAes128Key enc_title_key; - memcpy(enc_title_key.key, tik.getBody().getEncTitleKey(), 16); - fnd::aes::sAes128Key common_key, external_content_key; - if (mKeyCfg.getETicketCommonKey(nn::hac::ContentArchiveUtil::getMasterKeyRevisionFromKeyGeneration(tik.getBody().getCommonKeyId()), common_key) == true) - { - nn::hac::AesKeygen::generateKey(external_content_key.key, tik.getBody().getEncTitleKey(), common_key.key); - mKeyCfg.addNcaExternalContentKey(tik.getBody().getRightsId(), external_content_key); - } - else - { - std::cout << "[WARNING] Titlekey not imported from ticket because commonkey was not available" << std::endl; - } - } - else - { - std::cout << "[WARNING] Titlekey not imported from ticket because it is personalised" << std::endl; - } - } -} - -void UserSettings::populateUserSettings(sCmdArgs& args) -{ - // check invalid input - if (args.input_path.isSet == false) - throw fnd::Exception(kModuleName, "No input file specified"); - - // save arguments - mInputPath = *args.input_path; - mVerifyFile = args.verify_file.isSet; - mListFs = args.list_fs.isSet; - mXciUpdatePath = args.update_path; - mXciNormalPath = args.normal_path; - mXciSecurePath = args.secure_path; - mXciLogoPath = args.logo_path; - - mFsPath = args.fs_path; - mNcaPart0Path = args.part0_path; - mNcaPart1Path = args.part1_path; - mNcaPart2Path = args.part2_path; - mNcaPart3Path = args.part3_path; - - mKipExtractPath = args.kip_extract_path; - - // determine the architecture type for NSO/NRO - if (args.inst_type.isSet) - mIs64BitInstruction = getIs64BitInstructionFromString(*args.inst_type); - else - mIs64BitInstruction = true; // default 64bit - - mListApi = args.list_api.isSet; - mListSymbols = args.list_sym.isSet; - - mAssetIconPath = args.asset_icon_path; - mAssetNacpPath = args.asset_nacp_path; - - // determine output mode - mOutputMode = _BIT(OUTPUT_BASIC); - if (args.verbose_output.isSet) - { - mOutputMode |= _BIT(OUTPUT_KEY_DATA); - mOutputMode |= _BIT(OUTPUT_LAYOUT); - mOutputMode |= _BIT(OUTPUT_EXTENDED); - } - if (args.show_keys.isSet) - { - mOutputMode |= _BIT(OUTPUT_KEY_DATA); - } - if (args.show_layout.isSet) - { - mOutputMode |= _BIT(OUTPUT_LAYOUT); - } - - // determine input file type - if (args.file_type.isSet) - mFileType = getFileTypeFromString(*args.file_type); - else - mFileType = determineFileTypeFromFile(mInputPath); - - // check is the input file could be identified - if (mFileType == FILE_INVALID) - throw fnd::Exception(kModuleName, "Unknown file type."); -} - -FileType UserSettings::getFileTypeFromString(const std::string& type_str) -{ - std::string str = type_str; - std::transform(str.begin(), str.end(), str.begin(), ::tolower); - - FileType type; - if (str == "gc" || str == "gamecard" || str == "xci") - type = FILE_GAMECARD; - else if (str == "nsp") - type = FILE_NSP; - else if (str == "partitionfs" || str == "hashedpartitionfs" \ - || str == "pfs" || str == "pfs0" \ - || str == "hfs" || str == "hfs0") - type = FILE_PARTITIONFS; - else if (str == "romfs") - type = FILE_ROMFS; - else if (str == "nca" || str == "contentarchive") - type = FILE_NCA; - else if (str == "meta" || str == "npdm") - type = FILE_META; - else if (str == "cnmt") - type = FILE_CNMT; - else if (str == "nso") - type = FILE_NSO; - else if (str == "nro") - type = FILE_NRO; - else if (str == "ini") - type = FILE_INI; - else if (str == "kip") - type = FILE_KIP; - else if (str == "nacp") - type = FILE_NACP; - else if (str == "cert") - type = FILE_PKI_CERT; - else if (str == "tik") - type = FILE_ES_TIK; - else if (str == "aset" || str == "asset") - type = FILE_HB_ASSET; - else - type = FILE_INVALID; - - return type; -} - -FileType UserSettings::determineFileTypeFromFile(const std::string& path) -{ - static const size_t kMaxReadSize = 0x5000; - FileType file_type = FILE_INVALID; - fnd::SimpleFile file; - fnd::Vec scratch; - - // open file - file.open(path, file.Read); - - // read file - scratch.alloc(_MIN(kMaxReadSize, file.size())); - file.read(scratch.data(), 0, scratch.size()); - // close file - file.close(); - - // _TYPE_PTR resolves to a pointer of type 'st' located at scratch.data() -#define _TYPE_PTR(st) ((st*)(scratch.data())) -#define _ASSERT_SIZE(sz) (scratch.size() >= (sz)) - - // test gamecard - if (_ASSERT_SIZE(sizeof(nn::hac::sGcHeader_Rsa2048Signed)) && _TYPE_PTR(nn::hac::sGcHeader_Rsa2048Signed)->header.st_magic.get() == nn::hac::gc::kGcHeaderStructMagic) - file_type = FILE_GAMECARD; - else if (_ASSERT_SIZE(sizeof(nn::hac::sSdkGcHeader)) && _TYPE_PTR(nn::hac::sSdkGcHeader)->signed_header.header.st_magic.get() == nn::hac::gc::kGcHeaderStructMagic) - file_type = FILE_GAMECARD; - // test pfs0 - else if (_ASSERT_SIZE(sizeof(nn::hac::sPfsHeader)) && _TYPE_PTR(nn::hac::sPfsHeader)->st_magic.get() == nn::hac::pfs::kPfsStructMagic) - file_type = FILE_PARTITIONFS; - // test hfs0 - else if (_ASSERT_SIZE(sizeof(nn::hac::sPfsHeader)) && _TYPE_PTR(nn::hac::sPfsHeader)->st_magic.get() == nn::hac::pfs::kHashedPfsStructMagic) - file_type = FILE_PARTITIONFS; - // test romfs - else if (_ASSERT_SIZE(sizeof(nn::hac::sRomfsHeader)) && _TYPE_PTR(nn::hac::sRomfsHeader)->header_size.get() == sizeof(nn::hac::sRomfsHeader) && _TYPE_PTR(nn::hac::sRomfsHeader)->sections[1].offset.get() == (_TYPE_PTR(nn::hac::sRomfsHeader)->sections[0].offset.get() + _TYPE_PTR(nn::hac::sRomfsHeader)->sections[0].size.get())) - file_type = FILE_ROMFS; - // test npdm - else if (_ASSERT_SIZE(sizeof(nn::hac::sMetaHeader)) && _TYPE_PTR(nn::hac::sMetaHeader)->st_magic.get() == nn::hac::meta::kMetaStructMagic) - file_type = FILE_META; - // test nca - else if (determineValidNcaFromSample(scratch)) - file_type = FILE_NCA; - // test nso - else if (_ASSERT_SIZE(sizeof(nn::hac::sNsoHeader)) && _TYPE_PTR(nn::hac::sNsoHeader)->st_magic.get() == nn::hac::nso::kNsoStructMagic) - file_type = FILE_NSO; - // test nro - else if (_ASSERT_SIZE(sizeof(nn::hac::sNroHeader)) && _TYPE_PTR(nn::hac::sNroHeader)->st_magic.get() == nn::hac::nro::kNroStructMagic) - file_type = FILE_NRO; - // test ini - else if (_ASSERT_SIZE(sizeof(nn::hac::sIniHeader)) && _TYPE_PTR(nn::hac::sIniHeader)->st_magic.get() == nn::hac::ini::kIniStructMagic) - file_type = FILE_INI; - // test kip - else if (_ASSERT_SIZE(sizeof(nn::hac::sKipHeader)) && _TYPE_PTR(nn::hac::sKipHeader)->st_magic.get() == nn::hac::kip::kKipStructMagic) - file_type = FILE_KIP; - // test pki certificate - else if (determineValidEsCertFromSample(scratch)) - file_type = FILE_PKI_CERT; - // test ticket - else if (determineValidEsTikFromSample(scratch)) - file_type = FILE_ES_TIK; - // test hb asset - else if (_ASSERT_SIZE(sizeof(nn::hac::sAssetHeader)) && _TYPE_PTR(nn::hac::sAssetHeader)->st_magic.get() == nn::hac::aset::kAssetStructMagic) - file_type = FILE_HB_ASSET; - - // do heuristics - // test cnmt - else if (determineValidCnmtFromSample(scratch)) - file_type = FILE_CNMT; - // test nacp - else if (determineValidNacpFromSample(scratch)) - file_type = FILE_NACP; - - - // else unrecognised - else - file_type = FILE_INVALID; - -#undef _ASSERT_SIZE -#undef _TYPE_PTR - - return file_type; -} - -bool UserSettings::determineValidNcaFromSample(const fnd::Vec& sample) const -{ - // prepare decrypted NCA data - byte_t nca_raw[nn::hac::nca::kHeaderSize]; - nn::hac::sContentArchiveHeader* nca_header = (nn::hac::sContentArchiveHeader*)(nca_raw + nn::hac::ContentArchiveUtil::sectorToOffset(1)); - - if (sample.size() < nn::hac::nca::kHeaderSize) - return false; - - fnd::aes::sAesXts128Key header_key; - mKeyCfg.getContentArchiveHeaderKey(header_key); - nn::hac::ContentArchiveUtil::decryptContentArchiveHeader(sample.data(), nca_raw, header_key); - - if (nca_header->st_magic.get() != nn::hac::nca::kNca2StructMagic && nca_header->st_magic.get() != nn::hac::nca::kNca3StructMagic) - return false; - - return true; -} - -bool UserSettings::determineValidCnmtFromSample(const fnd::Vec& sample) const -{ - if (sample.size() < sizeof(nn::hac::sContentMetaHeader)) - return false; - - const nn::hac::sContentMetaHeader* data = (const nn::hac::sContentMetaHeader*)sample.data(); - - size_t minimum_size = sizeof(nn::hac::sContentMetaHeader) + data->exhdr_size.get() + data->content_count.get() * sizeof(nn::hac::sContentInfo) + data->content_meta_count.get() * sizeof(nn::hac::sContentMetaInfo) + nn::hac::cnmt::kDigestLen; - - if (sample.size() < minimum_size) - return false; - - // include exthdr/data check if applicable - if (data->exhdr_size.get() > 0) - { - if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Application) - { - const nn::hac::sApplicationMetaExtendedHeader* meta = (const nn::hac::sApplicationMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader)); - if ((meta->patch_id.get() & data->id.get()) != data->id.get()) - return false; - } - else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Patch) - { - const nn::hac::sPatchMetaExtendedHeader* meta = (const nn::hac::sPatchMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader)); - if ((meta->application_id.get() & data->id.get()) != meta->application_id.get()) - return false; - - minimum_size += meta->extended_data_size.get(); - } - else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::AddOnContent) - { - const nn::hac::sAddOnContentMetaExtendedHeader* meta = (const nn::hac::sAddOnContentMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader)); - if ((meta->application_id.get() & data->id.get()) != meta->application_id.get()) - return false; - } - else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Delta) - { - const nn::hac::sDeltaMetaExtendedHeader* meta = (const nn::hac::sDeltaMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader)); - if ((meta->application_id.get() & data->id.get()) != meta->application_id.get()) - return false; - - minimum_size += meta->extended_data_size.get(); - } - else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::SystemUpdate) - { - const nn::hac::sSystemUpdateMetaExtendedHeader* meta = (const nn::hac::sSystemUpdateMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader)); - - minimum_size += meta->extended_data_size.get(); - } - } - - if (sample.size() != minimum_size) - return false; - - return true; -} - -bool UserSettings::determineValidNacpFromSample(const fnd::Vec& sample) const -{ - if (sample.size() != sizeof(nn::hac::sApplicationControlProperty)) - return false; - - const nn::hac::sApplicationControlProperty* data = (const nn::hac::sApplicationControlProperty*)sample.data(); - - if (data->logo_type > (byte_t)nn::hac::nacp::LogoType::Nintendo) - return false; - - if (data->display_version[0] == 0) - return false; - - if (data->user_account_save_data_size.get() == 0 && data->user_account_save_data_journal_size.get() != 0) - return false; - - if (data->user_account_save_data_journal_size.get() == 0 && data->user_account_save_data_size.get() != 0) - return false; - - if (data->supported_language_flag.get() == 0) - return false; - - return true; -} - -bool UserSettings::determineValidEsCertFromSample(const fnd::Vec& sample) const -{ - nn::pki::SignatureBlock sign; - - try - { - sign.fromBytes(sample.data(), sample.size()); - } - catch (...) - { - return false; - } - - if (sign.isLittleEndian() == true) - return false; - - if (sign.getSignType() != nn::pki::sign::SIGN_ID_RSA4096_SHA256 && sign.getSignType() != nn::pki::sign::SIGN_ID_RSA2048_SHA256 && sign.getSignType() != nn::pki::sign::SIGN_ID_ECDSA240_SHA256) - return false; - - return true; -} - -bool UserSettings::determineValidEsTikFromSample(const fnd::Vec& sample) const -{ - nn::pki::SignatureBlock sign; - - try - { - sign.fromBytes(sample.data(), sample.size()); - } - catch (...) - { - return false; - } - - if (sign.isLittleEndian() == false) - return false; - - if (sign.getSignType() != nn::pki::sign::SIGN_ID_RSA2048_SHA256) - return false; - - return true; -} - -bool UserSettings::getIs64BitInstructionFromString(const std::string & type_str) -{ - std::string str = type_str; - std::transform(str.begin(), str.end(), str.begin(), ::tolower); - - bool flag; - if (str == "32bit") - flag = false; - else if (str == "64bit") - flag = true; - else - throw fnd::Exception(kModuleName, "Unsupported instruction type: " + str); - - return flag; -} - -void UserSettings::getHomePath(std::string& path) const -{ - // open other resource files in $HOME/.switch/prod.keys (or $HOME/.switch/dev.keys if -d/--dev is set). - path.clear(); - if (path.empty()) fnd::io::getEnvironVar(path, "HOME"); - if (path.empty()) fnd::io::getEnvironVar(path, "USERPROFILE"); - if (path.empty()) return; -} - -void UserSettings::getSwitchPath(std::string& path) const -{ - std::string home; - home.clear(); - getHomePath(home); - if (home.empty()) - return; - - path.clear(); - fnd::io::appendToPath(path, home); - fnd::io::appendToPath(path, kHomeSwitchDirStr); -} - -void UserSettings::dumpKeyConfig() const -{ - fnd::aes::sAes128Key aes_key; - fnd::aes::sAesXts128Key aesxts_key; - fnd::rsa::sRsa2048Key rsa2048_key; - fnd::rsa::sRsa4096Key rsa4096_key; - - const std::string kKeyIndex[kMasterKeyNum] = {"00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f","10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f"}; - - - std::cout << "[KeyConfiguration]" << std::endl; - std::cout << " NCA Keys:" << std::endl; - for (size_t i = 0; i < kMasterKeyNum; i++) - { - if (mKeyCfg.getContentArchiveHeader0SignKey(rsa2048_key, byte_t(i)) == true) - dumpRsa2048Key(rsa2048_key, "Header0-SignatureKey-" + kKeyIndex[i], 2); - } - for (size_t i = 0; i < kMasterKeyNum; i++) - { - if (mKeyCfg.getAcidSignKey(rsa2048_key, byte_t(i)) == true) - dumpRsa2048Key(rsa2048_key, "Acid-SignatureKey-" + kKeyIndex[i], 2); - } - - if (mKeyCfg.getContentArchiveHeaderKey(aesxts_key) == true) - dumpAesXtsKey(aesxts_key, "Header-EncryptionKey", 2); - - for (size_t i = 0; i < kMasterKeyNum; i++) - { - if (mKeyCfg.getNcaKeyAreaEncryptionKey(byte_t(i), 0, aes_key) == true) - dumpAesKey(aes_key, "KeyAreaEncryptionKey-Application-" + kKeyIndex[i], 2); - if (mKeyCfg.getNcaKeyAreaEncryptionKey(byte_t(i), 1, aes_key) == true) - dumpAesKey(aes_key, "KeyAreaEncryptionKey-Ocean-" + kKeyIndex[i], 2); - if (mKeyCfg.getNcaKeyAreaEncryptionKey(byte_t(i), 2, aes_key) == true) - dumpAesKey(aes_key, "KeyAreaEncryptionKey-System-" + kKeyIndex[i], 2); - } - - for (size_t i = 0; i < kMasterKeyNum; i++) - { - if (mKeyCfg.getNcaKeyAreaEncryptionKeyHw(byte_t(i), 0, aes_key) == true) - dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-Application-" + kKeyIndex[i], 2); - if (mKeyCfg.getNcaKeyAreaEncryptionKeyHw(byte_t(i), 1, aes_key) == true) - dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-Ocean-" + kKeyIndex[i], 2); - if (mKeyCfg.getNcaKeyAreaEncryptionKeyHw(byte_t(i), 2, aes_key) == true) - dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-System-" + kKeyIndex[i], 2); - } - - std::cout << " NRR Keys:" << std::endl; - for (size_t i = 0; i < kMasterKeyNum; i++) - { - if (mKeyCfg.getNrrCertificateSignKey(rsa2048_key, byte_t(i)) == true) - dumpRsa2048Key(rsa2048_key, "Certificate-SignatureKey-" + kKeyIndex[i], 2); - } - - std::cout << " XCI Keys:" << std::endl; - if (mKeyCfg.getXciHeaderSignKey(rsa2048_key) == true) - dumpRsa2048Key(rsa2048_key, "Header-SignatureKey", 2); - if (mKeyCfg.getXciHeaderKey(aes_key) == true) - dumpAesKey(aes_key, "ExtendedHeader-EncryptionKey", 2); - - - - - std::cout << " Package1 Keys:" << std::endl; - for (size_t i = 0; i < kMasterKeyNum; i++) - { - if (mKeyCfg.getPkg1Key(byte_t(i), aes_key) == true) - dumpAesKey(aes_key, "EncryptionKey-" + kKeyIndex[i], 2); - } - - std::cout << " Package2 Keys:" << std::endl; - if (mKeyCfg.getPkg2SignKey(rsa2048_key) == true) - dumpRsa2048Key(rsa2048_key, "Signature Key", 2); - for (size_t i = 0; i < kMasterKeyNum; i++) - { - if (mKeyCfg.getPkg2Key(byte_t(i), aes_key) == true) - dumpAesKey(aes_key, "EncryptionKey-" + kKeyIndex[i], 2); - } - - std::cout << " ETicket Keys:" << std::endl; - for (size_t i = 0; i < kMasterKeyNum; i++) - { - if (mKeyCfg.getETicketCommonKey(byte_t(i), aes_key) == true) - dumpAesKey(aes_key, "CommonKey-" + kKeyIndex[i], 2); - } - - if (mKeyCfg.getPkiRootSignKey("Root", rsa4096_key) == true) - dumpRsa4096Key(rsa4096_key, "NNPKI Root Key", 1); -} - -void UserSettings::dumpRsa2048Key(const fnd::rsa::sRsa2048Key& key, const std::string& name, size_t indent) const -{ - std::string indent_str; - - indent_str.clear(); - for (size_t i = 0; i < indent; i++) - { - indent_str += " "; - } - - std::cout << indent_str << name << ":" << std::endl; - if (key.modulus[0] != 0x00 && key.modulus[1] != 0x00) - { - std::cout << indent_str << " Modulus:" << std::endl; - for (size_t i = 0; i < 0x10; i++) - { - std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.modulus + i * 0x10, 0x10, true, ":") << std::endl; - } - } - if (key.priv_exponent[0] != 0x00 && key.priv_exponent[1] != 0x00) - { - std::cout << indent_str << " Private Exponent:" << std::endl; - for (size_t i = 0; i < 0x10; i++) - { - std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.priv_exponent + i * 0x10, 0x10, true, ":") << std::endl; - } - } -} - -void UserSettings::dumpRsa4096Key(const fnd::rsa::sRsa4096Key& key, const std::string& name, size_t indent) const -{ - std::string indent_str; - - indent_str.clear(); - for (size_t i = 0; i < indent; i++) - { - indent_str += " "; - } - - std::cout << indent_str << name << ":" << std::endl; - if (key.modulus[0] != 0x00 && key.modulus[1] != 0x00) - { - std::cout << indent_str << " Modulus:" << std::endl; - for (size_t i = 0; i < 0x20; i++) - { - std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.modulus + i * 0x10, 0x10, true, ":") << std::endl; - } - } - if (key.priv_exponent[0] != 0x00 && key.priv_exponent[1] != 0x00) - { - std::cout << indent_str << " Private Exponent:" << std::endl; - for (size_t i = 0; i < 0x20; i++) - { - std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.priv_exponent + i * 0x10, 0x10, true, ":") << std::endl; - } - } -} - -void UserSettings::dumpAesKey(const fnd::aes::sAes128Key& key, const std::string& name, size_t indent) const -{ - std::string indent_str; - - indent_str.clear(); - for (size_t i = 0; i < indent; i++) - { - indent_str += " "; - } - - std::cout << indent_str << name << ":" << std::endl; - std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.key, 0x10, true, ":") << std::endl; -} - -void UserSettings::dumpAesXtsKey(const fnd::aes::sAesXts128Key& key, const std::string& name, size_t indent) const -{ - std::string indent_str; - - indent_str.clear(); - for (size_t i = 0; i < indent; i++) - { - indent_str += " "; - } - - std::cout << indent_str << name << ":" << std::endl; - std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.key[0], 0x20, true, ":") << std::endl; -} \ No newline at end of file diff --git a/src/UserSettings.h b/src/UserSettings.h deleted file mode 100644 index 379fb9b..0000000 --- a/src/UserSettings.h +++ /dev/null @@ -1,138 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" -#include "KeyConfiguration.h" - -class UserSettings -{ -public: - UserSettings(); - - void parseCmdArgs(const std::vector& arg_list); - void showHelp(); - - // generic options - const std::string getInputPath() const; - const KeyConfiguration& getKeyCfg() const; - FileType getFileType() const; - bool isVerifyFile() const; - CliOutputMode getCliOutputMode() const; - - // specialised toggles - bool isListFs() const; - bool isListApi() const; - bool isListSymbols() const; - bool getIs64BitInstruction() const; - - // specialised paths - const sOptional& getXciUpdatePath() const; - const sOptional& getXciLogoPath() const; - const sOptional& getXciNormalPath() const; - const sOptional& getXciSecurePath() const; - const sOptional& getFsPath() const; - const sOptional& getNcaPart0Path() const; - const sOptional& getNcaPart1Path() const; - const sOptional& getNcaPart2Path() const; - const sOptional& getNcaPart3Path() const; - const sOptional& getKipExtractPath() const; - const sOptional& getAssetIconPath() const; - const sOptional& getAssetNacpPath() const; - const fnd::List>& getCertificateChain() const; - -private: - const std::string kModuleName = "UserSettings"; - - const std::string kHomeSwitchDirStr = ".switch"; - const std::string kGeneralKeyfileName[2] = { "prod.keys", "dev.keys" }; - const std::string kTitleKeyfileName = "title.keys"; - - - struct sCmdArgs - { - sCmdArgs() {} - sOptional input_path; - sOptional devkit_keys; - sOptional keyset_path; - sOptional file_type; - sOptional verify_file; - sOptional show_keys; - sOptional show_layout; - sOptional verbose_output; - sOptional list_fs; - sOptional update_path; - sOptional logo_path; - sOptional normal_path; - sOptional secure_path; - sOptional fs_path; - sOptional nca_titlekey; - sOptional nca_bodykey; - sOptional ticket_path; - sOptional cert_path; - sOptional part0_path; - sOptional part1_path; - sOptional part2_path; - sOptional part3_path; - sOptional kip_extract_path; - sOptional list_api; - sOptional list_sym; - sOptional inst_type; - sOptional asset_icon_path; - sOptional asset_nacp_path; - }; - - std::string mInputPath; - FileType mFileType; - KeyConfiguration mKeyCfg; - bool mVerifyFile; - CliOutputMode mOutputMode; - - bool mListFs; - sOptional mXciUpdatePath; - sOptional mXciLogoPath; - sOptional mXciNormalPath; - sOptional mXciSecurePath; - sOptional mFsPath; - - sOptional mNcaPart0Path; - sOptional mNcaPart1Path; - sOptional mNcaPart2Path; - sOptional mNcaPart3Path; - - sOptional mKipExtractPath; - - sOptional mAssetIconPath; - sOptional mAssetNacpPath; - - fnd::List> mCertChain; - - bool mListApi; - bool mListSymbols; - bool mIs64BitInstruction; - - void populateCmdArgs(const std::vector& arg_list, sCmdArgs& cmd_args); - void populateKeyset(sCmdArgs& args); - void populateUserSettings(sCmdArgs& args); - FileType getFileTypeFromString(const std::string& type_str); - FileType determineFileTypeFromFile(const std::string& path); - bool determineValidNcaFromSample(const fnd::Vec& sample) const; - bool determineValidCnmtFromSample(const fnd::Vec& sample) const; - bool determineValidNacpFromSample(const fnd::Vec& sample) const; - bool determineValidEsCertFromSample(const fnd::Vec& sample) const; - bool determineValidEsTikFromSample(const fnd::Vec& sample) const; - bool getIs64BitInstructionFromString(const std::string& type_str); - void getHomePath(std::string& path) const; - void getSwitchPath(std::string& path) const; - - void dumpKeyConfig() const; - void dumpRsa2048Key(const fnd::rsa::sRsa2048Key& key, const std::string& name, size_t indent) const; - void dumpRsa4096Key(const fnd::rsa::sRsa4096Key& key, const std::string& name, size_t indent) const; - void dumpAesKey(const fnd::aes::sAes128Key& key, const std::string& name, size_t indent) const; - void dumpAesXtsKey(const fnd::aes::sAesXts128Key& key, const std::string& name, size_t indent) const; -}; \ No newline at end of file diff --git a/src/common.h b/src/common.h deleted file mode 100644 index 8625a8f..0000000 --- a/src/common.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -static const size_t kMasterKeyNum = 0x20; -static const size_t kNcaKeakNum = nn::hac::nca::kKeyAreaEncryptionKeyNum; - -enum FileType -{ - FILE_GAMECARD, - FILE_NSP, - FILE_PARTITIONFS, - FILE_ROMFS, - FILE_NCA, - FILE_META, - FILE_CNMT, - FILE_NSO, - FILE_NRO, - FILE_NACP, - FILE_INI, - FILE_KIP, - FILE_PKI_CERT, - FILE_ES_TIK, - FILE_HB_ASSET, - FILE_INVALID = -1, -}; - -enum CliOutputModeFlag -{ - OUTPUT_BASIC, - OUTPUT_LAYOUT, - OUTPUT_KEY_DATA, - OUTPUT_EXTENDED -}; - -typedef byte_t CliOutputMode; - -template -struct sOptional -{ - bool isSet; - T var; - inline sOptional() : isSet(false) {} - inline sOptional(const T& other) : isSet(true), var(other) {} - inline sOptional(const sOptional& other) : isSet(other.isSet), var(other.var) {} - inline const T& operator=(const T& other) { isSet = true; var = other; return var; } - inline const sOptional& operator=(const sOptional& other) - { - isSet = other.isSet; - if (isSet) { - var = other.var; - } - return *this; - } - inline T& operator*() { return var; } -}; - -const byte_t kDummyRightsIdForUserTitleKey[nn::hac::nca::kRightsIdLen] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -const byte_t kDummyRightsIdForUserBodyKey[nn::hac::nca::kRightsIdLen] = {0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe}; \ No newline at end of file diff --git a/src/elf.h b/src/elf.h new file mode 100644 index 0000000..0fe891c --- /dev/null +++ b/src/elf.h @@ -0,0 +1,458 @@ +#pragma once +#include "types.h" + +namespace nstool +{ + namespace elf + { + /* These constants are for the segment types stored in the image headers */ + enum SegmentType + { + PT_NULL = 0, + PT_LOAD = 1, + PT_DYNAMIC = 2, + PT_INTERP = 3, + PT_NOTE = 4, + PT_SHLIB = 5, + PT_PHDR = 6, + PT_TLS = 7, /* Thread local storage segment */ + PT_LOOS = 0x60000000, /* OS-specific */ + PT_HIOS = 0x6fffffff, /* OS-specific */ + PT_LOPROC = 0x70000000, + PT_HIPROC = 0x7fffffff + }; + + /* These constants define the different elf file types */ + enum ElfType + { + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4, + ET_LOPROC = 0xff00, + ET_HIPROC = 0xffff + }; + + /* This is the info that is needed to parse the dynamic section of the file */ + enum DynamicSectionType + { + DT_NULL = 0, + DT_NEEDED = 1, + DT_PLTRELSZ = 2, + DT_PLTGOT = 3, + DT_HASH = 4, + DT_STRTAB = 5, + DT_SYMTAB = 6, + DT_RELA = 7, + DT_RELASZ = 8, + DT_RELAENT = 9, + DT_STRSZ = 10, + DT_SYMENT = 11, + DT_INIT = 12, + DT_FINI = 13, + DT_SONAME = 14, + DT_RPATH = 15, + DT_SYMBOLIC = 16, + DT_REL = 17, + DT_RELSZ = 18, + DT_RELENT = 19, + DT_PLTREL = 20, + DT_DEBUG = 21, + DT_TEXTREL = 22, + DT_JMPREL = 23, + DT_ENCODING = 32, + OLD_DT_LOOS = 0x60000000, + DT_LOOS = 0x6000000d, + DT_HIOS = 0x6ffff000, + DT_VALRNGLO = 0x6ffffd00, + DT_VALRNGHI = 0x6ffffdff, + DT_ADDRRNGLO = 0x6ffffe00, + DT_ADDRRNGHI = 0x6ffffeff, + DT_VERSYM = 0x6ffffff0, + DT_RELACOUNT = 0x6ffffff9, + DT_RELCOUNT = 0x6ffffffa, + DT_FLAGS_1 = 0x6ffffffb, + DT_VERDEF = 0x6ffffffc, + DT_VERDEFNUM = 0x6ffffffd, + DT_VERNEED = 0x6ffffffe, + DT_VERNEEDNUM = 0x6fffffff, + OLD_DT_HIOS = 0x6fffffff, + DT_LOPROC = 0x70000000, + DT_HIPROC = 0x7fffffff + }; + + /* This info is needed when parsing the symbol table */ + enum SymbolBinding + { + STB_LOCAL = 0, + STB_GLOBAL = 1, + STB_WEAK = 2, + STB_LOOS = 10, + STB_HIOS = 12, + STB_LOPROC, + STB_HIPROC = 0xf + }; + + enum SymbolType + { + STT_NOTYPE = 0, + STT_OBJECT = 1, + STT_FUNC = 2, + STT_SECTION = 3, + STT_FILE = 4, + STT_COMMON = 5, + STT_TLS = 6, + STT_LOOS = 10, + STT_HIOS = 12, + STT_LOPROC, + STT_HIPROC = 0xf + }; + + /* These constants define the permissions on sections in the program + header, p_flags. */ + enum PermissionFlag + { + PF_R = 0x4, + PF_W = 0x2, + PF_X = 0x1 + }; + + /* sh_type */ + enum SectionHeaderType + { + SHT_NULL = 0, + SHT_PROGBITS = 1, + SHT_SYMTAB = 2, + SHT_STRTAB = 3, + SHT_RELA = 4, + SHT_HASH = 5, + SHT_DYNAMIC = 6, + SHT_NOTE = 7, + SHT_NOBITS = 8, + SHT_REL = 9, + SHT_SHLIB = 10, + SHT_DYNSYM = 11, + SHT_NUM = 12, + SHT_LOPROC = 0x70000000, + SHT_HIPROC = 0x7fffffff, + SHT_LOUSER = 0x80000000, + SHT_HIUSER = 0xffffffff + }; + + /* sh_flags */ + enum SectionHeaderFlag + { + SHF_WRITE = 0x1, + SHF_ALLOC = 0x2, + SHF_EXECINSTR = 0x4, + SHF_RELA_LIVEPATCH = 0x00100000, + SHF_RO_AFTER_INIT = 0x00200000, + SHF_MASKPROC = 0xf0000000 + }; + + /* special section indexes */ + enum SpecialSectionIndex + { + SHN_UNDEF = 0, + SHN_LORESERVE = 0xff00, + SHN_LOPROC = 0xff00, + SHN_HIPROC = 0xff1f, + SHN_LOOS = 0xff20, + SHN_HIOS = 0xff3f, + SHN_ABS = 0xfff1, + SHN_COMMON = 0xfff2, + SHN_HIRESERVE = 0xffff + }; + + enum ElfIdentIndex + { + EI_MAG0 = 0, /* e_ident[] indexes */ + EI_MAG1 = 1, + EI_MAG2 = 2, + EI_MAG3 = 3, + EI_CLASS = 4, + EI_DATA = 5, + EI_VERSION = 6, + EI_OSABI = 7, + EI_PAD = 8 + }; + + enum ElfClass + { + ELFCLASSNONE = 0, /* EI_CLASS */ + ELFCLASS32 = 1, + ELFCLASS64 = 2, + ELFCLASSNUM = 3 + }; + + enum ElfData + { + ELFDATANONE = 0, /* e_ident[EI_DATA] */ + ELFDATA2LSB = 1, + ELFDATA2MSB = 2 + }; + + enum ElfVersion + { + EV_NONE = 0, /* e_version, EI_VERSION */ + EV_CURRENT = 1, + EV_NUM = 2, + }; + + enum ElfOsAbi + { + ELFOSABI_NONE = 0, + ELFOSABI_LINUX =3 + }; + + + /* + * Notes used in ET_CORE. Architectures export some of the arch register sets + * using the corresponding note types via the PTRACE_GETREGSET and + * PTRACE_SETREGSET requests. + */ + enum NoteType + { + NT_PRSTATUS = 1, + NT_PRFPREG = 2, + NT_PRPSINFO = 3, + NT_TASKSTRUCT = 4, + NT_AUXV = 6, + /* + * Note to userspace developers: size of NT_SIGINFO note may increase + * in the future to accomodate more fields, don't assume it is fixed! + */ + NT_SIGINFO = 0x53494749, + NT_FILE = 0x46494c45, + NT_PRXFPREG = 0x46e62b7f, /* copied from gdb5.1/include/elf/common.h */ + NT_PPC_VMX = 0x100, /* PowerPC Altivec/VMX registers */ + NT_PPC_SPE = 0x101, /* PowerPC SPE/EVR registers */ + NT_PPC_VSX = 0x102, /* PowerPC VSX registers */ + NT_PPC_TAR = 0x103, /* Target Address Register */ + NT_PPC_PPR = 0x104, /* Program Priority Register */ + NT_PPC_DSCR = 0x105, /* Data Stream Control Register */ + NT_PPC_EBB = 0x106, /* Event Based Branch Registers */ + NT_PPC_PMU = 0x107, /* Performance Monitor Registers */ + NT_PPC_TM_CGPR = 0x108, /* TM checkpointed GPR Registers */ + NT_PPC_TM_CFPR = 0x109, /* TM checkpointed FPR Registers */ + NT_PPC_TM_CVMX = 0x10a, /* TM checkpointed VMX Registers */ + NT_PPC_TM_CVSX = 0x10b, /* TM checkpointed VSX Registers */ + NT_PPC_TM_SPR = 0x10c, /* TM Special Purpose Registers */ + NT_PPC_TM_CTAR = 0x10d, /* TM checkpointed Target Address Register */ + NT_PPC_TM_CPPR = 0x10e, /* TM checkpointed Program Priority Register */ + NT_PPC_TM_CDSCR = 0x10f, /* TM checkpointed Data Stream Control Register */ + NT_PPC_PKEY = 0x110, /* Memory Protection Keys registers */ + NT_386_TLS = 0x200, /* i386 TLS slots (struct user_desc) */ + NT_386_IOPERM = 0x201, /* x86 io permission bitmap (1=deny) */ + NT_X86_XSTATE = 0x202, /* x86 extended state using xsave */ + NT_S390_HIGH_GPRS = 0x300, /* s390 upper register halves */ + NT_S390_TIMER = 0x301, /* s390 timer register */ + NT_S390_TODCMP = 0x302, /* s390 TOD clock comparator register */ + NT_S390_TODPREG = 0x303, /* s390 TOD programmable register */ + NT_S390_CTRS = 0x304, /* s390 control registers */ + NT_S390_PREFIX = 0x305, /* s390 prefix register */ + NT_S390_LAST_BREAK = 0x306, /* s390 breaking event address */ + NT_S390_SYSTEM_CALL = 0x307, /* s390 system call restart data */ + NT_S390_TDB = 0x308, /* s390 transaction diagnostic block */ + NT_S390_VXRS_LOW = 0x309, /* s390 vector registers 0-15 upper half */ + NT_S390_VXRS_HIGH = 0x30a, /* s390 vector registers 16-31 */ + NT_S390_GS_CB = 0x30b, /* s390 guarded storage registers */ + NT_S390_GS_BC = 0x30c, /* s390 guarded storage broadcast control block */ + NT_S390_RI_CB = 0x30d, /* s390 runtime instrumentation */ + NT_ARM_VFP = 0x400, /* ARM VFP/NEON registers */ + NT_ARM_TLS = 0x401, /* ARM TLS register */ + NT_ARM_HW_BREAK = 0x402, /* ARM hardware breakpoint registers */ + NT_ARM_HW_WATCH = 0x403, /* ARM hardware watchpoint registers */ + NT_ARM_SYSTEM_CALL = 0x404, /* ARM system call number */ + NT_ARM_SVE = 0x405, /* ARM Scalable Vector Extension registers */ + NT_ARC_V2 = 0x600, /* ARCv2 accumulator/extra registers */ + NT_VMCOREDD = 0x700, /* Vmcore Device Dump Note */ + NT_MIPS_DSP = 0x800, /* MIPS DSP ASE registers */ + NT_MIPS_FP_MODE = 0x801, /* MIPS floating-point mode */ + }; + + static const size_t kEIdentSize = 0x10; + static const byte_t kElfMagic[sizeof(uint32_t)] = {0x7f, 'E', 'L', 'F'}; + + + inline byte_t get_elf_st_bind(byte_t st_info) { return st_info >> 4; } + inline byte_t get_elf_st_type(byte_t st_info) { return st_info & 0xf; } + inline byte_t get_elf_st_info(byte_t st_bind, byte_t st_type) { return (st_type & 0xf) | ((st_bind & 0xf) << 4);} + + /* The following are used with relocations */ + #define ELF32_R_SYM(x) ((x) >> 8) + #define ELF32_R_TYPE(x) ((x) & 0xff) + + #define ELF64_R_SYM(i) ((i) >> 32) + #define ELF64_R_TYPE(i) ((i) & 0xffffffff) + } + + struct Elf32_Dyn + { + int32_t d_tag; + union{ + int32_t d_val; + uint32_t d_ptr; + } d_un; + }; + + struct Elf64_Dyn + { + int64_t d_tag; /* entry tag value */ + union { + uint64_t d_val; + uint64_t d_ptr; + } d_un; + }; + + struct Elf32_Rel + { + uint32_t r_offset; + uint32_t r_info; + }; + + struct Elf64_Rel + { + uint64_t r_offset; /* Location at which to apply the action */ + uint64_t r_info; /* index and type of relocation */ + }; + + struct Elf32_Rela + { + uint32_t r_offset; + uint32_t r_info; + int32_t r_addend; + }; + + struct Elf64_Rela + { + uint64_t r_offset; /* Location at which to apply the action */ + uint64_t r_info; /* index and type of relocation */ + int64_t r_addend; /* Constant addend used to compute value */ + }; + + struct Elf32_Sym + { + uint32_t st_name; + uint32_t st_value; + uint32_t st_size; + byte_t st_info; + byte_t st_other; + uint16_t st_shndx; + }; + + struct Elf64_Sym + { + uint32_t st_name; /* Symbol name, index in string tbl */ + byte_t st_info; /* Type and binding attributes */ + byte_t st_other; /* No defined meaning, 0 */ + uint16_t st_shndx; /* Associated section index */ + uint64_t st_value; /* Value of the symbol */ + uint64_t st_size; /* Associated symbol size */ + }; + + struct Elf32_Ehdr + { + byte_t e_ident[elf::kEIdentSize]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; /* Entry point */ + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; + }; + + struct Elf64_Ehdr + { + byte_t e_ident[elf::kEIdentSize]; /* ELF "magic number" */ + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint64_t e_entry; /* Entry point virtual address */ + uint64_t e_phoff; /* Program header table file offset */ + uint64_t e_shoff; /* Section header table file offset */ + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; + }; + + struct Elf32_Phdr + { + uint32_t p_type; + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; + }; + + struct Elf64_Phdr + { + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; /* Segment file offset */ + uint64_t p_vaddr; /* Segment virtual address */ + uint64_t p_paddr; /* Segment physical address */ + uint64_t p_filesz; /* Segment size in file */ + uint64_t p_memsz; /* Segment size in memory */ + uint64_t p_align; /* Segment alignment, file & memory */ + }; + + struct Elf32_Shdr + { + uint32_t sh_name; + uint32_t sh_type; + uint32_t sh_flags; + uint32_t sh_addr; + uint32_t sh_offset; + uint32_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint32_t sh_addralign; + uint32_t sh_entsize; + }; + + struct Elf64_Shdr + { + uint32_t sh_name; /* Section name, index in string tbl */ + uint32_t sh_type; /* Type of section */ + uint64_t sh_flags; /* Miscellaneous section attributes */ + uint64_t sh_addr; /* Section virtual addr at execution */ + uint64_t sh_offset; /* Section file offset */ + uint64_t sh_size; /* Size of section in bytes */ + uint32_t sh_link; /* Index of another section */ + uint32_t sh_info; /* Additional section information */ + uint64_t sh_addralign; /* Section alignment */ + uint64_t sh_entsize; /* Entry size if section holds table */ + }; + + /* Note header in a PT_NOTE section */ + struct Elf32_Nhdr + { + uint32_t n_namesz; /* Name size */ + uint32_t n_descsz; /* Content size */ + uint32_t n_type; /* Content type */ + }; + + /* Note header in a PT_NOTE section */ + struct Elf64_Nhdr + { + uint32_t n_namesz; /* Name size */ + uint32_t n_descsz; /* Content size */ + uint32_t n_type; /* Content type */ + }; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index bad4a3e..4c6ba2f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,8 @@ -#include -#include -#include -#include -#include "UserSettings.h" +#include +#include +#include "Settings.h" + +/* #include "GameCardProcess.h" #include "PfsProcess.h" #include "RomfsProcess.h" @@ -17,129 +17,116 @@ #include "PkiCertProcess.h" #include "EsTikProcess.h" #include "AssetProcess.h" +*/ -#ifdef _WIN32 -int wmain(int argc, wchar_t** argv) -#else -int main(int argc, char** argv) -#endif +int umain(const std::vector& args, const std::vector& env) { - std::vector args; - for (size_t i = 0; i < (size_t)argc; i++) + try { -#ifdef _WIN32 - args.push_back(fnd::StringConv::ConvertChar16ToChar8(std::u16string((char16_t*)argv[i]))); -#else - args.push_back(argv[i]); -#endif - } + nstool::Settings set = nstool::SettingsInitializer(args); + + std::shared_ptr infile_stream = std::make_shared(tc::io::FileStream(set.infile.path.get(), tc::io::FileMode::Open, tc::io::FileAccess::Read)); - UserSettings user_set; - try { - user_set.parseCmdArgs(args); - - fnd::SharedPtr inputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read)); - - if (user_set.getFileType() == FILE_GAMECARD) + if (set.infile.filetype == nstool::Settings::FILE_TYPE_GAMECARD) { GameCardProcess obj; - obj.setInputFile(inputFile); + obj.setInputFile(infile_stream); - obj.setKeyCfg(user_set.getKeyCfg()); + obj.setKeyCfg(set.opt.keybag); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); - if (user_set.getXciUpdatePath().isSet) - obj.setPartitionForExtract(nn::hac::gc::kUpdatePartitionStr, user_set.getXciUpdatePath().var); - if (user_set.getXciLogoPath().isSet) - obj.setPartitionForExtract(nn::hac::gc::kLogoPartitionStr, user_set.getXciLogoPath().var); - if (user_set.getXciNormalPath().isSet) - obj.setPartitionForExtract(nn::hac::gc::kNormalPartitionStr, user_set.getXciNormalPath().var); - if (user_set.getXciSecurePath().isSet) - obj.setPartitionForExtract(nn::hac::gc::kSecurePartitionStr, user_set.getXciSecurePath().var); + if (set.xci.update_extract_path.isSet()) + obj.setPartitionForExtract(nn::hac::gc::kUpdatePartitionStr, set.xci.update_extract_path.get()); + if (set.xci.logo_extract_path.isSet()) + obj.setPartitionForExtract(nn::hac::gc::kLogoPartitionStr, set.xci.logo_extract_path.get()); + if (user_set.getXciNormalPath().isSet()) + obj.setPartitionForExtract(nn::hac::gc::kNormalPartitionStr, user_set.getXciNormalPath().get()); + if (user_set.getXciSecurePath().isSet()) + obj.setPartitionForExtract(nn::hac::gc::kSecurePartitionStr, user_set.getXciSecurePath().get()); obj.setListFs(user_set.isListFs()); obj.process(); } - else if (user_set.getFileType() == FILE_PARTITIONFS || user_set.getFileType() == FILE_NSP) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_PARTITIONFS || set.infile.filetype == nstool::Settings::FILE_TYPE_NSP) { PfsProcess obj; - obj.setInputFile(inputFile); + obj.setInputFile(infile_stream); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); - if (user_set.getFsPath().isSet) - obj.setExtractPath(user_set.getFsPath().var); + if (user_set.getFsPath().isSet()) + obj.setExtractPath(user_set.getFsPath().get()); obj.setListFs(user_set.isListFs()); obj.process(); } - else if (user_set.getFileType() == FILE_ROMFS) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_ROMFS) { RomfsProcess obj; - obj.setInputFile(inputFile); + obj.setInputFile(infile_stream); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); - if (user_set.getFsPath().isSet) - obj.setExtractPath(user_set.getFsPath().var); + if (user_set.getFsPath().isSet()) + obj.setExtractPath(user_set.getFsPath().get()); obj.setListFs(user_set.isListFs()); obj.process(); } - else if (user_set.getFileType() == FILE_NCA) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_NCA) { NcaProcess obj; - obj.setInputFile(inputFile); - obj.setKeyCfg(user_set.getKeyCfg()); + obj.setInputFile(infile_stream); + obj.setKeyCfg(set.opt.keybag); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); - if (user_set.getNcaPart0Path().isSet) - obj.setPartition0ExtractPath(user_set.getNcaPart0Path().var); - if (user_set.getNcaPart1Path().isSet) - obj.setPartition1ExtractPath(user_set.getNcaPart1Path().var); - if (user_set.getNcaPart2Path().isSet) - obj.setPartition2ExtractPath(user_set.getNcaPart2Path().var); - if (user_set.getNcaPart3Path().isSet) - obj.setPartition3ExtractPath(user_set.getNcaPart3Path().var); + if (user_set.getNcaPart0Path().isSet()) + obj.setPartition0ExtractPath(user_set.getNcaPart0Path().get()); + if (user_set.getNcaPart1Path().isSet()) + obj.setPartition1ExtractPath(user_set.getNcaPart1Path().get()); + if (user_set.getNcaPart2Path().isSet()) + obj.setPartition2ExtractPath(user_set.getNcaPart2Path().get()); + if (user_set.getNcaPart3Path().isSet()) + obj.setPartition3ExtractPath(user_set.getNcaPart3Path().get()); obj.setListFs(user_set.isListFs()); obj.process(); } - else if (user_set.getFileType() == FILE_META) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_META) { MetaProcess obj; - obj.setInputFile(inputFile); - obj.setKeyCfg(user_set.getKeyCfg()); + obj.setInputFile(infile_stream); + obj.setKeyCfg(set.opt.keybag); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); obj.process(); } - else if (user_set.getFileType() == FILE_CNMT) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_CNMT) { CnmtProcess obj; - obj.setInputFile(inputFile); + obj.setInputFile(infile_stream); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); obj.process(); } - else if (user_set.getFileType() == FILE_NSO) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_NSO) { NsoProcess obj; - obj.setInputFile(inputFile); + obj.setInputFile(infile_stream); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); obj.setIs64BitInstruction(user_set.getIs64BitInstruction()); obj.setListApi(user_set.isListApi()); @@ -147,111 +134,162 @@ int main(int argc, char** argv) obj.process(); } - else if (user_set.getFileType() == FILE_NRO) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_NRO) { NroProcess obj; - obj.setInputFile(inputFile); + obj.setInputFile(infile_stream); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); obj.setIs64BitInstruction(user_set.getIs64BitInstruction()); obj.setListApi(user_set.isListApi()); obj.setListSymbols(user_set.isListSymbols()); - if (user_set.getAssetIconPath().isSet) - obj.setAssetIconExtractPath(user_set.getAssetIconPath().var); - if (user_set.getAssetNacpPath().isSet) - obj.setAssetNacpExtractPath(user_set.getAssetNacpPath().var); + if (user_set.getAssetIconPath().isSet()) + obj.setAssetIconExtractPath(user_set.getAssetIconPath().get()); + if (user_set.getAssetNacpPath().isSet()) + obj.setAssetNacpExtractPath(user_set.getAssetNacpPath().get()); - if (user_set.getFsPath().isSet) - obj.setAssetRomfsExtractPath(user_set.getFsPath().var); + if (user_set.getFsPath().isSet()) + obj.setAssetRomfsExtractPath(user_set.getFsPath().get()); obj.setAssetListFs(user_set.isListFs()); obj.process(); } - else if (user_set.getFileType() == FILE_NACP) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_NACP) { NacpProcess obj; - obj.setInputFile(inputFile); + obj.setInputFile(infile_stream); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); obj.process(); } - else if (user_set.getFileType() == FILE_INI) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_INI) { IniProcess obj; - obj.setInputFile(inputFile); + obj.setInputFile(infile_stream); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); - if (user_set.getKipExtractPath().isSet) - obj.setKipExtractPath(user_set.getKipExtractPath().var); + if (user_set.getKipExtractPath().isSet()) + obj.setKipExtractPath(user_set.getKipExtractPath().get()); obj.process(); } - else if (user_set.getFileType() == FILE_KIP) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_KIP) { KipProcess obj; - obj.setInputFile(inputFile); + obj.setInputFile(infile_stream); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); obj.process(); } - else if (user_set.getFileType() == FILE_PKI_CERT) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_PKI_CERT) { PkiCertProcess obj; - obj.setInputFile(inputFile); - obj.setKeyCfg(user_set.getKeyCfg()); + obj.setInputFile(infile_stream); + obj.setKeyCfg(set.opt.keybag); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); obj.process(); } - else if (user_set.getFileType() == FILE_ES_TIK) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_ES_TIK) { EsTikProcess obj; - obj.setInputFile(inputFile); - obj.setKeyCfg(user_set.getKeyCfg()); + obj.setInputFile(infile_stream); + obj.setKeyCfg(set.opt.keybag); obj.setCertificateChain(user_set.getCertificateChain()); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); obj.process(); } - else if (user_set.getFileType() == FILE_HB_ASSET) + else if (set.infile.filetype == nstool::Settings::FILE_TYPE_HB_ASSET) { AssetProcess obj; - obj.setInputFile(inputFile); + obj.setInputFile(infile_stream); obj.setCliOutputMode(user_set.getCliOutputMode()); - obj.setVerifyMode(user_set.isVerifyFile()); + obj.setVerifyMode(set.opt.verify); - if (user_set.getAssetIconPath().isSet) - obj.setIconExtractPath(user_set.getAssetIconPath().var); - if (user_set.getAssetNacpPath().isSet) - obj.setNacpExtractPath(user_set.getAssetNacpPath().var); + if (user_set.getAssetIconPath().isSet()) + obj.setIconExtractPath(user_set.getAssetIconPath().get()); + if (user_set.getAssetNacpPath().isSet()) + obj.setNacpExtractPath(user_set.getAssetNacpPath().get()); - if (user_set.getFsPath().isSet) - obj.setRomfsExtractPath(user_set.getFsPath().var); + if (user_set.getFsPath().isSet()) + obj.setRomfsExtractPath(user_set.getFsPath().get()); obj.setListFs(user_set.isListFs()); obj.process(); } - else + + switch (set.infile.filetype) { - throw fnd::Exception("main", "Unhandled file type"); + case nstool::Settings::FILE_TYPE_GAMECARD : + fmt::print("## FILE_TYPE_GAMECARD ##\n"); + break; + case nstool::Settings::FILE_TYPE_NSP : + fmt::print("## FILE_TYPE_NSP ##\n"); + break; + case nstool::Settings::FILE_TYPE_PARTITIONFS : + fmt::print("## FILE_TYPE_PARTITIONFS ##\n"); + break; + case nstool::Settings::FILE_TYPE_ROMFS : + fmt::print("## FILE_TYPE_ROMFS ##\n"); + break; + case nstool::Settings::FILE_TYPE_NCA : + fmt::print("## FILE_TYPE_NCA ##\n"); + break; + case nstool::Settings::FILE_TYPE_META : + fmt::print("## FILE_TYPE_META ##\n"); + break; + case nstool::Settings::FILE_TYPE_CNMT : + fmt::print("## FILE_TYPE_CNMT ##\n"); + break; + case nstool::Settings::FILE_TYPE_NSO : + fmt::print("## FILE_TYPE_NSO ##\n"); + break; + case nstool::Settings::FILE_TYPE_NRO : + fmt::print("## FILE_TYPE_NRO ##\n"); + break; + case nstool::Settings::FILE_TYPE_NACP : + fmt::print("## FILE_TYPE_NACP ##\n"); + break; + case nstool::Settings::FILE_TYPE_INI : + fmt::print("## FILE_TYPE_INI ##\n"); + break; + case nstool::Settings::FILE_TYPE_KIP : + fmt::print("## FILE_TYPE_KIP ##\n"); + break; + case nstool::Settings::FILE_TYPE_PKI_CERT : + fmt::print("## FILE_TYPE_PKI_CERT ##\n"); + break; + case nstool::Settings::FILE_TYPE_ES_TIK : + fmt::print("## FILE_TYPE_ES_TIK ##\n"); + break; + case nstool::Settings::FILE_TYPE_HB_ASSET : + fmt::print("## FILE_TYPE_HB_ASSET ##\n"); + break; + default: + fmt::print("## unknown({}) ##\n", (int)set.infile.filetype); + break; } + } - catch (const fnd::Exception& e) { - printf("\n\n%s\n", e.what()); + catch (tc::Exception& e) + { + fmt::print("[{0}{1}ERROR] {2}\n", e.module(), (strlen(e.module()) != 0 ? " ": ""), e.error()); + return 1; } return 0; } \ No newline at end of file diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..5721307 --- /dev/null +++ b/src/types.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include +#include +#include +#include + + +namespace nstool { + +struct CliOutputMode +{ + bool show_basic_info; + bool show_extended_info; + bool show_layout; + bool show_keydata; + + CliOutputMode() : show_basic_info(false), show_extended_info(false), show_layout(false), show_keydata(false) + {} + + CliOutputMode(bool show_basic_info, bool show_extended_info, bool show_layout, bool show_keydata) : show_basic_info(show_basic_info), show_extended_info(show_extended_info), show_layout(show_layout), show_keydata(show_keydata) + {} +}; + +} \ No newline at end of file diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..ccb157b --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,100 @@ +#include "util.h" + +#include +#include +#include + +#include +#include +#include + +inline bool isNotPrintable(char chr) { return isprint(chr) == false; } + +void nstool::processResFile(const std::shared_ptr& file, std::map& dict) +{ + if (file == nullptr || !file->canRead() || file->length() == 0) + { + return; + } + + std::stringstream in_stream; + + // populate string stream + tc::ByteData cache = tc::ByteData(0x1000); + file->seek(0, tc::io::SeekOrigin::Begin); + for (int64_t pos = 0; pos < file->length();) + { + size_t bytes_read = file->read(cache.data(), cache.size()); + + in_stream << std::string((char*)cache.data(), bytes_read); + + pos += tc::io::IOUtil::castSizeToInt64(bytes_read); + } + + // process stream + std::string line, key, value; + while (std::getline(in_stream, line)) + { + // read up to comment line + if (line.find(";") != std::string::npos) + line = line.substr(0, line.find(";")); + + // change chars to lower string + std::transform(line.begin(), line.end(), line.begin(), ::tolower); + + // strip whitespace + line.erase(std::remove(line.begin(), line.end(), ' '), line.end()); + + // strip nonprintable + line.erase(std::remove_if(line.begin(), line.end(), isNotPrintable), line.end()); + + // skip lines that don't have '=' + if (line.find("=") == std::string::npos) + continue; + + key = line.substr(0,line.find("=")); + value = line.substr(line.find("=")+1); + + // skip if key or value is empty + if (key.empty() || value.empty()) + continue; + + //std::cout << "[" + key + "]=(" + value + ")" << std::endl; + + dict[key] = value; + } + +} + +void nstool::writeSubStreamToFile(const std::shared_ptr& in_stream, int64_t offset, int64_t length, const tc::io::Path& out_path, size_t cache_size) +{ + writeStreamToStream(std::make_shared(tc::io::SubStream(in_stream, offset, length)), std::make_shared(tc::io::FileStream(out_path, tc::io::FileAccess::OpenOrCreate, tc::io::FileMode::Write)), cache_size); +} + + +void nstool::writeStreamToFile(const std::shared_ptr& in_stream, const tc::io::Path& out_path, size_t cache_size) +{ + writeStreamToStream(in_stream, std::make_shared(tc::io::FileStream(out_path, tc::io::FileAccess::OpenOrCreate, tc::io::FileMode::Write)), cache_size); +} + +void nstool::writeStreamToStream(const std::shared_ptr& in_stream, const std::shared_ptr& out_stream, size_t cache_size) +{ + // iterate thru child files + tc::ByteData cache = tc::ByteData(cache_size); + size_t cache_read_len; + + in_stream->seek(0, tc::io::SeekOrigin::Begin); + out_stream->seek(0, tc::io::SeekOrigin::Begin); + for (int64_t remaining_data = in_stream->length(); remaining_data > 0;) + { + cache_read_len = in_stream->read(cache.data(), cache.size()); + if (cache_read_len == 0) + { + throw tc::io::IOException(mModuleLabel, "Failed to read from RomFs file."); + } + + out_stream->write(cache.data(), cache_read_len); + + remaining_data -= int64_t(cache_read_len); + } +} \ No newline at end of file diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..04e01fb --- /dev/null +++ b/src/util.h @@ -0,0 +1,13 @@ +#pragma once +#include "types.h" + +namespace nstool +{ + +void processResFile(const std::shared_ptr& file, std::map& dict); + +void writeSubStreamToFile(const std::shared_ptr& in_stream, int64_t offset, int64_t length, const tc::io::Path& out_path, size_t cache_size = 0x10000); +void writeStreamToFile(const std::shared_ptr& in_stream, const tc::io::Path& out_path, size_t cache_size = 0x10000); +void writeStreamToStream(const std::shared_ptr& in_stream, const std::shared_ptr& out_stream, size_t cache_size = 0x10000); + +} \ No newline at end of file diff --git a/src/version.h b/src/version.h index 25ed5b5..cdf2ade 100644 --- a/src/version.h +++ b/src/version.h @@ -2,6 +2,6 @@ #define APP_NAME "NSTool" #define BIN_NAME "nstool" #define VER_MAJOR 1 -#define VER_MINOR 4 -#define VER_PATCH 1 +#define VER_MINOR 6 +#define VER_PATCH 0 #define AUTHORS "jakcron" \ No newline at end of file