public void LoadNsp(string nspFile) { FileStream file = new FileStream(nspFile, FileMode.Open, FileAccess.Read); Pfs nsp = new Pfs(file); PfsFileEntry ticketFile = nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik")); // Load title key from the NSP's ticket in case the user doesn't have a title key file if (ticketFile != null) { Ticket ticket = new Ticket(nsp.OpenFile(ticketFile)); KeySet.TitleKeys[ticket.RightsId] = ticket.GetTitleKey(KeySet); } Nca mainNca = null; Nca controlNca = null; foreach (PfsFileEntry ncaFile in nsp.Files.Where(x => x.Name.EndsWith(".nca"))) { Nca nca = new Nca(KeySet, nsp.OpenFile(ncaFile), true); if (nca.Header.ContentType == ContentType.Program) { mainNca = nca; } else if (nca.Header.ContentType == ContentType.Control) { controlNca = nca; } } if (mainNca != null) { LoadNca(mainNca, controlNca); return; } Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided NSP file"); }
private void ImportTitleKeysFromNsp(Pfs nsp, Keyset keySet) { foreach (PfsFileEntry ticketEntry in nsp.Files.Where(x => x.Name.EndsWith(".tik"))) { Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry).AsStream()); if (!keySet.TitleKeys.ContainsKey(ticket.RightsId)) { keySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(keySet)); } } }
public void Load(System.IO.Stream stream) { var Keys = Forms.SwitchKeySelectionForm.ShowKeySelector(); if (Keys == null) { throw new Exception("Failed to get keys. Please select valid paths!"); } Xci xci = new Xci(Keys, stream.AsStorage()); var CnmtNca = new Nca(Keys, xci.SecurePartition.OpenFile( xci.SecurePartition.Files.FirstOrDefault(s => s.Name.Contains(".cnmt.nca"))), false); var CnmtPfs = new Pfs(CnmtNca.OpenSection(0, false, IntegrityCheckLevel.None, true)); var Cnmt = new Cnmt(CnmtPfs.OpenFile(CnmtPfs.Files[0]).AsStream()); foreach (var entry in Cnmt.ContentEntries) { if (entry.Type == CnmtContentType.Program) { var Program = entry; string ncaFileName = $"{Program.NcaId.ToHexString().ToLower()}.nca"; Stream Input = xci.SecurePartition.OpenFile(ncaFileName).AsStream(); var Nca = new Nca(Keys, Input.AsStorage(), true); string root = Nca.Header.TitleId.ToString("X"); Romfs romfs = new Romfs( Nca.OpenSection(Nca.Sections.FirstOrDefault (s => s?.Type == SectionType.Romfs || s?.Type == SectionType.Bktr) .SectionNum, false, IntegrityCheckLevel.None, true)); if (Nca.CanOpenSection((int)ProgramPartitionType.Code)) { var exefs = new Pfs(Nca.OpenSection((int)ProgramPartitionType.Code, false, IntegrityCheckLevel.None, true)); foreach (var file in exefs.Files) { files.Add(new NSP.ExefsEntry(exefs, file, root)); } } for (int i = 0; i < romfs.Files.Count; i++) { files.Add(new NSP.FileEntry(romfs, romfs.Files[i], root)); } } } }
private long OpenFileSystemFromInternalFile(ServiceCtx Context, string FullPath) { DirectoryInfo ArchivePath = new DirectoryInfo(FullPath).Parent; while (string.IsNullOrWhiteSpace(ArchivePath.Extension)) { ArchivePath = ArchivePath.Parent; } if (ArchivePath.Extension == ".nsp" && File.Exists(ArchivePath.FullName)) { FileStream PfsFile = new FileStream( ArchivePath.FullName.TrimEnd(Path.DirectorySeparatorChar), FileMode.Open, FileAccess.Read); Pfs Nsp = new Pfs(PfsFile); PfsFileEntry TicketFile = Nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik")); if (TicketFile != null) { Ticket Ticket = new Ticket(Nsp.OpenFile(TicketFile)); Context.Device.System.KeySet.TitleKeys[Ticket.RightsId] = Ticket.GetTitleKey(Context.Device.System.KeySet); } string Filename = FullPath.Replace(ArchivePath.FullName, string.Empty).TrimStart('\\'); if (Nsp.FileExists(Filename)) { return(OpenNcaFs(Context, FullPath, Nsp.OpenFile(Filename))); } } return(MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist)); }
private long OpenFileSystemFromInternalFile(ServiceCtx context, string fullPath) { DirectoryInfo archivePath = new DirectoryInfo(fullPath).Parent; while (string.IsNullOrWhiteSpace(archivePath.Extension)) { archivePath = archivePath.Parent; } if (archivePath.Extension == ".nsp" && File.Exists(archivePath.FullName)) { FileStream pfsFile = new FileStream( archivePath.FullName.TrimEnd(Path.DirectorySeparatorChar), FileMode.Open, FileAccess.Read); Pfs nsp = new Pfs(pfsFile); PfsFileEntry ticketFile = nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik")); if (ticketFile != null) { Ticket ticket = new Ticket(nsp.OpenFile(ticketFile)); context.Device.System.KeySet.TitleKeys[ticket.RightsId] = ticket.GetTitleKey(context.Device.System.KeySet); } string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\'); if (nsp.FileExists(filename)) { return(OpenNcaFs(context, fullPath, nsp.OpenFile(filename))); } } return(MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist)); }
public void Load(System.IO.Stream stream) { Text = FileName; string homeFolder = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); string KeyFile = Path.Combine(homeFolder, ".switch", "prod.keys"); string TitleKeyFile = Path.Combine(homeFolder, ".switch", "title.keys"); var Keys = ExternalKeys.ReadKeyFile(KeyFile, TitleKeyFile); Stream Input; var Pfs = new Pfs(stream.AsStorage()); var CnmtNca = new Nca(Keys, Pfs.OpenFile(Pfs.Files.FirstOrDefault(s => s.Name.Contains(".cnmt.nca"))), false); var CnmtPfs = new Pfs(CnmtNca.OpenSection(0, false, IntegrityCheckLevel.None, true)); var Cnmt = new Cnmt(CnmtPfs.OpenFile(CnmtPfs.Files[0]).AsStream()); var Program = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Program); var CtrlEntry = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Control); if (CtrlEntry != null) { Control = new Nca(Keys, Pfs.OpenFile($"{CtrlEntry.NcaId.ToHexString().ToLower()}.nca"), false); } Input = Pfs.OpenFile($"{Program.NcaId.ToHexString().ToLower()}.nca").AsStream(); var Nca = new Nca(Keys, Input.AsStorage(), true); Romfs romfs = new Romfs( Nca.OpenSection(Nca.Sections.FirstOrDefault (s => s?.Type == SectionType.Romfs || s?.Type == SectionType.Bktr) .SectionNum, false, IntegrityCheckLevel.None, true)); romfsWrapper = new RomfsNodeWrapper(); romfsWrapper.romfs = romfs; romfsWrapper.FillTreeNodes(Nodes, romfs.RootDir); }
public long OpenFile(string Name, out IFile FileInterface) { Name = Name.TrimStart('/'); if (Pfs.FileExists(Name)) { Stream Stream = Pfs.OpenFile(Name); FileInterface = new IFile(Stream, Name); return(0); } FileInterface = null; return(MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist)); }
public long OpenFile(string name, out IFile fileInterface) { name = name.TrimStart('/'); if (_pfs.FileExists(name)) { Stream stream = _pfs.OpenFile(name).AsStream(); fileInterface = new IFile(stream, name); return(0); } fileInterface = null; return(MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist)); }
public void Load(System.IO.Stream stream) { var Keys = Forms.SwitchKeySelectionForm.ShowKeySelector(); if (Keys == null) { throw new Exception("Failed to get keys. Please select valid paths!"); } Stream Input; var Pfs = new Pfs(stream.AsStorage()); var CnmtNca = new Nca(Keys, Pfs.OpenFile(Pfs.Files.FirstOrDefault(s => s.Name.Contains(".cnmt.nca"))), false); var CnmtPfs = new Pfs(CnmtNca.OpenSection(0, false, IntegrityCheckLevel.None, true)); var Cnmt = new Cnmt(CnmtPfs.OpenFile(CnmtPfs.Files[0]).AsStream()); var Program = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Program); var CtrlEntry = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Control); if (CtrlEntry != null) { Control = new Nca(Keys, Pfs.OpenFile($"{CtrlEntry.NcaId.ToHexString().ToLower()}.nca"), false); } Input = Pfs.OpenFile($"{Program.NcaId.ToHexString().ToLower()}.nca").AsStream(); var Nca = new Nca(Keys, Input.AsStorage(), true); Romfs romfs = new Romfs( Nca.OpenSection(Nca.Sections.FirstOrDefault (s => s?.Type == SectionType.Romfs || s?.Type == SectionType.Bktr) .SectionNum, false, IntegrityCheckLevel.None, true)); if (Nca.CanOpenSection((int)ProgramPartitionType.Code)) { var exefs = new Pfs(Nca.OpenSection((int)ProgramPartitionType.Code, false, IntegrityCheckLevel.None, true)); foreach (var file in exefs.Files) { files.Add(new ExefsEntry(exefs, file)); } } for (int i = 0; i < romfs.Files.Count; i++) { files.Add(new FileEntry(romfs, romfs.Files[i])); } }
private long OpenNsp(ServiceCtx Context, string PfsPath) { FileStream PfsFile = new FileStream(PfsPath, FileMode.Open, FileAccess.Read); Pfs Nsp = new Pfs(PfsFile); PfsFileEntry TicketFile = Nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik")); if (TicketFile != null) { Ticket Ticket = new Ticket(Nsp.OpenFile(TicketFile)); Context.Device.System.KeySet.TitleKeys[Ticket.RightsId] = Ticket.GetTitleKey(Context.Device.System.KeySet); } IFileSystem NspFileSystem = new IFileSystem(PfsPath, new PFsProvider(Nsp)); MakeObject(Context, NspFileSystem); return(0); }
private long OpenNsp(ServiceCtx context, string pfsPath) { FileStream pfsFile = new FileStream(pfsPath, FileMode.Open, FileAccess.Read); Pfs nsp = new Pfs(pfsFile); PfsFileEntry ticketFile = nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik")); if (ticketFile != null) { Ticket ticket = new Ticket(nsp.OpenFile(ticketFile)); context.Device.System.KeySet.TitleKeys[ticket.RightsId] = ticket.GetTitleKey(context.Device.System.KeySet); } IFileSystem nspFileSystem = new IFileSystem(pfsPath, new PFsProvider(nsp)); MakeObject(context, nspFileSystem); return(0); }
static void Main(string[] args) { Console.WriteLine("Nintendo Switch NSP Verifier v1.00"); Console.WriteLine("Copyright 2018 CaitSith2"); Console.WriteLine(""); _path = args.Length >= 1 ? string.Join(" ", args) : Environment.CurrentDirectory; if (new[] { "--help", "-h" }.Any(x => x.Equals(_path, StringComparison.InvariantCultureIgnoreCase))) { Console.WriteLine("Usage: NSPVerify [path to NSP directory]"); Console.WriteLine(""); Console.WriteLine("If the tool is run without specifying a path, it will look for NSPs in the current directory and ALL sub-directories of current directory"); return; } if (!Directory.Exists(_path)) { Console.WriteLine("ERROR: Specified directory does not exist. specify --help for usage information."); return; } var fs = new FileSystem(_path); var keys = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch", "prod.keys"); if (File.Exists("keys.txt")) { keys = "keys.txt"; } if (!File.Exists(keys)) { Console.WriteLine($"Cannot verify NSPs without keys.txt. Either put it in the same directory as this tool,"); Console.WriteLine($"or place it in \"{Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch")}\" named as prod.keys"); PressAnyKey(); return; } var keyset = ExternalKeys.ReadKeyFile(keys); var badlist = new List <string>(); var exceptionlist = new List <string>(); var files = fs.GetFileSystemEntries("", "*.nsp", SearchOption.AllDirectories).ToList(); files.AddRange(fs.GetFileSystemEntries("", "*.nsx", SearchOption.AllDirectories)); if (files.Count == 0) { Console.WriteLine("Error: No NSP/NSX files in specified directory"); PressAnyKey(); return; } foreach (var file in files) { var filename = Path.GetFileName(file); var relativefilename = Util.GetRelativePath(file, Path.GetFullPath(_path)); Console.Write($"Checking {filename}: "); try { bool ok = true; using (var nspfile = fs.OpenFile(file, FileMode.Open, FileAccess.Read)) { var nspdata = new Pfs(nspfile); var cnmtfile = nspdata.Files.FirstOrDefault(x => x.Name.ToLowerInvariant().EndsWith(".cnmt.nca")); if (cnmtfile == null) { Console.WriteLine($"\rChecking {filename}: No cnmt.nca file present"); badlist.Add(relativefilename); continue; } var cnmtdata = nspdata.OpenFile(cnmtfile); Cnmt cnmt; using (var sr = new BinaryReader(cnmtdata)) { var cnmthash = SHA256.Create().ComputeHash(sr.ReadBytes((int)cnmtdata.Length)); if (!cnmtfile.Name.ToLowerInvariant().Contains(cnmthash.Take(16).ToArray().ToHexString())) { //Put failure here Console.WriteLine($"\rChecking {filename}: cnmt.nca file is corrupted"); badlist.Add(relativefilename); cnmtdata.Dispose(); continue; } cnmtdata.Position = 0; var cnmtnca = new Nca(keyset, cnmtdata, false); var section = cnmtnca.OpenSection(0, false); var sectionpfs = new Pfs(section); cnmt = new Cnmt(sectionpfs.OpenFile(sectionpfs.Files[0])); } foreach (var entry in cnmt.ContentEntries) { var entryfile = nspdata.Files.FirstOrDefault(x => x.Name.ToLowerInvariant().EndsWith(entry.NcaId.ToHexString() + ".nca")); if (entryfile == null) { if (entry.Type != CnmtContentType.UpdatePatch) { //Put failure here Console.WriteLine($"\rChecking {filename}: one of the entries required by the cnmt.nca is missing."); badlist.Add(relativefilename); break; } continue; } using (var entrynca = nspdata.OpenFile(entryfile)) { var hash = SHA256.Create(); using (var sr = new BinaryReader(entrynca)) { while (entrynca.Length != entrynca.Position) { var entryncadata = sr.ReadBytes(0x100000); hash.TransformBlock(entryncadata, 0, entryncadata.Length, entryncadata, 0); Console.Write($"\rChecking {filename}: {((entrynca.Position * 100.0) / entrynca.Length):0.0}%"); } hash.TransformFinalBlock(new byte[0], 0, 0); } if (hash.Hash.ToHexString().Equals(entry.Hash.ToHexString())) { Console.Write($"\rChecking {filename}: {100:0.0}%"); continue; } //Put failure here Console.WriteLine($"\rChecking {filename}: one of the entries required by the cnmt.nca is corrupted"); badlist.Add(relativefilename); ok = false; break; } } if (ok) { Console.WriteLine($"\rChecking {filename}: OK "); } //Put Success here } } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); exceptionlist.Add($"{relativefilename}{Environment.NewLine}Exception: \"{ex.GetType()}\" {ex.Message}{Environment.NewLine}Stack Trace: {ex.StackTrace}{Environment.NewLine}"); } } badlist.Insert(0, badlist.Count == 0 ? "None of the files are corrupted. :)" : "The following NSP/NSX files are corrupted:"); exceptionlist.Insert(0, exceptionlist.Count == 0 ? "No exceptions to log. :)" : "Exceptions caused while parsing the following NSP/NSX files:"); try { File.WriteAllText("Corrupted NSPs.txt", string.Join(Environment.NewLine, badlist)); File.WriteAllText("Exception Log.txt", string.Join(Environment.NewLine, exceptionlist)); } catch (Exception ex) { Console.WriteLine($"Could not write the output files \"Corrupted NSPs.txt\" and \"Exception Log.txt\" due to the following exception."); Console.WriteLine($"Exception: \"{ex.GetType()}\" {ex.Message}"); Console.WriteLine($"Stack Trace: {ex.StackTrace}{Environment.NewLine}"); Console.WriteLine(string.Join(Environment.NewLine, badlist)); Console.WriteLine(); Console.WriteLine(string.Join(Environment.NewLine, exceptionlist)); Console.WriteLine(); } Console.WriteLine("Done."); PressAnyKey(); }
public void LoadNca(Nca mainNca, Nca controlNca) { if (mainNca.Header.ContentType != ContentType.Program) { Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA"); return; } Stream romfsStream = mainNca.OpenSection(ProgramPartitionType.Data, false, FsIntegrityCheckLevel); Stream exefsStream = mainNca.OpenSection(ProgramPartitionType.Code, false, FsIntegrityCheckLevel); if (exefsStream == null) { Logger.PrintError(LogClass.Loader, "No ExeFS found in NCA"); return; } if (romfsStream == null) { Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA"); } else { Device.FileSystem.SetRomFs(romfsStream); } Pfs exefs = new Pfs(exefsStream); Npdm metaData = null; if (exefs.FileExists("main.npdm")) { Logger.PrintInfo(LogClass.Loader, "Loading main.npdm..."); metaData = new Npdm(exefs.OpenFile("main.npdm")); } else { Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!"); metaData = GetDefaultNpdm(); } List <IExecutable> staticObjects = new List <IExecutable>(); void LoadNso(string filename) { foreach (PfsFileEntry file in exefs.Files.Where(x => x.Name.StartsWith(filename))) { if (Path.GetExtension(file.Name) != string.Empty) { continue; } Logger.PrintInfo(LogClass.Loader, $"Loading {filename}..."); NxStaticObject staticObject = new NxStaticObject(exefs.OpenFile(file)); staticObjects.Add(staticObject); } } Nacp ReadControlData() { Romfs controlRomfs = new Romfs(controlNca.OpenSection(0, false, FsIntegrityCheckLevel)); byte[] controlFile = controlRomfs.GetFile("/control.nacp"); BinaryReader reader = new BinaryReader(new MemoryStream(controlFile)); Nacp controlData = new Nacp(reader); CurrentTitle = controlData.Languages[(int)State.DesiredTitleLanguage].Title; if (string.IsNullOrWhiteSpace(CurrentTitle)) { CurrentTitle = controlData.Languages.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title; } return(controlData); } if (controlNca != null) { ReadControlData(); } else { CurrentTitle = metaData.Aci0.TitleId.ToString("x16"); } if (!metaData.Is64Bits) { throw new NotImplementedException("32-bit titles are not supported!"); } LoadNso("rtld"); LoadNso("main"); LoadNso("subsdk"); LoadNso("sdk"); ContentManager.LoadEntries(); ProgramLoader.LoadStaticObjects(this, metaData, staticObjects.ToArray()); }
public void LoadNsp(string nspFile) { FileStream file = new FileStream(nspFile, FileMode.Open, FileAccess.Read); Pfs nsp = new Pfs(file.AsStorage(false)); foreach (PfsFileEntry ticketEntry in nsp.Files.Where(x => x.Name.EndsWith(".tik"))) { Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry).AsStream()); if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId)) { KeySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(KeySet)); } } Nca mainNca = null; Nca controlNca = null; foreach (PfsFileEntry ncaFile in nsp.Files.Where(x => x.Name.EndsWith(".nca"))) { Nca nca = new Nca(KeySet, nsp.OpenFile(ncaFile), true); if (nca.Header.ContentType == ContentType.Program) { mainNca = nca; } else if (nca.Header.ContentType == ContentType.Control) { controlNca = nca; } } if (mainNca != null) { LoadNca(mainNca, controlNca); return; } // This is not a normal NSP, it's actually a ExeFS as a NSP Npdm metaData = null; PfsFileEntry npdmFile = nsp.Files.FirstOrDefault(x => x.Name.Equals("main.npdm")); if (npdmFile != null) { Logger.PrintInfo(LogClass.Loader, $"Loading main.npdm..."); metaData = new Npdm(nsp.OpenFile(npdmFile).AsStream()); } else { Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!"); metaData = GetDefaultNpdm(); } List <IExecutable> staticObjects = new List <IExecutable>(); void LoadNso(string searchPattern) { PfsFileEntry entry = nsp.Files.FirstOrDefault(x => x.Name.Equals(searchPattern)); if (entry != null) { Logger.PrintInfo(LogClass.Loader, $"Loading {entry.Name}..."); NxStaticObject staticObject = new NxStaticObject(nsp.OpenFile(entry).AsStream()); staticObjects.Add(staticObject); } } CurrentTitle = metaData.Aci0.TitleId.ToString("x16"); LoadNso("rtld"); LoadNso("main"); LoadNso("subsdk*"); LoadNso("sdk"); ContentManager.LoadEntries(); if (staticObjects.Count == 0) { Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided NSP file"); } else { ProgramLoader.LoadStaticObjects(this, metaData, staticObjects.ToArray()); } }
private static (string, string) processCnmtNca(Nca nca, ref Title title, bool cnmtContent = true) { string biggestNca = null, controlNca = null; log?.WriteLine("Processing CNMT NCA"); try { Pfs ncaPfs = new Pfs(nca.OpenSection(0, false, IntegrityCheckLevel.ErrorOnInvalid, true)); PfsFileEntry[] ncaFileEntries = ncaPfs.Files; foreach (PfsFileEntry pfsEntry in ncaFileEntries) { Cnmt cnmt = new Cnmt(ncaPfs.OpenFile(pfsEntry).AsStream()); if (title.version == unchecked ((uint)-1) || cnmt.TitleVersion?.Version > title.version) { title.type = cnmt.Type; title.titleID = String.Format("{0:X16}", cnmt.TitleId); title.baseTitleID = String.Format("{0:X16}", cnmt.ApplicationTitleId); title.version = cnmt.TitleVersion?.Version ?? title.version; title.systemVersion = cnmt.MinimumSystemVersion?.Version ?? unchecked ((uint)-1); title.applicationVersion = cnmt.MinimumApplicationVersion?.Version ?? unchecked ((uint)-1); if (cnmtContent) { CnmtContentEntry[] contentEntries = cnmt.ContentEntries; foreach (CnmtContentEntry contentEntry in contentEntries) { if (title.type == TitleType.Application || title.type == TitleType.Patch) { if (contentEntry.Type == CnmtContentType.Program) { biggestNca = BitConverter.ToString(contentEntry.NcaId).Replace("-", "").ToLower() + ".nca"; log?.WriteLine("Found Biggest NCA {0}", biggestNca); } else if (contentEntry.Type == CnmtContentType.Control) { controlNca = BitConverter.ToString(contentEntry.NcaId).Replace("-", "").ToLower() + ".nca"; log?.WriteLine("Found Control NCA {0}", controlNca); } } else if (title.type == TitleType.AddOnContent) { if (contentEntry.Type == CnmtContentType.Data) { biggestNca = BitConverter.ToString(contentEntry.NcaId).Replace("-", "").ToLower() + ".nca"; log?.WriteLine("Found Biggest NCA {0}", biggestNca); } } } } } } } catch (MissingKeyException ex) { title.error = String.Format("Missing {0}: {1}", ex.Type == KeyType.Title ? "Title Key" : "Key", ex.Name.Replace("key_area_key_application", "master_key")); log?.WriteLine(title.error); } catch (FileNotFoundException) { } return(biggestNca, controlNca); }
public static Title processNsp(string filename) { Title title = new Title(); using (var filestream = new FileStream(filename, FileMode.Open, FileAccess.Read)) { Pfs pfs; string biggestNca = null, controlNca = null; try { pfs = new Pfs(filestream.AsStorage()); title.distribution = Title.Distribution.Digital; log?.WriteLine("Processing NSP {0}", filename); PfsFileEntry[] fileEntries = pfs.Files; foreach (PfsFileEntry entry in fileEntries) { if (entry.Name.EndsWith(".cnmt.xml")) { try { using (var cnmtXml = pfs.OpenFile(entry)) { (biggestNca, controlNca) = processCnmtXml(cnmtXml, ref title); } } catch (FileNotFoundException) { } title.structure.Add(Title.Structure.CnmtXml); } else if (entry.Name.EndsWith(".cnmt.nca")) { try { using (var cnmtNca = pfs.OpenFile(entry)) { var nca = processCnmtNca(cnmtNca, ref title); if (nca.Item1 != null && (nca.Item2 != null || title.type == TitleType.AddOnContent)) { (biggestNca, controlNca) = nca; } } } catch (FileNotFoundException) { if (pfs.FileExists(entry.Name.Replace(".nca", ".ncz"))) { title.error = "Unsupported Format: Compressed NCA"; } } title.structure.Add(Title.Structure.CnmtNca); } else if (entry.Name.EndsWith(".cert")) { title.structure.Add(Title.Structure.Cert); } else if (entry.Name.EndsWith(".tik")) { try { using (var tik = pfs.OpenFile(entry)) { if (entry.Name.Split('.')[0].TryToBytes(out byte[] rightsId)) { processTik(tik, rightsId, ref keyset, out byte[] titleKey); title.titleKey = BitConverter.ToString(titleKey).Replace("-", "").ToUpper(); } } } catch (FileNotFoundException) { if (pfs.FileExists(entry.Name.Replace(".nca", ".ncz"))) { title.error = "Unsupported Format: Compressed NCA"; } } title.structure.Add(Title.Structure.Tik); } else if (entry.Name.EndsWith(".legalinfo.xml")) { title.structure.Add(Title.Structure.LegalinfoXml); } else if (entry.Name.EndsWith(".nacp.xml")) { try { using (var nacpXml = pfs.OpenFile(entry)) { processNacpXml(nacpXml, ref title); } } catch (FileNotFoundException) { } title.structure.Add(Title.Structure.NacpXml); } else if (entry.Name.EndsWith(".programinfo.xml")) { title.structure.Add(Title.Structure.PrograminfoXml); } else if (entry.Name.Equals("cardspec.xml")) { title.structure.Add(Title.Structure.CardspecXml); } else if (entry.Name.Equals("authoringtoolinfo.xml")) { title.structure.Add(Title.Structure.AuthoringtoolinfoXml); } } if (!String.IsNullOrEmpty(biggestNca)) { try { using (var biggest = pfs.OpenFile(biggestNca)) { processBiggestNca(biggest, ref title); } } catch (FileNotFoundException) { if (pfs.FileExists(biggestNca.Replace(".nca", ".ncz"))) { title.error = "Unsupported Format: Compressed NCA"; } } } if (!String.IsNullOrEmpty(controlNca)) { try { using (var control = pfs.OpenFile(controlNca)) { processControlNca(control, ref title); } } catch (FileNotFoundException) { if (pfs.FileExists(controlNca.Replace(".nca", ".ncz"))) { title.error = "Unsupported Format: Compressed NCA"; } } } } catch (InvalidDataException) { return(null); } } if (title.type == TitleType.Application || title.type == TitleType.Patch) { if (versionList.TryGetValue(title.baseTitleID, out uint version)) { title.latestVersion = version; } } log?.WriteLine("NSP information for {0}: [{1}] {2}", filename, title.titleID, title.titleName); return(title); }
private static void Main(string[] args) { var keyFile = Environment.ExpandEnvironmentVariables("%USERPROFILE%/.switch/prod.keys"); var keysInUserDir = true; var getDeltasOnly = false; #region Pre-execution checks if (!File.Exists(keyFile)) { if (!File.Exists("prod.keys")) { Console.Error.WriteLine("Error: prod.keys is missing!"); return; } else { keysInUserDir = false; } } if (!File.Exists("edge.token")) { Console.Error.WriteLine("Error: Please add an edge token to a file named \"edge.token\"."); return; } if (!File.Exists("device.id")) { Console.Error.WriteLine("Error: Please add your device ID in hexadecimal text form to a file named \"device.id\"."); return; } if (!File.Exists("nx_tls_client_cert.pfx")) { Console.Error.WriteLine("Error: Please add your Switch certificate to a file named \"nx_tls_client_cert.pfx\"."); return; } #endregion var deviceID = Convert.ToInt64(File.ReadAllText("device.id"), 16); var keys = ExternalKeys.ReadKeyFile(keysInUserDir ? keyFile : "prod.keys"); var sysID = "0100000000000816"; // To-do: Clean up if (args[0] == "-s" || args[0] == sysID) { var JSON = (string)GET(deviceID, SunUrl, true); var Version = args.Length > 1 ? args[1] : (string)JObject.Parse(JSON)["system_update_metas"][0]["title_version"]; HEAD(deviceID, nMetaURL('s', sysID, Version, deviceID)); var contentID = HEAD(deviceID, nMetaURL('s', sysID, Version, deviceID)); using (var meta = (HttpWebResponse)GET(deviceID, nContentURL('s', contentID), false)) using (var rd = new BinaryReader(meta.GetResponseStream())) using (var strm = new MemoryStorage(rd.ReadBytes((int)meta.ContentLength))) { Directory.CreateDirectory(sysID); strm.WriteAllBytes($"{sysID}/{contentID}.cnmt.nca"); using (var nca = new Nca(keys, strm, false).OpenSection(0, false, IntegrityCheckLevel.None, false)) { var pfs = new Pfs(nca); var cnmt = new Cnmt(pfs.OpenFile(pfs.Files[0]).AsStream()); foreach (var entry in cnmt.MetaEntries) { var tid = $"{entry.TitleId:x16}"; HEAD(deviceID, nMetaURL('a', tid, $"{entry.Version.Version}", deviceID)); var cID = HEAD(deviceID, nMetaURL('a', tid, $"{entry.Version.Version}", deviceID)); using (var met2 = (HttpWebResponse)GET(deviceID, nContentURL('a', cID), false)) using (var rdr = new BinaryReader(met2.GetResponseStream())) using (var strm2 = new MemoryStorage(rdr.ReadBytes((int)meta.ContentLength))) { Directory.CreateDirectory($"{sysID}/{tid}"); strm2.WriteAllBytes($"{sysID}/{tid}/{cID}.cnmt.nca"); using (var nca2 = new Nca(keys, strm2, false).OpenSection(0, false, IntegrityCheckLevel.None, false)) { var pfs2 = new Pfs(nca2); var cnmt2 = new Cnmt(pfs2.OpenFile(pfs2.Files[0]).AsStream()); foreach (var entry2 in cnmt2.ContentEntries) { string NCAID = entry2.NcaId.ToHexString().ToLower(); using (var Req = (HttpWebResponse)GET(deviceID, nContentURL('c', NCAID), false)) using (var Output = File.OpenWrite($"{sysID}/{tid}/{NCAID}.nca")) Req.GetResponseStream().CopyTo(Output); } } } } } } return; } string id = null, idFirstReq = null, idSecondReq = null; List <string> tidTargets = new List <string>(), verTargets = new List <string>(), entryTargets = new List <string>(); var numOfListings = 0; if (args.Length == 2) { if (args[1] == "-d") { getDeltasOnly = true; } else if (args[0] == "-t") { var rightsID = args[1]; using (var tikReq = (HttpWebResponse)GET(deviceID, CETKURL(rightsID), false)) using (var strm = tikReq.GetResponseStream()) using (var rd = new BinaryReader(strm)) { File.WriteAllBytes($"{rightsID}.tik", rd.ReadBytes(0x2C0)); File.WriteAllBytes($"{rightsID}.cert", rd.ReadBytes(0x700)); } return; } } GET(deviceID, Aqua(deviceID), false); if (args.Length == 3) { numOfListings = 2; if (args[0].Substring(13, 3) != "000" && args[0].Substring(13, 3) != "800") { tidTargets.Add(null); tidTargets.Add(args[0]); } else { tidTargets.Add(null); tidTargets.Add($"{args[0].Substring(0, 13)}800"); } verTargets.Add(null); verTargets.Add(args[2]); } else { var Streq = (string)GET(deviceID, Superfly(GetBaseTID(args[0])), true); if (args[0].Substring(13, 3) == "000") { foreach (JToken Listing in JArray.Parse(Streq)) { if ((string)Listing["title_type"] != "AddOnContent") { numOfListings++; tidTargets.Add(Listing["title_id"].ToString()); verTargets.Add(Listing["version"].ToString()); } } } else { foreach (JToken Listing in JArray.Parse(Streq)) { if ((string)Listing["title_id"] == args[0]) { numOfListings++; tidTargets.Add(Listing["title_id"].ToString()); verTargets.Add(Listing["version"].ToString()); } } } } if (args.Length == 1) { id = HEAD(deviceID, MetaURL('a', tidTargets[0], verTargets[0], deviceID)); } if (args.Length == 1 && id != null) { GET(deviceID, ContentURL('a', id), true); } if (numOfListings >= 2) { idFirstReq = HEAD(deviceID, MetaURL('a', tidTargets[1], verTargets[1], deviceID)); } if (args.Length == 1 && numOfListings >= 2) { GET(deviceID, ContentURL('a', idFirstReq), true); } if (numOfListings >= 2) { idSecondReq = HEAD(deviceID, MetaURL('a', tidTargets[1], verTargets[1], deviceID)); } if (numOfListings >= 2) { GET(deviceID, ContentURL('a', idSecondReq), true); } if (args.Length == 1) { using (var meta = (HttpWebResponse)GET(deviceID, ContentURL('a', id), false)) using (var rd = new BinaryReader(meta.GetResponseStream())) using (var strm = new MemoryStorage(rd.ReadBytes((int)meta.ContentLength))) { Directory.CreateDirectory(tidTargets[0]); strm.WriteAllBytes($"{tidTargets[0]}/{id}.cnmt.nca"); using (var nca = new Nca(keys, strm, false).OpenSection(0, false, IntegrityCheckLevel.None, false)) { var pfs = new Pfs(nca); var cnmt = new Cnmt(pfs.OpenFile(pfs.Files[0]).AsStream()); foreach (var entry in cnmt.ContentEntries) { string NCAID = entry.NcaId.ToHexString().ToLower(); using (var Req = (HttpWebResponse)GET(deviceID, ContentURL('c', NCAID), false)) using (var Output = File.OpenWrite($"{tidTargets[0]}/{NCAID}.nca")) Req.GetResponseStream().CopyTo(Output); } } } } if (numOfListings >= 2) { using (var meta = (HttpWebResponse)GET(deviceID, ContentURL('a', idSecondReq), false)) using (var read = new BinaryReader(meta.GetResponseStream())) using (var metastrm = new MemoryStorage(read.ReadBytes((int)meta.ContentLength))) { Directory.CreateDirectory(tidTargets[1]); metastrm.WriteAllBytes($"{tidTargets[1]}/{idSecondReq}.cnmt.nca"); using (var nca = new Nca(keys, metastrm, false).OpenSection(0, false, IntegrityCheckLevel.None, false)) { var pfs = new Pfs(nca); var cnmt = new Cnmt(pfs.OpenFile(pfs.Files[0]).AsStream()); foreach (var entry in getDeltasOnly ? cnmt.ContentEntries.Where(e => e.Type == CnmtContentType.DeltaFragment) : cnmt.ContentEntries) { var ncaID = entry.NcaId.ToHexString().ToLower(); using (var request = (HttpWebResponse)GET(deviceID, ContentURL('c', ncaID), false)) using (var output = File.OpenWrite($"{tidTargets[1]}/{ncaID}.nca")) request.GetResponseStream().CopyTo(output); if (entry.Type == CnmtContentType.Program) { var rightsID = new Nca(keys, new StreamStorage (File.OpenRead($"{tidTargets[1]}/{ncaID}.nca"), false), false) .Header.RightsId.ToHexString().ToLower(); using (var tikReq = (HttpWebResponse)GET(deviceID, CETKURL(rightsID), false)) using (var strm = tikReq.GetResponseStream()) using (var rd = new BinaryReader(strm)) { File.WriteAllBytes($"{tidTargets[1]}/{rightsID}.tik", rd.ReadBytes(0x2C0)); File.WriteAllBytes($"{tidTargets[1]}/{rightsID}.cert", rd.ReadBytes(0x700)); } } } } } } }
private void OnNandFound() { Nand nand = NANDService.NAND; Stream NANDSource = NANDService.NANDSource; NANDSource.Seek(0x804000, SeekOrigin.Begin); // BCPKG2-1-Normal-Main offset + length of BootConfig FileStream pkg2stream = HACGUIKeyset.TempPkg2FileInfo.Create(); NANDSource.CopyToNew(pkg2stream, 0x7FC000); // rest of BCPPKG2-Normal-Main partition pkg2stream.Seek(0, SeekOrigin.Begin); byte[] pkg2raw = new byte[pkg2stream.Length]; pkg2stream.Read(pkg2raw, 0, pkg2raw.Length); Package2 pkg2 = new Package2(HACGUIKeyset.Keyset, new MemoryStream(pkg2raw)); HACGUIKeyset.RootTempPkg2FolderInfo.Create(); FileStream kernelstream = HACGUIKeyset.TempKernelFileInfo.Create(); FileStream INI1stream = HACGUIKeyset.TempINI1FileInfo.Create(); pkg2.OpenKernel().CopyTo(kernelstream); pkg2.OpenIni1().CopyTo(INI1stream); kernelstream.Close(); INI1stream.Close(); Ini1 INI1 = new Ini1(pkg2.OpenIni1()); List <HashSearchEntry> hashes = new List <HashSearchEntry>(); Dictionary <byte[], byte[]> keys = new Dictionary <byte[], byte[]>(); HACGUIKeyset.RootTempINI1Folder.Create(); foreach (Kip kip in INI1.Kips) { Stream rodatastream, datastream; switch (kip.Header.Name) { case "FS": hashes.Add(new HashSearchEntry(NintendoKeys.KeyAreaKeyApplicationSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.KeyAreaKeyOceanSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.KeyAreaKeySystemSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.HeaderKekSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.SaveMacKekSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.SaveMacKeySourceHash, 0x10)); rodatastream = new MemoryStream(kip.DecompressSection(1)); keys = rodatastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x10); Array.Copy(keys[NintendoKeys.KeyAreaKeyApplicationSourceHash], HACGUIKeyset.Keyset.KeyAreaKeyApplicationSource, 0x10); Array.Copy(keys[NintendoKeys.KeyAreaKeyOceanSourceHash], HACGUIKeyset.Keyset.KeyAreaKeyOceanSource, 0x10); Array.Copy(keys[NintendoKeys.KeyAreaKeySystemSourceHash], HACGUIKeyset.Keyset.KeyAreaKeySystemSource, 0x10); Array.Copy(keys[NintendoKeys.HeaderKekSourceHash], HACGUIKeyset.Keyset.HeaderKekSource, 0x10); Array.Copy(keys[NintendoKeys.SaveMacKekSourceHash], HACGUIKeyset.Keyset.SaveMacKekSource, 0x10); Array.Copy(keys[NintendoKeys.SaveMacKeySourceHash], HACGUIKeyset.Keyset.SaveMacKeySource, 0x10); hashes.Clear(); rodatastream.Seek(0, SeekOrigin.Begin); bool sdWarn = false; hashes.Add(new HashSearchEntry(NintendoKeys.SDCardKekSourceHash, 0x10)); try { keys = rodatastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x10); Array.Copy(keys[NintendoKeys.SDCardKekSourceHash], HACGUIKeyset.Keyset.SdCardKekSource, 0x10); } catch (EndOfStreamException) { MessageBox.Show("Failed to find SD card kek source! The NAND is probably from 1.0.0."); sdWarn = true; } if (!sdWarn) // don't try to find the rest of the keys if the other one couldn't be found { hashes.Clear(); rodatastream.Seek(0, SeekOrigin.Begin); hashes.Add(new HashSearchEntry(NintendoKeys.SDCardSaveKeySourceHash, 0x20)); hashes.Add(new HashSearchEntry(NintendoKeys.SDCardNcaKeySourceHash, 0x20)); keys = rodatastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x20); Array.Copy(keys[NintendoKeys.SDCardSaveKeySourceHash], HACGUIKeyset.Keyset.SdCardKeySources[0], 0x20); Array.Copy(keys[NintendoKeys.SDCardNcaKeySourceHash], HACGUIKeyset.Keyset.SdCardKeySources[1], 0x20); } hashes.Clear(); rodatastream.Close(); hashes.Add(new HashSearchEntry(NintendoKeys.HeaderKeySourceHash, 0x20)); datastream = new MemoryStream(kip.DecompressSection(2)); keys = datastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x20); Array.Copy(keys[NintendoKeys.HeaderKeySourceHash], HACGUIKeyset.Keyset.HeaderKeySource, 0x20); datastream.Close(); hashes.Clear(); break; case "spl": hashes.Add(new HashSearchEntry(NintendoKeys.AesKeyGenerationSourceHash, 0x10)); rodatastream = new MemoryStream(kip.DecompressSection(1)); keys = rodatastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x10); Array.Copy(keys[NintendoKeys.AesKeyGenerationSourceHash], HACGUIKeyset.Keyset.AesKeyGenerationSource, 0x10); rodatastream.Close(); hashes.Clear(); break; } FileStream kipstream = HACGUIKeyset.RootTempINI1Folder.GetFile(kip.Header.Name + ".kip").Create(); kip.OpenRawFile().CopyTo(kipstream); kipstream.Close(); } pkg2stream.Close(); INI1stream.Close(); HACGUIKeyset.Keyset.DeriveKeys(); SwitchFs fs = new SwitchFs(HACGUIKeyset.Keyset, NANDService.NAND.OpenSystemPartition()); foreach (KeyValuePair <string, Nca> kv in fs.Ncas) { Nca nca = kv.Value; switch (nca.Header.TitleId) { case 0x0100000000000033: // es switch (nca.Header.ContentType) { case ContentType.Program: NcaSection exefsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Pfs0); Stream pfsStream = nca.OpenSection(exefsSection.SectionNum, false, false); Pfs pfs = new Pfs(pfsStream); Nso nso = new Nso(pfs.OpenFile("main")); NsoSection section = nso.Sections[1]; Stream data = new MemoryStream(section.DecompressSection()); hashes.Clear(); hashes.Add(new HashSearchEntry(NintendoKeys.EticketRsaKekSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.EticketRsaKekekSourceHash, 0x10)); keys = data.FindKeyViaHash(hashes, new SHA256Managed(), 0x10, data.Length); byte[] EticketRsaKekSource = new byte[0x10]; byte[] EticketRsaKekekSource = new byte[0x10]; Array.Copy(keys[NintendoKeys.EticketRsaKekSourceHash], EticketRsaKekSource, 0x10); Array.Copy(keys[NintendoKeys.EticketRsaKekekSourceHash], EticketRsaKekekSource, 0x10); byte[] RsaOaepKekGenerationSource; XOR(NintendoKeys.KekMasks[0], NintendoKeys.KekSeeds[3], out RsaOaepKekGenerationSource); byte[] key1 = new byte[0x10]; Crypto.DecryptEcb(HACGUIKeyset.Keyset.MasterKeys[0], RsaOaepKekGenerationSource, key1, 0x10); byte[] key2 = new byte[0x10]; Crypto.DecryptEcb(key1, EticketRsaKekekSource, key2, 0x10); byte[] key3 = new byte[0x10]; Crypto.DecryptEcb(key2, EticketRsaKekSource, HACGUIKeyset.Keyset.EticketRsaKek, 0x10); break; } break; } } Stream prodinfo = nand.OpenProdInfo(); Stream prodinfoFile = HACGUIKeyset.TempPRODINFOFileInfo.Create(); prodinfo.CopyTo(prodinfoFile); prodinfo.Close(); prodinfoFile.Seek(0, SeekOrigin.Begin); Calibration cal0 = new Calibration(prodinfoFile); HACGUIKeyset.Keyset.EticketExtKeyRsa = Crypto.DecryptRsaKey(cal0.EticketExtKeyRsa, HACGUIKeyset.Keyset.EticketRsaKek); prodinfoFile.Close(); List <Ticket> tickets = new List <Ticket>(); NandPartition system = nand.OpenSystemPartition(); Stream e1Stream = system.OpenFile("save\\80000000000000E1", FileMode.Open, FileAccess.Read); tickets.AddRange(ReadTickets(HACGUIKeyset.Keyset, e1Stream)); Stream e2Stream = system.OpenFile("save\\80000000000000E2", FileMode.Open, FileAccess.Read); tickets.AddRange(ReadTickets(HACGUIKeyset.Keyset, e2Stream)); Stream nsAppmanStream = system.OpenFile("save\\8000000000000043", FileMode.Open, FileAccess.Read); Savefile save = new Savefile(HACGUIKeyset.Keyset, nsAppmanStream, false); Stream privateStream = save.OpenFile("/private"); byte[] sdSeed = new byte[0x10]; privateStream.Read(sdSeed, 0, 0x10); // Seek doesn't work so i just read twice privateStream.Read(sdSeed, 0, 0x10); HACGUIKeyset.Keyset.SetSdSeed(sdSeed); foreach (Ticket ticket in tickets) { HACGUIKeyset.Keyset.TitleKeys[ticket.RightsId] = new byte[0x10]; Array.Copy(ticket.TitleKeyBlock, HACGUIKeyset.Keyset.TitleKeys[ticket.RightsId], 0x10); } NANDService.Stop(); HACGUIKeyset.ProductionKeysFileInfo.Create().WriteString(HACGUIKeyset.PrintCommonKeys(HACGUIKeyset.Keyset, true)); HACGUIKeyset.ExtraKeysFileInfo.Create().WriteString(HACGUIKeyset.PrintCommonWithoutFriendlyKeys(HACGUIKeyset.Keyset)); HACGUIKeyset.ConsoleKeysFileInfo.Create().WriteString(ExternalKeys.PrintUniqueKeys(HACGUIKeyset.Keyset)); HACGUIKeyset.GetConsoleKeysFileInfoByName(PickConsole.ConsoleName).Create().WriteString(ExternalKeys.PrintUniqueKeys(HACGUIKeyset.Keyset)); HACGUIKeyset.TitleKeysFileInfo.Create().WriteString(ExternalKeys.PrintTitleKeys(HACGUIKeyset.Keyset)); }
public void LoadNca(Nca MainNca, Nca ControlNca) { NcaSection RomfsSection = MainNca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs || x?.Type == SectionType.Bktr); NcaSection ExefsSection = MainNca.Sections.FirstOrDefault(x => x?.IsExefs == true); if (ExefsSection == null) { Logger.PrintError(LogClass.Loader, "No ExeFS found in NCA"); return; } if (RomfsSection == null) { Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA"); } else { Stream RomfsStream = MainNca.OpenSection(RomfsSection.SectionNum, false, EnableFsIntegrityChecks); Device.FileSystem.SetRomFs(RomfsStream); } Stream ExefsStream = MainNca.OpenSection(ExefsSection.SectionNum, false, EnableFsIntegrityChecks); Pfs Exefs = new Pfs(ExefsStream); Npdm MetaData = null; if (Exefs.FileExists("main.npdm")) { Logger.PrintInfo(LogClass.Loader, "Loading main.npdm..."); MetaData = new Npdm(Exefs.OpenFile("main.npdm")); } else { Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!"); } Process MainProcess = MakeProcess(MetaData); void LoadNso(string Filename) { foreach (PfsFileEntry File in Exefs.Files.Where(x => x.Name.StartsWith(Filename))) { if (Path.GetExtension(File.Name) != string.Empty) { continue; } Logger.PrintInfo(LogClass.Loader, $"Loading {Filename}..."); string Name = Path.GetFileNameWithoutExtension(File.Name); Nso Program = new Nso(Exefs.OpenFile(File), Name); MainProcess.LoadProgram(Program); } } Nacp ReadControlData() { Romfs ControlRomfs = new Romfs(ControlNca.OpenSection(0, false, EnableFsIntegrityChecks)); byte[] ControlFile = ControlRomfs.GetFile("/control.nacp"); BinaryReader Reader = new BinaryReader(new MemoryStream(ControlFile)); Nacp ControlData = new Nacp(Reader); CurrentTitle = ControlData.Languages[(int)State.DesiredTitleLanguage].Title; if (string.IsNullOrWhiteSpace(CurrentTitle)) { CurrentTitle = ControlData.Languages.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title; } return(ControlData); } if (ControlNca != null) { MainProcess.ControlData = ReadControlData(); } else { CurrentTitle = MainProcess.MetaData.ACI0.TitleId.ToString("x16"); } if (!MainProcess.MetaData.Is64Bits) { throw new NotImplementedException("32-bit titles are unsupported!"); } LoadNso("rtld"); MainProcess.SetEmptyArgs(); LoadNso("main"); LoadNso("subsdk"); LoadNso("sdk"); MainProcess.Run(); }
static void Main(string[] args) { var path = args.Length >= 1 ? args[0] : Environment.CurrentDirectory; var fs = new FileSystem(path); if (!File.Exists("keys.txt")) { Console.WriteLine("Cannot verify NSPs without keys.txt"); Console.WriteLine(); Console.WriteLine("Press any key to continue"); Console.ReadKey(); return; } var keyset = ExternalKeys.ReadKeyFile("keys.txt"); var badlist = new List <string>(); var exceptionlist = new List <string>(); foreach (var file in fs.GetFileSystemEntries("", "*.nsp", SearchOption.AllDirectories)) { var filename = Path.GetFileName(file); var progress = $"Checking {filename}: "; Console.Write(progress); try { bool ok = true; using (var nspfile = fs.OpenFile(file, FileMode.Open, FileAccess.Read)) { var nspdata = new Pfs(nspfile); var cnmtfile = nspdata.Files.FirstOrDefault(x => x.Name.ToLowerInvariant().EndsWith(".cnmt.nca")); if (cnmtfile == null) { Console.WriteLine($"\rChecking {filename}: No cnmt.nca file present"); badlist.Add(filename); continue; } var cnmtdata = nspdata.OpenFile(cnmtfile); Cnmt cnmt; using (var sr = new BinaryReader(cnmtdata)) { var cnmthash = SHA256.Create().ComputeHash(sr.ReadBytes((int)cnmtdata.Length)); if (!cnmtfile.Name.ToLowerInvariant().Contains(cnmthash.Take(16).ToArray().ToHexString())) { //Put failure here Console.WriteLine($"\rChecking {filename}: cnmt.nca file is corrupted"); badlist.Add(filename); cnmtdata.Dispose(); continue; } cnmtdata.Position = 0; var cnmtnca = new Nca(keyset, cnmtdata, false); var section = cnmtnca.OpenSection(0, false); var sectionpfs = new Pfs(section); cnmt = new Cnmt(sectionpfs.OpenFile(sectionpfs.Files[0])); } foreach (var entry in cnmt.ContentEntries) { var entryfile = nspdata.Files.FirstOrDefault(x => x.Name.ToLowerInvariant().EndsWith(entry.NcaId.ToHexString() + ".nca")); if (entryfile == null) { if (entry.Type != CnmtContentType.UpdatePatch) { //Put failure here Console.WriteLine($"\rChecking {filename}: one of the entries required by the cnmt.nca is missing."); badlist.Add(filename); break; } continue; } using (var entrynca = nspdata.OpenFile(entryfile)) { var hash = SHA256.Create(); using (var sr = new BinaryReader(entrynca)) { while (entrynca.Length != entrynca.Position) { var entryncadata = sr.ReadBytes(0x100000); hash.TransformBlock(entryncadata, 0, entryncadata.Length, entryncadata, 0); Console.Write($"\rChecking {filename}: {((entrynca.Position * 100.0) / entrynca.Length):0.0}%"); } hash.TransformFinalBlock(new byte[0], 0, 0); } if (hash.Hash.ToHexString().Equals(entry.Hash.ToHexString())) { Console.Write($"\rChecking {filename}: {100:0.0}%"); continue; } //Put failure here Console.WriteLine($"\rChecking {filename}: one of the entries required by the cnmt.nca is corrupted"); badlist.Add(filename); ok = false; break; } } if (ok) { Console.WriteLine($"\rChecking {filename}: OK "); } //Put Success here } } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); exceptionlist.Add($"{filename}{Environment.NewLine}Exception: {ex.Message}{Environment.NewLine}Stack Trace: {ex.StackTrace}{Environment.NewLine}"); } } File.WriteAllText("Corrupted NSPs.txt", string.Join(Environment.NewLine, badlist)); File.WriteAllText("Exception Log.txt", string.Join(Environment.NewLine, exceptionlist)); Console.WriteLine(); Console.WriteLine("Press any key to continue"); Console.ReadKey(); }
public static Title processNsp(string filename) { Title title = new Title(); using (var filestream = new FileStream(filename, FileMode.Open, FileAccess.Read)) { Pfs pfs; string biggestNca = null, controlNca = null; try { pfs = new Pfs(filestream.AsStorage()); title.distribution = Title.Distribution.Digital; } catch (InvalidDataException) { return(null); } log?.WriteLine("Processing NSP {0}", filename); PfsFileEntry[] fileEntries = pfs.Files; foreach (PfsFileEntry entry in fileEntries) { if (entry.Name.EndsWith(".cnmt.xml")) { using (var cnmtXml = pfs.OpenFile(entry)) { (biggestNca, controlNca) = processCnmtXml(cnmtXml, ref title); } title.structure.Add(Title.Structure.CnmtXml); } else if (entry.Name.EndsWith(".cnmt.nca")) { using (var cnmtNca = pfs.OpenFile(entry)) { var nca = processCnmtNca(cnmtNca, ref title); if (nca.Item1 != null && (nca.Item2 != null || title.type == TitleType.AddOnContent)) { (biggestNca, controlNca) = nca; } } title.structure.Add(Title.Structure.CnmtNca); } else if (entry.Name.EndsWith(".cert")) { title.structure.Add(Title.Structure.Cert); } else if (entry.Name.EndsWith(".tik")) { title.structure.Add(Title.Structure.Tik); } else if (entry.Name.EndsWith(".legalinfo.xml")) { title.structure.Add(Title.Structure.LegalinfoXml); } else if (entry.Name.EndsWith(".nacp.xml")) { using (var nacpXml = pfs.OpenFile(entry)) { processNacpXml(nacpXml, ref title); } title.structure.Add(Title.Structure.NacpXml); } else if (entry.Name.EndsWith(".programinfo.xml")) { title.structure.Add(Title.Structure.PrograminfoXml); } else if (entry.Name.Equals("cardspec.xml")) { title.structure.Add(Title.Structure.CardspecXml); } else if (entry.Name.Equals("authoringtoolinfo.xml")) { title.structure.Add(Title.Structure.AuthoringtoolinfoXml); } } if (!String.IsNullOrEmpty(biggestNca)) { using (var biggest = pfs.OpenFile(biggestNca)) { processBiggestNca(biggest, ref title); } } if (!String.IsNullOrEmpty(controlNca)) { using (var control = pfs.OpenFile(controlNca)) { processControlNca(control, ref title); } } } if (title.type == TitleType.Application || title.type == TitleType.Patch) { if (versionList.TryGetValue(title.titleIDApplication, out uint version)) { title.latestVersion = version; } } log?.WriteLine("NSP information for {0}: [{1}] {2}", filename, title.titleID, title.titleName); return(title); }
//Open update only private void Open_NSP_Update(object sender, EventArgs e) { var Dialog = openFileDialog1.ShowDialog(); if (Dialog != DialogResult.Cancel) { Console.WriteLine("LOADING."); label8.Visible = true; this.Update(); treeView1.Nodes.Clear(); string FileToOpen = null; if (Program.FileArg != null) { FileToOpen = Program.FileArg; } else { FileToOpen = openFileDialog1.FileName; } Program.FileArg = null; Stream Input = null; try { string ExpEnv(string In) => Environment.ExpandEnvironmentVariables(In); var ProdKeys = ExpEnv(@"%USERPROFILE%\.switch\prod.keys"); var TitleKeys = ExpEnv(@"%USERPROFILE%\.switch\title.keys"); Console.WriteLine(FileToOpen); var Keys = ExternalKeys.ReadKeyFile(ProdKeys, TitleKeys); var Ext = (new FileInfo(FileToOpen).Extension); if (Ext == ".nsp") { var InputPFS = File.OpenRead(FileToOpen); var Pfs = new Pfs(InputPFS.AsStorage()); var CnmtNca = new Nca(Keys, Pfs.OpenFile(Pfs.Files.FirstOrDefault(s => s.Name.Contains(".cnmt.nca"))), false); var CnmtPfs = new Pfs(CnmtNca.OpenSection(0, false, IntegrityCheckLevel.None, true)); var Cnmt = new Cnmt(CnmtPfs.OpenFile(CnmtPfs.Files[0]).AsStream()); var Program = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Program); var CtrlEntry = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Control); if (CtrlEntry != null) { Control = new Nca(Keys, Pfs.OpenFile($"{CtrlEntry.NcaId.ToHexString().ToLower()}.nca"), false); } Input = Pfs.OpenFile($"{Program.NcaId.ToHexString().ToLower()}.nca").AsStream(); } else { Input = File.OpenRead(FileToOpen); } try { Nca = new Nca(Keys, Input.AsStorage(), true); if (Nca.HasRightsId && !Keys.TitleKeys.Keys.Any(k => k.SequenceEqual(Nca.Header.RightsId))) { MessageBox.Show($"Error: the titlekey for {Nca.Header.RightsId.ToHexString().ToLower()} is not present in your key file."); } else { var isUpdateNca = false; if (Nca.Sections.Any(s => s?.Type == SectionType.Bktr)) { isUpdateNca = true; } if (isUpdateNca) { var InputPFS = File.OpenRead(FileToOpen); var Pfs = new Pfs(InputPFS.AsStorage()); var CnmtNca = new Nca(Keys, Pfs.OpenFile(Pfs.Files.FirstOrDefault(s => s.Name.Contains(".cnmt.nca"))), false); var CnmtPfs = new Pfs(CnmtNca.OpenSection(0, false, IntegrityCheckLevel.None, true)); var Cnmt = new Cnmt(CnmtPfs.OpenFile(CnmtPfs.Files[0]).AsStream()); var Program = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Program); var CtrlEntry = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Control); if (CtrlEntry != null) { Control = new Nca(Keys, Pfs.OpenFile($"{CtrlEntry.NcaId.ToHexString().ToLower()}.nca"), false); } Input = Pfs.OpenFile($"{Program.NcaId.ToHexString().ToLower()}.nca").AsStream(); var Input2 = Pfs.OpenFile($"{Program.NcaId.ToHexString().ToLower()}.nca").AsStream(); Patch = new Nca(Keys, Input2.AsStorage(), true); Nca.SetBaseNca(Patch); } new Thread (() => { Thread.CurrentThread.IsBackground = true; var Info = GetTitleMeta($"{Nca.Header.TitleId:x16}"); label2.Invoke(new Action(() => { label2.Text = Info[0]; label3.Text = Info[1]; })); }).Start(); Rom = new Romfs( Nca.OpenSection(Nca.Sections.FirstOrDefault (s => s?.Type == SectionType.Romfs || s?.Type == SectionType.Bktr) .SectionNum, false, IntegrityCheckLevel.None, true) ); IO.PopulateTreeView(treeView1.Nodes, Rom.RootDir); Console.WriteLine("DONE."); fileToolStripMenuItem.Text = "File / Explore"; label8.Visible = false; this.Update(); } } catch { MessageBox.Show("There was an error reading the NCA. Are you sure the correct keys are present in your keyfiles?"); } } catch (ArgumentNullException) { MessageBox.Show("Error: key files are missing!"); } } }
private void Open() { treeView1.Nodes.Clear(); string FileToOpen = null; if (Program.FileArg != null) { FileToOpen = Program.FileArg; } else { FileToOpen = openFileDialog1.FileName; } Program.FileArg = null; Stream Input = null; try { string ExpEnv(string In) => Environment.ExpandEnvironmentVariables(In); var ProdKeys = ExpEnv(@"%USERPROFILE%\.switch\prod.keys"); var TitleKeys = ExpEnv(@"%USERPROFILE%\.switch\title.keys"); var Keys = ExternalKeys.ReadKeyFile(ProdKeys, TitleKeys); var Ext = (new FileInfo(FileToOpen).Extension); if (Ext == ".nsp") { var InputPFS = File.OpenRead(FileToOpen); var Pfs = new Pfs(InputPFS); var CnmtNca = new Nca(Keys, Pfs.OpenFile(Pfs.Files.FirstOrDefault(s => s.Name.Contains(".cnmt.nca"))), false); var CnmtPfs = new Pfs(CnmtNca.OpenSection(0, false, IntegrityCheckLevel.None)); var Cnmt = new Cnmt(CnmtPfs.OpenFile(CnmtPfs.Files[0])); var Program = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Program); var CtrlEntry = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Control); if (CtrlEntry != null) { Control = new Nca(Keys, Pfs.OpenFile($"{CtrlEntry.NcaId.ToHexString().ToLower()}.nca"), false); } Input = Pfs.OpenFile($"{Program.NcaId.ToHexString().ToLower()}.nca"); } else if (Ext == ".xci") { var InputPFS = File.OpenRead(FileToOpen); var Xci = new Xci(Keys, InputPFS); var CnmtNca = new Nca(Keys, Xci.SecurePartition.OpenFile(Xci.SecurePartition.Files.FirstOrDefault(s => s.Name.Contains(".cnmt.nca"))), false); var CnmtPfs = new Pfs(CnmtNca.OpenSection(0, false, IntegrityCheckLevel.None)); var Cnmt = new Cnmt(CnmtPfs.OpenFile(CnmtPfs.Files[0])); var Program = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Program); var CtrlEntry = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Control); if (CtrlEntry != null) { Control = new Nca(Keys, Xci.SecurePartition.OpenFile($"{CtrlEntry.NcaId.ToHexString().ToLower()}.nca"), false); } Input = Xci.SecurePartition.OpenFile($"{Program.NcaId.ToHexString().ToLower()}.nca"); } else if (FileToOpen.Split('.')[1] == "cnmt" && Ext == ".nca") { var TargetFile = File.OpenRead(FileToOpen); var CnmtNca = new Nca(Keys, TargetFile, false); var CnmtPfs = new Pfs(CnmtNca.OpenSection(0, false, IntegrityCheckLevel.None)); var Cnmt = new Cnmt(CnmtPfs.OpenFile(CnmtPfs.Files[0])); var Program = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Program); var CtrlEntry = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Control); if (CtrlEntry != null) { Control = new Nca(Keys, File.OpenRead($"{CtrlEntry.NcaId.ToHexString().ToLower()}.nca"), false); } Input = File.OpenRead($"{Program.NcaId.ToHexString().ToLower()}.nca"); } else { Input = File.OpenRead(FileToOpen); } try { Nca = new Nca(Keys, Input, true); if (Nca.HasRightsId && !Keys.TitleKeys.Keys.Any(k => k.SequenceEqual(Nca.Header.RightsId))) { MessageBox.Show($"Error: the titlekey for {Nca.Header.RightsId.ToHexString().ToLower()} is not present in your key file."); } else { bool isUpdateNca = false; if (Nca.Sections.Any(s => s?.Type == SectionType.Bktr)) { isUpdateNca = true; } if (isUpdateNca) { openFileDialog1.Title = "Select base Nca"; openFileDialog1.ShowDialog(); var Input2 = File.OpenRead(openFileDialog1.FileName); Patch = new Nca(Keys, Input2, true); Nca.SetBaseNca(Patch); } new Thread ( () => { Thread.CurrentThread.IsBackground = true; var Info = GetTitleMeta($"{Nca.Header.TitleId:x16}"); label2.Invoke(new Action(() => { label2.Text = Info[0]; label3.Text = Info[1]; })); } ) .Start(); Rom = new Romfs ( Nca.OpenSection ( Nca.Sections.FirstOrDefault (s => s?.Type == SectionType.Romfs || s?.Type == SectionType.Bktr) .SectionNum, false, IntegrityCheckLevel.None ) ); IO.PopulateTreeView(treeView1.Nodes, Rom.RootDir); } } catch { MessageBox.Show("There was an error reading the NCA. Are you sure the correct keys are present in your keyfiles?"); } } catch (ArgumentNullException) { MessageBox.Show("Error: key files are missing!"); } }
private void Open() { treeView1.Nodes.Clear(); string FileToOpen = null; if (Program.FileArg != null) { FileToOpen = Program.FileArg; } else { FileToOpen = openFileDialog1.FileName; } Program.FileArg = null; Stream Input = null; try { string ExpEnv(string In) { return(Environment.ExpandEnvironmentVariables(In)); } var ProdKeys = ExpEnv(@"%USERPROFILE%\.switch\prod.keys"); var TitleKeys = ExpEnv(@"%USERPROFILE%\.switch\title.keys"); var Keys = ExternalKeys.ReadKeyFile(ProdKeys, TitleKeys); var Ext = (new FileInfo(FileToOpen).Extension); if (Ext == ".nsp") { var InputPFS = File.OpenRead(FileToOpen); var Pfs = new Pfs(InputPFS); Input = Pfs.OpenFile ( Pfs.Files.OrderByDescending(s => s.Size) .FirstOrDefault() ); } else if (Ext == ".xci") { var InputPFS = File.OpenRead(FileToOpen); var Xci = new Xci(Keys, InputPFS); Input = Xci.SecurePartition.OpenFile ( Xci.SecurePartition.Files .OrderByDescending(s => s.Size) .FirstOrDefault() ); } else { Input = File.OpenRead(FileToOpen); } try { Nca = new Nca(Keys, Input, true); if (Nca.HasRightsId) { if (!Keys.TitleKeys.Keys.Contains(Nca.Header.RightsId)) { MessageBox.Show($"Error: the titlekey for {Nca.Header.RightsId.ToHexString()} is not present in your key file."); } } bool IsUpdateNca = false; foreach (var Section in Nca.Sections) { if (Section?.Type == SectionType.Bktr) { IsUpdateNca = true; } } if (IsUpdateNca) { openFileDialog1.Title = "Select base Nca"; openFileDialog1.ShowDialog(); var Input2 = File.OpenRead(openFileDialog1.FileName); Patch = new Nca(Keys, Input2, true); Nca.SetBaseNca(Patch); } new Thread ( () => { Thread.CurrentThread.IsBackground = true; var Info = GetTitleMeta($"{Nca.Header.TitleId:x16}"); label2.Invoke ( new Action ( () => { label2.Text = Info[0]; } ) ); label3.Invoke ( new Action ( () => { label3.Text = Info[1]; } ) ); } ) .Start(); Rom = new Romfs ( Nca.OpenSection ( Nca.Sections.FirstOrDefault (s => s?.Type == SectionType.Romfs || s?.Type == SectionType.Bktr) .SectionNum, false, false ) ); IO.PopulateTreeView(treeView1.Nodes, Rom.RootDir); } catch (Exception) { MessageBox.Show("There was an error reading the NCA. Are you sure the correct keys are present in your keyfiles?"); } } catch (Exception) { MessageBox.Show("Error: key files are missing!"); } }