Begin migration from libfnd to libtoolchain

This commit is contained in:
jakcron 2021-09-28 19:15:54 +08:00
parent 6bc4cd8a8c
commit 60acda6615
65 changed files with 3311 additions and 3346 deletions

View file

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio Version 16
VisualStudioVersion = 15.0.28010.2036 VisualStudioVersion = 16.0.31229.75
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nstool", "nstool\nstool.vcxproj", "{775EF5EB-CA49-4994-8AC4-47B4A5385266}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nstool", "nstool\nstool.vcxproj", "{775EF5EB-CA49-4994-8AC4-47B4A5385266}"
EndProject EndProject
@ -38,6 +38,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-pki", "..\..\de
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmbedtls", "..\..\deps\libmbedtls\build\visualstudio\libmbedtls\libmbedtls.vcxproj", "{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmbedtls", "..\..\deps\libmbedtls\build\visualstudio\libmbedtls\libmbedtls.vcxproj", "{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}"
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64
@ -110,6 +114,22 @@ Global
{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.Build.0 = 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.ActiveCfg = Release|Win32
{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -122,6 +142,8 @@ Global
{24D001B4-D439-4967-9371-DC3E0523EB19} = {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} {0BEF63A0-2801-4563-AB65-1E2FD881C3AF} = {05929EAE-4471-4E8E-A6F3-793A81623D7F}
{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C} = {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 EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {ABDCFB40-D6B3-44A9-92B5-0D7AB38D9FB8} SolutionGuid = {ABDCFB40-D6B3-44A9-92B5-0D7AB38D9FB8}

View file

@ -76,7 +76,8 @@
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(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</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(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</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile> </ClCompile>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -85,7 +86,8 @@
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(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</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(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</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile> </ClCompile>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -96,7 +98,8 @@
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(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</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(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</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile> </ClCompile>
<Link> <Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
@ -111,7 +114,8 @@
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(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</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(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</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile> </ClCompile>
<Link> <Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
@ -119,76 +123,46 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\deps\libfnd\build\visualstudio\libfnd\libfnd.vcxproj"> <ProjectReference Include="$(SolutionDir)..\..\deps\libfmt\build\visualstudio\libfmt\libfmt.vcxproj">
<Project>{f4b0540e-0aae-4006-944b-356944ef61fa}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)..\..\deps\libfnd\build\visualstudio\libfnd\libfnd.vcxproj">
<Project>{4e578016-34ba-4a1e-b8ec-37a48780b6ca}</Project> <Project>{4e578016-34ba-4a1e-b8ec-37a48780b6ca}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\..\deps\liblz4\build\visualstudio\liblz4\liblz4.vcxproj"> <ProjectReference Include="$(SolutionDir)..\..\deps\liblz4\build\visualstudio\liblz4\liblz4.vcxproj">
<Project>{e741aded-7900-4e07-8db0-d008c336c3fb}</Project> <Project>{e741aded-7900-4e07-8db0-d008c336c3fb}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\..\deps\libnintendo-es\build\visualstudio\libnintendo-es\libnintendo-es.vcxproj"> <ProjectReference Include="$(SolutionDir)..\..\deps\libnintendo-es\build\visualstudio\libnintendo-es\libnintendo-es.vcxproj">
<Project>{8616d6c9-c8de-4c3f-afc2-625636664c2b}</Project> <Project>{8616d6c9-c8de-4c3f-afc2-625636664c2b}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\..\deps\libnintendo-hac-hb\build\visualstudio\libnintendo-hac-hb\libnintendo-hac-hb.vcxproj"> <ProjectReference Include="$(SolutionDir)..\..\deps\libnintendo-hac-hb\build\visualstudio\libnintendo-hac-hb\libnintendo-hac-hb.vcxproj">
<Project>{24d001b4-d439-4967-9371-dc3e0523eb19}</Project> <Project>{24d001b4-d439-4967-9371-dc3e0523eb19}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\..\deps\libnintendo-hac\build\visualstudio\libnintendo-hac\libnintendo-hac.vcxproj"> <ProjectReference Include="$(SolutionDir)..\..\deps\libnintendo-hac\build\visualstudio\libnintendo-hac\libnintendo-hac.vcxproj">
<Project>{8885c125-83fb-4f73-a93a-c712b1434d54}</Project> <Project>{8885c125-83fb-4f73-a93a-c712b1434d54}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\..\deps\libnintendo-pki\build\visualstudio\libnintendo-pki\libnintendo-pki.vcxproj"> <ProjectReference Include="$(SolutionDir)..\..\deps\libnintendo-pki\build\visualstudio\libnintendo-pki\libnintendo-pki.vcxproj">
<Project>{0bef63a0-2801-4563-ab65-1e2fd881c3af}</Project> <Project>{0bef63a0-2801-4563-ab65-1e2fd881c3af}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\..\deps\libmbedtls\build\visualstudio\libmbedtls\libmbedtls.vcxproj"> <ProjectReference Include="$(SolutionDir)..\..\deps\libmbedtls\build\visualstudio\libmbedtls\libmbedtls.vcxproj">
<Project>{7a7c66f3-2b5b-4e23-85d8-2a74fedad92c}</Project> <Project>{7a7c66f3-2b5b-4e23-85d8-2a74fedad92c}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="$(SolutionDir)..\..\deps\libtoolchain\build\visualstudio\libtoolchain\libtoolchain.vcxproj">
<Project>{e194e4b8-1482-40a2-901b-75d4387822e9}</Project>
</ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\..\src\AssetProcess.cpp" /> <ClInclude Include="..\..\..\src\KeyBag.h" />
<ClCompile Include="..\..\..\src\CnmtProcess.cpp" /> <ClInclude Include="..\..\..\src\Settings.h" />
<ClCompile Include="..\..\..\src\CompressedArchiveIFile.cpp" /> <ClInclude Include="..\..\..\src\types.h" />
<ClCompile Include="..\..\..\src\ElfSymbolParser.cpp" /> <ClInclude Include="..\..\..\src\util.h" />
<ClCompile Include="..\..\..\src\EsTikProcess.cpp" /> <ClInclude Include="..\..\..\src\version.h" />
<ClCompile Include="..\..\..\src\GameCardProcess.cpp" />
<ClCompile Include="..\..\..\src\IniProcess.cpp" />
<ClCompile Include="..\..\..\src\KeyConfiguration.cpp" />
<ClCompile Include="..\..\..\src\KipProcess.cpp" />
<ClCompile Include="..\..\..\src\main.cpp" />
<ClCompile Include="..\..\..\src\MetaProcess.cpp" />
<ClCompile Include="..\..\..\src\NacpProcess.cpp" />
<ClCompile Include="..\..\..\src\NcaProcess.cpp" />
<ClCompile Include="..\..\..\src\NroProcess.cpp" />
<ClCompile Include="..\..\..\src\NsoProcess.cpp" />
<ClCompile Include="..\..\..\src\PfsProcess.cpp" />
<ClCompile Include="..\..\..\src\PkiCertProcess.cpp" />
<ClCompile Include="..\..\..\src\PkiValidator.cpp" />
<ClCompile Include="..\..\..\src\RoMetadataProcess.cpp" />
<ClCompile Include="..\..\..\src\RomfsProcess.cpp" />
<ClCompile Include="..\..\..\src\SdkApiString.cpp" />
<ClCompile Include="..\..\..\src\UserSettings.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\src\AssetProcess.h" /> <ClCompile Include="..\..\..\src\KeyBag.cpp" />
<ClInclude Include="..\..\..\src\CnmtProcess.h" /> <ClCompile Include="..\..\..\src\main.cpp" />
<ClInclude Include="..\..\..\src\common.h" /> <ClCompile Include="..\..\..\src\Settings.cpp" />
<ClInclude Include="..\..\..\src\CompressedArchiveIFile.h" /> <ClCompile Include="..\..\..\src\util.cpp" />
<ClInclude Include="..\..\..\src\ElfSymbolParser.h" />
<ClInclude Include="..\..\..\src\EsTikProcess.h" />
<ClInclude Include="..\..\..\src\GameCardProcess.h" />
<ClInclude Include="..\..\..\src\IniProcess.h" />
<ClInclude Include="..\..\..\src\KeyConfiguration.h" />
<ClInclude Include="..\..\..\src\KipProcess.h" />
<ClInclude Include="..\..\..\src\MetaProcess.h" />
<ClInclude Include="..\..\..\src\NacpProcess.h" />
<ClInclude Include="..\..\..\src\NcaProcess.h" />
<ClInclude Include="..\..\..\src\NroProcess.h" />
<ClInclude Include="..\..\..\src\NsoProcess.h" />
<ClInclude Include="..\..\..\src\PfsProcess.h" />
<ClInclude Include="..\..\..\src\PkiCertProcess.h" />
<ClInclude Include="..\..\..\src\PkiValidator.h" />
<ClInclude Include="..\..\..\src\RoMetadataProcess.h" />
<ClInclude Include="..\..\..\src\RomfsProcess.h" />
<ClInclude Include="..\..\..\src\SdkApiString.h" />
<ClInclude Include="..\..\..\src\UserSettings.h" />
<ClInclude Include="..\..\..\src\version.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

View file

@ -15,142 +15,34 @@
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\..\src\AssetProcess.cpp"> <ClInclude Include="..\..\..\src\KeyBag.h">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\CnmtProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\CompressedArchiveIFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\ElfSymbolParser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\EsTikProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\GameCardProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\IniProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\KeyConfiguration.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\KipProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\MetaProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\NacpProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\NcaProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\NroProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\NsoProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\PfsProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\PkiCertProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\PkiValidator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\RoMetadataProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\RomfsProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\SdkApiString.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\UserSettings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\AssetProcess.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\src\CnmtProcess.h"> <ClInclude Include="..\..\..\src\Settings.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\src\common.h"> <ClInclude Include="..\..\..\src\types.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\CompressedArchiveIFile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\ElfSymbolParser.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\EsTikProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\GameCardProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\IniProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\KeyConfiguration.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\KipProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\MetaProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\NacpProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\NcaProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\NroProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\NsoProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\PfsProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\PkiCertProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\PkiValidator.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\RoMetadataProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\RomfsProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\SdkApiString.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\UserSettings.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\src\version.h"> <ClInclude Include="..\..\..\src\version.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\src\util.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\KeyBag.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\Settings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

2
deps/libfnd vendored

@ -1 +1 @@
Subproject commit b6a74e03d2c3fb272e900f32554b2cc0d18e7d26 Subproject commit 27705aeb2394dbe21f580cc742792537e3a0cbed

2
deps/liblz4 vendored

@ -1 +1 @@
Subproject commit 298f2ecfa6c966472eda9a4f2b93121a060d1867 Subproject commit 555e43086b348a640179ddf2ecd86d8503c12b85

2
deps/libmbedtls vendored

@ -1 +1 @@
Subproject commit 30ef43f1d6ef00d9d94e19270ae8b646e821ecc7 Subproject commit 597bb57271177d776682104dc7c8ea8b62670d1d

2
deps/libnintendo-es vendored

@ -1 +1 @@
Subproject commit f96b4f96552da4258f4212427137d6ff40c45392 Subproject commit 7572682f1fa819fd7ef1a4b639cb14fa67128f0d

@ -1 +1 @@
Subproject commit 33cfca799ccdcc4c34f73696da9fe31f104dd23f Subproject commit 02c6703c9720d98197b3bb697fdab12008a9829e

@ -1 +1 @@
Subproject commit db9af77ec23d170ec703a13cd5cd9b67cd47d3a3 Subproject commit e52fb0e1ebc558f68bb438bd278b05704c5aaeb3

@ -1 +1 @@
Subproject commit 040405bc6f9936e4e61c80b5ab384b3d95c395cd Subproject commit b8a10663a99f7b5fedf11139549e8bf1b289c0e0

2
deps/libtoolchain vendored

@ -1 +1 @@
Subproject commit 0be82cf582b4af7539f57a261e17e5769f4f8cfa Subproject commit 7948f581d32ebbfdf5a872b96c37938690f665e7

View file

@ -1,6 +1,6 @@
# C++/C Recursive Project Makefile # C++/C Recursive Project Makefile
# (c) Jack # (c) Jack
# Version 3 # Version 4
# Project Name # Project Name
PROJECT_NAME = nstool PROJECT_NAME = nstool
@ -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_SO_FILENAME = $(PROJECT_SONAME).$(PROJECT_SO_VER_MINOR).$(PROJECT_SO_VER_PATCH)
# Project Dependencies # Project Dependencies
PROJECT_DEPEND_LOCAL = nintendo-hac-hb nintendo-hac nintendo-es nintendo-pki fnd mbedtls lz4 PROJECT_DEPEND = mbedtls lz4 toolchain fmt nintendo-hac nintendo-hac-hb nintendo-es nintendo-pki
PROJECT_DEPEND_EXTERNAL = 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 # Generate compiler flags for including project include path
ifneq ($(PROJECT_INCLUDE_PATH),) ifneq ($(PROJECT_INCLUDE_PATH),)
@ -40,14 +40,14 @@ ifneq ($(PROJECT_INCLUDE_PATH),)
endif endif
# Generate compiler flags for local included dependencies # Generate compiler flags for local included dependencies
ifneq ($(PROJECT_DEPEND_LOCAL),) ifneq ($(PROJECT_DEPEND_LOCAL_DIR),)
LIB += $(foreach dep,$(PROJECT_DEPEND_LOCAL), -L"$(ROOT_PROJECT_DEPENDENCY_PATH)/lib$(dep)/bin" -l$(dep)) LIB += $(foreach dep,$(PROJECT_DEPEND_LOCAL_DIR), -L"$(ROOT_PROJECT_DEPENDENCY_PATH)/$(dep)/bin")
INC += $(foreach dep,$(PROJECT_DEPEND_LOCAL), -I"$(ROOT_PROJECT_DEPENDENCY_PATH)/lib$(dep)/include") INC += $(foreach dep,$(PROJECT_DEPEND_LOCAL_DIR), -I"$(ROOT_PROJECT_DEPENDENCY_PATH)/$(dep)/include")
endif endif
# Generate compiler flags for external dependencies # Generate compiler flags for external dependencies
ifneq ($(PROJECT_DEPEND_EXTERNAL),) ifneq ($(PROJECT_DEPEND),)
LIB += $(foreach dep,$(PROJECT_DEPEND_EXTERNAL), -l$(dep)) LIB += $(foreach dep,$(PROJECT_DEPEND), -l$(dep))
endif endif
# Detect Platform # Detect Platform
@ -170,8 +170,8 @@ endif
# Dependencies # Dependencies
.PHONY: deps .PHONY: deps
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 .PHONY: clean_deps
clean_deps: clean_deps:
@$(foreach lib,$(PROJECT_DEPEND_LOCAL), cd "$(ROOT_PROJECT_DEPENDENCY_PATH)/lib$(lib)" && $(MAKE) clean && cd "$(PROJECT_PATH)";) @$(foreach lib,$(PROJECT_DEPEND_LOCAL_DIR), cd "$(ROOT_PROJECT_DEPENDENCY_PATH)/$(lib)" && $(MAKE) clean && cd "$(PROJECT_PATH)";)

View file

@ -1,115 +1,103 @@
#include <iostream>
#include <iomanip>
#include <fnd/SimpleFile.h>
#include <fnd/OffsetAdjustedIFile.h>
#include <fnd/Vec.h>
#include "AssetProcess.h" #include "AssetProcess.h"
#include "utils.h"
AssetProcess::AssetProcess() : nstool::AssetProcess::AssetProcess() :
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false) mVerify(false)
{ {
} }
void AssetProcess::process() void nstool::AssetProcess::process()
{ {
importHeader(); importHeader();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
displayHeader(); displayHeader();
processSections(); processSections();
} }
void AssetProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::AssetProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void AssetProcess::setCliOutputMode(CliOutputMode type) void nstool::AssetProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void AssetProcess::setVerifyMode(bool verify) void nstool::AssetProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
void AssetProcess::setListFs(bool list) void nstool::AssetProcess::setListFs(bool list)
{ {
mRomfs.setListFs(list); mRomfs.setListFs(list);
} }
void AssetProcess::setIconExtractPath(const std::string& path) void nstool::AssetProcess::setIconExtractPath(const std::string& path)
{ {
mIconExtractPath = path; mIconExtractPath = path;
} }
void AssetProcess::setNacpExtractPath(const std::string& path) void nstool::AssetProcess::setNacpExtractPath(const std::string& path)
{ {
mNacpExtractPath = path; mNacpExtractPath = path;
} }
void AssetProcess::setRomfsExtractPath(const std::string& path) void nstool::AssetProcess::setRomfsExtractPath(const std::string& path)
{ {
mRomfs.setExtractPath(path); mRomfs.setExtractPath(path);
} }
void AssetProcess::importHeader() void nstool::AssetProcess::importHeader()
{ {
fnd::Vec<byte_t> 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)); 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()); 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()) if ((mHdr.getIconInfo().size + mHdr.getIconInfo().offset) > file_size)
throw fnd::Exception(kModuleName, "ASET geometry for icon beyond file size"); throw tc::Exception(kModuleName, "ASET geometry for icon beyond file size");
fnd::SimpleFile outfile(mIconExtractPath.var, fnd::SimpleFile::Create); writeSubStreamToFile(mFile, tc::io::IOUtil::castSizeToInt64(mHdr.getIconInfo().offset), tc::io::IOUtil::castSizeToInt64(mHdr.getIconInfo().size), mIconExtractPath.get());
fnd::Vec<byte_t> cache;
cache.alloc(mHdr.getIconInfo().size);
(*mFile)->read(cache.data(), mHdr.getIconInfo().offset, cache.size());
outfile.write(cache.data(), cache.size());
outfile.close();
} }
if (mHdr.getNacpInfo().size > 0) if (mHdr.getNacpInfo().size > 0)
{ {
if ((mHdr.getNacpInfo().size + mHdr.getNacpInfo().offset) > (*mFile)->size()) if ((mHdr.getNacpInfo().size + mHdr.getNacpInfo().offset) > file_size)
throw fnd::Exception(kModuleName, "ASET geometry for nacp beyond 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); writeSubStreamToFile(mFile, tc::io::IOUtil::castSizeToInt64(mHdr.getNacpInfo().offset), tc::io::IOUtil::castSizeToInt64(mHdr.getNacpInfo().size), mNacpExtractPath.get());
fnd::Vec<byte_t> cache;
cache.alloc(mHdr.getNacpInfo().size);
(*mFile)->read(cache.data(), mHdr.getNacpInfo().offset, cache.size());
outfile.write(cache.data(), cache.size());
outfile.close();
} }
mNacp.setInputFile(new fnd::OffsetAdjustedIFile(mFile, mHdr.getNacpInfo().offset, mHdr.getNacpInfo().size)); mNacp.setInputFile(std::make_shared<tc::io::SubStream>(mFile, tc::io::IOUtil::castSizeToInt64(mHdr.getNacpInfo().offset), tc::io::IOUtil::castSizeToInt64(mHdr.getNacpInfo().size)));
mNacp.setCliOutputMode(mCliOutputMode); mNacp.setCliOutputMode(mCliOutputMode);
mNacp.setVerifyMode(mVerify); mNacp.setVerifyMode(mVerify);
@ -118,10 +106,10 @@ void AssetProcess::processSections()
if (mHdr.getRomfsInfo().size > 0) if (mHdr.getRomfsInfo().size > 0)
{ {
if ((mHdr.getRomfsInfo().size + mHdr.getRomfsInfo().offset) > (*mFile)->size()) if ((mHdr.getRomfsInfo().size + mHdr.getRomfsInfo().offset) > file_size)
throw fnd::Exception(kModuleName, "ASET geometry for romfs beyond 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<tc::io::SubStream>(mFile, tc::io::IOUtil::castSizeToInt64(mHdr.getRomfsInfo().offset), tc::io::IOUtil::castSizeToInt64(mHdr.getRomfsInfo().size)));
mRomfs.setCliOutputMode(mCliOutputMode); mRomfs.setCliOutputMode(mCliOutputMode);
mRomfs.setVerifyMode(mVerify); 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 << "[ASET Header]" << std::endl;
std::cout << " Icon:" << std::endl; std::cout << " Icon:" << std::endl;

View file

@ -1,13 +1,11 @@
#pragma once #pragma once
#include <string> #include "types.h"
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <nn/hac/AssetHeader.h>
#include "NacpProcess.h" #include "NacpProcess.h"
#include "RomfsProcess.h" #include "RomfsProcess.h"
#include "common.h" #include <nn/hac/AssetHeader.h>
namespace nstool {
class AssetProcess class AssetProcess
{ {
@ -16,7 +14,7 @@ public:
void process(); void process();
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -30,12 +28,12 @@ public:
private: private:
const std::string kModuleName = "AssetProcess"; const std::string kModuleName = "AssetProcess";
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
sOptional<std::string> mIconExtractPath; tc::Optional<tc::io::Path> mIconExtractPath;
sOptional<std::string> mNacpExtractPath; tc::Optional<tc::io::Path> mNacpExtractPath;
nn::hac::AssetHeader mHdr; nn::hac::AssetHeader mHdr;
NacpProcess mNacp; NacpProcess mNacp;
@ -45,3 +43,5 @@ private:
void processSections(); void processSections();
void displayHeader(); void displayHeader();
}; };
}

View file

@ -3,53 +3,50 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <fnd/SimpleTextOutput.h>
#include <fnd/OffsetAdjustedIFile.h>
#include <nn/hac/ContentMetaUtil.h> #include <nn/hac/ContentMetaUtil.h>
CnmtProcess::CnmtProcess() : nstool::CnmtProcess::CnmtProcess() :
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false) mVerify(false)
{ {
} }
void CnmtProcess::process() void nstool::CnmtProcess::process()
{ {
importCnmt(); importCnmt();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
displayCnmt(); displayCnmt();
} }
void CnmtProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::CnmtProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void CnmtProcess::setCliOutputMode(CliOutputMode type) void nstool::CnmtProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void CnmtProcess::setVerifyMode(bool verify) void nstool::CnmtProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
const nn::hac::ContentMeta& CnmtProcess::getContentMeta() const const nn::hac::ContentMeta& nstool::CnmtProcess::getContentMeta() const
{ {
return mCnmt; return mCnmt;
} }
void CnmtProcess::importCnmt() void nstool::CnmtProcess::importCnmt()
{ {
fnd::Vec<byte_t> 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.");
} }
scratch.alloc((*mFile)->size()); scratch.alloc((*mFile)->size());
@ -58,7 +55,7 @@ void CnmtProcess::importCnmt()
mCnmt.fromBytes(scratch.data(), scratch.size()); mCnmt.fromBytes(scratch.data(), scratch.size());
} }
void CnmtProcess::displayCnmt() void nstool::CnmtProcess::displayCnmt()
{ {
std::cout << "[ContentMeta]" << std::endl; std::cout << "[ContentMeta]" << std::endl;
std::cout << " TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getTitleId() << 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; 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 << "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; 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<nn::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix) void nstool::CnmtProcess::displayContentMetaInfoList(const std::vector<nn::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix)
{ {
for (size_t i = 0; i < content_meta_info_list.size(); i++) for (size_t i = 0; i < content_meta_info_list.size(); i++)
{ {

View file

@ -1,11 +1,9 @@
#pragma once #pragma once
#include <string> #include "types.h"
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <nn/hac/ContentMeta.h> #include <nn/hac/ContentMeta.h>
#include "common.h" namespace nstool {
class CnmtProcess class CnmtProcess
{ {
@ -14,7 +12,7 @@ public:
void process(); void process();
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -23,7 +21,7 @@ public:
private: private:
const std::string kModuleName = "CnmtProcess"; const std::string kModuleName = "CnmtProcess";
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
@ -35,3 +33,5 @@ private:
void displayContentMetaInfo(const nn::hac::ContentMetaInfo& content_meta_info, const std::string& prefix); void displayContentMetaInfo(const nn::hac::ContentMetaInfo& content_meta_info, const std::string& prefix);
void displayContentMetaInfoList(const std::vector<nn::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix); void displayContentMetaInfoList(const std::vector<nn::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix);
}; };
}

View file

@ -1,195 +0,0 @@
#include "CompressedArchiveIFile.h"
#include <fnd/lz4.h>
#include <iostream>
CompressedArchiveIFile::CompressedArchiveIFile(const fnd::SharedPtr<fnd::IFile>& base_file, size_t compression_meta_offset) :
mFile(base_file),
mCompEntries(),
mLogicalFileSize(0),
mCacheCapacity(nn::hac::compression::kRomfsBlockSize),
mCurrentCacheDataSize(0),
mCache(std::shared_ptr<byte_t>(new byte_t[mCacheCapacity])),
mScratch(std::shared_ptr<byte_t>(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<byte_t> entries_raw = std::shared_ptr<byte_t>(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<size_t>(offset, mLogicalFileSize);
}
void CompressedArchiveIFile::read(byte_t* out, size_t len)
{
// limit len to the end of the logical file
len = std::min<size_t>(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<size_t>(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;
}

View file

@ -1,51 +0,0 @@
#pragma once
#include <sstream>
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <memory>
#include <vector>
#include <nn/hac/define/compression.h>
class CompressedArchiveIFile : public fnd::IFile
{
public:
CompressedArchiveIFile(const fnd::SharedPtr<fnd::IFile>& 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<fnd::IFile> mFile;
// compression metadata
std::vector<CompressionEntry> 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<byte_t> mCache; // where decompressed data resides
std::shared_ptr<byte_t> 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);
};

View file

@ -1,26 +1,26 @@
#include "ElfSymbolParser.h" #include "ElfSymbolParser.h"
ElfSymbolParser::ElfSymbolParser() nstool::ElfSymbolParser::ElfSymbolParser()
{ {
mSymbolList.clear(); mSymbolList.clear();
} }
void ElfSymbolParser::operator=(const ElfSymbolParser& other) void nstool::ElfSymbolParser::operator=(const ElfSymbolParser& other)
{ {
mSymbolList = other.mSymbolList; mSymbolList = other.mSymbolList;
} }
bool ElfSymbolParser::operator==(const ElfSymbolParser& other) const bool nstool::ElfSymbolParser::operator==(const ElfSymbolParser& other) const
{ {
return mSymbolList == other.mSymbolList; return mSymbolList == other.mSymbolList;
} }
bool ElfSymbolParser::operator!=(const ElfSymbolParser& other) const bool nstool::ElfSymbolParser::operator!=(const ElfSymbolParser& other) const
{ {
return !(*this == other); 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); 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) 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++); //for (; dyn_str[name_pos] == 0x00 && name_pos < dyn_str_size; name_pos++);
symbol.name = std::string((char*)&dyn_str[name_pos]); symbol.name = std::string((char*)&dyn_str[name_pos]);
mSymbolList.addElement(symbol); mSymbolList.push_back(symbol);
} }
} }
const fnd::List<ElfSymbolParser::sElfSymbol>& ElfSymbolParser::getSymbolList() const const std::vector<nstool::ElfSymbolParser::sElfSymbol>& nstool::ElfSymbolParser::getSymbolList() const
{ {
return mSymbolList; return mSymbolList;
} }

View file

@ -1,7 +1,8 @@
#pragma once #pragma once
#include <string> #include "types.h"
#include <fnd/List.h> #include "elf.h"
#include <fnd/elf.h>
namespace nstool {
class ElfSymbolParser 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); 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<sElfSymbol>& getSymbolList() const; const std::vector<sElfSymbol>& getSymbolList() const;
private: private:
const std::string kModuleName = "ElfSymbolParser"; const std::string kModuleName = "ElfSymbolParser";
// data // data
fnd::List<sElfSymbol> mSymbolList; std::vector<sElfSymbol> mSymbolList;
}; };
}

View file

@ -8,57 +8,57 @@
EsTikProcess::EsTikProcess() : nstool::EsTikProcess::EsTikProcess() :
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false) mVerify(false)
{ {
} }
void EsTikProcess::process() void nstool::EsTikProcess::process()
{ {
importTicket(); importTicket();
if (mVerify) if (mVerify)
verifyTicket(); verifyTicket();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
displayTicket(); displayTicket();
} }
void EsTikProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::EsTikProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void EsTikProcess::setKeyCfg(const KeyConfiguration& keycfg) void nstool::EsTikProcess::setKeyCfg(const KeyBag& keycfg)
{ {
mKeyCfg = keycfg; mKeyCfg = keycfg;
} }
void EsTikProcess::setCertificateChain(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& certs) void nstool::EsTikProcess::setCertificateChain(const std::vector<nn::pki::SignedData<nn::pki::CertificateBody>>& certs)
{ {
mCerts = certs; mCerts = certs;
} }
void EsTikProcess::setCliOutputMode(CliOutputMode mode) void nstool::EsTikProcess::setCliOutputMode(CliOutputMode mode)
{ {
mCliOutputMode = mode; mCliOutputMode = mode;
} }
void EsTikProcess::setVerifyMode(bool verify) void nstool::EsTikProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
void EsTikProcess::importTicket() void nstool::EsTikProcess::importTicket()
{ {
fnd::Vec<byte_t> 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.");
} }
scratch.alloc((*mFile)->size()); scratch.alloc((*mFile)->size());
@ -66,10 +66,10 @@ void EsTikProcess::importTicket()
mTik.fromBytes(scratch.data(), scratch.size()); mTik.fromBytes(scratch.data(), scratch.size());
} }
void EsTikProcess::verifyTicket() void nstool::EsTikProcess::verifyTicket()
{ {
PkiValidator pki_validator; PkiValidator pki_validator;
fnd::Vec<byte_t> tik_hash; tc::ByteData tik_hash;
switch (nn::pki::sign::getHashAlgo(mTik.getSignature().getSignType())) switch (nn::pki::sign::getHashAlgo(mTik.getSignature().getSignType()))
{ {
@ -89,13 +89,13 @@ void EsTikProcess::verifyTicket()
pki_validator.addCertificates(mCerts); pki_validator.addCertificates(mCerts);
pki_validator.validateSignature(mTik.getBody().getIssuer(), mTik.getSignature().getSignType(), mTik.getSignature().getSignature(), tik_hash); 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; 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) #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 << "[ES Ticket]" << std::endl;
std::cout << " SignType: " << getSignTypeStr(mTik.getSignature().getSignType()); 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 << " (0x" << std::hex << mTik.getSignature().getSignType() << ")";
std::cout << std::endl; std::cout << std::endl;
@ -129,7 +129,7 @@ void EsTikProcess::displayTicket()
} }
std::cout << " Version: v" << _SPLIT_VER(body.getTicketVersion()); 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 << " (" << (uint32_t)body.getTicketVersion() << ")";
std::cout << std::endl; 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; std::cout << " Reserved Region:" << std::endl;
fnd::SimpleTextOutput::hexDump(body.getReservedRegion(), 8, 0x10, 4); 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; 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 << " DeviceId: 0x" << std::hex << std::setw(16) << std::setfill('0') << body.getDeviceId() << std::endl;
std::cout << " RightsId: " << std::endl << " "; std::cout << " RightsId: " << std::endl << " ";
@ -167,7 +167,7 @@ void EsTikProcess::displayTicket()
#undef _SPLIT_VER #undef _SPLIT_VER
} }
const char* EsTikProcess::getSignTypeStr(uint32_t type) const const char* nstool::EsTikProcess::getSignTypeStr(uint32_t type) const
{ {
const char* str = nullptr; const char* str = nullptr;
switch(type) switch(type)
@ -197,7 +197,7 @@ const char* EsTikProcess::getSignTypeStr(uint32_t type) const
return str; return str;
} }
const char* EsTikProcess::getTitleKeyPersonalisationStr(byte_t flag) const const char* nstool::EsTikProcess::getTitleKeyPersonalisationStr(byte_t flag) const
{ {
const char* str = nullptr; const char* str = nullptr;
switch(flag) switch(flag)
@ -215,7 +215,7 @@ const char* EsTikProcess::getTitleKeyPersonalisationStr(byte_t flag) const
return str; return str;
} }
const char* EsTikProcess::getLicenseTypeStr(byte_t flag) const const char* nstool::EsTikProcess::getLicenseTypeStr(byte_t flag) const
{ {
const char* str = nullptr; const char* str = nullptr;
switch(flag) switch(flag)
@ -245,7 +245,7 @@ const char* EsTikProcess::getLicenseTypeStr(byte_t flag) const
return str; return str;
} }
const char* EsTikProcess::getPropertyFlagStr(byte_t flag) const const char* nstool::EsTikProcess::getPropertyFlagStr(byte_t flag) const
{ {
const char* str = nullptr; const char* str = nullptr;
switch(flag) switch(flag)

View file

@ -1,14 +1,12 @@
#pragma once #pragma once
#include <string> #include "types.h"
#include <fnd/types.h> #include "KeyBag.h"
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <fnd/Vec.h>
#include <nn/pki/SignedData.h> #include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h> #include <nn/pki/CertificateBody.h>
#include <nn/es/TicketBody_V2.h> #include <nn/es/TicketBody_V2.h>
#include "KeyConfiguration.h"
#include "common.h" namespace nstool {
class EsTikProcess class EsTikProcess
{ {
@ -17,21 +15,21 @@ public:
void process(); void process();
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setKeyCfg(const KeyConfiguration& keycfg); void setKeyCfg(const KeyBag& keycfg);
void setCertificateChain(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& certs); void setCertificateChain(const std::vector<nn::pki::SignedData<nn::pki::CertificateBody>>& certs);
void setCliOutputMode(CliOutputMode mode); void setCliOutputMode(CliOutputMode mode);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
private: private:
const std::string kModuleName = "EsTikProcess"; const std::string kModuleName = "EsTikProcess";
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
KeyConfiguration mKeyCfg; KeyBag mKeyCfg;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>> mCerts; std::vector<nn::pki::SignedData<nn::pki::CertificateBody>> mCerts;
nn::pki::SignedData<nn::es::TicketBody_V2> mTik; nn::pki::SignedData<nn::es::TicketBody_V2> mTik;
@ -43,3 +41,5 @@ private:
const char* getLicenseTypeStr(byte_t flag) const; const char* getLicenseTypeStr(byte_t flag) const;
const char* getPropertyFlagStr(byte_t flag) const; const char* getPropertyFlagStr(byte_t flag) const;
}; };
}

View file

@ -7,9 +7,9 @@
#include <nn/hac/ContentArchiveUtil.h> #include <nn/hac/ContentArchiveUtil.h>
#include "GameCardProcess.h" #include "GameCardProcess.h"
GameCardProcess::GameCardProcess() : nstool::GameCardProcess::GameCardProcess() :
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false), mVerify(false),
mListFs(false), mListFs(false),
mProccessExtendedHeader(false), mProccessExtendedHeader(false),
@ -18,7 +18,7 @@ GameCardProcess::GameCardProcess() :
{ {
} }
void GameCardProcess::process() void nstool::GameCardProcess::process()
{ {
importHeader(); importHeader();
@ -27,7 +27,7 @@ void GameCardProcess::process()
validateXciSignature(); validateXciSignature();
// display header // display header
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
displayHeader(); displayHeader();
// process root partition // process root partition
@ -37,43 +37,43 @@ void GameCardProcess::process()
processPartitionPfs(); processPartitionPfs();
} }
void GameCardProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::GameCardProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void GameCardProcess::setKeyCfg(const KeyConfiguration& keycfg) void nstool::GameCardProcess::setKeyCfg(const KeyBag& keycfg)
{ {
mKeyCfg = keycfg; mKeyCfg = keycfg;
} }
void GameCardProcess::setCliOutputMode(CliOutputMode type) void nstool::GameCardProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void GameCardProcess::setVerifyMode(bool verify) void nstool::GameCardProcess::setVerifyMode(bool verify)
{ {
mVerify = 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; mListFs = list_fs;
} }
void GameCardProcess::importHeader() void nstool::GameCardProcess::importHeader()
{ {
fnd::Vec<byte_t> 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.");
} }
// allocate memory for header // allocate memory for header
@ -95,7 +95,7 @@ void GameCardProcess::importHeader()
} }
else 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); 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); memcpy(mHdrSignature, hdr_ptr->signature, fnd::rsa::kRsa2048Size);
// decrypt extended header // decrypt extended header
fnd::aes::sAes128Key header_key; KeyBag::aes128_key_t header_key;
if (mKeyCfg.getXciHeaderKey(header_key)) if (mKeyCfg.getXciHeaderKey(header_key))
{ {
nn::hac::GameCardUtil::decryptXciHeader(&hdr_ptr->header, header_key.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)); 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 << "[GameCard Header]" << std::endl;
std::cout << " CardHeaderVersion: " << std::dec << (uint32_t)mHdr.getCardHeaderVersion() << 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()); 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 << " (0x" << std::hex << (uint32_t)mHdr.getRomSizeType() << ")";
std::cout << std::endl; std::cout << std::endl;
std::cout << " PackageId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getPackageId() << 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 << " 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; 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, true, ":") << std::endl;
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes+0x10, 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 << " Extended Header AesCbc IV:" << std::endl;
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), true, ":") << 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 << " SelSec: 0x" << std::hex << mHdr.getSelSec() << std::endl;
std::cout << " SelT1Key: 0x" << std::hex << mHdr.getSelT1Key() << std::endl; std::cout << " SelT1Key: 0x" << std::hex << mHdr.getSelT1Key() << std::endl;
std::cout << " SelKey: 0x" << std::hex << mHdr.getSelKey() << 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(); std::cout << " RomAreaStartPage: 0x" << std::hex << mHdr.getRomAreaStartPage();
if (mHdr.getRomAreaStartPage() != (uint32_t)(-1)) if (mHdr.getRomAreaStartPage() != (uint32_t)(-1))
@ -180,7 +180,7 @@ void GameCardProcess::displayHeader()
std::cout << " PartitionFs Header:" << std::endl; std::cout << " PartitionFs Header:" << std::endl;
std::cout << " Offset: 0x" << std::hex << mHdr.getPartitionFsAddress() << std::endl; std::cout << " Offset: 0x" << std::hex << mHdr.getPartitionFsAddress() << std::endl;
std::cout << " Size: 0x" << std::hex << mHdr.getPartitionFsSize() << 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 << " Hash:" << std::endl;
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes, 0x10, true, ":") << 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<byte_t> scratch; tc::ByteData scratch;
fnd::sha::sSha256Hash calc_hash; fnd::sha::sSha256Hash calc_hash;
if (use_salt) if (use_salt)
{ {
@ -228,12 +228,12 @@ bool GameCardProcess::validateRegionOfFile(size_t offset, size_t len, const byte
return calc_hash.compare(test_hash); 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); return validateRegionOfFile(offset, len, test_hash, false, 0);
} }
void GameCardProcess::validateXciSignature() void nstool::GameCardProcess::validateXciSignature()
{ {
fnd::rsa::sRsa2048Key header_sign_key; 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) 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(); mRootPfs.process();
} }
void GameCardProcess::processPartitionPfs() void nstool::GameCardProcess::processPartitionPfs()
{ {
const fnd::List<nn::hac::PartitionFsHeader::sFile>& rootPartitions = mRootPfs.getPfsHeader().getFileList(); const std::vector<nn::hac::PartitionFsHeader::sFile>& rootPartitions = mRootPfs.getPfsHeader().getFileList();
for (size_t i = 0; i < rootPartitions.size(); i++) 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 // this must be validated here because only the size of the root partiton header is known at verification time

View file

@ -1,14 +1,11 @@
#pragma once #pragma once
#include <string> #include "types.h"
#include <fnd/types.h> #include "KeyBag.h"
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <fnd/List.h>
#include <nn/hac/GameCardHeader.h>
#include "KeyConfiguration.h"
#include "PfsProcess.h" #include "PfsProcess.h"
#include "common.h" #include <nn/hac/GameCardHeader.h>
namespace nstool {
class GameCardProcess class GameCardProcess
{ {
@ -18,8 +15,8 @@ public:
void process(); void process();
// generic // generic
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setKeyCfg(const KeyConfiguration& keycfg); void setKeyCfg(const KeyBag& keycfg);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -31,8 +28,8 @@ private:
const std::string kModuleName = "GameCardProcess"; const std::string kModuleName = "GameCardProcess";
const std::string kXciMountPointName = "gamecard:/"; const std::string kXciMountPointName = "gamecard:/";
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
KeyConfiguration mKeyCfg; KeyBag mKeyCfg;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
bool mListFs; bool mListFs;
@ -65,7 +62,7 @@ private:
nn::hac::GameCardHeader mHdr; nn::hac::GameCardHeader mHdr;
PfsProcess mRootPfs; PfsProcess mRootPfs;
fnd::List<sExtractInfo> mExtractInfo; std::vector<sExtractInfo> mExtractInfo;
void importHeader(); void importHeader();
void displayHeader(); void displayHeader();
@ -75,3 +72,5 @@ private:
void processRootPfs(); void processRootPfs();
void processPartitionPfs(); void processPartitionPfs();
}; };
}

View file

@ -9,20 +9,20 @@
#include "KipProcess.h" #include "KipProcess.h"
IniProcess::IniProcess() : nstool::IniProcess::IniProcess() :
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false), mVerify(false),
mDoExtractKip(false), mDoExtractKip(false),
mKipExtractPath() mKipExtractPath()
{ {
} }
void IniProcess::process() void nstool::IniProcess::process()
{ {
importHeader(); importHeader();
importKipList(); importKipList();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
{ {
displayHeader(); displayHeader();
displayKipList(); displayKipList();
@ -33,39 +33,39 @@ void IniProcess::process()
} }
} }
void IniProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::IniProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void IniProcess::setCliOutputMode(CliOutputMode type) void nstool::IniProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void IniProcess::setVerifyMode(bool verify) void nstool::IniProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
void IniProcess::setKipExtractPath(const std::string& path) void nstool::IniProcess::setKipExtractPath(const std::string& path)
{ {
mDoExtractKip = true; mDoExtractKip = true;
mKipExtractPath = path; mKipExtractPath = path;
} }
void IniProcess::importHeader() void nstool::IniProcess::importHeader()
{ {
fnd::Vec<byte_t> 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::sIniHeader)) 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)); scratch.alloc(sizeof(nn::hac::sIniHeader));
@ -74,14 +74,14 @@ void IniProcess::importHeader()
mHdr.fromBytes(scratch.data(), scratch.size()); mHdr.fromBytes(scratch.data(), scratch.size());
} }
void IniProcess::importKipList() void nstool::IniProcess::importKipList()
{ {
// kip pos info // kip pos info
size_t kip_pos = sizeof(nn::hac::sIniHeader); size_t kip_pos = sizeof(nn::hac::sIniHeader);
size_t kip_size = 0; size_t kip_size = 0;
// tmp data to determine size // tmp data to determine size
fnd::Vec<byte_t> hdr_raw; tc::ByteData hdr_raw;
nn::hac::KernelInitialProcessHeader hdr; nn::hac::KernelInitialProcessHeader hdr;
hdr_raw.alloc(sizeof(nn::hac::sKipHeader)); hdr_raw.alloc(sizeof(nn::hac::sKipHeader));
@ -90,19 +90,19 @@ void IniProcess::importKipList()
(*mFile)->read(hdr_raw.data(), kip_pos, hdr_raw.size()); (*mFile)->read(hdr_raw.data(), kip_pos, hdr_raw.size());
hdr.fromBytes(hdr_raw.data(), hdr_raw.size()); hdr.fromBytes(hdr_raw.data(), hdr_raw.size());
kip_size = getKipSizeFromHeader(hdr); 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; kip_pos += kip_size;
} }
} }
void IniProcess::displayHeader() void nstool::IniProcess::displayHeader()
{ {
std::cout << "[INI Header]" << std::endl; std::cout << "[INI Header]" << std::endl;
std::cout << " Size: 0x" << std::hex << mHdr.getSize() << std::endl; std::cout << " Size: 0x" << std::hex << mHdr.getSize() << std::endl;
std::cout << " KIP Num: " << std::dec << (uint32_t)mHdr.getKipNum() << 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++) 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<byte_t> cache; tc::ByteData cache;
nn::hac::KernelInitialProcessHeader hdr; nn::hac::KernelInitialProcessHeader hdr;
@ -151,7 +151,7 @@ void IniProcess::extractKipList()
// get kip file size // get kip file size
out_size = (*mKipList[i])->size(); out_size = (*mKipList[i])->size();
// extract kip // extract kip
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
printf("extract=[%s]\n", out_path.c_str()); printf("extract=[%s]\n", out_path.c_str());
(*mKipList[i])->seek(0); (*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; return sizeof(nn::hac::sKipHeader) + hdr.getTextSegmentInfo().file_layout.size + hdr.getRoSegmentInfo().file_layout.size + hdr.getDataSegmentInfo().file_layout.size;
} }

View file

@ -1,14 +1,10 @@
#pragma once #pragma once
#include <vector> #include "types.h"
#include <string>
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <fnd/List.h>
#include <fnd/SharedPtr.h>
#include <nn/hac/IniHeader.h> #include <nn/hac/IniHeader.h>
#include <nn/hac/KernelInitialProcessHeader.h> #include <nn/hac/KernelInitialProcessHeader.h>
#include "common.h" namespace nstool {
class IniProcess class IniProcess
{ {
@ -17,7 +13,7 @@ public:
void process(); void process();
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -27,7 +23,7 @@ private:
const std::string kKipExtention = ".kip"; const std::string kKipExtention = ".kip";
const size_t kCacheSize = 0x10000; const size_t kCacheSize = 0x10000;
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
@ -35,7 +31,7 @@ private:
std::string mKipExtractPath; std::string mKipExtractPath;
nn::hac::IniHeader mHdr; nn::hac::IniHeader mHdr;
fnd::List<fnd::SharedPtr<fnd::IFile>> mKipList; std::vector<std::shared_ptr<tc::io::IStream>> mKipList;
void importHeader(); void importHeader();
void importKipList(); void importKipList();
@ -45,3 +41,5 @@ private:
size_t getKipSizeFromHeader(const nn::hac::KernelInitialProcessHeader& hdr) const; size_t getKipSizeFromHeader(const nn::hac::KernelInitialProcessHeader& hdr) const;
}; };
}

568
src/KeyBag.cpp Normal file
View file

@ -0,0 +1,568 @@
#include "KeyBag.h"
#include "util.h"
#include <tc/cli/FormatUtil.h>
#include <nn/hac/define/gc.h>
#include <nn/hac/AesKeygen.h>
#include <nn/pki/SignUtils.h>
#include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h>
#include <nn/es/TicketBody_V2.h>
nstool::KeyBagInitializer::KeyBagInitializer(bool isDev, const tc::Optional<tc::io::Path>& keyfile_path, const tc::Optional<tc::io::Path>& tik_path, const tc::Optional<tc::io::Path>& 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<tc::io::FileStream> keyfile_stream = std::make_shared<tc::io::FileStream>(tc::io::FileStream(keyfile_path, tc::io::FileMode::Open, tc::io::FileAccess::Read));
// import keyfile into a dictionary
std::map<std::string, std::string> keyfile_dict;
processResFile(keyfile_stream, keyfile_dict);
// sources for key derivation
std::map<byte_t, aes128_key_t> master_key;
tc::Optional<aes128_key_t> package2_key_source;
tc::Optional<aes128_key_t> ticket_titlekek_source;
std::array<tc::Optional<aes128_key_t>, 3> key_area_key_source;
tc::Optional<aes128_key_t> aes_kek_generation_source;
tc::Optional<aes128_key_t> aes_key_generation_source;
tc::Optional<aes128_key_t> nca_header_kek_source;
tc::Optional<aes128_xtskey_t> nca_header_key_source;
tc::Optional<rsa_key_t> 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<std::string> kMasterBase = { "master" };
std::vector<std::string> kPkg1Base = { "package1" };
std::vector<std::string> kPkg2Base = { "package2" };
std::vector<std::string> kXciHeaderBase = { "xci_header" };
std::vector<std::string> kContentArchiveHeaderBase = { "nca_header", "header" };
std::vector<std::string> kAcidBase = { "acid" };
std::vector<std::string> kNrrCertBase = { "nrr_certificate" };
std::vector<std::string> kPkiRootBase = { "pki_root" };
std::vector<std::string> kTicketCommonKeyBase = { "ticket_commonkey", "titlekek" };
std::vector<std::string> kNcaKeyAreaEncKeyBase = { "nca_key_area_key", "key_area_key", "nca_body_keak" };
std::vector<std::string> kNcaKeyAreaEncKeyHwBase = { "nca_key_area_key_hw", "key_area_hw_key" };
std::vector<std::string> kKekGenBase = { "aes_kek_generation" };
std::vector<std::string> 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<std::string> 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<byte_t, aes128_key_t> 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<aes128_key_t> 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<aes128_key_t> 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<tc::Optional<aes128_key_t>, 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<aes128_key_t> 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<aes128_key_t> 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<aes128_key_t> 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<aes128_xtskey_t> 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<rsa_key_t> 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<tc::io::FileStream> certfile_stream;
try {
certfile_stream = std::make_shared<tc::io::FileStream>(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<nn::pki::CertificateBody> 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<tc::io::FileStream> tik_stream;
try {
tik_stream = std::make_shared<tc::io::FileStream>(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<nn::es::TicketBody_V2> 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;
}
}

76
src/KeyBag.h Normal file
View file

@ -0,0 +1,76 @@
#pragma once
#include <string>
#include <vector>
#include <array>
#include <map>
#include <tc/Optional.h>
#include <tc/io.h>
#include <nn/hac/define/types.h>
#include <nn/hac/define/nca.h>
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<key_generation_t, rsa_key_t> acid_sign_key;
// pkg1 and pkg2
std::map<key_generation_t, aes128_key_t> pkg1_key;
std::map<key_generation_t, aes128_key_t> pkg2_key;
tc::Optional<rsa_key_t> pkg2_sign_key;
// nca
tc::Optional<aes128_xtskey_t> nca_header_key;
std::map<key_generation_t, rsa_key_t> nca_header_sign0_key;
std::array<std::map<key_generation_t, aes128_key_t>, kNcaKeakNum> nca_key_area_encryption_key;
std::array<std::map<key_generation_t, aes128_key_t>, kNcaKeakNum> nca_key_area_encryption_key_hw;
// external content keys (nca<->ticket)
std::map<rights_id_t, aes128_key_t> external_content_keys;
tc::Optional<aes128_key_t> 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<aes128_key_t> 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<key_generation_t, rsa_key_t> nrr_certificate_sign_key;
// xci
tc::Optional<rsa_key_t> xci_header_sign_key;
std::map<byte_t, aes128_key_t> xci_header_key;
// ticket
std::map<key_generation_t, aes128_key_t> 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_issuer_t, BroadOnRsaSignerProfile> broadon_rsa_signer;
};
class KeyBagInitializer : public KeyBag
{
public:
KeyBagInitializer(bool isDev, const tc::Optional<tc::io::Path>& keyfile_path, const tc::Optional<tc::io::Path>& tik_path, const tc::Optional<tc::io::Path>& 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);
};
}

View file

@ -1,413 +0,0 @@
#include "KeyConfiguration.h"
#include <fnd/ResourceFileReader.h>
#include <fnd/SimpleTextOutput.h>
#include <nn/hac/AesKeygen.h>
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<byte_t> 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;
}

View file

@ -1,217 +0,0 @@
#pragma once
#include <string>
#include <cstring>
#include <fnd/types.h>
#include <fnd/aes.h>
#include <fnd/rsa.h>
#include <fnd/ecdsa.h>
#include <nn/hac/define/nca.h>
#include <nn/pki/SignedData.h>
#include <nn/es/TicketBody_V2.h>
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<sPkiRootKey> mPkiRootKeyList;
/* Nca External Keys */
fnd::List<sNcaExternalContentKey> mNcaExternalContentKeyList;
template <class T>
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;
}
};

View file

@ -9,51 +9,51 @@
#include <nn/hac/KernelCapabilityUtil.h> #include <nn/hac/KernelCapabilityUtil.h>
KipProcess::KipProcess(): nstool::KipProcess::KipProcess():
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false) mVerify(false)
{ {
} }
void KipProcess::process() void nstool::KipProcess::process()
{ {
importHeader(); importHeader();
//importCodeSegments(); //importCodeSegments();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
{ {
displayHeader(); displayHeader();
displayKernelCap(mHdr.getKernelCapabilities()); displayKernelCap(mHdr.getKernelCapabilities());
} }
} }
void KipProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::KipProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void KipProcess::setCliOutputMode(CliOutputMode type) void nstool::KipProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void KipProcess::setVerifyMode(bool verify) void nstool::KipProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
void KipProcess::importHeader() void nstool::KipProcess::importHeader()
{ {
fnd::Vec<byte_t> 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::sKipHeader)) 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)); scratch.alloc(sizeof(nn::hac::sKipHeader));
@ -62,10 +62,10 @@ void KipProcess::importHeader()
mHdr.fromBytes(scratch.data(), scratch.size()); mHdr.fromBytes(scratch.data(), scratch.size());
} }
void KipProcess::importCodeSegments() void nstool::KipProcess::importCodeSegments()
{ {
#ifdef _KIP_COMPRESSION_IMPLEMENTED #ifdef _KIP_COMPRESSION_IMPLEMENTED
fnd::Vec<byte_t> scratch; tc::ByteData scratch;
uint32_t decompressed_len; uint32_t decompressed_len;
#endif #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); fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mTextBlob.data(), (uint32_t)mTextBlob.size(), decompressed_len);
if (decompressed_len != mTextBlob.size()) 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 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); fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mRoBlob.data(), (uint32_t)mRoBlob.size(), decompressed_len);
if (decompressed_len != mRoBlob.size()) 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 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); fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mDataBlob.data(), (uint32_t)mDataBlob.size(), decompressed_len);
if (decompressed_len != mDataBlob.size()) 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 else
@ -139,7 +139,7 @@ void KipProcess::importCodeSegments()
#endif #endif
} }
void KipProcess::displayHeader() void nstool::KipProcess::displayHeader()
{ {
std::cout << "[KIP Header]" << std::endl; std::cout << "[KIP Header]" << std::endl;
std::cout << " Meta:" << 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 << " UseSecureMemory: " << std::boolalpha << mHdr.getUseSecureMemoryFlag() << std::endl;
std::cout << " Program Sections:" << std::endl; std::cout << " Program Sections:" << std::endl;
std::cout << " .text:" << 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 << " 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; 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 << " 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 << " MemorySize: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.size << std::endl;
std::cout << " .ro:" << 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 << " 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; 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 << " 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 << " MemorySize: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.size << std::endl;
std::cout << " .data:" << 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 << " 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; 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; std::cout << "[Kernel Capabilities]" << std::endl;
if (kern.getThreadInfo().isSet()) if (kern.getThreadInfo().isSet())
@ -207,8 +207,8 @@ void KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
} }
if (kern.getMemoryMaps().isSet()) if (kern.getMemoryMaps().isSet())
{ {
fnd::List<nn::hac::MemoryMappingHandler::sMemoryMapping> maps = kern.getMemoryMaps().getMemoryMaps(); std::vector<nn::hac::MemoryMappingHandler::sMemoryMapping> maps = kern.getMemoryMaps().getMemoryMaps();
fnd::List<nn::hac::MemoryMappingHandler::sMemoryMapping> ioMaps = kern.getMemoryMaps().getIoMemoryMaps(); std::vector<nn::hac::MemoryMappingHandler::sMemoryMapping> ioMaps = kern.getMemoryMaps().getIoMemoryMaps();
std::cout << " MemoryMaps:" << std::endl; std::cout << " MemoryMaps:" << std::endl;
for (size_t i = 0; i < maps.size(); i++) 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()) if (kern.getInterupts().isSet())
{ {
fnd::List<uint16_t> interupts = kern.getInterupts().getInteruptList(); std::vector<uint16_t> interupts = kern.getInterupts().getInteruptList();
std::cout << " Interupts Flags:" << std::endl; std::cout << " Interupts Flags:" << std::endl;
for (uint32_t i = 0; i < interupts.size(); i++) for (uint32_t i = 0; i < interupts.size(); i++)
{ {

View file

@ -1,12 +1,9 @@
#pragma once #pragma once
#include <vector> #include "types.h"
#include <string>
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <nn/hac/KernelInitialProcessHeader.h> #include <nn/hac/KernelInitialProcessHeader.h>
#include "common.h" namespace nstool {
class KipProcess class KipProcess
{ {
@ -15,21 +12,23 @@ public:
void process(); void process();
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
private: private:
const std::string kModuleName = "KipProcess"; const std::string kModuleName = "KipProcess";
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
nn::hac::KernelInitialProcessHeader mHdr; nn::hac::KernelInitialProcessHeader mHdr;
fnd::Vec<byte_t> mTextBlob, mRoBlob, mDataBlob; tc::ByteData mTextBlob, mRoBlob, mDataBlob;
void importHeader(); void importHeader();
void importCodeSegments(); void importCodeSegments();
void displayHeader(); void displayHeader();
void displayKernelCap(const nn::hac::KernelCapabilityControl& kern); void displayKernelCap(const nn::hac::KernelCapabilityControl& kern);
}; };
}

View file

@ -10,14 +10,14 @@
#include <fnd/SimpleTextOutput.h> #include <fnd/SimpleTextOutput.h>
MetaProcess::MetaProcess() : nstool::MetaProcess::MetaProcess() :
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false) mVerify(false)
{ {
} }
void MetaProcess::process() void nstool::MetaProcess::process()
{ {
importMeta(); importMeta();
@ -27,7 +27,7 @@ void MetaProcess::process()
validateAciFromAcid(mMeta.getAccessControlInfo(), mMeta.getAccessControlInfoDesc()); validateAciFromAcid(mMeta.getAccessControlInfo(), mMeta.getAccessControlInfoDesc());
} }
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
{ {
// npdm binary // npdm binary
displayMetaHeader(mMeta); displayMetaHeader(mMeta);
@ -39,7 +39,7 @@ void MetaProcess::process()
displayKernelCap(mMeta.getAccessControlInfo().getKernelCapabilities()); displayKernelCap(mMeta.getAccessControlInfo().getKernelCapabilities());
// acid binary // acid binary
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mCliOutputMode.show_extended_info)
{ {
displayAciDescHdr(mMeta.getAccessControlInfoDesc()); displayAciDescHdr(mMeta.getAccessControlInfoDesc());
displayFac(mMeta.getAccessControlInfoDesc().getFileSystemAccessControl()); displayFac(mMeta.getAccessControlInfoDesc().getFileSystemAccessControl());
@ -49,38 +49,38 @@ void MetaProcess::process()
} }
} }
void MetaProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::MetaProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void MetaProcess::setKeyCfg(const KeyConfiguration& keycfg) void nstool::MetaProcess::setKeyCfg(const KeyBag& keycfg)
{ {
mKeyCfg = keycfg; mKeyCfg = keycfg;
} }
void MetaProcess::setCliOutputMode(CliOutputMode type) void nstool::MetaProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void MetaProcess::setVerifyMode(bool verify) void nstool::MetaProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
const nn::hac::Meta& MetaProcess::getMeta() const const nn::hac::Meta& nstool::MetaProcess::getMeta() const
{ {
return mMeta; return mMeta;
} }
void MetaProcess::importMeta() void nstool::MetaProcess::importMeta()
{ {
fnd::Vec<byte_t> 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.");
} }
scratch.alloc((*mFile)->size()); scratch.alloc((*mFile)->size());
@ -89,12 +89,12 @@ void MetaProcess::importMeta()
mMeta.fromBytes(scratch.data(), scratch.size()); 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 { try {
fnd::rsa::sRsa2048Key acid_sign_key; fnd::rsa::sRsa2048Key acid_sign_key;
if (mKeyCfg.getAcidSignKey(acid_sign_key, key_generation) != true) if (mKeyCfg.getAcidSignKey(acid_sign_key, key_generation) != true)
throw fnd::Exception(); throw tc::Exception();
acid.validateSignature(acid_sign_key); 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 // check Program ID
if (acid.getProgramIdRestrict().min > 0 && aci.getProgramId() < acid.getProgramIdRestrict().min) 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 << "[Meta Header]" << std::endl;
std::cout << " ACID KeyGeneration: " << std::dec << (uint32_t)hdr.getAccessControlInfoDescKeyGeneration() << 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 << "[Access Control Info]" << std::endl;
std::cout << " ProgramID: 0x" << std::hex << std::setw(16) << std::setfill('0') << aci.getProgramId() << 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 << "[Access Control Info Desc]" << std::endl;
std::cout << " Flags: " << 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; 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 << "[FS Access Control]" << std::endl;
std::cout << " Format Version: " << std::dec << (uint32_t)fac.getFormatVersion() << 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 // output string info
std::cout << nn::hac::FileSystemAccessUtil::getFsAccessFlagAsString(nn::hac::fac::FsAccessFlag(flag)); 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 << " (bit " << std::dec << (uint32_t)flag << ")";
} }
std::cout << std::endl; 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 Access Control]" << std::endl;
std::cout << " Service List:" << 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); 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; std::cout << "[Kernel Capabilities]" << std::endl;
if (kern.getThreadInfo().isSet()) if (kern.getThreadInfo().isSet())
@ -435,7 +435,7 @@ void MetaProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
} }
if (kern.getInterupts().isSet()) if (kern.getInterupts().isSet())
{ {
fnd::List<uint16_t> interupts = kern.getInterupts().getInteruptList(); std::vector<uint16_t> interupts = kern.getInterupts().getInteruptList();
std::cout << " Interupts Flags:" << std::endl; std::cout << " Interupts Flags:" << std::endl;
for (uint32_t i = 0; i < interupts.size(); i++) for (uint32_t i = 0; i < interupts.size(); i++)
{ {

View file

@ -1,12 +1,10 @@
#pragma once #pragma once
#include <string> #include "types.h"
#include <fnd/types.h> #include "KeyBag.h"
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <nn/hac/Meta.h>
#include "KeyConfiguration.h"
#include "common.h" #include <nn/hac/Meta.h>
namespace nstool {
class MetaProcess class MetaProcess
{ {
@ -15,8 +13,8 @@ public:
void process(); void process();
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setKeyCfg(const KeyConfiguration& keycfg); void setKeyCfg(const KeyBag& keycfg);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -25,8 +23,8 @@ public:
private: private:
const std::string kModuleName = "MetaProcess"; const std::string kModuleName = "MetaProcess";
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
KeyConfiguration mKeyCfg; KeyBag mKeyCfg;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
@ -44,3 +42,5 @@ private:
void displaySac(const nn::hac::ServiceAccessControl& sac); void displaySac(const nn::hac::ServiceAccessControl& sac);
void displayKernelCap(const nn::hac::KernelCapabilityControl& kern); void displayKernelCap(const nn::hac::KernelCapabilityControl& kern);
}; };
}

View file

@ -9,48 +9,48 @@
#include <nn/hac/ApplicationControlPropertyUtil.h> #include <nn/hac/ApplicationControlPropertyUtil.h>
NacpProcess::NacpProcess() : nstool::NacpProcess::NacpProcess() :
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode((1 << OUTPUT_BASIC)),
mVerify(false) mVerify(false)
{ {
} }
void NacpProcess::process() void nstool::NacpProcess::process()
{ {
importNacp(); importNacp();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
displayNacp(); displayNacp();
} }
void NacpProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::NacpProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void NacpProcess::setCliOutputMode(CliOutputMode type) void nstool::NacpProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void NacpProcess::setVerifyMode(bool verify) void nstool::NacpProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
const nn::hac::ApplicationControlProperty& NacpProcess::getApplicationControlProperty() const const nn::hac::ApplicationControlProperty& nstool::NacpProcess::getApplicationControlProperty() const
{ {
return mNacp; return mNacp;
} }
void NacpProcess::importNacp() void nstool::NacpProcess::importNacp()
{ {
fnd::Vec<byte_t> 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.");
} }
scratch.alloc((*mFile)->size()); scratch.alloc((*mFile)->size());
@ -59,7 +59,7 @@ void NacpProcess::importNacp()
mNacp.fromBytes(scratch.data(), scratch.size()); mNacp.fromBytes(scratch.data(), scratch.size());
} }
void NacpProcess::displayNacp() void nstool::NacpProcess::displayNacp()
{ {
std::cout << "[ApplicationControlProperty]" << std::endl; std::cout << "[ApplicationControlProperty]" << std::endl;
@ -74,7 +74,7 @@ void NacpProcess::displayNacp()
std::cout << " Publisher: " << itr->publisher << std::endl; 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; std::cout << " Title: None" << std::endl;
} }
@ -84,25 +84,25 @@ void NacpProcess::displayNacp()
{ {
std::cout << " ISBN: " << mNacp.getIsbn() << std::endl; 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; std::cout << " ISBN: (NotSet)" << std::endl;
} }
// StartupUserAccount // 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; std::cout << " StartupUserAccount: " << nn::hac::ApplicationControlPropertyUtil::getStartupUserAccountAsString(mNacp.getStartupUserAccount()) << std::endl;
} }
// UserAccountSwitchLock // 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; std::cout << " UserAccountSwitchLock: " << nn::hac::ApplicationControlPropertyUtil::getUserAccountSwitchLockAsString(mNacp.getUserAccountSwitchLock()) << std::endl;
} }
// AddOnContentRegistrationType // 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; 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; 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; std::cout << " Attribute: None" << std::endl;
} }
@ -130,7 +130,7 @@ void NacpProcess::displayNacp()
std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getLanguageAsString(*itr) << std::endl; 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; std::cout << " SupportedLanguage: None" << std::endl;
} }
@ -144,37 +144,37 @@ void NacpProcess::displayNacp()
std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getParentalControlFlagAsString(*itr) << std::endl; 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; std::cout << " ParentalControl: None" << std::endl;
} }
// Screenshot // 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; std::cout << " Screenshot: " << nn::hac::ApplicationControlPropertyUtil::getScreenshotAsString(mNacp.getScreenshot()) << std::endl;
} }
// VideoCapture // 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; std::cout << " VideoCapture: " << nn::hac::ApplicationControlPropertyUtil::getVideoCaptureAsString(mNacp.getVideoCapture()) << std::endl;
} }
// DataLossConfirmation // 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; std::cout << " DataLossConfirmation: " << nn::hac::ApplicationControlPropertyUtil::getDataLossConfirmationAsString(mNacp.getDataLossConfirmation()) << std::endl;
} }
// PlayLogPolicy // 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; std::cout << " PlayLogPolicy: " << nn::hac::ApplicationControlPropertyUtil::getPlayLogPolicyAsString(mNacp.getPlayLogPolicy()) << std::endl;
} }
// PresenceGroupId // 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; 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; 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; std::cout << " RatingAge: None" << std::endl;
} }
@ -200,49 +200,49 @@ void NacpProcess::displayNacp()
{ {
std::cout << " DisplayVersion: " << mNacp.getDisplayVersion() << std::endl; 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; std::cout << " DisplayVersion: (NotSet)" << std::endl;
} }
// AddOnContentBaseId // 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; std::cout << " AddOnContentBaseId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getAddOnContentBaseId() << std::endl;
} }
// SaveDataOwnerId // 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; std::cout << " SaveDataOwnerId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getSaveDataOwnerId() << std::endl;
} }
// UserAccountSaveDataSize // 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; std::cout << " UserAccountSaveDataSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().size) << std::endl;
} }
// UserAccountSaveDataJournalSize // 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; std::cout << " UserAccountSaveDataJournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().journal_size) << std::endl;
} }
// DeviceSaveDataSize // 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; std::cout << " DeviceSaveDataSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().size) << std::endl;
} }
// DeviceSaveDataJournalSize // 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; std::cout << " DeviceSaveDataJournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().journal_size) << std::endl;
} }
// BcatDeliveryCacheStorageSize // 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; 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; 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; 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; 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; std::cout << " LocalCommunicationId: None" << std::endl;
} }
// LogoType // 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; std::cout << " LogoType: " << nn::hac::ApplicationControlPropertyUtil::getLogoTypeAsString(mNacp.getLogoType()) << std::endl;
//} //}
// LogoHandling // 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; std::cout << " LogoHandling: " << nn::hac::ApplicationControlPropertyUtil::getLogoHandlingAsString(mNacp.getLogoHandling()) << std::endl;
} }
// RuntimeAddOnContentInstall // 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; std::cout << " RuntimeAddOnContentInstall: " << nn::hac::ApplicationControlPropertyUtil::getRuntimeAddOnContentInstallAsString(mNacp.getRuntimeAddOnContentInstall()) << std::endl;
} }
// RuntimeParameterDelivery // 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; std::cout << " RuntimeParameterDelivery: " << nn::hac::ApplicationControlPropertyUtil::getRuntimeParameterDeliveryAsString(mNacp.getRuntimeParameterDelivery()) << std::endl;
} }
// CrashReport // 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; std::cout << " CrashReport: " << nn::hac::ApplicationControlPropertyUtil::getCrashReportAsString(mNacp.getCrashReport()) << std::endl;
} }
// Hdcp // 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; std::cout << " Hdcp: " << nn::hac::ApplicationControlPropertyUtil::getHdcpAsString(mNacp.getHdcp()) << std::endl;
} }
// SeedForPsuedoDeviceId // 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; 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; 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; std::cout << " BcatPassphase: (NotSet)" << std::endl;
} }
@ -332,61 +332,61 @@ void NacpProcess::displayNacp()
std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getStartupUserAccountOptionFlagAsString(*itr) << std::endl; 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; std::cout << " StartupUserAccountOption: None" << std::endl;
} }
// UserAccountSaveDataSizeMax // 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; std::cout << " UserAccountSaveDataSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().size) << std::endl;
} }
// UserAccountSaveDataJournalSizeMax // 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; std::cout << " UserAccountSaveDataJournalSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().journal_size) << std::endl;
} }
// DeviceSaveDataSizeMax // 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; std::cout << " DeviceSaveDataSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().size) << std::endl;
} }
// DeviceSaveDataJournalSizeMax // 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; std::cout << " DeviceSaveDataJournalSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().journal_size) << std::endl;
} }
// TemporaryStorageSize // 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; std::cout << " TemporaryStorageSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getTemporaryStorageSize()) << std::endl;
} }
// CacheStorageSize // 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; std::cout << " CacheStorageSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().size) << std::endl;
} }
// CacheStorageJournalSize // 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; std::cout << " CacheStorageJournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().journal_size) << std::endl;
} }
// CacheStorageDataAndJournalSizeMax // 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; std::cout << " CacheStorageDataAndJournalSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageDataAndJournalSizeMax()) << std::endl;
} }
// CacheStorageIndexMax // 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; 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; 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; std::cout << " PlayLogQueryableApplicationId: None" << std::endl;
} }
// PlayLogQueryCapability // 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; 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; 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; std::cout << " Repair: None" << std::endl;
} }
// ProgramIndex // 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; 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; 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; 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 << " 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; 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; 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; 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; 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; std::cout << " NeighborDetectionClientConfiguration: None" << std::endl;
} }
// JitConfiguration // 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 << " JitConfiguration:" << std::endl;
std::cout << " IsEnabled: " << std::boolalpha << mNacp.getJitConfiguration().is_enabled << std::endl; std::cout << " IsEnabled: " << std::boolalpha << mNacp.getJitConfiguration().is_enabled << std::endl;
@ -491,19 +491,19 @@ void NacpProcess::displayNacp()
} }
// PlayReportPermission // 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; std::cout << " PlayReportPermission: " << nn::hac::ApplicationControlPropertyUtil::getPlayReportPermissionAsString(mNacp.getPlayReportPermission()) << std::endl;
} }
// CrashScreenshotForProd // 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; std::cout << " CrashScreenshotForProd: " << nn::hac::ApplicationControlPropertyUtil::getCrashScreenshotForProdAsString(mNacp.getCrashScreenshotForProd()) << std::endl;
} }
// CrashScreenshotForDev // 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; 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; 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; std::cout << " AccessibleLaunchRequiredVersion: None" << std::endl;
} }

View file

@ -1,11 +1,9 @@
#pragma once #pragma once
#include <string> #include "types.h"
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <nn/hac/ApplicationControlProperty.h> #include <nn/hac/ApplicationControlProperty.h>
#include "common.h" namespace nstool {
class NacpProcess class NacpProcess
{ {
@ -14,7 +12,7 @@ public:
void process(); void process();
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -23,7 +21,7 @@ public:
private: private:
const std::string kModuleName = "NacpProcess"; const std::string kModuleName = "NacpProcess";
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
@ -32,3 +30,5 @@ private:
void importNacp(); void importNacp();
void displayNacp(); void displayNacp();
}; };
}

View file

@ -18,9 +18,9 @@
#include <nn/hac/HierarchicalSha256Header.h> #include <nn/hac/HierarchicalSha256Header.h>
#include <nn/hac/HierarchicalIntegrityHeader.h> #include <nn/hac/HierarchicalIntegrityHeader.h>
NcaProcess::NcaProcess() : nstool::NcaProcess::NcaProcess() :
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false), mVerify(false),
mListFs(false) mListFs(false)
{ {
@ -30,7 +30,7 @@ NcaProcess::NcaProcess() :
} }
} }
void NcaProcess::process() void nstool::NcaProcess::process()
{ {
// import header // import header
importHeader(); importHeader();
@ -46,67 +46,67 @@ void NcaProcess::process()
validateNcaSignatures(); validateNcaSignatures();
// display header // display header
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
displayHeader(); displayHeader();
// process partition // process partition
processPartitions(); processPartitions();
} }
void NcaProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::NcaProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void NcaProcess::setKeyCfg(const KeyConfiguration& keycfg) void nstool::NcaProcess::setKeyCfg(const KeyBag& keycfg)
{ {
mKeyCfg = keycfg; mKeyCfg = keycfg;
} }
void NcaProcess::setCliOutputMode(CliOutputMode type) void nstool::NcaProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void NcaProcess::setVerifyMode(bool verify) void nstool::NcaProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
void NcaProcess::setPartition0ExtractPath(const std::string& path) void nstool::NcaProcess::setPartition0ExtractPath(const std::string& path)
{ {
mPartitionPath[0].path = path; mPartitionPath[0].path = path;
mPartitionPath[0].doExtract = true; 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].path = path;
mPartitionPath[1].doExtract = true; 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].path = path;
mPartitionPath[2].doExtract = true; 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].path = path;
mPartitionPath[3].doExtract = true; mPartitionPath[3].doExtract = true;
} }
void NcaProcess::setListFs(bool list_fs) void nstool::NcaProcess::setListFs(bool list_fs)
{ {
mListFs = list_fs; mListFs = list_fs;
} }
void NcaProcess::importHeader() void nstool::NcaProcess::importHeader()
{ {
if (*mFile == nullptr) if (*mFile == nullptr)
{ {
throw fnd::Exception(kModuleName, "No file reader set."); throw tc::Exception(kModuleName, "No file reader set.");
} }
// read header block // read header block
@ -124,10 +124,10 @@ void NcaProcess::importHeader()
mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sContentArchiveHeader)); mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sContentArchiveHeader));
} }
void NcaProcess::generateNcaBodyEncryptionKeys() void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
{ {
// create zeros key // 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)); memset(zero_aesctr_key.key, 0, sizeof(zero_aesctr_key));
// get key data from header // get key data from header
@ -136,8 +136,8 @@ void NcaProcess::generateNcaBodyEncryptionKeys()
// process key area // process key area
sKeys::sKeyAreaKey kak; sKeys::sKeyAreaKey kak;
fnd::aes::sAes128Key key_area_enc_key; KeyBag::aes128_key_t key_area_enc_key;
const fnd::aes::sAes128Key* key_area = (const fnd::aes::sAes128Key*) mHdr.getKeyArea(); 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++) for (size_t i = 0; i < nn::hac::nca::kKeyAreaKeyNum; i++)
{ {
@ -161,7 +161,7 @@ void NcaProcess::generateNcaBodyEncryptionKeys()
{ {
kak.decrypted = false; 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 this has a rights id, the key needs to be sourced from a ticket
if (mHdr.hasRightsId() == true) if (mHdr.hasRightsId() == true)
{ {
fnd::aes::sAes128Key tmp_key; KeyBag::aes128_key_t tmp_key;
if (mKeyCfg.getNcaExternalContentKey(mHdr.getRightsId(), tmp_key) == true) if (mKeyCfg.getNcaExternalContentKey(mHdr.getRightsId(), tmp_key) == true)
{ {
mContentKey.aes_ctr = tmp_key; mContentKey.aes_ctr = tmp_key;
} }
else if (mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserTitleKey, tmp_key) == true) 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) if (mKeyCfg.getETicketCommonKey(masterkey_rev, common_key) == true)
{ {
nn::hac::AesKeygen::generateKey(tmp_key.key, tmp_key.key, common_key.key); nn::hac::AesKeygen::generateKey(tmp_key.key, tmp_key.key, common_key.key);
@ -189,7 +189,7 @@ void NcaProcess::generateNcaBodyEncryptionKeys()
// otherwise decrypt key area // otherwise decrypt key area
else 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++) 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) 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 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; 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 << "[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; std::stringstream error;
@ -244,7 +244,7 @@ void NcaProcess::generatePartitionConfiguration()
{ {
error.clear(); error.clear();
error << "NCA FS Header [" << partition.header_index << "] Hash: FAIL \n"; 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.clear();
error << "NCA FS Header [" << partition.header_index << "] Version(" << fs_header.version.get() << "): UNSUPPORTED"; 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 // 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); // info.hash_tree_meta.importData(fs_header.hash_info, nn::hac::nca::kHashInfoLen, LayeredIntegrityMetadata::HASH_TYPE_SHA256);
nn::hac::HierarchicalSha256Header hdr; nn::hac::HierarchicalSha256Header hdr;
fnd::List<fnd::LayeredIntegrityMetadata::sLayer> hash_layers; std::vector<fnd::LayeredIntegrityMetadata::sLayer> hash_layers;
fnd::LayeredIntegrityMetadata::sLayer data_layer; fnd::LayeredIntegrityMetadata::sLayer data_layer;
fnd::List<fnd::sha::sSha256Hash> master_hash_list; std::vector<fnd::sha::sSha256Hash> master_hash_list;
// import raw data // import raw data
hdr.fromBytes(fs_header.hash_info, nn::hac::nca::kHashInfoLen); hdr.fromBytes(fs_header.hash_info, nn::hac::nca::kHashInfoLen);
@ -287,10 +287,10 @@ void NcaProcess::generatePartitionConfiguration()
} }
else 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 // write data into metadata
info.layered_intergrity_metadata.setAlignHashToBlock(false); 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); // info.hash_tree_meta.importData(fs_header.hash_info, nn::hac::nca::kHashInfoLen, LayeredIntegrityMetadata::HASH_TYPE_INTEGRITY);
nn::hac::HierarchicalIntegrityHeader hdr; nn::hac::HierarchicalIntegrityHeader hdr;
fnd::List<fnd::LayeredIntegrityMetadata::sLayer> hash_layers; std::vector<fnd::LayeredIntegrityMetadata::sLayer> hash_layers;
fnd::LayeredIntegrityMetadata::sLayer data_layer; fnd::LayeredIntegrityMetadata::sLayer data_layer;
fnd::List<fnd::sha::sSha256Hash> master_hash_list; std::vector<fnd::sha::sSha256Hash> master_hash_list;
hdr.fromBytes(fs_header.hash_info, nn::hac::nca::kHashInfoLen); hdr.fromBytes(fs_header.hash_info, nn::hac::nca::kHashInfoLen);
for (size_t i = 0; i < hdr.getLayerInfo().size(); i++) for (size_t i = 0; i < hdr.getLayerInfo().size(); i++)
@ -312,14 +312,14 @@ void NcaProcess::generatePartitionConfiguration()
fnd::LayeredIntegrityMetadata::sLayer layer; fnd::LayeredIntegrityMetadata::sLayer layer;
layer.offset = hdr.getLayerInfo()[i].offset; layer.offset = hdr.getLayerInfo()[i].offset;
layer.size = hdr.getLayerInfo()[i].size; 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()) if (i + 1 == hdr.getLayerInfo().size())
{ {
data_layer = layer; data_layer = layer;
} }
else else
{ {
hash_layers.addElement(layer); hash_layers.push_back(layer);
} }
} }
@ -342,7 +342,7 @@ void NcaProcess::generatePartitionConfiguration()
default: default:
error.clear(); error.clear();
error << "FormatType(" << nn::hac::ContentArchiveUtil::getFormatTypeAsString(info.format_type) << "): UNKNOWN"; 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 // create reader based on encryption type0
@ -352,21 +352,21 @@ void NcaProcess::generatePartitionConfiguration()
} }
else if (info.enc_type == nn::hac::nca::EncryptionType::AesCtr) else if (info.enc_type == nn::hac::nca::EncryptionType::AesCtr)
{ {
if (mContentKey.aes_ctr.isSet == false) if (mContentKey.aes_ctr.isNull())
throw fnd::Exception(kModuleName, "AES-CTR Key was not determined"); throw tc::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); 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) else if (info.enc_type == nn::hac::nca::EncryptionType::AesXts || info.enc_type == nn::hac::nca::EncryptionType::AesCtrEx)
{ {
error.clear(); error.clear();
error << "EncryptionType(" << nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type) << "): UNSUPPORTED"; error << "EncryptionType(" << nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type) << "): UNSUPPORTED";
throw fnd::Exception(kModuleName, error.str()); throw tc::Exception(kModuleName, error.str());
} }
else else
{ {
error.clear(); error.clear();
error << "EncryptionType(" << nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type) << "): UNKNOWN"; 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 // filter out unrecognised hash types, and hash based readers
@ -378,17 +378,17 @@ void NcaProcess::generatePartitionConfiguration()
{ {
error.clear(); error.clear();
error << "HashType(" << nn::hac::ContentArchiveUtil::getHashTypeAsString(info.hash_type) << "): UNKNOWN"; 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()); info.fail_reason = std::string(e.error());
} }
} }
} }
void NcaProcess::validateNcaSignatures() void nstool::NcaProcess::validateNcaSignatures()
{ {
// validate signature[0] // validate signature[0]
fnd::rsa::sRsa2048Key sign0_key; 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 << "[NCA Header]" << std::endl;
std::cout << " Format Type: " << nn::hac::ContentArchiveUtil::getFormatHeaderVersionAsString((nn::hac::nca::HeaderFormatVersion)mHdr.getFormatVersion()) << 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; 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 << " Key Area:" << std::endl;
std::cout << " <--------------------------------------------------------------------------------------------------------->" << std::endl; std::cout << " <--------------------------------------------------------------------------------------------------------->" << std::endl;
@ -486,7 +486,7 @@ void NcaProcess::displayHeader()
std::cout << " <--------------------------------------------------------------------------------------------------------->" << std::endl; std::cout << " <--------------------------------------------------------------------------------------------------------->" << std::endl;
} }
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) if (mCliOutputMode.show_layout)
{ {
std::cout << " Partitions:" << std::endl; std::cout << " Partitions:" << std::endl;
for (size_t i = 0; i < mHdr.getPartitionEntryList().size(); i++) 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++) for (size_t i = 0; i < mHdr.getPartitionEntryList().size(); i++)
{ {
@ -609,13 +609,13 @@ void NcaProcess::processPartitions()
romfs.setExtractPath(mPartitionPath[index].path); romfs.setExtractPath(mPartitionPath[index].path);
romfs.process(); 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; 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; const char* str = nullptr;

View file

@ -1,14 +1,10 @@
#pragma once #pragma once
#include <string> #include "types.h"
#include <fnd/types.h> #include "KeyBag.h"
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <fnd/LayeredIntegrityMetadata.h>
#include <nn/hac/ContentArchiveHeader.h> #include <nn/hac/ContentArchiveHeader.h>
#include "KeyConfiguration.h"
namespace nstool {
#include "common.h"
class NcaProcess class NcaProcess
{ {
@ -18,8 +14,8 @@ public:
void process(); void process();
// generic // generic
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setKeyCfg(const KeyConfiguration& keycfg); void setKeyCfg(const KeyBag& keycfg);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -35,8 +31,8 @@ private:
const std::string kNpdmExefsPath = "main.npdm"; const std::string kNpdmExefsPath = "main.npdm";
// user options // user options
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
KeyConfiguration mKeyCfg; KeyBag mKeyCfg;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
@ -60,8 +56,8 @@ private:
{ {
byte_t index; byte_t index;
bool decrypted; bool decrypted;
fnd::aes::sAes128Key enc; KeyBag::aes128_key_t enc;
fnd::aes::sAes128Key dec; KeyBag::aes128_key_t dec;
void operator=(const sKeyAreaKey& other) void operator=(const sKeyAreaKey& other)
{ {
@ -84,14 +80,14 @@ private:
return !(*this == other); return !(*this == other);
} }
}; };
fnd::List<sKeyAreaKey> kak_list; std::vector<sKeyAreaKey> kak_list;
sOptional<fnd::aes::sAes128Key> aes_ctr; tc::Optional<KeyBag::aes128_key_t> aes_ctr;
} mContentKey; } mContentKey;
struct sPartitionInfo struct sPartitionInfo
{ {
fnd::SharedPtr<fnd::IFile> reader; std::shared_ptr<tc::io::IStream> reader;
std::string fail_reason; std::string fail_reason;
size_t offset; size_t offset;
size_t size; size_t size;
@ -113,3 +109,5 @@ private:
const char* getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const; const char* getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const;
}; };
}

View file

@ -7,19 +7,19 @@
#include <nn/hac/define/nro-hb.h> #include <nn/hac/define/nro-hb.h>
#include "NroProcess.h" #include "NroProcess.h"
NroProcess::NroProcess(): nstool::NroProcess::NroProcess():
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false) mVerify(false)
{ {
} }
void NroProcess::process() void nstool::NroProcess::process()
{ {
importHeader(); importHeader();
importCodeSegments(); importCodeSegments();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
displayHeader(); displayHeader();
processRoMeta(); processRoMeta();
@ -28,73 +28,73 @@ void NroProcess::process()
mAssetProc.process(); mAssetProc.process();
} }
void NroProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::NroProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void NroProcess::setCliOutputMode(CliOutputMode type) void nstool::NroProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void NroProcess::setVerifyMode(bool verify) void nstool::NroProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
void NroProcess::setIs64BitInstruction(bool flag) void nstool::NroProcess::setIs64BitInstruction(bool flag)
{ {
mRoMeta.setIs64BitInstruction(flag); mRoMeta.setIs64BitInstruction(flag);
} }
void NroProcess::setListApi(bool listApi) void nstool::NroProcess::setListApi(bool listApi)
{ {
mRoMeta.setListApi(listApi); mRoMeta.setListApi(listApi);
} }
void NroProcess::setListSymbols(bool listSymbols) void nstool::NroProcess::setListSymbols(bool listSymbols)
{ {
mRoMeta.setListSymbols(listSymbols); mRoMeta.setListSymbols(listSymbols);
} }
void NroProcess::setAssetListFs(bool list) void nstool::NroProcess::setAssetListFs(bool list)
{ {
mAssetProc.setListFs(list); mAssetProc.setListFs(list);
} }
void NroProcess::setAssetIconExtractPath(const std::string& path) void nstool::NroProcess::setAssetIconExtractPath(const std::string& path)
{ {
mAssetProc.setIconExtractPath(path); mAssetProc.setIconExtractPath(path);
} }
void NroProcess::setAssetNacpExtractPath(const std::string& path) void nstool::NroProcess::setAssetNacpExtractPath(const std::string& path)
{ {
mAssetProc.setNacpExtractPath(path); mAssetProc.setNacpExtractPath(path);
} }
void NroProcess::setAssetRomfsExtractPath(const std::string& path) void nstool::NroProcess::setAssetRomfsExtractPath(const std::string& path)
{ {
mAssetProc.setRomfsExtractPath(path); mAssetProc.setRomfsExtractPath(path);
} }
const RoMetadataProcess& NroProcess::getRoMetadataProcess() const const RoMetadataProcess& nstool::NroProcess::getRoMetadataProcess() const
{ {
return mRoMeta; return mRoMeta;
} }
void NroProcess::importHeader() void nstool::NroProcess::importHeader()
{ {
fnd::Vec<byte_t> 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::sNroHeader)) 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)); scratch.alloc(sizeof(nn::hac::sNroHeader));
@ -104,7 +104,7 @@ void NroProcess::importHeader()
// setup homebrew extension // setup homebrew extension
nn::hac::sNroHeader* raw_hdr = (nn::hac::sNroHeader*)scratch.data(); 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<uint64_t>*)raw_hdr->reserved_0)->get() == nn::hac::nro::kNroHomebrewStructMagic && (*mFile)->size() > mHdr.getNroSize())
{ {
mIsHomebrewNro = true; mIsHomebrewNro = true;
mAssetProc.setInputFile(new fnd::OffsetAdjustedIFile(mFile, mHdr.getNroSize(), (*mFile)->size() - mHdr.getNroSize())); mAssetProc.setInputFile(new fnd::OffsetAdjustedIFile(mFile, mHdr.getNroSize(), (*mFile)->size() - mHdr.getNroSize()));
@ -115,7 +115,7 @@ void NroProcess::importHeader()
mIsHomebrewNro = false; mIsHomebrewNro = false;
} }
void NroProcess::importCodeSegments() void nstool::NroProcess::importCodeSegments()
{ {
mTextBlob.alloc(mHdr.getTextInfo().size); mTextBlob.alloc(mHdr.getTextInfo().size);
(*mFile)->read(mTextBlob.data(), mHdr.getTextInfo().memory_offset, mTextBlob.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()); (*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 << "[NRO Header]" << std::endl;
std::cout << " RoCrt: " << std::endl; std::cout << " RoCrt: " << std::endl;
@ -140,7 +140,7 @@ void NroProcess::displayHeader()
std::cout << " .ro:" << std::endl; std::cout << " .ro:" << std::endl;
std::cout << " Offset: 0x" << std::hex << mHdr.getRoInfo().memory_offset << 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; 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 << " .api_info:" << std::endl;
std::cout << " Offset: 0x" << std::hex << mHdr.getRoEmbeddedInfo().memory_offset << 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; std::cout << " Size: 0x" << std::hex << mHdr.getBssSize() << std::endl;
} }
void NroProcess::processRoMeta() void nstool::NroProcess::processRoMeta()
{ {
if (mRoBlob.size()) if (mRoBlob.size())
{ {

View file

@ -1,15 +1,12 @@
#pragma once #pragma once
#include <vector> #include "types.h"
#include <string> #include "RoMetadataProcess.h"
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <nn/hac/define/meta.h>
#include <nn/hac/NroHeader.h>
#include "AssetProcess.h" #include "AssetProcess.h"
#include "common.h" #include <nn/hac/define/meta.h>
#include "RoMetadataProcess.h" #include <nn/hac/NroHeader.h>
namespace nstool {
class NroProcess class NroProcess
{ {
@ -18,7 +15,7 @@ public:
void process(); void process();
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -36,12 +33,12 @@ public:
private: private:
const std::string kModuleName = "NroProcess"; const std::string kModuleName = "NroProcess";
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
nn::hac::NroHeader mHdr; nn::hac::NroHeader mHdr;
fnd::Vec<byte_t> mTextBlob, mRoBlob, mDataBlob; tc::ByteData mTextBlob, mRoBlob, mDataBlob;
RoMetadataProcess mRoMeta; RoMetadataProcess mRoMeta;
bool mIsHomebrewNro; bool mIsHomebrewNro;
AssetProcess mAssetProc; AssetProcess mAssetProc;
@ -51,3 +48,5 @@ private:
void displayHeader(); void displayHeader();
void processRoMeta(); void processRoMeta();
}; };
}

View file

@ -6,9 +6,9 @@
#include <fnd/lz4.h> #include <fnd/lz4.h>
#include "NsoProcess.h" #include "NsoProcess.h"
NsoProcess::NsoProcess(): nstool::NsoProcess::NsoProcess():
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false), mVerify(false),
mIs64BitInstruction(true), mIs64BitInstruction(true),
mListApi(false), mListApi(false),
@ -16,63 +16,63 @@ NsoProcess::NsoProcess():
{ {
} }
void NsoProcess::process() void nstool::NsoProcess::process()
{ {
importHeader(); importHeader();
importCodeSegments(); importCodeSegments();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
displayNsoHeader(); displayNsoHeader();
processRoMeta(); processRoMeta();
} }
void NsoProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::NsoProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void NsoProcess::setCliOutputMode(CliOutputMode type) void nstool::NsoProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void NsoProcess::setVerifyMode(bool verify) void nstool::NsoProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
void NsoProcess::setIs64BitInstruction(bool flag) void nstool::NsoProcess::setIs64BitInstruction(bool flag)
{ {
mRoMeta.setIs64BitInstruction(flag); mRoMeta.setIs64BitInstruction(flag);
} }
void NsoProcess::setListApi(bool listApi) void nstool::NsoProcess::setListApi(bool listApi)
{ {
mRoMeta.setListApi(listApi); mRoMeta.setListApi(listApi);
} }
void NsoProcess::setListSymbols(bool listSymbols) void nstool::NsoProcess::setListSymbols(bool listSymbols)
{ {
mRoMeta.setListSymbols(listSymbols); mRoMeta.setListSymbols(listSymbols);
} }
const RoMetadataProcess& NsoProcess::getRoMetadataProcess() const const RoMetadataProcess& nstool::NsoProcess::getRoMetadataProcess() const
{ {
return mRoMeta; return mRoMeta;
} }
void NsoProcess::importHeader() void nstool::NsoProcess::importHeader()
{ {
fnd::Vec<byte_t> 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::sNsoHeader)) 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)); scratch.alloc(sizeof(nn::hac::sNsoHeader));
@ -81,9 +81,9 @@ void NsoProcess::importHeader()
mHdr.fromBytes(scratch.data(), scratch.size()); mHdr.fromBytes(scratch.data(), scratch.size());
} }
void NsoProcess::importCodeSegments() void nstool::NsoProcess::importCodeSegments()
{ {
fnd::Vec<byte_t> scratch; tc::ByteData scratch;
uint32_t decompressed_len; uint32_t decompressed_len;
fnd::sha::sSha256Hash calc_hash; 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); fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mTextBlob.data(), (uint32_t)mTextBlob.size(), decompressed_len);
if (decompressed_len != mTextBlob.size()) 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 else
@ -109,7 +109,7 @@ void NsoProcess::importCodeSegments()
fnd::sha::Sha256(mTextBlob.data(), mTextBlob.size(), calc_hash.bytes); fnd::sha::Sha256(mTextBlob.data(), mTextBlob.size(), calc_hash.bytes);
if (calc_hash != mHdr.getTextSegmentInfo().hash) 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); fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mRoBlob.data(), (uint32_t)mRoBlob.size(), decompressed_len);
if (decompressed_len != mRoBlob.size()) 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 else
@ -135,7 +135,7 @@ void NsoProcess::importCodeSegments()
fnd::sha::Sha256(mRoBlob.data(), mRoBlob.size(), calc_hash.bytes); fnd::sha::Sha256(mRoBlob.data(), mRoBlob.size(), calc_hash.bytes);
if (calc_hash != mHdr.getRoSegmentInfo().hash) 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); fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mDataBlob.data(), (uint32_t)mDataBlob.size(), decompressed_len);
if (decompressed_len != mDataBlob.size()) 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 else
@ -161,16 +161,16 @@ void NsoProcess::importCodeSegments()
fnd::sha::Sha256(mDataBlob.data(), mDataBlob.size(), calc_hash.bytes); fnd::sha::Sha256(mDataBlob.data(), mDataBlob.size(), calc_hash.bytes);
if (calc_hash != mHdr.getDataSegmentInfo().hash) 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 << "[NSO Header]" << std::endl;
std::cout << " ModuleId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize, false, "") << 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 << " Program Segments:" << std::endl;
std::cout << " .module_name:" << std::endl; std::cout << " .module_name:" << std::endl;
@ -190,18 +190,18 @@ void NsoProcess::displayNsoHeader()
std::cout << " .text:" << std::endl; std::cout << " .text:" << std::endl;
std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.offset << 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; 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 << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getTextSegmentInfo().hash.bytes, 32, false, "") << std::endl;
} }
std::cout << " .ro:" << std::endl; std::cout << " .ro:" << std::endl;
std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.offset << 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; 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; 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 << " .api_info:" << std::endl;
std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoEmbeddedInfo().offset << 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 << " .data:" << std::endl;
std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.offset << 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; 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; 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; std::cout << " MemorySize: 0x" << std::hex << mHdr.getBssSize() << std::endl;
} }
void NsoProcess::processRoMeta() void nstool::NsoProcess::processRoMeta()
{ {
if (mRoBlob.size()) if (mRoBlob.size())
{ {

View file

@ -1,14 +1,11 @@
#pragma once #pragma once
#include <vector> #include "types.h"
#include <string> #include "RoMetadataProcess.h"
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <nn/hac/define/meta.h> #include <nn/hac/define/meta.h>
#include <nn/hac/NsoHeader.h> #include <nn/hac/NsoHeader.h>
#include "common.h" namespace nstool {
#include "RoMetadataProcess.h"
class NsoProcess class NsoProcess
{ {
@ -17,7 +14,7 @@ public:
void process(); void process();
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -29,7 +26,7 @@ public:
private: private:
const std::string kModuleName = "NsoProcess"; const std::string kModuleName = "NsoProcess";
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
bool mIs64BitInstruction; bool mIs64BitInstruction;
@ -37,7 +34,7 @@ private:
bool mListSymbols; bool mListSymbols;
nn::hac::NsoHeader mHdr; nn::hac::NsoHeader mHdr;
fnd::Vec<byte_t> mTextBlob, mRoBlob, mDataBlob; tc::ByteData mTextBlob, mRoBlob, mDataBlob;
RoMetadataProcess mRoMeta; RoMetadataProcess mRoMeta;
void importHeader(); void importHeader();
@ -45,3 +42,5 @@ private:
void displayNsoHeader(); void displayNsoHeader();
void processRoMeta(); void processRoMeta();
}; };
}

View file

@ -9,9 +9,9 @@
#include <nn/hac/PartitionFsUtil.h> #include <nn/hac/PartitionFsUtil.h>
PfsProcess::PfsProcess() : nstool::PfsProcess::PfsProcess() :
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false), mVerify(false),
mExtractPath(), mExtractPath(),
mExtract(false), mExtract(false),
@ -21,14 +21,14 @@ PfsProcess::PfsProcess() :
{ {
} }
void PfsProcess::process() void nstool::PfsProcess::process()
{ {
importHeader(); importHeader();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
{ {
displayHeader(); displayHeader();
if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mListFs || mCliOutputMode.show_extended_info)
displayFs(); displayFs();
} }
if (mPfs.getFsType() == mPfs.TYPE_HFS0 && mVerify) if (mPfs.getFsType() == mPfs.TYPE_HFS0 && mVerify)
@ -37,49 +37,49 @@ void PfsProcess::process()
extractFs(); extractFs();
} }
void PfsProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::PfsProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void PfsProcess::setCliOutputMode(CliOutputMode type) void nstool::PfsProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void PfsProcess::setVerifyMode(bool verify) void nstool::PfsProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
void PfsProcess::setMountPointName(const std::string& mount_name) void nstool::PfsProcess::setMountPointName(const std::string& mount_name)
{ {
mMountName = mount_name; mMountName = mount_name;
} }
void PfsProcess::setExtractPath(const std::string& path) void nstool::PfsProcess::setExtractPath(const std::string& path)
{ {
mExtract = true; mExtract = true;
mExtractPath = path; mExtractPath = path;
} }
void PfsProcess::setListFs(bool list_fs) void nstool::PfsProcess::setListFs(bool list_fs)
{ {
mListFs = list_fs; mListFs = list_fs;
} }
const nn::hac::PartitionFsHeader& PfsProcess::getPfsHeader() const const nn::hac::PartitionFsHeader& nstool::PfsProcess::getPfsHeader() const
{ {
return mPfs; return mPfs;
} }
void PfsProcess::importHeader() void nstool::PfsProcess::importHeader()
{ {
fnd::Vec<byte_t> 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.");
} }
// open minimum header to get full header size // open minimum header to get full header size
@ -87,7 +87,7 @@ void PfsProcess::importHeader()
(*mFile)->read(scratch.data(), 0, scratch.size()); (*mFile)->read(scratch.data(), 0, scratch.size());
if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false) 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())); size_t pfsHeaderSize = determineHeaderSize(((nn::hac::sPfsHeader*)scratch.data()));
@ -97,7 +97,7 @@ void PfsProcess::importHeader()
mPfs.fromBytes(scratch.data(), scratch.size()); mPfs.fromBytes(scratch.data(), scratch.size());
} }
void PfsProcess::displayHeader() void nstool::PfsProcess::displayHeader()
{ {
std::cout << "[PartitionFS]" << std::endl; std::cout << "[PartitionFS]" << std::endl;
std::cout << " Type: " << nn::hac::PartitionFsUtil::getFsTypeAsString(mPfs.getFsType()) << 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++) for (size_t i = 0; i < mPfs.getFileList().size(); i++)
{ {
const nn::hac::PartitionFsHeader::sFile& file = mPfs.getFileList()[i]; const nn::hac::PartitionFsHeader::sFile& file = mPfs.getFileList()[i];
std::cout << " " << file.name; std::cout << " " << file.name;
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) if (mCliOutputMode.show_layout)
{ {
switch (mPfs.getFsType()) 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; size_t fileEntrySize = 0;
if (hdr->st_magic.get() == nn::hac::pfs::kPfsStructMagic) 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(); 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; 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; fnd::sha::sSha256Hash hash;
const fnd::List<nn::hac::PartitionFsHeader::sFile>& file = mPfs.getFileList(); const std::vector<nn::hac::PartitionFsHeader::sFile>& file = mPfs.getFileList();
for (size_t i = 0; i < file.size(); i++) for (size_t i = 0; i < file.size(); i++)
{ {
mCache.alloc(file[i].hash_protected_size); 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 // allocate only when extractDir is invoked
mCache.alloc(kCacheSize); mCache.alloc(kCacheSize);
@ -175,7 +175,7 @@ void PfsProcess::extractFs()
fnd::io::makeDirectory(mExtractPath); fnd::io::makeDirectory(mExtractPath);
fnd::SimpleFile outFile; fnd::SimpleFile outFile;
const fnd::List<nn::hac::PartitionFsHeader::sFile>& file = mPfs.getFileList(); const std::vector<nn::hac::PartitionFsHeader::sFile>& file = mPfs.getFileList();
std::string file_path; std::string file_path;
for (size_t i = 0; i < file.size(); i++) 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, mExtractPath);
fnd::io::appendToPath(file_path, file[i].name); 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()); printf("extract=[%s]\n", file_path.c_str());
outFile.open(file_path, outFile.Create); outFile.open(file_path, outFile.Create);

View file

@ -1,11 +1,9 @@
#pragma once #pragma once
#include <string> #include "types.h"
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <nn/hac/PartitionFsHeader.h> #include <nn/hac/PartitionFsHeader.h>
#include "common.h" namespace nstool {
class PfsProcess class PfsProcess
{ {
@ -15,7 +13,7 @@ public:
void process(); void process();
// generic // generic
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -30,7 +28,7 @@ private:
const std::string kModuleName = "PfsProcess"; const std::string kModuleName = "PfsProcess";
static const size_t kCacheSize = 0x10000; static const size_t kCacheSize = 0x10000;
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
@ -39,7 +37,7 @@ private:
std::string mMountName; std::string mMountName;
bool mListFs; bool mListFs;
fnd::Vec<byte_t> mCache; tc::ByteData mCache;
nn::hac::PartitionFsHeader mPfs; nn::hac::PartitionFsHeader mPfs;
@ -51,3 +49,5 @@ private:
void validateHfs(); void validateHfs();
void extractFs(); void extractFs();
}; };
}

View file

@ -6,51 +6,51 @@
#include "PkiCertProcess.h" #include "PkiCertProcess.h"
#include "PkiValidator.h" #include "PkiValidator.h"
PkiCertProcess::PkiCertProcess() : nstool::PkiCertProcess::PkiCertProcess() :
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false) mVerify(false)
{ {
} }
void PkiCertProcess::process() void nstool::PkiCertProcess::process()
{ {
importCerts(); importCerts();
if (mVerify) if (mVerify)
validateCerts(); validateCerts();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
displayCerts(); displayCerts();
} }
void PkiCertProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::PkiCertProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void PkiCertProcess::setKeyCfg(const KeyConfiguration& keycfg) void nstool::PkiCertProcess::setKeyCfg(const KeyBag& keycfg)
{ {
mKeyCfg = keycfg; mKeyCfg = keycfg;
} }
void PkiCertProcess::setCliOutputMode(CliOutputMode mode) void nstool::PkiCertProcess::setCliOutputMode(CliOutputMode mode)
{ {
mCliOutputMode = mode; mCliOutputMode = mode;
} }
void PkiCertProcess::setVerifyMode(bool verify) void nstool::PkiCertProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
void PkiCertProcess::importCerts() void nstool::PkiCertProcess::importCerts()
{ {
fnd::Vec<byte_t> 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.");
} }
scratch.alloc((*mFile)->size()); 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()) 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); 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; PkiValidator pki;
@ -73,14 +73,14 @@ void PkiCertProcess::validateCerts()
pki.setKeyCfg(mKeyCfg); pki.setKeyCfg(mKeyCfg);
pki.addCertificates(mCert); pki.addCertificates(mCert);
} }
catch (const fnd::Exception& e) catch (const tc::Exception& e)
{ {
std::cout << "[WARNING] " << e.error() << std::endl; std::cout << "[WARNING] " << e.error() << std::endl;
return; return;
} }
} }
void PkiCertProcess::displayCerts() void nstool::PkiCertProcess::displayCerts()
{ {
for (size_t i = 0; i < mCert.size(); i++) for (size_t i = 0; i < mCert.size(); i++)
{ {
@ -88,19 +88,19 @@ void PkiCertProcess::displayCerts()
} }
} }
void PkiCertProcess::displayCert(const nn::pki::SignedData<nn::pki::CertificateBody>& cert) void nstool::PkiCertProcess::displayCert(const nn::pki::SignedData<nn::pki::CertificateBody>& cert)
{ {
std::cout << "[NNPKI Certificate]" << std::endl; std::cout << "[NNPKI Certificate]" << std::endl;
std::cout << " SignType " << getSignTypeStr(cert.getSignature().getSignType()); 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 << " (0x" << std::hex << cert.getSignature().getSignType() << ") (" << getEndiannessStr(cert.getSignature().isLittleEndian()) << ")";
std::cout << std::endl; std::cout << std::endl;
std::cout << " Issuer: " << cert.getBody().getIssuer() << std::endl; std::cout << " Issuer: " << cert.getBody().getIssuer() << std::endl;
std::cout << " Subject: " << cert.getBody().getSubject() << std::endl; std::cout << " Subject: " << cert.getBody().getSubject() << std::endl;
std::cout << " PublicKeyType: " << getPublicKeyTypeStr(cert.getBody().getPublicKeyType()); 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::dec << cert.getBody().getPublicKeyType() << ")";
std::cout << std::endl; std::cout << std::endl;
std::cout << " CertID: 0x" << std::hex << cert.getBody().getCertId() << std::endl; std::cout << " CertID: 0x" << std::hex << cert.getBody().getCertId() << std::endl;
@ -131,12 +131,12 @@ void PkiCertProcess::displayCert(const nn::pki::SignedData<nn::pki::CertificateB
} }
} }
size_t PkiCertProcess::getHexDumpLen(size_t max_size) const size_t nstool::PkiCertProcess::getHexDumpLen(size_t max_size) const
{ {
return _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED) ? max_size : kSmallHexDumpLen; return mCliOutputMode.show_extended_info ? max_size : kSmallHexDumpLen;
} }
const char* PkiCertProcess::getSignTypeStr(nn::pki::sign::SignatureId type) const const char* nstool::PkiCertProcess::getSignTypeStr(nn::pki::sign::SignatureId type) const
{ {
const char* str; const char* str;
switch (type) switch (type)
@ -166,12 +166,12 @@ const char* PkiCertProcess::getSignTypeStr(nn::pki::sign::SignatureId type) cons
return str; return str;
} }
const char* PkiCertProcess::getEndiannessStr(bool isLittleEndian) const const char* nstool::PkiCertProcess::getEndiannessStr(bool isLittleEndian) const
{ {
return isLittleEndian ? "LittleEndian" : "BigEndian"; return isLittleEndian ? "LittleEndian" : "BigEndian";
} }
const char* PkiCertProcess::getPublicKeyTypeStr(nn::pki::cert::PublicKeyType type) const const char* nstool::PkiCertProcess::getPublicKeyTypeStr(nn::pki::cert::PublicKeyType type) const
{ {
const char* str; const char* str;
switch (type) switch (type)

View file

@ -1,14 +1,11 @@
#pragma once #pragma once
#include <string> #include "types.h"
#include <fnd/types.h> #include "KeyBag.h"
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <fnd/List.h>
#include <fnd/Vec.h>
#include <nn/pki/SignedData.h> #include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h> #include <nn/pki/CertificateBody.h>
#include "KeyConfiguration.h"
#include "common.h" namespace nstool {
class PkiCertProcess class PkiCertProcess
{ {
@ -17,8 +14,8 @@ public:
void process(); void process();
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setKeyCfg(const KeyConfiguration& keycfg); void setKeyCfg(const KeyBag& keycfg);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -26,12 +23,12 @@ private:
const std::string kModuleName = "PkiCertProcess"; const std::string kModuleName = "PkiCertProcess";
static const size_t kSmallHexDumpLen = 0x10; static const size_t kSmallHexDumpLen = 0x10;
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
KeyConfiguration mKeyCfg; KeyBag mKeyCfg;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>> mCert; std::vector<nn::pki::SignedData<nn::pki::CertificateBody>> mCert;
void importCerts(); void importCerts();
void validateCerts(); void validateCerts();
@ -43,3 +40,5 @@ private:
const char* getEndiannessStr(bool isLittleEndian) const; const char* getEndiannessStr(bool isLittleEndian) const;
const char* getPublicKeyTypeStr(nn::pki::cert::PublicKeyType type) const; const char* getPublicKeyTypeStr(nn::pki::cert::PublicKeyType type) const;
}; };
}

View file

@ -4,15 +4,15 @@
#include <nn/pki/SignUtils.h> #include <nn/pki/SignUtils.h>
#include "PkiValidator.h" #include "PkiValidator.h"
PkiValidator::PkiValidator() nstool::PkiValidator::PkiValidator()
{ {
clearCertificates(); clearCertificates();
} }
void PkiValidator::setKeyCfg(const KeyConfiguration& keycfg) void nstool::PkiValidator::setKeyCfg(const KeyBag& keycfg)
{ {
// save a copy of the certificate bank // save a copy of the certificate bank
fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>> old_certs = mCertificateBank; std::vector<nn::pki::SignedData<nn::pki::CertificateBody>> old_certs = mCertificateBank;
// clear the certificate bank // clear the certificate bank
mCertificateBank.clear(); mCertificateBank.clear();
@ -27,7 +27,7 @@ void PkiValidator::setKeyCfg(const KeyConfiguration& keycfg)
} }
} }
void PkiValidator::addCertificates(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& certs) void nstool::PkiValidator::addCertificates(const std::vector<nn::pki::SignedData<nn::pki::CertificateBody>>& certs)
{ {
for (size_t i = 0; i < certs.size(); i++) for (size_t i = 0; i < certs.size(); i++)
{ {
@ -35,12 +35,12 @@ void PkiValidator::addCertificates(const fnd::List<nn::pki::SignedData<nn::pki::
} }
} }
void PkiValidator::addCertificate(const nn::pki::SignedData<nn::pki::CertificateBody>& cert) void nstool::PkiValidator::addCertificate(const nn::pki::SignedData<nn::pki::CertificateBody>& cert)
{ {
std::string cert_ident; std::string cert_ident;
nn::pki::sign::SignatureAlgo cert_sign_algo; nn::pki::sign::SignatureAlgo cert_sign_algo;
nn::pki::sign::HashAlgo cert_hash_algo; nn::pki::sign::HashAlgo cert_hash_algo;
fnd::Vec<byte_t> cert_hash; tc::ByteData cert_hash;
try try
{ {
@ -48,7 +48,7 @@ void PkiValidator::addCertificate(const nn::pki::SignedData<nn::pki::Certificate
if (doesCertExist(cert_ident) == true) if (doesCertExist(cert_ident) == true)
{ {
throw fnd::Exception(kModuleName, "Certificate already exists"); throw tc::Exception(kModuleName, "Certificate already exists");
} }
cert_sign_algo = nn::pki::sign::getSignatureAlgo(cert.getSignature().getSignType()); cert_sign_algo = nn::pki::sign::getSignatureAlgo(cert.getSignature().getSignType());
@ -66,27 +66,27 @@ void PkiValidator::addCertificate(const nn::pki::SignedData<nn::pki::Certificate
fnd::sha::Sha256(cert.getBody().getBytes().data(), cert.getBody().getBytes().size(), cert_hash.data()); fnd::sha::Sha256(cert.getBody().getBytes().data(), cert.getBody().getBytes().size(), cert_hash.data());
break; break;
default: default:
throw fnd::Exception(kModuleName, "Unrecognised hash type"); throw tc::Exception(kModuleName, "Unrecognised hash type");
} }
validateSignature(cert.getBody().getIssuer(), cert.getSignature().getSignType(), cert.getSignature().getSignature(), cert_hash); validateSignature(cert.getBody().getIssuer(), cert.getSignature().getSignType(), cert.getSignature().getSignature(), cert_hash);
mCertificateBank.addElement(cert); mCertificateBank.push_back(cert);
} }
catch (const fnd::Exception& e) catch (const tc::Exception& e)
{ {
std::stringstream ss; std::stringstream ss;
ss << "Failed to add certificate " << cert_ident << " (" << e.error() << ")"; ss << "Failed to add certificate " << cert_ident << " (" << e.error() << ")";
throw fnd::Exception(kModuleName, ss.str()); throw tc::Exception(kModuleName, ss.str());
} }
} }
void PkiValidator::clearCertificates() void nstool::PkiValidator::clearCertificates()
{ {
mCertificateBank.clear(); mCertificateBank.clear();
} }
void PkiValidator::validateSignature(const std::string& issuer, nn::pki::sign::SignatureId signature_id, const fnd::Vec<byte_t>& signature, const fnd::Vec<byte_t>& 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::SignatureAlgo sign_algo = nn::pki::sign::getSignatureAlgo(signature_id);
nn::pki::sign::HashAlgo hash_algo = nn::pki::sign::getHashAlgo(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) 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 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 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) 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 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) if (sig_validate_res != 0)
{ {
throw fnd::Exception(kModuleName, "Incorrect signature"); throw tc::Exception(kModuleName, "Incorrect signature");
} }
} }
void PkiValidator::makeCertIdent(const nn::pki::SignedData<nn::pki::CertificateBody>& cert, std::string& ident) const void nstool::PkiValidator::makeCertIdent(const nn::pki::SignedData<nn::pki::CertificateBody>& cert, std::string& ident) const
{ {
makeCertIdent(cert.getBody().getIssuer(), cert.getBody().getSubject(), ident); 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 = issuer + nn::pki::sign::kIdentDelimiter + subject;
ident = ident.substr(0, _MIN(ident.length(),64)); 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; bool exists = false;
std::string full_cert_name; std::string full_cert_name;
@ -179,7 +179,7 @@ bool PkiValidator::doesCertExist(const std::string& ident) const
return exists; return exists;
} }
const nn::pki::SignedData<nn::pki::CertificateBody>& PkiValidator::getCert(const std::string& ident) const const nn::pki::SignedData<nn::pki::CertificateBody>& nstool::PkiValidator::getCert(const std::string& ident) const
{ {
std::string full_cert_name; std::string full_cert_name;
for (size_t i = 0; i < mCertificateBank.size(); i++) for (size_t i = 0; i < mCertificateBank.size(); i++)
@ -191,10 +191,10 @@ const nn::pki::SignedData<nn::pki::CertificateBody>& 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; fnd::sha::HashType hash_type = fnd::sha::HASH_SHA1;

View file

@ -1,30 +1,29 @@
#pragma once #pragma once
#include <fnd/types.h> #include "types.h"
#include <fnd/List.h> #include "KeyBag.h"
#include <fnd/Vec.h>
#include <fnd/rsa.h>
#include <nn/pki/SignedData.h> #include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h> #include <nn/pki/CertificateBody.h>
#include <string>
#include "KeyConfiguration.h" namespace nstool {
class PkiValidator class PkiValidator
{ {
public: public:
PkiValidator(); PkiValidator();
void setKeyCfg(const KeyConfiguration& keycfg); void setKeyCfg(const KeyBag& keycfg);
void addCertificates(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& certs); void addCertificates(const std::vector<nn::pki::SignedData<nn::pki::CertificateBody>>& certs);
void addCertificate(const nn::pki::SignedData<nn::pki::CertificateBody>& cert); void addCertificate(const nn::pki::SignedData<nn::pki::CertificateBody>& cert);
void clearCertificates(); void clearCertificates();
void validateSignature(const std::string& issuer, nn::pki::sign::SignatureId signature_id, const fnd::Vec<byte_t>& signature, const fnd::Vec<byte_t>& hash) const; void validateSignature(const std::string& issuer, nn::pki::sign::SignatureId signature_id, const tc::ByteData& signature, const tc::ByteData& hash) const;
private: private:
const std::string kModuleName = "NNPkiValidator"; const std::string kModuleName = "NNPkiValidator";
KeyConfiguration mKeyCfg; KeyBag mKeyCfg;
fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>> mCertificateBank; std::vector<nn::pki::SignedData<nn::pki::CertificateBody>> mCertificateBank;
void makeCertIdent(const nn::pki::SignedData<nn::pki::CertificateBody>& cert, std::string& ident) const; void makeCertIdent(const nn::pki::SignedData<nn::pki::CertificateBody>& cert, std::string& ident) const;
void makeCertIdent(const std::string& issuer, const std::string& subject, std::string& ident) const; void makeCertIdent(const std::string& issuer, const std::string& subject, std::string& ident) const;
@ -32,3 +31,5 @@ private:
const nn::pki::SignedData<nn::pki::CertificateBody>& getCert(const std::string& ident) const; const nn::pki::SignedData<nn::pki::CertificateBody>& getCert(const std::string& ident) const;
fnd::sha::HashType getCryptoHashAlgoFromEsSignHashAlgo(nn::pki::sign::HashAlgo hash_algo) const; fnd::sha::HashType getCryptoHashAlgoFromEsSignHashAlgo(nn::pki::sign::HashAlgo hash_algo) const;
}; };
}

View file

@ -5,8 +5,8 @@
#include "RoMetadataProcess.h" #include "RoMetadataProcess.h"
RoMetadataProcess::RoMetadataProcess() : nstool::RoMetadataProcess::RoMetadataProcess() :
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mIs64BitInstruction(true), mIs64BitInstruction(true),
mListApi(false), mListApi(false),
mListSymbols(false), mListSymbols(false),
@ -23,90 +23,90 @@ RoMetadataProcess::RoMetadataProcess() :
} }
void RoMetadataProcess::process() void nstool::RoMetadataProcess::process()
{ {
importApiList(); importApiList();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
displayRoMetaData(); displayRoMetaData();
} }
void RoMetadataProcess::setRoBinary(const fnd::Vec<byte_t>& bin) void nstool::RoMetadataProcess::setRoBinary(const tc::ByteData& bin)
{ {
mRoBlob = 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.offset = offset;
mApiInfo.size = size; 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.offset = offset;
mDynSym.size = size; 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.offset = offset;
mDynStr.size = size; mDynStr.size = size;
} }
void RoMetadataProcess::setCliOutputMode(CliOutputMode type) void nstool::RoMetadataProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void RoMetadataProcess::setIs64BitInstruction(bool flag) void nstool::RoMetadataProcess::setIs64BitInstruction(bool flag)
{ {
mIs64BitInstruction = flag; mIs64BitInstruction = flag;
} }
void RoMetadataProcess::setListApi(bool listApi) void nstool::RoMetadataProcess::setListApi(bool listApi)
{ {
mListApi = listApi; mListApi = listApi;
} }
void RoMetadataProcess::setListSymbols(bool listSymbols) void nstool::RoMetadataProcess::setListSymbols(bool listSymbols)
{ {
mListSymbols = listSymbols; mListSymbols = listSymbols;
} }
const std::vector<SdkApiString>& RoMetadataProcess::getSdkVerApiList() const const std::vector<SdkApiString>& nstool::RoMetadataProcess::getSdkVerApiList() const
{ {
return mSdkVerApiList; return mSdkVerApiList;
} }
const std::vector<SdkApiString>& RoMetadataProcess::getPublicApiList() const const std::vector<SdkApiString>& nstool::RoMetadataProcess::getPublicApiList() const
{ {
return mPublicApiList; return mPublicApiList;
} }
const std::vector<SdkApiString>& RoMetadataProcess::getDebugApiList() const const std::vector<SdkApiString>& nstool::RoMetadataProcess::getDebugApiList() const
{ {
return mDebugApiList; return mDebugApiList;
} }
const std::vector<SdkApiString>& RoMetadataProcess::getPrivateApiList() const const std::vector<SdkApiString>& nstool::RoMetadataProcess::getPrivateApiList() const
{ {
return mPrivateApiList; return mPrivateApiList;
} }
const std::vector<SdkApiString>& RoMetadataProcess::getGuidelineApiList() const const std::vector<SdkApiString>& nstool::RoMetadataProcess::getGuidelineApiList() const
{ {
return mGuidelineApiList; return mGuidelineApiList;
} }
const fnd::List<ElfSymbolParser::sElfSymbol>& RoMetadataProcess::getSymbolList() const const std::vector<ElfSymbolParser::sElfSymbol>& nstool::RoMetadataProcess::getSymbolList() const
{ {
return mSymbolList.getSymbolList(); return mSymbolList.getSymbolList();
} }
void RoMetadataProcess::importApiList() void nstool::RoMetadataProcess::importApiList()
{ {
if (mRoBlob.size() == 0) if (mRoBlob.size() == 0)
{ {
throw fnd::Exception(kModuleName, "No ro binary set."); throw tc::Exception(kModuleName, "No ro binary set.");
} }
if (mApiInfo.size > 0) 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(); 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; std::cout << "[SDK API List]" << std::endl;
if (mSdkVerApiList.size() > 0) 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; std::cout << "[Symbol List]" << std::endl;
for (size_t i = 0; i < mSymbolList.getSymbolList().size(); i++) 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; const char* str;
switch (shn_index) switch (shn_index)
@ -235,7 +235,7 @@ const char* RoMetadataProcess::getSectionIndexStr(uint16_t shn_index) const
return str; return str;
} }
const char* RoMetadataProcess::getSymbolTypeStr(byte_t symbol_type) const const char* nstool::RoMetadataProcess::getSymbolTypeStr(byte_t symbol_type) const
{ {
const char* str; const char* str;
switch (symbol_type) switch (symbol_type)
@ -274,7 +274,7 @@ const char* RoMetadataProcess::getSymbolTypeStr(byte_t symbol_type) const
return str; return str;
} }
const char* RoMetadataProcess::getSymbolBindingStr(byte_t symbol_binding) const const char* nstool::RoMetadataProcess::getSymbolBindingStr(byte_t symbol_binding) const
{ {
const char* str; const char* str;
switch (symbol_binding) switch (symbol_binding)

View file

@ -1,14 +1,11 @@
#pragma once #pragma once
#include <vector> #include "types.h"
#include <string> #include "SdkApiString.h"
#include <fnd/types.h> #include "ElfSymbolParser.h"
#include <fnd/Vec.h>
#include <nn/hac/define/meta.h> #include <nn/hac/define/meta.h>
#include "common.h" namespace nstool {
#include "SdkApiString.h"
#include "ElfSymbolParser.h"
class RoMetadataProcess class RoMetadataProcess
{ {
@ -17,7 +14,7 @@ public:
void process(); void process();
void setRoBinary(const fnd::Vec<byte_t>& bin); void setRoBinary(const tc::ByteData& bin);
void setApiInfo(size_t offset, size_t size); void setApiInfo(size_t offset, size_t size);
void setDynSym(size_t offset, size_t size); void setDynSym(size_t offset, size_t size);
void setDynStr(size_t offset, size_t size); void setDynStr(size_t offset, size_t size);
@ -33,7 +30,7 @@ public:
const std::vector<SdkApiString>& getDebugApiList() const; const std::vector<SdkApiString>& getDebugApiList() const;
const std::vector<SdkApiString>& getPrivateApiList() const; const std::vector<SdkApiString>& getPrivateApiList() const;
const std::vector<SdkApiString>& getGuidelineApiList() const; const std::vector<SdkApiString>& getGuidelineApiList() const;
const fnd::List<ElfSymbolParser::sElfSymbol>& getSymbolList() const; const std::vector<ElfSymbolParser::sElfSymbol>& getSymbolList() const;
private: private:
const std::string kModuleName = "RoMetadataProcess"; const std::string kModuleName = "RoMetadataProcess";
@ -52,7 +49,7 @@ private:
sLayout mApiInfo; sLayout mApiInfo;
sLayout mDynSym; sLayout mDynSym;
sLayout mDynStr; sLayout mDynStr;
fnd::Vec<byte_t> mRoBlob; tc::ByteData mRoBlob;
std::vector<SdkApiString> mSdkVerApiList; std::vector<SdkApiString> mSdkVerApiList;
std::vector<SdkApiString> mPublicApiList; std::vector<SdkApiString> mPublicApiList;
std::vector<SdkApiString> mDebugApiList; std::vector<SdkApiString> mDebugApiList;
@ -68,3 +65,5 @@ private:
const char* getSymbolTypeStr(byte_t symbol_type) const; const char* getSymbolTypeStr(byte_t symbol_type) const;
const char* getSymbolBindingStr(byte_t symbol_binding) const; const char* getSymbolBindingStr(byte_t symbol_binding) const;
}; };
}

View file

@ -6,9 +6,9 @@
#include "CompressedArchiveIFile.h" #include "CompressedArchiveIFile.h"
#include "RomfsProcess.h" #include "RomfsProcess.h"
RomfsProcess::RomfsProcess() : nstool::RomfsProcess::RomfsProcess() :
mFile(), mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(true, false, false, false),
mVerify(false), mVerify(false),
mExtractPath(), mExtractPath(),
mExtract(false), mExtract(false),
@ -22,14 +22,14 @@ RomfsProcess::RomfsProcess() :
mRootDir.file_list.clear(); mRootDir.file_list.clear();
} }
void RomfsProcess::process() void nstool::RomfsProcess::process()
{ {
resolveRomfs(); resolveRomfs();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (mCliOutputMode.show_basic_info)
{ {
displayHeader(); displayHeader();
if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mListFs || mCliOutputMode.show_extended_info)
displayFs(); displayFs();
} }
@ -37,43 +37,43 @@ void RomfsProcess::process()
extractFs(); extractFs();
} }
void RomfsProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file) void nstool::RomfsProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
{ {
mFile = file; mFile = file;
} }
void RomfsProcess::setCliOutputMode(CliOutputMode type) void nstool::RomfsProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputMode = type; mCliOutputMode = type;
} }
void RomfsProcess::setVerifyMode(bool verify) void nstool::RomfsProcess::setVerifyMode(bool verify)
{ {
mVerify = verify; mVerify = verify;
} }
void RomfsProcess::setMountPointName(const std::string& mount_name) void nstool::RomfsProcess::setMountPointName(const std::string& mount_name)
{ {
mMountName = mount_name; mMountName = mount_name;
} }
void RomfsProcess::setExtractPath(const std::string& path) void nstool::RomfsProcess::setExtractPath(const std::string& path)
{ {
mExtract = true; mExtract = true;
mExtractPath = path; mExtractPath = path;
} }
void RomfsProcess::setListFs(bool list_fs) void nstool::RomfsProcess::setListFs(bool list_fs)
{ {
mListFs = list_fs; mListFs = list_fs;
} }
const RomfsProcess::sDirectory& RomfsProcess::getRootDir() const const nstool::RomfsProcess::sDirectory& nstool::RomfsProcess::getRootDir() const
{ {
return mRootDir; 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++) 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); printTab(tab);
std::cout << file.name; 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::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ")";
} }
std::cout << std::endl; 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) 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 << "[RomFS]" << std::endl;
std::cout << " DirNum: " << std::dec << mDirNum << 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); 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 dir_path;
std::string file_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_path);
fnd::io::appendToPath(file_path, dir.file_list[i].name); 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; std::cout << "extract=[" << file_path << "]" << std::endl;
outFile.open(file_path, outFile.Create); 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 // allocate only when extractDir is invoked
mCache.alloc(kCacheSize); mCache.alloc(kCacheSize);
extractDir(mExtractPath, mRootDir); 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; bool validLayout = true;
@ -199,7 +199,7 @@ bool RomfsProcess::validateHeaderLayout(const nn::hac::sRomfsHeader* hdr) const
return validLayout; 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); 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); 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(); file_addr = f_node->sibling.get();
mFileNum++; mFileNum++;
@ -239,7 +239,7 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir)
{ {
nn::hac::sRomfsDirEntry* c_node = get_dir_node(child_addr); 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()); importDirectory(child_addr, dir.dir_list.atBack());
child_addr = c_node->sibling.get(); 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) if (*mFile == nullptr)
{ {
throw fnd::Exception(kModuleName, "No file reader set."); throw tc::Exception(kModuleName, "No file reader set.");
} }
// read header // read header
@ -260,7 +260,7 @@ void RomfsProcess::resolveRomfs()
// logic check on the header layout // logic check on the header layout
if (validateHeaderLayout(&mHdr) == false) if (validateHeaderLayout(&mHdr) == false)
{ {
throw fnd::Exception(kModuleName, "Invalid ROMFS Header"); throw tc::Exception(kModuleName, "Invalid ROMFS Header");
} }
// check for romfs compression // 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 || \ 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) 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) // 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 // quick check to make sure the offset at least before the last entry offset
if (first_entry_offset >= (physical_size - sizeof(nn::hac::sCompressionEntry))) 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 // read first compression entry
@ -306,7 +306,7 @@ void RomfsProcess::resolveRomfs()
entry[0].physical_size.get() != 0x200 || \ entry[0].physical_size.get() != 0x200 || \
entry[0].compression_type != (byte_t)nn::hac::compression::CompressionType::None) 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. // 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)->hash.get() != nn::hac::romfs::kInvalidAddr \
|| get_dir_node(0)->name_size.get() != 0) || 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 // import directory into internal structure

View file

@ -1,13 +1,9 @@
#pragma once #pragma once
#include <string> #include "types.h"
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <fnd/Vec.h>
#include <fnd/List.h>
#include <nn/hac/define/romfs.h> #include <nn/hac/define/romfs.h>
#include "common.h" namespace nstool {
class RomfsProcess class RomfsProcess
{ {
@ -18,8 +14,8 @@ public:
struct sDirectory struct sDirectory
{ {
std::string name; std::string name;
fnd::List<sDirectory> dir_list; std::vector<sDirectory> dir_list;
fnd::List<sFile> file_list; std::vector<sFile> file_list;
void operator=(const sDirectory& other) void operator=(const sDirectory& other)
{ {
@ -82,7 +78,7 @@ public:
void process(); void process();
// generic // generic
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file); void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -96,8 +92,13 @@ private:
const std::string kModuleName = "RomfsProcess"; const std::string kModuleName = "RomfsProcess";
static const size_t kCacheSize = 0x10000; static const size_t kCacheSize = 0x10000;
fnd::SharedPtr<fnd::IFile> mFile; std::shared_ptr<tc::io::IStream> mFile;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mShowBasicInfo;
bool mShowExtendedInfo;
bool mShowLayoutInfo;
bool mShowKeydata;
bool mVerbose;
bool mVerify; bool mVerify;
std::string mExtractPath; std::string mExtractPath;
@ -105,13 +106,13 @@ private:
std::string mMountName; std::string mMountName;
bool mListFs; bool mListFs;
fnd::Vec<byte_t> mCache; tc::ByteData mCache;
size_t mDirNum; size_t mDirNum;
size_t mFileNum; size_t mFileNum;
nn::hac::sRomfsHeader mHdr; nn::hac::sRomfsHeader mHdr;
fnd::Vec<byte_t> mDirNodes; tc::ByteData mDirNodes;
fnd::Vec<byte_t> mFileNodes; tc::ByteData mFileNodes;
sDirectory mRootDir; sDirectory mRootDir;
inline nn::hac::sRomfsDirEntry* get_dir_node(uint32_t offset) { return (nn::hac::sRomfsDirEntry*)(mDirNodes.data() + offset); } inline nn::hac::sRomfsDirEntry* get_dir_node(uint32_t offset) { return (nn::hac::sRomfsDirEntry*)(mDirNodes.data() + offset); }
@ -132,3 +133,5 @@ private:
void importDirectory(uint32_t dir_offset, sDirectory& dir); void importDirectory(uint32_t dir_offset, sDirectory& dir);
void resolveRomfs(); void resolveRomfs();
}; };
}

View file

@ -1,13 +1,13 @@
#include <sstream> #include <sstream>
#include "SdkApiString.h" #include "SdkApiString.h"
SdkApiString::SdkApiString(const std::string& full_str) : nstool::SdkApiString::SdkApiString(const std::string& full_str) :
SdkApiString(API_MIDDLEWARE, "", "") SdkApiString(API_MIDDLEWARE, "", "")
{ {
resolveApiString(full_str); 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), mApiType(type),
mVenderName(vender_name), mVenderName(vender_name),
mModuleName(module_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; mApiType = other.mApiType;
mVenderName = other.mVenderName; mVenderName = other.mVenderName;
mModuleName = other.mModuleName; mModuleName = other.mModuleName;
} }
SdkApiString::ApiType SdkApiString::getApiType() const nstool::SdkApiString::ApiType nstool::SdkApiString::getApiType() const
{ {
return mApiType; return mApiType;
} }
void SdkApiString::setApiType(ApiType type) void nstool::SdkApiString::setApiType(ApiType type)
{ {
mApiType = type; mApiType = type;
} }
const std::string& SdkApiString::getVenderName() const const std::string& nstool::SdkApiString::getVenderName() const
{ {
return mVenderName; return mVenderName;
} }
void SdkApiString::setVenderName(const std::string& name) void nstool::SdkApiString::setVenderName(const std::string& name)
{ {
mVenderName = name; mVenderName = name;
} }
const std::string& SdkApiString::getModuleName() const const std::string& nstool::SdkApiString::getModuleName() const
{ {
return mModuleName; return mModuleName;
} }
void SdkApiString::setModuleName(const std::string& name) void nstool::SdkApiString::setModuleName(const std::string& name)
{ {
mModuleName = 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::stringstream list_stream(full_str);
std::string api_type, vender, module; std::string api_type, vender, module;

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <string> #include "types.h"
namespace nstool {
class SdkApiString class SdkApiString
{ {
@ -43,3 +45,5 @@ private:
void resolveApiString(const std::string& full_str); void resolveApiString(const std::string& full_str);
}; };
}

819
src/Settings.cpp Normal file
View file

@ -0,0 +1,819 @@
#include <tc/cli.h>
#include <tc/os/Environment.h>
#include <tc/ArgumentException.h>
#include <tc/io/FileStream.h>
#include <tc/io/StreamSource.h>
#include "types.h"
#include "version.h"
#include "Settings.h"
#include <nn/hac/ContentArchiveUtil.h>
#include <nn/hac/AesKeygen.h>
#include <nn/hac/define/gc.h>
#include <nn/hac/define/pfs.h>
#include <nn/hac/define/nca.h>
#include <nn/hac/define/meta.h>
#include <nn/hac/define/romfs.h>
#include <nn/hac/define/cnmt.h>
#include <nn/hac/define/nacp.h>
#include <nn/hac/define/nso.h>
#include <nn/hac/define/nro.h>
#include <nn/hac/define/ini.h>
#include <nn/hac/define/kip.h>
#include <nn/hac/define/aset.h>
#include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h>
#include <nn/pki/SignUtils.h>
#include <nn/es/TicketBody_V2.h>
class UnkOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
public:
UnkOptionHandler(const std::string& module_label) : mModuleLabel(module_label)
{}
const std::vector<std::string>& getOptionStrings() const
{
throw tc::InvalidOperationException("getOptionStrings() not defined for UnkOptionHandler.");
}
void processOption(const std::string& option, const std::vector<std::string>& 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<std::string>& opts) :
mWarnMessage(warn_message),
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
{
return mOptStrings;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
fmt::print("[WARNING] Option \"{}\" is deprecated.{}{}\n", option, (mWarnMessage.empty() ? "" : " "), mWarnMessage);
}
private:
std::string mWarnMessage;
std::vector<std::string> mOptStrings;
};
class FlagOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
public:
FlagOptionHandler(bool& flag, const std::vector<std::string>& opts) :
mFlag(flag),
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
{
return mOptStrings;
}
void processOption(const std::string& option, const std::vector<std::string>& 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<std::string> mOptStrings;
};
class SingleParamStringOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
public:
SingleParamStringOptionHandler(tc::Optional<std::string>& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
{
return mOptStrings;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
{
throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires a parameter.", option));
}
mParam = params[0];
}
private:
tc::Optional<std::string>& mParam;
std::vector<std::string> mOptStrings;
};
class SingleParamPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
public:
SingleParamPathOptionHandler(tc::Optional<tc::io::Path>& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
{
return mOptStrings;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
{
throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires a parameter.", option));
}
mParam = params[0];
}
private:
tc::Optional<tc::io::Path>& mParam;
std::vector<std::string> mOptStrings;
};
class SingleParamSizetOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
public:
SingleParamSizetOptionHandler(size_t& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
{
return mOptStrings;
}
void processOption(const std::string& option, const std::vector<std::string>& 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<std::string> mOptStrings;
};
class SingleParamAesKeyOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
public:
SingleParamAesKeyOptionHandler(tc::Optional<nstool::KeyBag::aes128_key_t>& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
{
return mOptStrings;
}
void processOption(const std::string& option, const std::vector<std::string>& 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<nstool::KeyBag::aes128_key_t>& mParam;
std::vector<std::string> mOptStrings;
};
class FileTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
public:
FileTypeOptionHandler(nstool::Settings::FileType& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
{
return mOptStrings;
}
void processOption(const std::string& option, const std::vector<std::string>& 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<std::string> mOptStrings;
};
class InstructionTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
public:
InstructionTypeOptionHandler(bool& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
{}
const std::vector<std::string>& getOptionStrings() const
{
return mOptStrings;
}
void processOption(const std::string& option, const std::vector<std::string>& 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<std::string> mOptStrings;
};
nstool::SettingsInitializer::SettingsInitializer(const std::vector<std::string>& 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 <path>\"?\n", opt.is_dev ? "dev.keys" : "prod.keys");
}
}
else {
fmt::print("[WARNING] Failed to located \"{}\" keyfile. Maybe specify it with \"-k <path>\"?\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<std::string>& 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<UnkOptionHandler>(new UnkOptionHandler(mModuleLabel)));
// register handler for deprecated options DeprecatedOptionHandler
// none just yet
// get option flags
opts.registerOptionHandler(std::shared_ptr<FlagOptionHandler>(new FlagOptionHandler(opt.show_layout, {"--showlayout"})));
opts.registerOptionHandler(std::shared_ptr<FlagOptionHandler>(new FlagOptionHandler(opt.show_keydata, { "--showkeys" })));
opts.registerOptionHandler(std::shared_ptr<FlagOptionHandler>(new FlagOptionHandler(opt.verbose, {"-v", "--verbose"})));
opts.registerOptionHandler(std::shared_ptr<FlagOptionHandler>(new FlagOptionHandler(opt.verify, {"-y", "--verify"})));
opts.registerOptionHandler(std::shared_ptr<FlagOptionHandler>(new FlagOptionHandler(opt.is_dev, {"-d", "--dev"})));
// process input file type
opts.registerOptionHandler(std::shared_ptr<FileTypeOptionHandler>(new FileTypeOptionHandler(infile.filetype, { "-t", "--intype" })));
// get user-provided keydata
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(mKeysetPath, {"-k", "--keyset"})));
opts.registerOptionHandler(std::shared_ptr<SingleParamAesKeyOptionHandler>(new SingleParamAesKeyOptionHandler(mTitleKey, {"--titlekey"})));
opts.registerOptionHandler(std::shared_ptr<SingleParamAesKeyOptionHandler>(new SingleParamAesKeyOptionHandler(mBodyKey, {"--bodykey"})));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(mTikPath, {"--tik"})));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(mCertPath, {"--cert"})));
// code options
opts.registerOptionHandler(std::shared_ptr<FlagOptionHandler>(new FlagOptionHandler(code.list_api, { "--listapi" })));
opts.registerOptionHandler(std::shared_ptr<FlagOptionHandler>(new FlagOptionHandler(code.list_symbols, { "--listsym" })));
opts.registerOptionHandler(std::shared_ptr<InstructionTypeOptionHandler>(new InstructionTypeOptionHandler(code.is_64bit_instruction, { "--insttype" })));
// fs options
opts.registerOptionHandler(std::shared_ptr<FlagOptionHandler>(new FlagOptionHandler(fs.show_fs_tree, { "--listfs" })));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(fs.extract_path, { "--fsdir" })));
// xci options
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(xci.update_extract_path, { "--update" })));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(xci.normal_extract_path, { "--normal" })));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(xci.secure_extract_path, { "--secure" })));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(xci.logo_extract_path, { "--logo" })));
// nca options
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(nca.part0_extract_path, { "--part0" })));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(nca.part1_extract_path, { "--part1" })));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(nca.part2_extract_path, { "--part2" })));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(nca.part3_extract_path, { "--part3" })));
// kip options
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(kip.extract_path, { "--kipdir" })));
// aset options
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(aset.icon_extract_path, { "--icon" })));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(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>(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... ] <file>\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 <dir> --logo <dir> --normal <dir> --secure <dir>] <.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 <dir>] <file>\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 <key> --titlekey <key>] [--part0 <dir> ...] <.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 <inst. type>] <file>\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 <dir>] <file>\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 <file> --nacp <file> --fsdir <dir>] <file>\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;
}

155
src/Settings.h Normal file
View file

@ -0,0 +1,155 @@
#pragma once
#include "types.h"
#include <string>
#include <vector>
#include <tc/Optional.h>
#include <tc/io.h>
#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<tc::io::Path> 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<tc::io::Path> extract_path;
} fs;
// XCI options
struct XciOptions
{
tc::Optional<tc::io::Path> update_extract_path;
tc::Optional<tc::io::Path> logo_extract_path;
tc::Optional<tc::io::Path> normal_extract_path;
tc::Optional<tc::io::Path> secure_extract_path;
} xci;
// NCA options
struct NcaOptions
{
tc::Optional<tc::io::Path> part0_extract_path;
tc::Optional<tc::io::Path> part1_extract_path;
tc::Optional<tc::io::Path> part2_extract_path;
tc::Optional<tc::io::Path> part3_extract_path;
} nca;
// KIP options
struct KipOptions
{
tc::Optional<tc::io::Path> extract_path;
} kip;
// ASET Options
struct AsetOptions
{
tc::Optional<tc::io::Path> icon_extract_path;
tc::Optional<tc::io::Path> nacp_extract_path;
} aset;
Settings()
{
infile.filetype = FILE_TYPE_ERROR;
infile.path = tc::Optional<tc::io::Path>();
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<tc::io::Path>();
xci.logo_extract_path = tc::Optional<tc::io::Path>();
xci.normal_extract_path = tc::Optional<tc::io::Path>();
xci.secure_extract_path = tc::Optional<tc::io::Path>();
fs.show_fs_tree = false;
fs.extract_path = tc::Optional<tc::io::Path>();
nca.part0_extract_path = tc::Optional<tc::io::Path>();
nca.part1_extract_path = tc::Optional<tc::io::Path>();
nca.part2_extract_path = tc::Optional<tc::io::Path>();
nca.part3_extract_path = tc::Optional<tc::io::Path>();
kip.extract_path = tc::Optional<tc::io::Path>();
aset.icon_extract_path = tc::Optional<tc::io::Path>();
aset.nacp_extract_path = tc::Optional<tc::io::Path>();
}
};
class SettingsInitializer : public Settings
{
public:
SettingsInitializer(const std::vector<std::string>& args);
private:
void parse_args(const std::vector<std::string>& args);
void determine_filetype();
void usage_text();
std::string mModuleLabel;
bool mShowLayout;
bool mShowKeydata;
tc::Optional<tc::io::Path> mKeysetPath;
tc::Optional<KeyBag::aes128_key_t> mTitleKey;
tc::Optional<KeyBag::aes128_key_t> mBodyKey;
tc::Optional<tc::io::Path> mTikPath;
tc::Optional<tc::io::Path> 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;
};
}

File diff suppressed because it is too large Load diff

View file

@ -1,138 +0,0 @@
#pragma once
#include <vector>
#include <string>
#include <fnd/types.h>
#include <fnd/Vec.h>
#include <fnd/List.h>
#include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h>
#include <nn/hac/define/meta.h>
#include "common.h"
#include "KeyConfiguration.h"
class UserSettings
{
public:
UserSettings();
void parseCmdArgs(const std::vector<std::string>& 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<std::string>& getXciUpdatePath() const;
const sOptional<std::string>& getXciLogoPath() const;
const sOptional<std::string>& getXciNormalPath() const;
const sOptional<std::string>& getXciSecurePath() const;
const sOptional<std::string>& getFsPath() const;
const sOptional<std::string>& getNcaPart0Path() const;
const sOptional<std::string>& getNcaPart1Path() const;
const sOptional<std::string>& getNcaPart2Path() const;
const sOptional<std::string>& getNcaPart3Path() const;
const sOptional<std::string>& getKipExtractPath() const;
const sOptional<std::string>& getAssetIconPath() const;
const sOptional<std::string>& getAssetNacpPath() const;
const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& 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<std::string> input_path;
sOptional<bool> devkit_keys;
sOptional<std::string> keyset_path;
sOptional<std::string> file_type;
sOptional<bool> verify_file;
sOptional<bool> show_keys;
sOptional<bool> show_layout;
sOptional<bool> verbose_output;
sOptional<bool> list_fs;
sOptional<std::string> update_path;
sOptional<std::string> logo_path;
sOptional<std::string> normal_path;
sOptional<std::string> secure_path;
sOptional<std::string> fs_path;
sOptional<std::string> nca_titlekey;
sOptional<std::string> nca_bodykey;
sOptional<std::string> ticket_path;
sOptional<std::string> cert_path;
sOptional<std::string> part0_path;
sOptional<std::string> part1_path;
sOptional<std::string> part2_path;
sOptional<std::string> part3_path;
sOptional<std::string> kip_extract_path;
sOptional<bool> list_api;
sOptional<bool> list_sym;
sOptional<std::string> inst_type;
sOptional<std::string> asset_icon_path;
sOptional<std::string> asset_nacp_path;
};
std::string mInputPath;
FileType mFileType;
KeyConfiguration mKeyCfg;
bool mVerifyFile;
CliOutputMode mOutputMode;
bool mListFs;
sOptional<std::string> mXciUpdatePath;
sOptional<std::string> mXciLogoPath;
sOptional<std::string> mXciNormalPath;
sOptional<std::string> mXciSecurePath;
sOptional<std::string> mFsPath;
sOptional<std::string> mNcaPart0Path;
sOptional<std::string> mNcaPart1Path;
sOptional<std::string> mNcaPart2Path;
sOptional<std::string> mNcaPart3Path;
sOptional<std::string> mKipExtractPath;
sOptional<std::string> mAssetIconPath;
sOptional<std::string> mAssetNacpPath;
fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>> mCertChain;
bool mListApi;
bool mListSymbols;
bool mIs64BitInstruction;
void populateCmdArgs(const std::vector<std::string>& 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<byte_t>& sample) const;
bool determineValidCnmtFromSample(const fnd::Vec<byte_t>& sample) const;
bool determineValidNacpFromSample(const fnd::Vec<byte_t>& sample) const;
bool determineValidEsCertFromSample(const fnd::Vec<byte_t>& sample) const;
bool determineValidEsTikFromSample(const fnd::Vec<byte_t>& 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;
};

View file

@ -1,62 +0,0 @@
#pragma once
#include <string>
#include <fnd/types.h>
#include <fnd/aes.h>
#include <fnd/rsa.h>
#include <nn/hac/define/nca.h>
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 <typename T>
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<T>& operator=(const sOptional<T>& 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};

458
src/elf.h Normal file
View file

@ -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 */
};
}

View file

@ -1,8 +1,8 @@
#include <cstdio> #include <tc.h>
#include <fnd/SimpleFile.h> #include <tc/os/UnicodeMain.h>
#include <fnd/SharedPtr.h> #include "Settings.h"
#include <fnd/StringConv.h>
#include "UserSettings.h" /*
#include "GameCardProcess.h" #include "GameCardProcess.h"
#include "PfsProcess.h" #include "PfsProcess.h"
#include "RomfsProcess.h" #include "RomfsProcess.h"
@ -17,129 +17,116 @@
#include "PkiCertProcess.h" #include "PkiCertProcess.h"
#include "EsTikProcess.h" #include "EsTikProcess.h"
#include "AssetProcess.h" #include "AssetProcess.h"
*/
#ifdef _WIN32 int umain(const std::vector<std::string>& args, const std::vector<std::string>& env)
int wmain(int argc, wchar_t** argv)
#else
int main(int argc, char** argv)
#endif
{ {
std::vector<std::string> args; try
for (size_t i = 0; i < (size_t)argc; i++)
{ {
#ifdef _WIN32 nstool::Settings set = nstool::SettingsInitializer(args);
args.push_back(fnd::StringConv::ConvertChar16ToChar8(std::u16string((char16_t*)argv[i])));
#else
args.push_back(argv[i]);
#endif
}
UserSettings user_set; std::shared_ptr<tc::io::IStream> infile_stream = std::make_shared<tc::io::FileStream>(tc::io::FileStream(set.infile.path.get(), tc::io::FileMode::Open, tc::io::FileAccess::Read));
try {
user_set.parseCmdArgs(args);
fnd::SharedPtr<fnd::IFile> inputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read)); if (set.infile.filetype == nstool::Settings::FILE_TYPE_GAMECARD)
if (user_set.getFileType() == FILE_GAMECARD)
{ {
GameCardProcess obj; 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.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
if (user_set.getXciUpdatePath().isSet) if (set.xci.update_extract_path.isSet())
obj.setPartitionForExtract(nn::hac::gc::kUpdatePartitionStr, user_set.getXciUpdatePath().var); obj.setPartitionForExtract(nn::hac::gc::kUpdatePartitionStr, set.xci.update_extract_path.get());
if (user_set.getXciLogoPath().isSet) if (set.xci.logo_extract_path.isSet())
obj.setPartitionForExtract(nn::hac::gc::kLogoPartitionStr, user_set.getXciLogoPath().var); obj.setPartitionForExtract(nn::hac::gc::kLogoPartitionStr, set.xci.logo_extract_path.get());
if (user_set.getXciNormalPath().isSet) if (user_set.getXciNormalPath().isSet())
obj.setPartitionForExtract(nn::hac::gc::kNormalPartitionStr, user_set.getXciNormalPath().var); obj.setPartitionForExtract(nn::hac::gc::kNormalPartitionStr, user_set.getXciNormalPath().get());
if (user_set.getXciSecurePath().isSet) if (user_set.getXciSecurePath().isSet())
obj.setPartitionForExtract(nn::hac::gc::kSecurePartitionStr, user_set.getXciSecurePath().var); obj.setPartitionForExtract(nn::hac::gc::kSecurePartitionStr, user_set.getXciSecurePath().get());
obj.setListFs(user_set.isListFs()); obj.setListFs(user_set.isListFs());
obj.process(); 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; PfsProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
if (user_set.getFsPath().isSet) if (user_set.getFsPath().isSet())
obj.setExtractPath(user_set.getFsPath().var); obj.setExtractPath(user_set.getFsPath().get());
obj.setListFs(user_set.isListFs()); obj.setListFs(user_set.isListFs());
obj.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_ROMFS) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_ROMFS)
{ {
RomfsProcess obj; RomfsProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
if (user_set.getFsPath().isSet) if (user_set.getFsPath().isSet())
obj.setExtractPath(user_set.getFsPath().var); obj.setExtractPath(user_set.getFsPath().get());
obj.setListFs(user_set.isListFs()); obj.setListFs(user_set.isListFs());
obj.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_NCA) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_NCA)
{ {
NcaProcess obj; NcaProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setKeyCfg(user_set.getKeyCfg()); obj.setKeyCfg(set.opt.keybag);
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
if (user_set.getNcaPart0Path().isSet) if (user_set.getNcaPart0Path().isSet())
obj.setPartition0ExtractPath(user_set.getNcaPart0Path().var); obj.setPartition0ExtractPath(user_set.getNcaPart0Path().get());
if (user_set.getNcaPart1Path().isSet) if (user_set.getNcaPart1Path().isSet())
obj.setPartition1ExtractPath(user_set.getNcaPart1Path().var); obj.setPartition1ExtractPath(user_set.getNcaPart1Path().get());
if (user_set.getNcaPart2Path().isSet) if (user_set.getNcaPart2Path().isSet())
obj.setPartition2ExtractPath(user_set.getNcaPart2Path().var); obj.setPartition2ExtractPath(user_set.getNcaPart2Path().get());
if (user_set.getNcaPart3Path().isSet) if (user_set.getNcaPart3Path().isSet())
obj.setPartition3ExtractPath(user_set.getNcaPart3Path().var); obj.setPartition3ExtractPath(user_set.getNcaPart3Path().get());
obj.setListFs(user_set.isListFs()); obj.setListFs(user_set.isListFs());
obj.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_META) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_META)
{ {
MetaProcess obj; MetaProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setKeyCfg(user_set.getKeyCfg()); obj.setKeyCfg(set.opt.keybag);
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
obj.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_CNMT) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_CNMT)
{ {
CnmtProcess obj; CnmtProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
obj.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_NSO) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_NSO)
{ {
NsoProcess obj; NsoProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
obj.setIs64BitInstruction(user_set.getIs64BitInstruction()); obj.setIs64BitInstruction(user_set.getIs64BitInstruction());
obj.setListApi(user_set.isListApi()); obj.setListApi(user_set.isListApi());
@ -147,111 +134,162 @@ int main(int argc, char** argv)
obj.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_NRO) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_NRO)
{ {
NroProcess obj; NroProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
obj.setIs64BitInstruction(user_set.getIs64BitInstruction()); obj.setIs64BitInstruction(user_set.getIs64BitInstruction());
obj.setListApi(user_set.isListApi()); obj.setListApi(user_set.isListApi());
obj.setListSymbols(user_set.isListSymbols()); obj.setListSymbols(user_set.isListSymbols());
if (user_set.getAssetIconPath().isSet) if (user_set.getAssetIconPath().isSet())
obj.setAssetIconExtractPath(user_set.getAssetIconPath().var); obj.setAssetIconExtractPath(user_set.getAssetIconPath().get());
if (user_set.getAssetNacpPath().isSet) if (user_set.getAssetNacpPath().isSet())
obj.setAssetNacpExtractPath(user_set.getAssetNacpPath().var); obj.setAssetNacpExtractPath(user_set.getAssetNacpPath().get());
if (user_set.getFsPath().isSet) if (user_set.getFsPath().isSet())
obj.setAssetRomfsExtractPath(user_set.getFsPath().var); obj.setAssetRomfsExtractPath(user_set.getFsPath().get());
obj.setAssetListFs(user_set.isListFs()); obj.setAssetListFs(user_set.isListFs());
obj.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_NACP) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_NACP)
{ {
NacpProcess obj; NacpProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
obj.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_INI) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_INI)
{ {
IniProcess obj; IniProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
if (user_set.getKipExtractPath().isSet) if (user_set.getKipExtractPath().isSet())
obj.setKipExtractPath(user_set.getKipExtractPath().var); obj.setKipExtractPath(user_set.getKipExtractPath().get());
obj.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_KIP) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_KIP)
{ {
KipProcess obj; KipProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
obj.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_PKI_CERT) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_PKI_CERT)
{ {
PkiCertProcess obj; PkiCertProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setKeyCfg(user_set.getKeyCfg()); obj.setKeyCfg(set.opt.keybag);
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
obj.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_ES_TIK) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_ES_TIK)
{ {
EsTikProcess obj; EsTikProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setKeyCfg(user_set.getKeyCfg()); obj.setKeyCfg(set.opt.keybag);
obj.setCertificateChain(user_set.getCertificateChain()); obj.setCertificateChain(user_set.getCertificateChain());
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
obj.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_HB_ASSET) else if (set.infile.filetype == nstool::Settings::FILE_TYPE_HB_ASSET)
{ {
AssetProcess obj; AssetProcess obj;
obj.setInputFile(inputFile); obj.setInputFile(infile_stream);
obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(set.opt.verify);
if (user_set.getAssetIconPath().isSet) if (user_set.getAssetIconPath().isSet())
obj.setIconExtractPath(user_set.getAssetIconPath().var); obj.setIconExtractPath(user_set.getAssetIconPath().get());
if (user_set.getAssetNacpPath().isSet) if (user_set.getAssetNacpPath().isSet())
obj.setNacpExtractPath(user_set.getAssetNacpPath().var); obj.setNacpExtractPath(user_set.getAssetNacpPath().get());
if (user_set.getFsPath().isSet) if (user_set.getFsPath().isSet())
obj.setRomfsExtractPath(user_set.getFsPath().var); obj.setRomfsExtractPath(user_set.getFsPath().get());
obj.setListFs(user_set.isListFs()); obj.setListFs(user_set.isListFs());
obj.process(); 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) { catch (tc::Exception& e)
printf("\n\n%s\n", e.what()); {
fmt::print("[{0}{1}ERROR] {2}\n", e.module(), (strlen(e.module()) != 0 ? " ": ""), e.error());
return 1;
} }
return 0; return 0;
} }

26
src/types.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include <tc/types.h>
#include <tc/Optional.h>
#include <tc/io.h>
#include <tc/io/IOUtil.h>
#include <tc/cli.h>
#include <fmt/core.h>
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)
{}
};
}

100
src/util.cpp Normal file
View file

@ -0,0 +1,100 @@
#include "util.h"
#include <tc/io/FileStream.h>
#include <tc/io/SubStream.h>
#include <tc/io/IOUtil.h>
#include <sstream>
#include <algorithm>
#include <iostream>
inline bool isNotPrintable(char chr) { return isprint(chr) == false; }
void nstool::processResFile(const std::shared_ptr<tc::io::IStream>& file, std::map<std::string, std::string>& 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<tc::io::IStream>& 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>(tc::io::SubStream(in_stream, offset, length)), std::make_shared<tc::io::FileStream>(tc::io::FileStream(out_path, tc::io::FileAccess::OpenOrCreate, tc::io::FileMode::Write)), cache_size);
}
void nstool::writeStreamToFile(const std::shared_ptr<tc::io::IStream>& in_stream, const tc::io::Path& out_path, size_t cache_size)
{
writeStreamToStream(in_stream, std::make_shared<tc::io::FileStream>(tc::io::FileStream(out_path, tc::io::FileAccess::OpenOrCreate, tc::io::FileMode::Write)), cache_size);
}
void nstool::writeStreamToStream(const std::shared_ptr<tc::io::IStream>& in_stream, const std::shared_ptr<tc::io::IStream>& 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);
}
}

13
src/util.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include "types.h"
namespace nstool
{
void processResFile(const std::shared_ptr<tc::io::IStream>& file, std::map<std::string, std::string>& dict);
void writeSubStreamToFile(const std::shared_ptr<tc::io::IStream>& 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<tc::io::IStream>& in_stream, const tc::io::Path& out_path, size_t cache_size = 0x10000);
void writeStreamToStream(const std::shared_ptr<tc::io::IStream>& in_stream, const std::shared_ptr<tc::io::IStream>& out_stream, size_t cache_size = 0x10000);
}

View file

@ -2,6 +2,6 @@
#define APP_NAME "NSTool" #define APP_NAME "NSTool"
#define BIN_NAME "nstool" #define BIN_NAME "nstool"
#define VER_MAJOR 1 #define VER_MAJOR 1
#define VER_MINOR 4 #define VER_MINOR 6
#define VER_PATCH 1 #define VER_PATCH 0
#define AUTHORS "jakcron" #define AUTHORS "jakcron"