public void Load(System.IO.Stream stream) { 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)); for (int i = 0; i < romfs.Files.Count; i++) { files.Add(new FileEntry(romfs, romfs.Files[i])); } }
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!"); } 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()); foreach (var entry in Cnmt.ContentEntries) { if (entry.Type == CnmtContentType.Program) { var Program = entry; string ncaFileName = $"{Program.NcaId.ToHexString().ToLower()}.nca"; Stream Input = Pfs.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 ExefsEntry(exefs, file, root)); } } for (int i = 0; i < romfs.Files.Count; i++) { files.Add(new FileEntry(romfs, romfs.Files[i], root)); } } } 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); } }
public CnmtItem(Cnmt cnmt, SectionItem parentSectionItem, DirectoryEntryEx directoryEntry) : base(parentSectionItem, directoryEntry) { Cnmt = cnmt ?? throw new ArgumentNullException(nameof(cnmt)); ParentItem = parentSectionItem; PatchLevel = GetPatchLevel(Cnmt.TitleVersion); TitleId = Cnmt.TitleId.ToStrId(); ApplicationTitleId = Cnmt.ApplicationTitleId.ToStrId(); PatchTitleId = Cnmt.PatchTitleId.ToStrId(); TitleVersion = Cnmt.TitleVersion?.Version.ToString(); }
public static CnmtExtended GetCnmtExtended(string folderPath, Keyset keyset, Output Out) { var dirDecrypted = new DirectoryInfo(folderPath); foreach (var inFile in dirDecrypted.GetFiles("*.cnmt.nca")) { Out.Log($"{inFile}\r\n"); var ncaStorage = new StreamStorage(new FileStream(inFile.FullName, FileMode.Open, FileAccess.Read), false); var DecryptedHeader = new byte[0xC00]; ncaStorage.Read(DecryptedHeader, 0, 0xC00, 0); var Header = new NcaHeader(new BinaryReader(new MemoryStream(DecryptedHeader)), keyset); for (var i = 0; i < 4; ++i) { var section = NcaParseSection.ParseSection(Header, i); if (section == null || section.Header.Type != SectionType.Pfs0) { continue; } IStorage sectionStorage = ncaStorage.Slice(section.Offset, section.Size, false); IStorage pfs0Storage = sectionStorage.Slice(section.Header.Sha256Info.DataOffset, section.Header.Sha256Info.DataSize, false); var Pfs0Header = new PartitionFileSystemHeader(new BinaryReader(pfs0Storage.AsStream())); var FileDict = Pfs0Header.Files.ToDictionary(x => x.Name, x => x); foreach (var file in FileDict) { if (file.Key.EndsWith(".cnmt")) { IStorage fileStorage = pfs0Storage.Slice(Pfs0Header.HeaderSize + file.Value.Offset, file.Value.Size, false); var metadata = new Cnmt(fileStorage.AsStream()); if (metadata.ExtendedData != null) { ncaStorage.Dispose(); return(metadata.ExtendedData); } } } } ncaStorage.Dispose(); } return(null); }
// fs must contain AOC nca files in its root public void AddAocData(IFileSystem fs, string containerPath, ulong aocBaseId) { _virtualFileSystem.ImportTickets(fs); foreach (var ncaPath in fs.EnumerateEntries("*.cnmt.nca", SearchOptions.Default)) { fs.OpenFile(out IFile ncaFile, ncaPath.FullPath.ToU8Span(), OpenMode.Read); using (ncaFile) { var nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage()); if (nca.Header.ContentType != NcaContentType.Meta) { Logger.Warning?.Print(LogClass.Application, $"{ncaPath} is not a valid metadata file"); continue; } using var pfs0 = nca.OpenFileSystem(0, Switch.GetIntegrityCheckLevel()); pfs0.OpenFile(out IFile cnmtFile, pfs0.EnumerateEntries().Single().FullPath.ToU8Span(), OpenMode.Read); using (cnmtFile) { var cnmt = new Cnmt(cnmtFile.AsStream()); if (cnmt.Type != ContentMetaType.AddOnContent || (cnmt.TitleId & 0xFFFFFFFFFFFFE000) != aocBaseId) { continue; } string ncaId = BitConverter.ToString(cnmt.ContentEntries[0].NcaId).Replace("-", "").ToLower(); if (!_aocData.TryAdd(cnmt.TitleId, new AocItem(containerPath, $"{ncaId}.nca", true))) { Logger.Warning?.Print(LogClass.Application, $"Duplicate AddOnContent detected. TitleId {cnmt.TitleId:X16}"); } else { Logger.Info?.Print(LogClass.Application, $"Found AddOnContent with TitleId {cnmt.TitleId:X16}"); } } } } }
public CnmtInfo[] GetContentEntries(IStorage NcaStorage) { if (Config.Keyset is null) { throw new ArgumentNullException(nameof(Config.Keyset)); } List <CnmtInfo> res = new List <CnmtInfo>(); var nca = new Nca(Config.Keyset, NcaStorage); using IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); foreach (var entry in fs.EnumerateEntries("/", "*.cnmt")) { fs.OpenFile(out IFile fp, new U8Span(entry.Name), OpenMode.Read); Cnmt cnmt = new Cnmt(fp.AsStream()); foreach (var meta_entry in cnmt.MetaEntries) { var i = new CnmtInfo { IsMeta = true, TitleID = $"0{meta_entry.TitleId:X}", Version = meta_entry.Version.Version.ToString() }; Trace.WriteLine($"[GetContentEntries] From {cnmt.TitleId:x} => {i}"); res.Add(i); } foreach (var content_entry in cnmt.ContentEntries) { var i = new CnmtInfo { IsMeta = false, NcaID = content_entry.NcaId.ToHexString().ToLower(), }; Trace.WriteLine($"[GetContentEntries] From {cnmt.TitleId:x} => {i}"); res.Add(i); } } return(res.ToArray()); }
public void AddNcaInfo() { if (Config.verbose) { Console.WriteLine($"Parsing File: {path}"); } infile = new LocalStorage(path, FileAccess.Read); try { data = new Nca(Config.keyset, infile); } catch (Exception e) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Unable to create NCA class. Is your keyset file valid?"); Console.WriteLine($"Error: {e.Message}"); Console.ResetColor(); Environment.Exit(0); } if (header.ContentType == NcaContentType.Meta) { using IFileSystem fs = data.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; fs.OpenFile(out IFile cnmtFile, new U8Span(cnmtPath), OpenMode.Read).ThrowIfFailure(); cnmt = new Cnmt(cnmtFile.AsStream()); cnmtFile.GetSize(out long size); byte[] cnmtRaw = new byte[size]; cnmtFile.Read(out long none, 0, cnmtRaw); cnmt_raw = new CnmtRawParser(cnmtRaw); } titleId = header.TitleId.ToString("x16").ToUpper(); }
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!"); } }
//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!"); } } }
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(); }
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); }
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)); } } } } } } }
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(); }
private void BuildChildItems(SectionItem parentItem) { try { const string?ROOT_PATH = "/"; var fileSystem = parentItem.FileSystem; if (fileSystem == null) { return; } var directoryEntries = SafeGetDirectoryEntries(fileSystem, ROOT_PATH, parentItem); foreach (var directoryEntry in directoryEntries) { var entryName = directoryEntry.Name; var entryPath = directoryEntry.FullPath; // NACP File if (parentItem.ParentItem.ContentType == NcaContentType.Control && string.Equals(entryName, NacpItem.NacpFileName, StringComparison.OrdinalIgnoreCase) && directoryEntry.Type == DirectoryEntryType.File) { IFile nacpFile; try { using var uniqueRefFile = new UniqueRef <IFile>(); fileSystem.OpenFile(ref uniqueRefFile.Ref(), entryPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); nacpFile = uniqueRefFile.Release(); } catch (Exception ex) { OnLoadingException(ex, parentItem); var message = LocalizationManager.Instance.Current.Keys.LoadingError_FailedToOpenNacpFile.SafeFormat(ex.Message); parentItem.Errors.Add(TREE_LOADING_CATEGORY, message); _logger.LogError(ex, message); continue; } ApplicationControlProperty nacp; try { var blitStruct = new BlitStruct <ApplicationControlProperty>(1); nacpFile.Read(out _, 0, blitStruct.ByteSpan).ThrowIfFailure(); nacp = blitStruct.Value; } catch (Exception ex) { OnLoadingException(ex, parentItem); var message = LocalizationManager.Instance.Current.Keys.LoadingError_FailedToLoadNacpFile.SafeFormat(ex.Message); parentItem.Errors.Add(TREE_LOADING_CATEGORY, message); _logger.LogError(ex, message); continue; } parentItem.ChildItems.Add(new NacpItem(nacp, parentItem, directoryEntry)); } // CNMT File else if (parentItem.ParentItem.ContentType == NcaContentType.Meta && entryName.EndsWith(".cnmt", StringComparison.OrdinalIgnoreCase) && directoryEntry.Type == DirectoryEntryType.File) { IFile cnmtFile; try { using var uniqueRefFile = new UniqueRef <IFile>(); fileSystem.OpenFile(ref uniqueRefFile.Ref(), entryPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); cnmtFile = uniqueRefFile.Release(); } catch (Exception ex) { OnLoadingException(ex, parentItem); var message = LocalizationManager.Instance.Current.Keys.LoadingError_FailedToOpenCnmtFile.SafeFormat(ex.Message); parentItem.Errors.Add(TREE_LOADING_CATEGORY, message); _logger.LogError(ex, message); continue; } Cnmt cnmt; try { cnmt = new Cnmt(cnmtFile.AsStream()); } catch (Exception ex) { OnLoadingException(ex, parentItem); var message = LocalizationManager.Instance.Current.Keys.LoadingError_FailedToLoadCnmtFile.SafeFormat(ex.Message); parentItem.Errors.Add(TREE_LOADING_CATEGORY, message); _logger.LogError(ex, message); continue; } parentItem.ChildItems.Add(new CnmtItem(cnmt, parentItem, directoryEntry)); } // MAIN file else if (parentItem.ParentItem.ContentType == NcaContentType.Program && string.Equals(entryName, "main", StringComparison.OrdinalIgnoreCase) && directoryEntry.Type == DirectoryEntryType.File) { IFile nsoFile; try { using var uniqueRefFile = new UniqueRef <IFile>(); fileSystem.OpenFile(ref uniqueRefFile.Ref(), entryPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); nsoFile = uniqueRefFile.Release(); } catch (Exception ex) { OnLoadingException(ex, parentItem); var message = LocalizationManager.Instance.Current.Keys.LoadingError_FailedToOpenMainFile.SafeFormat(ex.Message); parentItem.Errors.Add(TREE_LOADING_CATEGORY, message); _logger.LogError(ex, message); continue; } NsoHeader?nsoHeader; try { var nsoReader = new NsoReader(); nsoReader.Initialize(nsoFile).ThrowIfFailure(); nsoHeader = nsoReader.Header; } catch (Exception ex) { OnLoadingException(ex, parentItem); var message = LocalizationManager.Instance.Current.Keys.LoadingError_FailedToLoadMainFile.SafeFormat(ex.Message); parentItem.Errors.Add(TREE_LOADING_CATEGORY, message); _logger.LogError(ex, message); continue; } parentItem.ChildItems.Add(new MainItem(nsoHeader.Value, parentItem, directoryEntry)); } else { var directoryEntryItem = new DirectoryEntryItem(parentItem, directoryEntry); BuildChildItems(directoryEntryItem); parentItem.ChildItems.Add(directoryEntryItem); } } } catch (Exception ex) { OnLoadingException(ex, parentItem); var message = LocalizationManager.Instance.Current.Keys.LoadingError_FailedToLoadSectionContent.SafeFormat(ex.Message); parentItem.Errors.Add(TREE_LOADING_CATEGORY, message); _logger.LogError(ex, message); } }