mirror of
https://github.com/jakcron/nstool.git
synced 2024-12-22 10:45:28 +00:00
Begin migration from libfnd to libtoolchain
This commit is contained in:
parent
6bc4cd8a8c
commit
60acda6615
|
@ -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}
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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
2
deps/libfnd
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit b6a74e03d2c3fb272e900f32554b2cc0d18e7d26
|
Subproject commit 27705aeb2394dbe21f580cc742792537e3a0cbed
|
2
deps/liblz4
vendored
2
deps/liblz4
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 298f2ecfa6c966472eda9a4f2b93121a060d1867
|
Subproject commit 555e43086b348a640179ddf2ecd86d8503c12b85
|
2
deps/libmbedtls
vendored
2
deps/libmbedtls
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 30ef43f1d6ef00d9d94e19270ae8b646e821ecc7
|
Subproject commit 597bb57271177d776682104dc7c8ea8b62670d1d
|
2
deps/libnintendo-es
vendored
2
deps/libnintendo-es
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit f96b4f96552da4258f4212427137d6ff40c45392
|
Subproject commit 7572682f1fa819fd7ef1a4b639cb14fa67128f0d
|
2
deps/libnintendo-hac
vendored
2
deps/libnintendo-hac
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 33cfca799ccdcc4c34f73696da9fe31f104dd23f
|
Subproject commit 02c6703c9720d98197b3bb697fdab12008a9829e
|
2
deps/libnintendo-hac-hb
vendored
2
deps/libnintendo-hac-hb
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit db9af77ec23d170ec703a13cd5cd9b67cd47d3a3
|
Subproject commit e52fb0e1ebc558f68bb438bd278b05704c5aaeb3
|
2
deps/libnintendo-pki
vendored
2
deps/libnintendo-pki
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 040405bc6f9936e4e61c80b5ab384b3d95c395cd
|
Subproject commit b8a10663a99f7b5fedf11139549e8bf1b289c0e0
|
2
deps/libtoolchain
vendored
2
deps/libtoolchain
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 0be82cf582b4af7539f57a261e17e5769f4f8cfa
|
Subproject commit 7948f581d32ebbfdf5a872b96c37938690f665e7
|
20
makefile
20
makefile
|
@ -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)";)
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
};
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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
568
src/KeyBag.cpp
Normal 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
76
src/KeyBag.h
Normal 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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())
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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())
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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
819
src/Settings.cpp
Normal 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
155
src/Settings.h
Normal 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
1086
src/UserSettings.cpp
1086
src/UserSettings.cpp
File diff suppressed because it is too large
Load diff
|
@ -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;
|
|
||||||
};
|
|
62
src/common.h
62
src/common.h
|
@ -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
458
src/elf.h
Normal 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 */
|
||||||
|
};
|
||||||
|
}
|
254
src/main.cpp
254
src/main.cpp
|
@ -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
26
src/types.h
Normal 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
100
src/util.cpp
Normal 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
13
src/util.h
Normal 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);
|
||||||
|
|
||||||
|
}
|
|
@ -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"
|
Loading…
Reference in a new issue