Extract ExeFS and RomFS for more input types

This commit is contained in:
Alex Barney 2018-08-22 15:36:06 -05:00
parent dce63507d1
commit 8433b2c91a
2 changed files with 132 additions and 33 deletions

View file

@ -156,7 +156,10 @@ namespace hactoolnet
sb.AppendLine(" --section1dir <dir> Specify Section 1 directory path."); sb.AppendLine(" --section1dir <dir> Specify Section 1 directory path.");
sb.AppendLine(" --section2dir <dir> Specify Section 2 directory path."); sb.AppendLine(" --section2dir <dir> Specify Section 2 directory path.");
sb.AppendLine(" --section3dir <dir> Specify Section 3 directory path."); sb.AppendLine(" --section3dir <dir> Specify Section 3 directory path.");
sb.AppendLine(" --romfsdir <dir> Specify main RomFS directory path."); sb.AppendLine(" --exefs <file> Specify ExeFS directory path.");
sb.AppendLine(" --exefsdir <dir> Specify ExeFS directory path.");
sb.AppendLine(" --romfs <file> Specify RomFS directory path.");
sb.AppendLine(" --romfsdir <dir> Specify RomFS directory path.");
sb.AppendLine(" --listromfs List files in RomFS."); sb.AppendLine(" --listromfs List files in RomFS.");
sb.AppendLine(" --basenca Set Base NCA to use with update partitions."); sb.AppendLine(" --basenca Set Base NCA to use with update partitions.");
sb.AppendLine("XCI options:"); sb.AppendLine("XCI options:");
@ -166,13 +169,19 @@ namespace hactoolnet
sb.AppendLine(" --securedir <dir> Specify secure XCI directory path."); sb.AppendLine(" --securedir <dir> Specify secure XCI directory path.");
sb.AppendLine(" --logodir <dir> Specify logo XCI directory path."); sb.AppendLine(" --logodir <dir> Specify logo XCI directory path.");
sb.AppendLine(" --outdir <dir> Specify XCI directory path."); sb.AppendLine(" --outdir <dir> Specify XCI directory path.");
sb.AppendLine(" --exefs <file> Specify main ExeFS file path.");
sb.AppendLine(" --exefsdir <dir> Specify main ExeFS directory path.");
sb.AppendLine(" --romfs <file> Specify main RomFS file path.");
sb.AppendLine(" --romfsdir <dir> Specify main RomFS directory path."); sb.AppendLine(" --romfsdir <dir> Specify main RomFS directory path.");
sb.AppendLine("Switch FS options:"); sb.AppendLine("Switch FS options:");
sb.AppendLine(" --sdseed <seed> Set console unique seed for SD card NAX0 encryption."); sb.AppendLine(" --sdseed <seed> Set console unique seed for SD card NAX0 encryption.");
sb.AppendLine(" --listapps List application info."); sb.AppendLine(" --listapps List application info.");
sb.AppendLine(" --listtitles List title info for all titles."); sb.AppendLine(" --listtitles List title info for all titles.");
sb.AppendLine(" --title <title id> Specify title ID to use."); sb.AppendLine(" --title <title id> Specify title ID to use.");
sb.AppendLine(" --outdir <dir> Specify directory path to save title to. (--title must be specified)"); sb.AppendLine(" --outdir <dir> Specify directory path to save title NCAs to. (--title must be specified)");
sb.AppendLine(" --exefs <file> Specify ExeFS directory path. (--title must be specified)");
sb.AppendLine(" --exefsdir <dir> Specify ExeFS directory path. (--title must be specified)");
sb.AppendLine(" --romfs <file> Specify RomFS directory path. (--title must be specified)");
sb.AppendLine(" --romfsdir <dir> Specify RomFS directory path. (--title must be specified)"); sb.AppendLine(" --romfsdir <dir> Specify RomFS directory path. (--title must be specified)");
sb.AppendLine("Savefile options:"); sb.AppendLine("Savefile options:");
sb.AppendLine(" --outdir <dir> Specify directory path to save contents to."); sb.AppendLine(" --outdir <dir> Specify directory path to save contents to.");

View file

@ -95,7 +95,7 @@ namespace hactoolnet
} }
} }
if (ctx.Options.RomfsOutDir != null) if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null)
{ {
NcaSection section = nca.Sections.FirstOrDefault(x => x.Type == SectionType.Romfs || x.Type == SectionType.Bktr); NcaSection section = nca.Sections.FirstOrDefault(x => x.Type == SectionType.Romfs || x.Type == SectionType.Bktr);
@ -105,27 +105,25 @@ namespace hactoolnet
return; return;
} }
if (section.Type == SectionType.Bktr) if (section.Type == SectionType.Bktr && ctx.Options.BaseNca == null)
{ {
if (ctx.Options.BaseNca == null) ctx.Logger.LogMessage("Cannot save BKTR section without base RomFS");
{ return;
ctx.Logger.LogMessage("Cannot save BKTR section without base RomFS");
return;
}
var bktr = nca.OpenSection(1, false);
var romfs = new Romfs(bktr);
romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger);
} }
else
if (ctx.Options.RomfsOut != null)
{
nca.ExportSection(section.SectionNum, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Logger);
}
if (ctx.Options.RomfsOutDir != null)
{ {
var romfs = new Romfs(nca.OpenSection(section.SectionNum, false)); var romfs = new Romfs(nca.OpenSection(section.SectionNum, false));
romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger); romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger);
} }
} }
if (ctx.Options.ExefsOutDir != null) if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null)
{ {
NcaSection section = nca.Sections.FirstOrDefault(x => x.IsExefs); NcaSection section = nca.Sections.FirstOrDefault(x => x.IsExefs);
@ -135,7 +133,15 @@ namespace hactoolnet
return; return;
} }
nca.ExtractSection(section.SectionNum, ctx.Options.ExefsOutDir, ctx.Logger); if (ctx.Options.ExefsOut != null)
{
nca.ExportSection(section.SectionNum, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Logger);
}
if (ctx.Options.ExefsOutDir != null)
{
nca.ExtractSection(section.SectionNum, ctx.Options.ExefsOutDir, ctx.Logger);
}
} }
ctx.Logger.LogMessage(nca.Dump()); ctx.Logger.LogMessage(nca.Dump());
@ -156,7 +162,47 @@ namespace hactoolnet
ctx.Logger.LogMessage(ListApplications(switchFs)); ctx.Logger.LogMessage(ListApplications(switchFs));
} }
if (ctx.Options.RomfsOutDir != null) if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null)
{
var id = ctx.Options.TitleId;
if (id == 0)
{
ctx.Logger.LogMessage("Title ID must be specified to dump ExeFS");
return;
}
if (!switchFs.Titles.TryGetValue(id, out var title))
{
ctx.Logger.LogMessage($"Could not find title {id:X16}");
return;
}
if (title.MainNca == null)
{
ctx.Logger.LogMessage($"Could not find main data for title {id:X16}");
return;
}
var section = title.MainNca.Sections.FirstOrDefault(x => x.IsExefs == true);
if (section == null)
{
ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no ExeFS section");
return;
}
if (ctx.Options.ExefsOutDir != null)
{
title.MainNca.ExtractSection(section.SectionNum, ctx.Options.ExefsOutDir, ctx.Logger);
}
if (ctx.Options.ExefsOut != null)
{
title.MainNca.ExportSection(section.SectionNum, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Logger);
}
}
if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null)
{ {
var id = ctx.Options.TitleId; var id = ctx.Options.TitleId;
if (id == 0) if (id == 0)
@ -181,12 +227,20 @@ namespace hactoolnet
if (section == null) if (section == null)
{ {
ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no Rom FS section"); ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no RomFS section");
return; return;
} }
var romfs = new Romfs(title.MainNca.OpenSection(section.SectionNum, false)); if (ctx.Options.RomfsOutDir != null)
romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger); {
var romfs = new Romfs(title.MainNca.OpenSection(section.SectionNum, false));
romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger);
}
if (ctx.Options.RomfsOut != null)
{
title.MainNca.ExportSection(section.SectionNum, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Logger);
}
} }
if (ctx.Options.OutDir != null) if (ctx.Options.OutDir != null)
@ -249,27 +303,39 @@ namespace hactoolnet
} }
} }
if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null) if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null)
{ {
if (xci.SecurePartition == null) var mainNca = GetXciMainNca(xci, ctx);
if (mainNca == null)
{ {
ctx.Logger.LogMessage("Could not find secure partition"); ctx.Logger.LogMessage("Could not find Program NCA");
return; return;
} }
Nca mainNca = null; var exefsSection = mainNca.Sections.FirstOrDefault(x => x.IsExefs == true);
foreach (var fileEntry in xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".nca"))) if (exefsSection == null)
{ {
var ncaStream = xci.SecurePartition.OpenFile(fileEntry); ctx.Logger.LogMessage("NCA has no ExeFS section");
var nca = new Nca(ctx.Keyset, ncaStream, true); return;
if (nca.Header.ContentType == ContentType.Program)
{
mainNca = nca;
}
} }
if (ctx.Options.ExefsOutDir != null)
{
mainNca.ExtractSection(exefsSection.SectionNum, ctx.Options.ExefsOutDir, ctx.Logger);
}
if (ctx.Options.ExefsOut != null)
{
mainNca.ExportSection(exefsSection.SectionNum, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Logger);
}
}
if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null)
{
var mainNca = GetXciMainNca(xci, ctx);
if (mainNca == null) if (mainNca == null)
{ {
ctx.Logger.LogMessage("Could not find Program NCA"); ctx.Logger.LogMessage("Could not find Program NCA");
@ -298,6 +364,30 @@ namespace hactoolnet
} }
} }
private static Nca GetXciMainNca(Xci xci, Context ctx)
{
if (xci.SecurePartition == null)
{
ctx.Logger.LogMessage("Could not find secure partition");
return null;
}
Nca mainNca = null;
foreach (var fileEntry in xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".nca")))
{
var ncaStream = xci.SecurePartition.OpenFile(fileEntry);
var nca = new Nca(ctx.Keyset, ncaStream, true);
if (nca.Header.ContentType == ContentType.Program)
{
mainNca = nca;
}
}
return mainNca;
}
private static void OpenKeyset(Context ctx) private static void OpenKeyset(Context ctx)
{ {
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);