static void AddSdk(ExeFS exefs, Nso custom) { Nso sdk = exefs.GetNso(NsoTypeEnum.sdk); exefs.SetNso(sdk, NsoTypeEnum.subsdk0); exefs.SetNso(custom, NsoTypeEnum.sdk); }
public void LoadCart(string ExeFsDir, string RomFsFile = null) { if (RomFsFile != null) { Ns.VFs.LoadRomFs(RomFsFile); } Process MainProcess = MakeProcess(); void LoadNso(string FileName) { foreach (string File in Directory.GetFiles(ExeFsDir, FileName)) { if (Path.GetExtension(File) != string.Empty) { continue; } Ns.Log.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(File)}..."); using (FileStream Input = new FileStream(File, FileMode.Open)) { string Name = Path.GetFileNameWithoutExtension(File); Nso Program = new Nso(Input, Name); MainProcess.LoadProgram(Program); } } } void LoadNpdm(string FileName) { string File = Directory.GetFiles(ExeFsDir, FileName)[0]; Ns.Log.PrintInfo(LogClass.Loader, "Loading Title Metadata..."); using (FileStream Input = new FileStream(File, FileMode.Open)) { MainProcess.Metadata = new Npdm(Input); } } LoadNpdm("*.npdm"); if (!MainProcess.Metadata.Is64Bits) { throw new Exception("32-bit titles are unsupported!"); } LoadNso("rtld"); MainProcess.SetEmptyArgs(); LoadNso("main"); LoadNso("subsdk*"); LoadNso("sdk"); MainProcess.Run(); }
static void Main(string[] args) { "Starting load...".Print(); var recompiler = new Recompiler(); args.ForEach(fn => recompiler.Load(Nso.Read(fn, File.OpenRead(fn)))); "Loaded".Print(); recompiler.Run(); }
private void ProcessNsoSet(List <IFile> list) { if (list.Count == 0) { return; } var nsos = new List <(Nso nso, IFile file)>(); foreach (IFile file in list) { var nso = new Nso(file.AsStorage()); nsos.Add((nso, file)); } var nsoInfos = new List <NsoInfo>(); foreach ((Nso nso, IFile file)nso in nsos) { try { nsoInfos.Add(GetNsoInfo(nso)); } catch (Exception ex) { Console.WriteLine($"Error processing {nso.nso.BuildId.ToHexString()}"); Console.WriteLine(ex); } } var set = new NsoSet(); set.Nsos.AddRange(nsoInfos); NsoSets.Add(set); Version maxVersion = set.Nsos.Where(x => x.Version != null).Select(x => x.Version).Max(); if (maxVersion != null) { NsoInfo maxInfo = set.Nsos.First(x => x.Version == maxVersion); set.Version = maxVersion; set.MaxVersionNso = maxInfo; } foreach (NsoInfo info in nsoInfos) { info.Sets.Add(set); } }
private void ProcessNso(string nsoPath) { FsClient.OpenFile(out FileHandle nsoHandle, nsoPath, OpenMode.Read).ThrowIfFailure(); using (nsoHandle) using (var nsoStorage = new FileHandleStorage(nsoHandle, true)) using (var nsoFile = new StorageFile(nsoStorage, OpenMode.Read)) { var nso = new Nso(nsoStorage); NsoInfo info = GetNsoInfo((nso, nsoFile)); ParseNsoName(nsoPath, info); } }
public void LoadCart(string ExeFsDir, string RomFsFile = null) { if (RomFsFile != null) { Ns.VFs.LoadRomFs(RomFsFile); } int ProcessId = IdGen.GenerateId(); Process MainProcess = new Process(Ns, Allocator, ProcessId); void LoadNso(string FileName) { foreach (string File in Directory.GetFiles(ExeFsDir, FileName)) { if (Path.GetExtension(File) != string.Empty) { continue; } Logging.Info($"Loading {Path.GetFileNameWithoutExtension(File)}..."); using (FileStream Input = new FileStream(File, FileMode.Open)) { Nso Program = new Nso(Input); MainProcess.LoadProgram(Program); } } } LoadNso("rtld"); MainProcess.SetEmptyArgs(); LoadNso("main"); LoadNso("subsdk*"); LoadNso("sdk"); MainProcess.InitializeHeap(); MainProcess.Run(); Processes.TryAdd(ProcessId, MainProcess); }
static void Main(string[] args) { if (args.Length != 5) { Console.WriteLine($"Invalid Arg Nb ({args.Length})"); ShowInfo(); return; } string indir = args[0]; string subsdkPath = args[1]; string outdir = args[2]; string lstFile = args[3]; string configFile = args[4]; Console.WriteLine($"Current dir : {Environment.CurrentDirectory}"); if (!Directory.Exists(indir) || !File.Exists(subsdkPath) || !Directory.Exists(outdir) || !File.Exists(lstFile) || !File.Exists(configFile)) { Console.WriteLine($"Invalid Args :"); foreach (var arg in args) { Console.WriteLine(arg); } ShowInfo(); return; } ExeFS exefs = new ExeFS(indir); Nso custom = new Nso(subsdkPath); //allocate 0x100 bytes at the end of .bss for the module_object AllocModObj(custom); AddSdk(exefs, custom); ApplyPatches(exefs, lstFile, configFile); Console.WriteLine("Exporting..."); exefs.ExportAsDir(outdir); Console.WriteLine("Done!"); }
public void LoadCart(string ExeFsDir, string RomFsFile = null) { if (RomFsFile != null) { Ns.VFs.LoadRomFs(RomFsFile); } Process MainProcess = MakeProcess(); void LoadNso(string FileName) { foreach (string File in Directory.GetFiles(ExeFsDir, FileName)) { if (Path.GetExtension(File) != string.Empty) { continue; } Ns.Log.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(File)}..."); using (FileStream Input = new FileStream(File, FileMode.Open)) { string Name = Path.GetFileNameWithoutExtension(File); Nso Program = new Nso(Input, Name); MainProcess.LoadProgram(Program); } } } LoadNso("rtld"); MainProcess.SetEmptyArgs(); LoadNso("main"); LoadNso("subsdk*"); LoadNso("sdk"); MainProcess.Run(); }
static void Main(string[] args) { if (args.Length != 4) { Console.WriteLine("Usage: IPSwitch-PatchMaker.exe [name of patch] [unpatched NSO] [patched NSO] [save location]"); return; } string patchname = args[0]; FileInfo unpatchednsoPath = new FileInfo(args[1]), patchednsoPath = new FileInfo(args[2]), save = new FileInfo(args[3]); using (var patchedstream = File.OpenRead(patchednsoPath.FullName)) using (var unpatchedstream = File.OpenRead(unpatchednsoPath.FullName)) { var unpatchedNso = new Nso(unpatchedstream.AsStorage()); var patchedNso = new Nso(patchedstream.AsStorage()); if (patchedNso.Sections.Length != unpatchedNso.Sections.Length) { Console.WriteLine("The NSO section lengths do not match (NSO comes from a diffrent application?)"); return; } List <string> patcharraylist = new List <string> { $"//{patchname}", "@enabled" }; string patch, offset = string.Empty; for (int i = 0; i < unpatchedNso.Sections.Length; i++) { NsoSection unpatchedSection = unpatchedNso.Sections[i], patchedSection = patchedNso.Sections[i]; byte[] unpatchedData = unpatchedSection.DecompressSection(), patchedData = patchedSection.DecompressSection(); for (int index = 0; index < patchedData.Length; index++) { if (patchedData[index] != unpatchedData[index]) { offset = $"{index:X8}"; patch = $"{patchedData[index]:X2}"; patcharraylist.Add($"{offset} {patch}"); } else { Console.WriteLine("No diffrences found."); break; } } } File.WriteAllLines(save.FullName, patcharraylist); Console.WriteLine($"Done, {patcharraylist.Count - 2} were different."); } }
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(); }
public void LoadCart(string ExeFsDir, string RomFsFile = null) { if (RomFsFile != null) { Device.FileSystem.LoadRomFs(RomFsFile); } string NpdmFileName = Path.Combine(ExeFsDir, "main.npdm"); Npdm MetaData = null; if (File.Exists(NpdmFileName)) { Logger.PrintInfo(LogClass.Loader, $"Loading main.npdm..."); using (FileStream Input = new FileStream(NpdmFileName, FileMode.Open)) { MetaData = new Npdm(Input); } } else { Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!"); } Process MainProcess = MakeProcess(MetaData); void LoadNso(string FileName) { foreach (string File in Directory.GetFiles(ExeFsDir, FileName)) { if (Path.GetExtension(File) != string.Empty) { continue; } Logger.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(File)}..."); using (FileStream Input = new FileStream(File, FileMode.Open)) { string Name = Path.GetFileNameWithoutExtension(File); Nso Program = new Nso(Input, Name); MainProcess.LoadProgram(Program); } } } if (!(MainProcess.MetaData?.Is64Bits ?? true)) { throw new NotImplementedException("32-bit titles are unsupported!"); } CurrentTitle = MainProcess.MetaData.ACI0.TitleId.ToString("x16"); LoadNso("rtld"); MainProcess.SetEmptyArgs(); LoadNso("main"); LoadNso("subsdk*"); LoadNso("sdk"); MainProcess.Run(); }
private void OnNandFound() { Nand nand = NANDService.NAND; // stream package2 to memory IStorage pkg2nand = nand.OpenPackage2(0); // 0 -> BCPKG2-1-Normal-Main byte[] pkg2raw = new byte[0x7FC000]; // maximum size of pkg2 pkg2nand.Read(0x4000, pkg2raw); MemoryStorage pkg2memory = new MemoryStorage(pkg2raw); HACGUIKeyset.RootTempFolderInfo.Create(); // copy to file for end user using (FileStream pkg2file = HACGUIKeyset.TempPkg2FileInfo.Create()) pkg2memory.CopyToStream(pkg2file); Package2 pkg2 = new Package2(HACGUIKeyset.Keyset, pkg2memory); HACGUIKeyset.RootTempPkg2FolderInfo.Create(); // make sure it exists using (FileStream kernelstream = HACGUIKeyset.TempKernelFileInfo.Create()) pkg2.OpenKernel().CopyToStream(kernelstream); using (FileStream INI1stream = HACGUIKeyset.TempINI1FileInfo.Create()) pkg2.OpenIni1().CopyToStream(INI1stream); Ini1 INI1 = new Ini1(pkg2.OpenIni1()); List <HashSearchEntry> hashes = new List <HashSearchEntry>(); HACGUIKeyset.RootTempINI1FolderInfo.Create(); foreach (Kip kip in INI1.Kips) { using (Stream rodatastream = new MemoryStream(kip.DecompressSection(1))) switch (kip.Header.Name) { case "FS": hashes.Add(new HashSearchEntry( NintendoKeys.KeyAreaKeyApplicationSourceHash, () => HACGUIKeyset.Keyset.KeyAreaKeyApplicationSource, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.KeyAreaKeyOceanSourceHash, () => HACGUIKeyset.Keyset.KeyAreaKeyOceanSource, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.KeyAreaKeySystemSourceHash, () => HACGUIKeyset.Keyset.KeyAreaKeySystemSource, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.HeaderKekSourceHash, () => HACGUIKeyset.Keyset.HeaderKekSource, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.SaveMacKekSourceHash, () => HACGUIKeyset.Keyset.SaveMacKekSource, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.SaveMacKeySourceHash, () => HACGUIKeyset.Keyset.SaveMacKeySource, 0x10)); rodatastream.FindKeysViaHash(hashes, new SHA256Managed(), 0x10); hashes.Clear(); rodatastream.Seek(0, SeekOrigin.Begin); bool sdWarn = false; hashes.Add(new HashSearchEntry(NintendoKeys.SDCardKekSourceHash, () => HACGUIKeyset.Keyset.SdCardKekSource, 0x10)); try { rodatastream.FindKeysViaHash(hashes, new SHA256Managed(), 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, () => HACGUIKeyset.Keyset.SdCardKeySources[0], 0x20)); hashes.Add(new HashSearchEntry( NintendoKeys.SDCardNcaKeySourceHash, () => HACGUIKeyset.Keyset.SdCardKeySources[1], 0x20)); rodatastream.FindKeysViaHash(hashes, new SHA256Managed(), 0x20); } hashes.Clear(); hashes.Add(new HashSearchEntry( NintendoKeys.HeaderKeySourceHash, () => HACGUIKeyset.Keyset.HeaderKeySource, 0x20)); using (Stream datastream = new MemoryStream(kip.DecompressSection(2))) datastream.FindKeysViaHash(hashes, new SHA256Managed(), 0x20); hashes.Clear(); break; case "spl": hashes.Clear(); hashes.Add(new HashSearchEntry( NintendoKeys.AesKeyGenerationSourceHash, () => HACGUIKeyset.Keyset.AesKeyGenerationSource, 0x10)); rodatastream.FindKeysViaHash(hashes, new SHA256Managed(), 0x10); break; } using (FileStream kipstream = HACGUIKeyset.RootTempINI1FolderInfo.GetFile(kip.Header.Name + ".kip").Create()) kip.OpenRawFile().CopyToStream(kipstream); } HACGUIKeyset.Keyset.DeriveKeys(); SwitchFs fs = SwitchFs.OpenNandPartition(HACGUIKeyset.Keyset, nand.OpenSystemPartition()); NintendoKeys.KekSeeds[1].XOR(NintendoKeys.KekMasks[0], out byte[] RsaPrivateKekGenerationSource); NintendoKeys.KekSeeds[3].XOR(NintendoKeys.KekMasks[0], out byte[] RsaOaepKekGenerationSource); foreach (Nca nca in fs.Ncas.Values.Select(n => n.Nca)) { ulong titleId = nca.Header.TitleId; if (!new ulong[] { // check if title ID is one that needs to be processed before opening it 0x0100000000000033, // es 0x0100000000000024, // ssl }.Contains(titleId)) { continue; } // mainly to check if the NCA can be decrypted if (!nca.CanOpenSection(0)) { continue; } if (nca.Header.ContentType != NcaContentType.Program) { continue; } IFileSystem pfs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.ErrorOnInvalid); pfs.OpenFile(out IFile nsoFile, "main".ToU8Span(), OpenMode.Read); Nso nso = new Nso(new FileStorage(nsoFile)); NsoSection section = nso.Sections[1]; Stream data = new MemoryStream(section.DecompressSection()); byte[] key1; byte[] key2; switch (titleId) { case 0x0100000000000033: // es hashes.Clear(); byte[] EticketRsaKekSource = new byte[0x10]; byte[] EticketRsaKekekSource = new byte[0x10]; hashes.Add(new HashSearchEntry( NintendoKeys.EticketRsaKekSourceHash, () => EticketRsaKekSource, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.EticketRsaKekekSourceHash, () => EticketRsaKekekSource, 0x10)); data.FindKeysViaHash(hashes, new SHA256Managed(), 0x10, data.Length); key1 = new byte[0x10]; new AesEcbDecryptor(HACGUIKeyset.Keyset.MasterKeys[0]).Transform(RsaOaepKekGenerationSource, key1); key2 = new byte[0x10]; new AesEcbDecryptor(key1).Transform(EticketRsaKekekSource, key2); new AesEcbDecryptor(key2).Transform(EticketRsaKekSource, HACGUIKeyset.Keyset.EticketRsaKek); break; case 0x0100000000000024: // ssl hashes.Clear(); byte[] SslAesKeyX = new byte[0x10]; byte[] SslRsaKeyY = new byte[0x10]; hashes.Add(new HashSearchEntry( NintendoKeys.SslAesKeyXHash, () => SslAesKeyX, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.SslRsaKeyYHash, () => SslRsaKeyY, 0x10)); data.FindKeysViaHash(hashes, new SHA256Managed(), 0x10, data.Length); key1 = new byte[0x10]; new AesEcbDecryptor(HACGUIKeyset.Keyset.MasterKeys[0]).Transform(RsaPrivateKekGenerationSource, key1); key2 = new byte[0x10]; new AesEcbDecryptor(key1).Transform(SslAesKeyX, key2); new AesEcbDecryptor(key2).Transform(SslRsaKeyY, HACGUIKeyset.Keyset.SslRsaKek); break; } } // save PRODINFO to file, then derive eticket_ext_key_rsa if (!TryDumpCert(nand: nand)) { MessageBox.Show($"Failed to parse decrypted certificate. If you are using Incognito, select your PRODINFO backup now."); Dispatcher.Invoke(() => // dispatcher is required, otherwise a deadlock occurs. probably some threading issue { while (true) { FileInfo info = RequestOpenFileFromUser(".bin", "PRODINFO backup (.bin)|*.bin", "Select a valid PRODINFO backup...", "PRODINFO.bin"); if (info != null) { if (TryDumpCert(info)) { break; } } else { MessageBox.Show("Failed to parse provided PRODINFO. You must have a valid PRODINFO backup."); } } }); } // get tickets new DecryptTicketsTask(PickConsolePage.ConsoleName).CreateTask().RunSynchronously(); FatFileSystemProvider system = NANDService.NAND.OpenSystemPartition(); system.OpenFile(out IFile nsAppmanFile, "save\\8000000000000043".ToU8Span(), OpenMode.Read); IStorage nsAppmanStorage = nsAppmanFile.AsStorage(); SaveDataFileSystem nsAppmanSave = new SaveDataFileSystem(HACGUIKeyset.Keyset, nsAppmanStorage, IntegrityCheckLevel.ErrorOnInvalid, false); nsAppmanSave.OpenFile(out IFile privateFile, "/private".ToU8Span(), OpenMode.Read); byte[] sdIdenitifer = new byte[0x10]; byte[] sdSeed = new byte[0x10]; using (nsAppmanFile) using (nsAppmanSave) using (privateFile) { IStorage privateStorage = privateFile.AsStorage(); privateStorage.Read(0, sdIdenitifer); // stored on SD and NAND, used to uniquely idenitfy the SD/NAND privateStorage.Read(0x10, sdSeed); } HACGUIKeyset.Keyset.SetSdSeed(sdSeed); Preferences.Current.SdIdentifiers[sdIdenitifer.ToHexString()] = sdSeed.ToHexString(); NANDService.Stop(); DirectoryInfo oldKeysDirectory = HACGUIKeyset.RootFolderInfo.GetDirectory("keys"); if (oldKeysDirectory.Exists) { oldKeysDirectory.Delete(true); // fix old versions after restructure of directory } // write all keys to file new SaveKeysetTask(PickConsolePage.ConsoleName).CreateTask().RunSynchronously(); Preferences.Current.DefaultConsoleName = PickConsolePage.ConsoleName; Preferences.Current.Write(); }
static void AllocModObj(Nso nso) { nso.RwdataSegment.BssOrAlign += 0x100; ModHeader.CreateModHeader(nso, nso.GetModAddr(), nso.ModSection.DynamicAddr, nso.ModSection.EhStartAddr, nso.ModSection.EhEndAddr, nso.ModSection.BssEndAddr); }
private void OnNandFound() { Nand nand = NANDService.NAND; FileStream pkg2file = HACGUIKeyset.TempPkg2FileInfo.Create(); IStorage pkg2nand = nand.OpenPackage2(0); byte[] pkg2raw = new byte[0x7FC000]; pkg2nand.Read(pkg2raw, 0x4000); MemoryStorage pkg2memory = new MemoryStorage(pkg2raw); pkg2memory.CopyToStream(pkg2file); Package2 pkg2 = new Package2(HACGUIKeyset.Keyset, pkg2memory); HACGUIKeyset.RootTempPkg2FolderInfo.Create(); FileStream kernelstream = HACGUIKeyset.TempKernelFileInfo.Create(); FileStream INI1stream = HACGUIKeyset.TempINI1FileInfo.Create(); pkg2.OpenKernel().CopyToStream(kernelstream); pkg2.OpenIni1().CopyToStream(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().CopyToStream(kipstream); kipstream.Close(); } pkg2file.Close(); INI1stream.Close(); HACGUIKeyset.Keyset.DeriveKeys(); SwitchFs fs = SwitchFs.OpenNandPartition(HACGUIKeyset.Keyset, NANDService.NAND.OpenSystemPartition()); foreach (KeyValuePair <string, Nca> kv in fs.Ncas) { Nca nca = kv.Value; if (nca.CanOpenSection(0)) // mainly a check if the NCA can be decrypted { switch (nca.Header.TitleId) { case 0x0100000000000033: // es switch (nca.Header.ContentType) { case ContentType.Program: NcaSection exefsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Pfs0); IStorage pfsStorage = nca.OpenSection(exefsSection.SectionNum, false, IntegrityCheckLevel.ErrorOnInvalid, false); PartitionFileSystem pfs = new PartitionFileSystem(pfsStorage); Nso nso = new Nso(new FileStorage(pfs.OpenFile("main", OpenMode.Read))); 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); Crypto.DecryptEcb(key2, EticketRsaKekSource, HACGUIKeyset.Keyset.EticketRsaKek, 0x10); break; } break; case 0x0100000000000024: // ssl switch (nca.Header.ContentType) { case ContentType.Program: NcaSection exefsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Pfs0); IStorage pfsStorage = nca.OpenSection(exefsSection.SectionNum, false, IntegrityCheckLevel.ErrorOnInvalid, false); PartitionFileSystem pfs = new PartitionFileSystem(pfsStorage); Nso nso = new Nso(new FileStorage(pfs.OpenFile("main", OpenMode.Read))); NsoSection section = nso.Sections[1]; Stream data = new MemoryStream(section.DecompressSection()); hashes.Clear(); hashes.Add(new HashSearchEntry(NintendoKeys.SslAesKeyXHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.SslRsaKeyYHash, 0x10)); keys = data.FindKeyViaHash(hashes, new SHA256Managed(), 0x10, data.Length); byte[] SslAesKeyX = new byte[0x10]; byte[] SslRsaKeyY = new byte[0x10]; Array.Copy(keys[NintendoKeys.SslAesKeyXHash], SslAesKeyX, 0x10); Array.Copy(keys[NintendoKeys.SslRsaKeyYHash], SslRsaKeyY, 0x10); byte[] RsaPrivateKekGenerationSource; XOR(NintendoKeys.KekMasks[0], NintendoKeys.KekSeeds[1], out RsaPrivateKekGenerationSource); byte[] key1 = new byte[0x10]; Crypto.DecryptEcb(HACGUIKeyset.Keyset.MasterKeys[0], RsaPrivateKekGenerationSource, key1, 0x10); byte[] key2 = new byte[0x10]; Crypto.DecryptEcb(key1, SslAesKeyX, key2, 0x10); Crypto.DecryptEcb(key2, SslRsaKeyY, HACGUIKeyset.Keyset.SslRsaKek, 0x10); break; } break; } } } // save PRODINFO to file, then derive eticket_ext_key_rsa 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); // get client certificate prodinfo.Seek(0x0AD0, SeekOrigin.Begin); byte[] buffer; buffer = new byte[0x4]; prodinfo.Read(buffer, 0, buffer.Length); // read cert length uint certLength = BitConverter.ToUInt32(buffer, 0); buffer = new byte[certLength]; prodinfo.Seek(0x0AE0, SeekOrigin.Begin); // should be redundant? prodinfo.Read(buffer, 0, buffer.Length); // read actual cert byte[] counter = cal0.SslExtKey.Take(0x10).ToArray(); byte[] key = cal0.SslExtKey.Skip(0x10).ToArray(); // bit strange structure but it works new Aes128CtrTransform(HACGUIKeyset.Keyset.SslRsaKek, counter).TransformBlock(key); // decrypt private key X509Certificate2 certificate = new X509Certificate2(); certificate.Import(buffer); certificate.ImportPrivateKey(key); byte[] pfx = certificate.Export(X509ContentType.Pkcs12, "switch"); Stream pfxStream = HACGUIKeyset.GetClientCertificateByName(PickConsolePage.ConsoleName).Create(); pfxStream.Write(pfx, 0, pfx.Length); pfxStream.Close(); prodinfoFile.Close(); // get tickets List <Ticket> tickets = new List <Ticket>(); FatFileSystemProvider system = nand.OpenSystemPartition(); const string e1FileName = "save\\80000000000000E1"; const string e2FileName = "save\\80000000000000E2"; if (system.FileExists(e1FileName)) { IFile e1File = system.OpenFile(e1FileName, OpenMode.Read); IStorage e1Storage = new FileStorage(e1File); tickets.AddRange(DumpTickets(HACGUIKeyset.Keyset, e1Storage, PickConsolePage.ConsoleName)); } if (system.FileExists(e2FileName)) { IFile e2File = system.OpenFile(e2FileName, OpenMode.Read); IStorage e2Storage = new FileStorage(e2File); tickets.AddRange(DumpTickets(HACGUIKeyset.Keyset, e2Storage, PickConsolePage.ConsoleName)); } IStorage nsAppmanStorage = new FileStorage(system.OpenFile("save\\8000000000000043", OpenMode.Read)); SaveDataFileSystem save = new SaveDataFileSystem(HACGUIKeyset.Keyset, nsAppmanStorage, IntegrityCheckLevel.ErrorOnInvalid, false); IStorage privateStorage = new FileStorage(save.OpenFile("/private", OpenMode.Read)); byte[] sdSeed = new byte[0x10]; privateStorage.Read(sdSeed, 0x10); HACGUIKeyset.Keyset.SetSdSeed(sdSeed); foreach (Ticket ticket in tickets) { HACGUIKeyset.Keyset.TitleKeys[ticket.RightsId] = new byte[0x10]; Array.Copy(ticket.GetTitleKey(HACGUIKeyset.Keyset), HACGUIKeyset.Keyset.TitleKeys[ticket.RightsId], 0x10); } NANDService.Stop(); DirectoryInfo oldKeysDirectory = HACGUIKeyset.RootFolderInfo.GetDirectory("keys"); if (oldKeysDirectory.Exists) { oldKeysDirectory.Delete(true); // fix old versions after restructure of directory } // write all keys to file new SaveKeysetTask(PickConsolePage.ConsoleName).CreateTask().RunSynchronously(); Preferences.Current.DefaultConsoleName = PickConsolePage.ConsoleName; Preferences.Current.Write(); }