private (Nca Main, Nca patch, Nca Control) GetXciGameData(Xci xci) { if (!xci.HasPartition(XciPartitionType.Secure)) { throw new InvalidDataException("Could not find XCI secure partition"); } Nca mainNca = null; Nca patchNca = null; Nca controlNca = null; XciPartition securePartition = xci.OpenPartition(XciPartitionType.Secure); foreach (DirectoryEntry ticketEntry in securePartition.EnumerateEntries("*.tik")) { Ticket ticket = new Ticket(securePartition.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream()); if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId)) { KeySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(KeySet)); } } foreach (DirectoryEntry fileEntry in securePartition.EnumerateEntries("*.nca")) { IStorage ncaStorage = securePartition.OpenFile(fileEntry.FullPath, OpenMode.Read).AsStorage(); Nca nca = new Nca(KeySet, ncaStorage); if (nca.Header.ContentType == ContentType.Program) { int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, ContentType.Program); if (nca.Header.GetFsHeader(dataIndex).IsPatchSection()) { patchNca = nca; } else { mainNca = nca; } } else if (nca.Header.ContentType == ContentType.Control) { controlNca = nca; } } if (mainNca == null) { Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided XCI file"); } if (controlNca != null) { ReadControlData(controlNca); } return(mainNca, patchNca, controlNca); }
private static Nca GetXciMainNca(Xci xci, Context ctx) { XciPartition partition = xci.OpenPartition(XciPartitionType.Secure); if (partition == null) { ctx.Logger.LogMessage("Could not find secure partition"); return(null); } Nca mainNca = null; foreach (PartitionFileEntry fileEntry in partition.Files.Where(x => x.Name.EndsWith(".nca"))) { IStorage ncaStorage = partition.OpenFile(fileEntry, OpenMode.Read).AsStorage(); var nca = new Nca(ctx.Keyset, ncaStorage); if (nca.Header.ContentType == NcaContentType.Program) { mainNca = nca; } } return(mainNca); }
static void Main(string[] args) { Console.Title = "XCIRepacker v0.1 by Ac_K"; Console.WriteLine(Environment.NewLine + " XCIRepacker v0.1 by Ac_K" + Environment.NewLine + Environment.NewLine + " Provide with the courtesy of the mob." + Environment.NewLine + Environment.NewLine + "---------------------------------------" + Environment.NewLine); if (args.Length == 1) { Keyset keySet = OpenKeyset(); if (keySet != null) { if (File.Exists(args[0])) { try { Xci xciFile = new Xci(keySet, new LocalStorage(args[0], FileAccess.Read)); if (xciFile.HasPartition(XciPartitionType.Secure)) { XciPartition xciPartition = xciFile.OpenPartition(XciPartitionType.Root); IFile ncaStorage = xciPartition.OpenFile("secure", OpenMode.Read); string outputPath = Path.GetDirectoryName(args[0]) + Path.GetFileNameWithoutExtension(args[0]) + ".nsp"; Console.WriteLine($" Input File Path: {args[0]}"); Console.WriteLine($" Output File Path: {outputPath}" + Environment.NewLine); using (Stream dataInput = ncaStorage.AsStream()) using (FileStream fileOutput = new FileStream(outputPath, FileMode.Create, FileAccess.ReadWrite)) using (BinaryReader reader = new BinaryReader(fileOutput)) using (BinaryWriter writer = new BinaryWriter(fileOutput)) { int bytesRead = -1; long totalReads = 0; long totalBytes = dataInput.Length; byte[] bytes = new byte[_bufferSize]; Console.WriteLine(" Extracting Secure partition..." + Environment.NewLine); while ((bytesRead = dataInput.Read(bytes, 0, _bufferSize)) > 0) { fileOutput.Write(bytes, 0, bytesRead); totalReads += bytesRead; DrawTextProgressBar(totalReads, totalBytes); } Console.WriteLine(Environment.NewLine + Environment.NewLine + " Secure partition extracted!" + Environment.NewLine + Environment.NewLine + "---------------------------------------" + Environment.NewLine); Console.Write(" Patching HFS0 Header to PFS0..."); fileOutput.Position = 0; string Magic = Encoding.ASCII.GetString(reader.ReadBytes(0x04)); if (Magic == "HFS0") { fileOutput.Seek(0x00, SeekOrigin.Begin); writer.Write(new byte[] { 0x50, 0x46, 0x53, 0x30 }); // PFS0 int filesNumber = reader.ReadInt32(); // Skip write files number because is at same offset int filesNamesSize = reader.ReadInt32(); reader.ReadInt32(); // Skip reserved long HFS0HeaderSize = filesNamesSize + 0x10; for (int i = 0; i < filesNumber; i++) { fileOutput.Seek((i * 0x40) + 0x10, SeekOrigin.Begin); long fileOffset = reader.ReadInt64(); long fileSize = reader.ReadInt64(); int fileNameOffset = reader.ReadInt32(); int hashedSize = reader.ReadInt32(); reader.ReadInt64(); // reserved reader.ReadBytes(0x20); HFS0HeaderSize += 0x40; fileOutput.Seek((i * 0x18) + 0x10, SeekOrigin.Begin); writer.Write(fileOffset); writer.Write(fileSize); writer.Write(fileNameOffset); writer.Write(0x00); // reserved } long endPatchedHeader = fileOutput.Position; fileOutput.Seek((4 * 0x40) + 0x10, SeekOrigin.Begin); byte[] filesNamesTable = reader.ReadBytes(filesNamesSize); fileOutput.Seek(endPatchedHeader, SeekOrigin.Begin); writer.Write(filesNamesTable); int shiftSize = (int)(HFS0HeaderSize - fileOutput.Position); writer.Write(new byte[shiftSize]); fileOutput.Seek(0x08, SeekOrigin.Begin); writer.Write(filesNamesSize + shiftSize); Console.WriteLine(" Done!"); } else { Console.WriteLine(" ERROR: Extracted file isn't HFS0!"); } } } } catch (Exception ex) { Console.WriteLine($" ERROR: {ex.Message}"); } } else { Console.WriteLine(" ERROR: XCI file not found!"); } } else { Console.WriteLine(" ERROR: Keys file not found!"); } } else { Console.WriteLine(" USAGE: XCIRepacker.exe \"PathOfFile.xci\""); } Console.ReadKey(); }
public static void Process(Context ctx) { using (var file = new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.Read)) { var xci = new Xci(ctx.Keyset, file.AsStorage()); ctx.Logger.LogMessage(xci.Print()); if (ctx.Options.RootDir != null) { xci.RootPartition?.Extract(ctx.Options.RootDir, ctx.Logger); } if (ctx.Options.UpdateDir != null) { xci.UpdatePartition?.Extract(ctx.Options.UpdateDir, ctx.Logger); } if (ctx.Options.NormalDir != null) { xci.NormalPartition?.Extract(ctx.Options.NormalDir, ctx.Logger); } if (ctx.Options.SecureDir != null) { xci.SecurePartition?.Extract(ctx.Options.SecureDir, ctx.Logger); } if (ctx.Options.LogoDir != null) { xci.LogoPartition?.Extract(ctx.Options.LogoDir, ctx.Logger); } if (ctx.Options.OutDir != null && xci.RootPartition != null) { XciPartition root = xci.RootPartition; if (root == null) { ctx.Logger.LogMessage("Could not find root partition"); return; } foreach (PfsFileEntry sub in root.Files) { var subPfs = new Pfs(root.OpenFile(sub)); string subDir = Path.Combine(ctx.Options.OutDir, sub.Name); subPfs.Extract(subDir, ctx.Logger); } } if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null) { Nca mainNca = GetXciMainNca(xci, ctx); if (mainNca == null) { ctx.Logger.LogMessage("Could not find Program NCA"); return; } NcaSection exefsSection = mainNca.Sections[(int)ProgramPartitionType.Code]; if (exefsSection == null) { ctx.Logger.LogMessage("NCA has no ExeFS section"); return; } if (ctx.Options.ExefsOutDir != null) { mainNca.ExtractSection(exefsSection.SectionNum, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger); } if (ctx.Options.ExefsOut != null) { mainNca.ExportSection(exefsSection.SectionNum, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger); } } if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null) { Nca mainNca = GetXciMainNca(xci, ctx); if (mainNca == null) { ctx.Logger.LogMessage("Could not find Program NCA"); return; } NcaSection romfsSection = mainNca.Sections.FirstOrDefault(x => x.Type == SectionType.Romfs); if (romfsSection == null) { ctx.Logger.LogMessage("NCA has no RomFS section"); return; } if (ctx.Options.RomfsOutDir != null) { var romfs = new Romfs(mainNca.OpenSection(romfsSection.SectionNum, false, ctx.Options.IntegrityLevel, true)); romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger); } if (ctx.Options.RomfsOut != null) { mainNca.ExportSection(romfsSection.SectionNum, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger); } } } }
public static void Process(Context ctx) { using (var file = new LocalStorage(ctx.Options.InFile, FileAccess.Read)) { var xci = new Xci(ctx.Keyset, file); ctx.Logger.LogMessage(xci.Print()); if (ctx.Options.RootDir != null) { xci.OpenPartition(XciPartitionType.Root).Extract(ctx.Options.RootDir, ctx.Logger); } if (ctx.Options.UpdateDir != null && xci.HasPartition(XciPartitionType.Update)) { xci.OpenPartition(XciPartitionType.Update).Extract(ctx.Options.UpdateDir, ctx.Logger); } if (ctx.Options.NormalDir != null && xci.HasPartition(XciPartitionType.Normal)) { xci.OpenPartition(XciPartitionType.Normal).Extract(ctx.Options.NormalDir, ctx.Logger); } if (ctx.Options.SecureDir != null && xci.HasPartition(XciPartitionType.Secure)) { xci.OpenPartition(XciPartitionType.Secure).Extract(ctx.Options.SecureDir, ctx.Logger); } if (ctx.Options.LogoDir != null && xci.HasPartition(XciPartitionType.Logo)) { xci.OpenPartition(XciPartitionType.Logo).Extract(ctx.Options.LogoDir, ctx.Logger); } if (ctx.Options.OutDir != null) { XciPartition root = xci.OpenPartition(XciPartitionType.Root); if (root == null) { ctx.Logger.LogMessage("Could not find root partition"); return; } foreach (PartitionFileEntry sub in root.Files) { var subPfs = new PartitionFileSystem(root.OpenFile(sub, OpenMode.Read).AsStorage()); string subDir = Path.Combine(ctx.Options.OutDir, sub.Name); subPfs.Extract(subDir, ctx.Logger); } } if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null) { Nca mainNca = GetXciMainNca(xci, ctx); if (mainNca == null) { ctx.Logger.LogMessage("Could not find Program NCA"); return; } if (!mainNca.SectionExists(NcaSectionType.Code)) { ctx.Logger.LogMessage("NCA has no ExeFS section"); return; } if (ctx.Options.ExefsOutDir != null) { mainNca.ExtractSection(NcaSectionType.Code, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger); } if (ctx.Options.ExefsOut != null) { mainNca.ExportSection(NcaSectionType.Code, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger); } } if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null || ctx.Options.ListRomFs) { Nca mainNca = GetXciMainNca(xci, ctx); if (mainNca == null) { ctx.Logger.LogMessage("Could not find Program NCA"); return; } if (!mainNca.SectionExists(NcaSectionType.Data)) { ctx.Logger.LogMessage("NCA has no RomFS section"); return; } ProcessRomfs.Process(ctx, mainNca.OpenStorage(NcaSectionType.Data, ctx.Options.IntegrityLevel, false)); } } }