Exemple #1
0
        public Xb2FileSystem(string sdPath)
        {
            SwitchFs    sdFs   = OpenSdCard(sdPath);
            Application xb2App = sdFs.Applications[0x0100E95004038000];

            IFileSystem mainFs  = xb2App.Patch.MainNca.OpenSectionFileSystem(1, IntegrityCheckLevel.ErrorOnInvalid);
            IFile       mainArh = mainFs.OpenFile("/bf2.arh", OpenMode.Read);
            IFile       mainArd = mainFs.OpenFile("/bf2.ard", OpenMode.Read);

            var mainArchiveFs = new ArchiveFileSystem(mainArh, mainArd);

            var fsList = new List <IFileSystem>();

            fsList.Add(xb2App.Patch.MainNca.OpenSectionFileSystem(1, IntegrityCheckLevel.ErrorOnInvalid));
            fsList.Add(mainArchiveFs);

            foreach (Title aoc in xb2App.AddOnContent.OrderBy(x => x.Id))
            {
                IFileSystem aocFs = aoc.MainNca.OpenSectionFileSystem(0, IntegrityCheckLevel.ErrorOnInvalid);
                fsList.Add(aocFs);

                if (aoc.Id == 0x0100E95004039001)
                {
                    IFile aocArh = aocFs.OpenFile("/aoc1.arh", OpenMode.Read);
                    IFile aocArd = aocFs.OpenFile("/aoc1.ard", OpenMode.Read);

                    var aocArchiveFs = new ArchiveFileSystem(aocArh, aocArd);
                    fsList.Add(aocArchiveFs);
                }
            }

            fsList.Reverse();
            BaseFs = new LayeredFileSystem(fsList);
        }
Exemple #2
0
        private static SwitchFs OpenSdCard(string path, IProgressReport logger = null)
        {
            SwitchFs switchFs;
            Keyset   keyset = OpenKeyset();

            var baseFs = new LocalFileSystem(path);

            if (Directory.Exists(Path.Combine(path, "Nintendo", "Contents", "registered")))
            {
                logger?.LogMessage("Treating path as SD card storage");
                switchFs = SwitchFs.OpenSdCard(keyset, baseFs);
            }
            else if (Directory.Exists(Path.Combine(path, "Contents", "registered")))
            {
                logger?.LogMessage("Treating path as NAND storage");
                switchFs = SwitchFs.OpenNandPartition(keyset, baseFs);
            }
            else
            {
                logger?.LogMessage("Treating path as a directory of loose NCAs");
                switchFs = SwitchFs.OpenNcaDirectory(keyset, baseFs);
            }

            return(switchFs);
        }
Exemple #3
0
        public SwitchFs LoadFileSystem(Func <SwitchFs> fs)
        {
            FS = fs();
            Ready(this, null);

            return(FS);
        }
Exemple #4
0
        public static void Listnca(string sdfs, string fwint, Keyset keyset, JsonWriter writer)
        {
            SwitchFs        switchFs;
            LocalFileSystem baseFs = new LocalFileSystem(sdfs);

            switchFs = SwitchFs.OpenNcaDirectory(keyset, baseFs);
            string lasttitleid = "";
            string lastncaid   = "";
            string type;

            foreach (SwitchFsNca nca in switchFs.Ncas.Values.OrderBy(x => x.Nca.Header.TitleId))
            {
                if (nca.Nca.Header.TitleId.ToString("X16") != lasttitleid)
                {
                    writer.WritePropertyName(nca.Nca.Header.TitleId.ToString("X16"));
                    writer.WriteStartObject();
                    writer.WritePropertyName(nca.Nca.Header.ContentType.ToString());
                    writer.WriteValue(nca.NcaId);
                    // solo contiene META
                    if (int.Parse(fwint) >= 738197944)
                    {
                        if ("0100000000000825" == nca.Nca.Header.TitleId.ToString("X16") || "0100000000000029" == nca.Nca.Header.TitleId.ToString("X16") || "0100000000000816" == nca.Nca.Header.TitleId.ToString("X16"))
                        {
                            writer.WriteEnd();
                        }
                    }
                    else if ("010000000000001B" == nca.Nca.Header.TitleId.ToString("X16") || "0100000000000029" == nca.Nca.Header.TitleId.ToString("X16") || "0100000000000816" == nca.Nca.Header.TitleId.ToString("X16"))
                    {
                        writer.WriteEnd();
                    }

                    lastncaid   = nca.NcaId;
                    lasttitleid = nca.Nca.Header.TitleId.ToString("X16");
                }
                if (lastncaid != nca.NcaId && lasttitleid == nca.Nca.Header.TitleId.ToString())
                {
                    if (nca.Nca.Header.ContentType.ToString() == "Data" || nca.Nca.Header.ContentType.ToString() == "PublicData")
                    {
                        type = "Program";
                    }
                    else
                    {
                        type = nca.Nca.Header.ContentType.ToString();
                    }
                    writer.WritePropertyName(type);
                    writer.WriteValue(nca.NcaId);
                    writer.WriteEnd();
                    lastncaid   = nca.NcaId;
                    lasttitleid = nca.Nca.Header.TitleId.ToString("X16");
                }
                else if (lastncaid != nca.NcaId && lasttitleid != nca.Nca.Header.TitleId.ToString())
                {
                    writer.WritePropertyName(nca.Nca.Header.ContentType.ToString());
                    writer.WriteValue(nca.NcaId);
                    writer.WriteEnd();
                    lastncaid   = nca.NcaId;
                    lasttitleid = nca.Nca.Header.TitleId.ToString("X16");
                }
            }
        }
Exemple #5
0
        static void ListTitles(SwitchFs sdfs)
        {
            foreach (Title title in sdfs.Titles.Values.OrderBy(x => x.Id))
            {
                Console.WriteLine($"{title.Name} {title.Control?.DisplayVersion}");
                Console.WriteLine($"{title.Id:X16} v{title.Version.Version} ({title.Version}) {title.Metadata.Type}");

                foreach (CnmtContentEntry content in title.Metadata.ContentEntries)
                {
                    Console.WriteLine(
                        $"    {content.NcaId.ToHexString()}.nca {content.Type} {Util.GetBytesReadable(content.Size)}");
                }

                foreach (Nca nca in title.Ncas)
                {
                    Console.WriteLine($"      {nca.HasRightsId} {nca.NcaId} {nca.Header.ContentType}");

                    foreach (NcaSection sect in nca.Sections.Where(x => x != null))
                    {
                        Console.WriteLine($"        {sect.SectionNum} {sect.Type} {sect.Header.EncryptionType} {sect.MasterHashValidity}");
                    }
                }

                Console.WriteLine("");
            }
        }
Exemple #6
0
        private static void CheckForNcaFolders(Context ctx, SwitchFs switchFs)
        {
#if NETCOREAPP
            // Skip this until Linux gets FAT attribute support
            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                return;
            }
#endif

            IFileSystem fs = switchFs.ContentFs;

            DirectoryEntry[] ncaDirs = fs.EnumerateEntries("*.nca", SearchOptions.RecurseSubdirectories)
                                       .Where(x => x.Type == DirectoryEntryType.Directory)
                                       .Where(x => fs.FileExists($"{x.FullPath}/00"))
                                       .ToArray();

            if (ncaDirs.Length > 0)
            {
                ctx.Logger.LogMessage("Warning: NCA folders without the archive flag were found. Fixing...");
            }

            foreach (DirectoryEntry file in ncaDirs)
            {
                fs.SetConcatenationFileAttribute(file.FullPath);
                ctx.Logger.LogMessage($"{file.FullPath}");
            }
        }
Exemple #7
0
        public void LoadFileSystem(Func <SwitchFs> fsf, TitleSource source)
        {
            SwitchFs fs = fsf();

            Ready?.Invoke(source);
            IndexedFilesystems[source].Add(fs);
        }
Exemple #8
0
        private static void ValidateSwitchFs(Context ctx, SwitchFs switchFs)
        {
            if (ctx.Options.TitleId != 0)
            {
                ulong id = ctx.Options.TitleId;

                if (!switchFs.Titles.TryGetValue(id, out Title title))
                {
                    ctx.Logger.LogMessage($"Could not find title {id:X16}");
                    return;
                }

                ValidateTitle(ctx, title, "");

                return;
            }

            foreach (Application app in switchFs.Applications.Values)
            {
                ctx.Logger.LogMessage($"Checking {app.Name}...");

                Title mainTitle = app.Patch ?? app.Main;

                if (mainTitle != null)
                {
                    ValidateTitle(ctx, mainTitle, "Main title");
                }

                foreach (Title title in app.AddOnContent)
                {
                    ValidateTitle(ctx, title, "Add-on content");
                }
            }
        }
Exemple #9
0
        private static void SaveTitle(Context ctx, SwitchFs switchFs)
        {
            ulong id = ctx.Options.TitleId;

            if (id == 0)
            {
                ctx.Logger.LogMessage("Title ID must be specified to save title");
                return;
            }

            if (!switchFs.Titles.TryGetValue(id, out Title title))
            {
                ctx.Logger.LogMessage($"Could not find title {id:X16}");
                return;
            }

            string saveDir = Path.Combine(ctx.Options.OutDir, $"{title.Id:X16}v{title.Version.Version}");

            Directory.CreateDirectory(saveDir);

            foreach (SwitchFsNca nca in title.Ncas)
            {
                Stream stream  = nca.Nca.BaseStorage.AsStream();
                string outFile = Path.Combine(saveDir, nca.Filename);
                ctx.Logger.LogMessage(nca.Filename);
                using (var outStream = new FileStream(outFile, FileMode.Create, FileAccess.ReadWrite))
                {
                    stream.CopyStream(outStream, stream.Length, ctx.Logger);
                }
            }
        }
Exemple #10
0
 private static void ExportSdSaves(Context ctx, SwitchFs switchFs)
 {
     foreach (KeyValuePair <string, SaveDataFileSystem> save in switchFs.Saves)
     {
         string outDir = Path.Combine(ctx.Options.SaveOutDir, save.Key);
         save.Value.Extract(outDir, ctx.Logger);
     }
 }
Exemple #11
0
        public SwitchFS(string switchFsDir, IProgressReport logger = null)
        {
            FileSystemDir = switchFsDir;

            Keyset = GetKeyset(logger);
            var localFs = new LocalFileSystem(switchFsDir);

            SwitchFs = SwitchFs.OpenSdCard(Keyset, localFs);
        }
Exemple #12
0
 private static void ReadSwitchFs(string nandFile)
 {
     using (var logger = new ProgressBar())
         using (var stream = new FileStream(nandFile, FileMode.Open, FileAccess.Read))
         {
             Keyset keyset = OpenKeyset();
             var    nand   = new Nand(stream, keyset);
             FatFileSystemProvider user = nand.OpenSystemPartition();
             SwitchFs sdfs = SwitchFs.OpenNandPartition(keyset, user);
         }
 }
Exemple #13
0
        static string ListNcas(SwitchFs sdfs)
        {
            var table = new TableBuilder("NCA ID", "Type", "Title ID");

            foreach (SwitchFsNca nca in sdfs.Ncas.Values.OrderBy(x => x.NcaId))
            {
                table.AddRow(nca.NcaId, nca.Nca.Header.ContentType.Print(), nca.Nca.Header.TitleId.ToString("X16"));
            }

            return(table.Print());
        }
Exemple #14
0
        public static void CreateNsp(Context ctx, SwitchFs switchFs)
        {
            ulong id = ctx.Options.TitleId;

            if (id == 0)
            {
                ctx.Logger.LogMessage("Title ID must be specified to save title");
                return;
            }

            if (!switchFs.Titles.TryGetValue(id, out Title title))
            {
                ctx.Logger.LogMessage($"Could not find title {id:X16}");
                return;
            }

            var builder = new PartitionFileSystemBuilder();

            foreach (SwitchFsNca nca in title.Ncas)
            {
                builder.AddFile(nca.Filename, nca.Nca.BaseStorage.AsFile(OpenMode.Read));
            }

            var ticket = new Ticket
            {
                SignatureType    = TicketSigType.Rsa2048Sha256,
                Signature        = new byte[0x200],
                Issuer           = "Root-CA00000003-XS00000020",
                FormatVersion    = 2,
                RightsId         = title.MainNca.Nca.Header.RightsId.ToArray(),
                TitleKeyBlock    = title.MainNca.Nca.GetDecryptedTitleKey(),
                CryptoType       = title.MainNca.Nca.Header.KeyGeneration,
                SectHeaderOffset = 0x2C0
            };

            byte[] ticketBytes = ticket.GetBytes();
            builder.AddFile($"{ticket.RightsId.ToHexString()}.tik", new MemoryStream(ticketBytes).AsIFile(OpenMode.ReadWrite));

            Assembly thisAssembly = Assembly.GetExecutingAssembly();
            Stream   cert         = thisAssembly.GetManifestResourceStream("hactoolnet.CA00000003_XS00000020");

            builder.AddFile($"{ticket.RightsId.ToHexString()}.cert", cert.AsIFile(OpenMode.Read));

            using (var outStream = new FileStream(ctx.Options.NspOut, FileMode.Create, FileAccess.ReadWrite))
            {
                IStorage builtPfs = builder.Build(PartitionFileSystemType.Standard);
                builtPfs.GetSize(out long pfsSize).ThrowIfFailure();

                builtPfs.CopyToStream(outStream, pfsSize, ctx.Logger);
            }
        }
Exemple #15
0
        public static void CreateNsp(Context ctx, SwitchFs switchFs)
        {
            ulong id = ctx.Options.TitleId;

            if (id == 0)
            {
                ctx.Logger.LogMessage("Title ID must be specified to save title");
                return;
            }

            if (!switchFs.Titles.TryGetValue(id, out Title title))
            {
                ctx.Logger.LogMessage($"Could not find title {id:X16}");
                return;
            }

            var builder = new Pfs0Builder();

            foreach (Nca nca in title.Ncas)
            {
                builder.AddFile(nca.Filename, nca.GetStorage().AsStream());
            }

            var ticket = new Ticket
            {
                SignatureType    = TicketSigType.Rsa2048Sha256,
                Signature        = new byte[0x200],
                Issuer           = "Root-CA00000003-XS00000020",
                FormatVersion    = 2,
                RightsId         = title.MainNca.Header.RightsId,
                TitleKeyBlock    = title.MainNca.TitleKey,
                CryptoType       = title.MainNca.Header.CryptoType2,
                SectHeaderOffset = 0x2C0
            };

            byte[] ticketBytes = ticket.GetBytes();
            builder.AddFile($"{ticket.RightsId.ToHexString()}.tik", new MemoryStream(ticketBytes));

            Assembly thisAssembly = Assembly.GetExecutingAssembly();
            Stream   cert         = thisAssembly.GetManifestResourceStream("hactoolnet.CA00000003_XS00000020");

            builder.AddFile($"{ticket.RightsId.ToHexString()}.cert", cert);


            using (var outStream = new FileStream(ctx.Options.NspOut, FileMode.Create, FileAccess.ReadWrite))
            {
                builder.Build(outStream, ctx.Logger);
            }
        }
Exemple #16
0
        static string ListTitles(SwitchFs sdfs)
        {
            var table = new TableBuilder("Title ID", "Version", "", "Type", "Size", "Display Version", "Name");

            foreach (Title title in sdfs.Titles.Values.OrderBy(x => x.Id))
            {
                table.AddRow($"{title.Id:X16}",
                             $"v{title.Version?.Version}",
                             title.Version?.ToString(),
                             title.Metadata?.Type.Print(),
                             Utilities.GetBytesReadable(title.GetSize()),
                             title.Control.Value.DisplayVersion.ToString(),
                             title.Name);
            }

            return(table.Print());
        }
Exemple #17
0
        static string ListApplications(SwitchFs sdfs)
        {
            var sb = new StringBuilder();

            foreach (Application app in sdfs.Applications.Values.OrderBy(x => x.Name))
            {
                if (app.Main != null)
                {
                    sb.AppendLine($"{app.Name} v{app.DisplayVersion} ({app.Main.Id.ToString("X16")})");
                    sb.AppendLine($"Software: {Utilities.GetBytesReadable(app.Main.GetSize())}");
                }
                else
                {
                    sb.AppendLine($"{app.Name} v{app.DisplayVersion}");
                }

                if (app.Patch != null)
                {
                    sb.AppendLine($"Update Data: {Utilities.GetBytesReadable(app.Patch.GetSize())}");
                }

                if (app.AddOnContent.Count > 0)
                {
                    sb.AppendLine($"DLC: {Utilities.GetBytesReadable(app.AddOnContent.Sum(x => x.GetSize()))}");
                }

                ref ApplicationControlProperty nacp = ref app.Nacp.Value;

                long userTotalSaveDataSize   = nacp.UserAccountSaveDataSize + nacp.UserAccountSaveDataJournalSize;
                long deviceTotalSaveDataSize = nacp.DeviceSaveDataSize + nacp.DeviceSaveDataJournalSize;

                if (userTotalSaveDataSize > 0)
                {
                    sb.AppendLine($"User save: {Utilities.GetBytesReadable(userTotalSaveDataSize)}");
                }
                if (deviceTotalSaveDataSize > 0)
                {
                    sb.AppendLine($"System save: {Utilities.GetBytesReadable(deviceTotalSaveDataSize)}");
                }
                if (nacp.BcatDeliveryCacheStorageSize > 0)
                {
                    sb.AppendLine($"BCAT save: {Utilities.GetBytesReadable(nacp.BcatDeliveryCacheStorageSize)}");
                }

                sb.AppendLine();
            }
Exemple #18
0
        public static void ListTitleid(string sdfs, Keyset keyset, JsonWriter writer)
        {
            SwitchFs        switchFs;
            LocalFileSystem baseFs = new LocalFileSystem(sdfs);

            switchFs = SwitchFs.OpenNcaDirectory(keyset, baseFs);
            string lasttitleid = "";

            foreach (SwitchFsNca nca in switchFs.Ncas.Values.OrderBy(x => x.Nca.Header.TitleId))
            {
                if (nca.Nca.Header.TitleId.ToString("X16") == lasttitleid)
                {
                    continue;
                }
                lasttitleid = nca.Nca.Header.TitleId.ToString("X16");
                writer.WriteValue(nca.Nca.Header.TitleId.ToString("X16"));
            }
        }
Exemple #19
0
        public static void MatchupBaseNca(this IEnumerable <SwitchFsNca> ncas)
        {
            PseudoFileSystem ps = ncas.MakeFs();
            SwitchFs         fs = SwitchFs.OpenNcaDirectory(HACGUIKeyset.Keyset, ps);

            foreach (KeyValuePair <ulong, LibHac.Application> kv in fs.Applications)
            {
                ulong tid = kv.Key;
                LibHac.Application app = kv.Value;

                if (app.Patch != null && app.Main != null)
                {
                    foreach (SwitchFsNca nca in app.Patch.Ncas)
                    {
                        ContentType type    = nca.Nca.Header.ContentType;
                        SwitchFsNca baseNca = app.Main.Ncas.Where(n => n.Nca.Header.ContentType == type).FirstOrDefault();
                        if (baseNca != null)
                        {
                            bool hasPatch = false;
                            for (int i = 0; i < 4; i++)
                            {
                                Nca n = nca.Nca;
                                if (n.CanOpenSection(i))
                                {
                                    NcaFsHeader section = n.Header.GetFsHeader(i);
                                    if (section.IsPatchSection())
                                    {
                                        hasPatch = true;
                                        break;
                                    }
                                }
                            }
                            if (hasPatch)
                            {
                                ncas.Where(n => n.Filename == nca.Filename.Replace("/", "")).First().BaseNca = baseNca.Nca; // set original NCA, not new parsed one
                            }
                        }
                    }
                }
            }
        }
Exemple #20
0
        static string ListApplications(SwitchFs sdfs)
        {
            var sb = new StringBuilder();

            foreach (Application app in sdfs.Applications.Values.OrderBy(x => x.Name))
            {
                sb.AppendLine($"{app.Name} v{app.DisplayVersion}");

                if (app.Main != null)
                {
                    sb.AppendLine($"Software: {Util.GetBytesReadable(app.Main.GetSize())}");
                }

                if (app.Patch != null)
                {
                    sb.AppendLine($"Update Data: {Util.GetBytesReadable(app.Patch.GetSize())}");
                }

                if (app.AddOnContent.Count > 0)
                {
                    sb.AppendLine($"DLC: {Util.GetBytesReadable(app.AddOnContent.Sum(x => x.GetSize()))}");
                }

                if (app.Nacp?.UserTotalSaveDataSize > 0)
                {
                    sb.AppendLine($"User save: {Util.GetBytesReadable(app.Nacp.UserTotalSaveDataSize)}");
                }
                if (app.Nacp?.DeviceTotalSaveDataSize > 0)
                {
                    sb.AppendLine($"System save: {Util.GetBytesReadable(app.Nacp.DeviceTotalSaveDataSize)}");
                }
                if (app.Nacp?.BcatDeliveryCacheStorageSize > 0)
                {
                    sb.AppendLine($"BCAT save: {Util.GetBytesReadable(app.Nacp.BcatDeliveryCacheStorageSize)}");
                }

                sb.AppendLine();
            }

            return(sb.ToString());
        }
Exemple #21
0
        public static List <FsTitle> processSd(string path)
        {
            try
            {
                using (var fs = new SwitchFs(keyset, new FileSystem(path), true))
                {
                    log?.WriteLine("{0} of {1} NCA processed", fs?.Titles?.Select(title => title.Value.Ncas.Count)?.Sum(), fs?.Ncas?.Count);

                    List <Application> applications = fs?.Applications?.Values?.ToList() ?? new List <Application>();

                    log?.WriteLine("Found {0} applications", applications?.Count);

                    List <FsTitle> fsTitles = new List <FsTitle>();

                    foreach (Application application in applications)
                    {
                        if (application.Main != null)
                        {
                            if (application.Main.MetaNca != null || application.Patch?.MetaNca == null)
                            {
                                fsTitles.Add(application.Main);
                            }
                        }

                        if (application.Patch?.MetaNca != null)
                        {
                            fsTitles.Add(application.Patch);
                        }

                        fsTitles.AddRange(application.AddOnContent);
                    }

                    return(fsTitles.OrderBy(fsTitle => fsTitle.Id).ToList());
                }
            }
            catch (DirectoryNotFoundException)
            {
                return(null);
            }
        }
Exemple #22
0
        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));
        }
Exemple #23
0
        private void ImportGameDataClicked(object sender, RoutedEventArgs arg)
        {
            string filter = @"
                Any game data (*.xci,*.nca,*.nsp)|*.xci;*.nca;*.nsp|
                NX Card Image (*.xci)|*.xci|
                Nintendo Content Archive (*.nca)|*.nca|
                Nintendo Installable Package (*.nsp)|*.nsp
            ".FilterMultilineString();

            FileInfo[] files = RequestOpenFilesFromUser(".*", filter, "Select game data...");

            if (files == null)
            {
                return;
            }

            TaskManagerPage.Current.Queue.Submit(new RunTask("Processing imported game data...", new Task(() =>
            {
                IEnumerable <FileInfo> ncas = files.Where((f) =>
                {
                    try
                    {
                        new Nca(HACGUIKeyset.Keyset, new LocalFile(f.FullName, OpenMode.Read).AsStorage());
                        return(true);
                    }
                    catch (Exception)
                    {
                        return(false);
                    }
                });
                IEnumerable <FileInfo> xcis = files.Except(ncas).Where((f) =>
                {
                    try
                    {
                        new Xci(HACGUIKeyset.Keyset, new LocalFile(f.FullName, OpenMode.Read).AsStorage());
                        return(true);
                    }
                    catch (Exception)
                    {
                        return(false);
                    }
                });
                IEnumerable <FileInfo> nsp = files.Except(ncas).Except(xcis).Where((f) =>
                {
                    try
                    {
                        new PartitionFileSystem(new LocalFile(f.FullName, OpenMode.Read).AsStorage());
                        return(true);
                    }
                    catch (Exception)
                    {
                        return(false);
                    }
                });

                List <SwitchFs> switchFilesystems = new List <SwitchFs>();
                if (ncas.Any())
                {
                    switchFilesystems.Add(SwitchFs.OpenNcaDirectory(HACGUIKeyset.Keyset, ncas.MakeFs()));
                }

                foreach (FileInfo file in xcis)
                {
                    Xci xci = new Xci(HACGUIKeyset.Keyset, new LocalFile(file.FullName, OpenMode.Read).AsStorage());
                    switchFilesystems.Add(SwitchFs.OpenNcaDirectory(HACGUIKeyset.Keyset, xci.OpenPartition(XciPartitionType.Secure)));
                }

                bool foundTicket = true;
                foreach (FileInfo file in nsp)
                {
                    PartitionFileSystem fs = new PartitionFileSystem(new LocalFile(file.FullName, OpenMode.Read).AsStorage());
                    foreach (DirectoryEntry d in fs.EnumerateEntries().Where(e => e.Type == DirectoryEntryType.File && e.Name.EndsWith(".tik")))
                    {
                        using (IFile tikFile = fs.OpenFile(d.FullPath, OpenMode.Read)) {
                            Ticket t = new Ticket(new BinaryReader(tikFile.AsStream()));
                            try
                            {
                                HACGUIKeyset.Keyset.TitleKeys[t.RightsId] = t.GetTitleKey(HACGUIKeyset.Keyset);
                                foundTicket = true;
                            } catch (Exception e)
                            {
                                MessageBox.Show("Failed to import .tik file included in NSP.");
                            }
                        }
                    }
                    switchFilesystems.Add(SwitchFs.OpenNcaDirectory(HACGUIKeyset.Keyset, fs));
                }

                if (foundTicket)
                {
                    TaskManagerPage.Current.Queue.Submit(new SaveKeysetTask(Preferences.Current.DefaultConsoleName));
                }

                foreach (SwitchFs fs in switchFilesystems)
                {
                    DeviceService.FsView.LoadFileSystemAsync("Opening imported data...", () => fs, FSView.TitleSource.Imported, false);
                }
            })));
        }
Exemple #24
0
        public static void Start()
        {
            if (!Started)
            {
                Started = true;

                NANDSystemTitleView = new FSView(TitleSource.NAND);
                NANDUserTitleView   = new FSView(TitleSource.NAND);
                SDTitleView         = new FSView(TitleSource.SD);

                Applications = new Dictionary <ulong, Application>();
                Titles       = new Dictionary <ulong, Title>();
                Saves        = new Dictionary <string, SaveDataFileSystem>();

                SDService.OnSDPluggedIn += (drive) =>
                {
                    SDTitleView.Ready += (_, __) =>
                    {
                        StatusService.SDStatus = StatusService.Status.OK;
                    };

                    SDTitleView.LoadFileSystemAsync("Opening SD filesystem...", () => SwitchFs.OpenSdCard(HACGUIKeyset.Keyset, new LocalFileSystem(drive.RootDirectory.FullName)), true);
                    Update();

                    StatusService.SDStatus = StatusService.Status.Progress;
                };

                SDService.OnSDRemoved += (drive) =>
                {
                    StatusService.SDStatus = StatusService.Status.Incorrect;
                    SDTitleView.FS         = null;
                    Update();
                };

                NANDService.OnNANDPluggedIn += () =>
                {
                    void onComplete()
                    {
                        StatusService.NANDStatus = StatusService.Status.OK;
                        Update();
                    };

                    int count = 0;
                    NANDSystemTitleView.Ready += (_, __) =>
                    {
                        count++;
                        if (count >= 2)
                        {
                            onComplete();
                        }
                    };
                    NANDUserTitleView.Ready += (_, __) =>
                    {
                        count++;
                        if (count >= 2)
                        {
                            onComplete();
                        }
                    };

                    NANDUserTitleView.LoadFileSystemAsync("Opening NAND user filesystem...", () => SwitchFs.OpenNandPartition(HACGUIKeyset.Keyset, NANDService.NAND.OpenUserPartition()), false);
                    NANDSystemTitleView.LoadFileSystemAsync("Opening NAND system filesystem...", () => SwitchFs.OpenNandPartition(HACGUIKeyset.Keyset, NANDService.NAND.OpenSystemPartition()), true);
                    TaskManagerPage.Current.Queue.Submit(new DecryptTicketsTask());

                    StatusService.NANDStatus = StatusService.Status.Progress;
                };

                NANDService.OnNANDRemoved += () =>
                {
                    StatusService.NANDStatus = StatusService.Status.Incorrect;

                    NANDSystemTitleView.FS = null;
                    NANDUserTitleView.FS   = null;

                    Update();
                };

                SDService.Start();
                NANDService.Start();

                Update();
            }
        }
Exemple #25
0
        public static void Process(Context ctx)
        {
            var switchFs = new SwitchFs(ctx.Keyset, new FileSystem(ctx.Options.InFile));

            if (ctx.Options.ListTitles)
            {
                ListTitles(switchFs);
            }

            if (ctx.Options.ListApps)
            {
                ctx.Logger.LogMessage(ListApplications(switchFs));
            }

            if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null)
            {
                ulong id = ctx.Options.TitleId;
                if (id == 0)
                {
                    ctx.Logger.LogMessage("Title ID must be specified to dump ExeFS");
                    return;
                }

                if (!switchFs.Titles.TryGetValue(id, out Title title))
                {
                    ctx.Logger.LogMessage($"Could not find title {id:X16}");
                    return;
                }

                if (title.MainNca == null)
                {
                    ctx.Logger.LogMessage($"Could not find main data for title {id:X16}");
                    return;
                }

                NcaSection section = title.MainNca.Sections[(int)ProgramPartitionType.Code];

                if (section == null)
                {
                    ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no ExeFS section");
                    return;
                }

                if (ctx.Options.ExefsOutDir != null)
                {
                    title.MainNca.ExtractSection(section.SectionNum, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
                }

                if (ctx.Options.ExefsOut != null)
                {
                    title.MainNca.ExportSection(section.SectionNum, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
                }
            }

            if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null)
            {
                ulong id = ctx.Options.TitleId;
                if (id == 0)
                {
                    ctx.Logger.LogMessage("Title ID must be specified to dump RomFS");
                    return;
                }

                if (!switchFs.Titles.TryGetValue(id, out Title title))
                {
                    ctx.Logger.LogMessage($"Could not find title {id:X16}");
                    return;
                }

                if (title.MainNca == null)
                {
                    ctx.Logger.LogMessage($"Could not find main data for title {id:X16}");
                    return;
                }

                NcaSection section = title.MainNca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs || x?.Type == SectionType.Bktr);

                if (section == null)
                {
                    ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no RomFS section");
                    return;
                }

                if (ctx.Options.RomfsOutDir != null)
                {
                    var romfs = new Romfs(title.MainNca.OpenSection(section.SectionNum, false, ctx.Options.IntegrityLevel));
                    romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger);
                }

                if (ctx.Options.RomfsOut != null)
                {
                    title.MainNca.ExportSection(section.SectionNum, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
                }
            }

            if (ctx.Options.OutDir != null)
            {
                SaveTitle(ctx, switchFs);
            }

            if (ctx.Options.NspOut != null)
            {
                ProcessNsp.CreateNsp(ctx, switchFs);
            }

            if (ctx.Options.SaveOutDir != null)
            {
                ExportSdSaves(ctx, switchFs);
            }

            if (ctx.Options.Validate)
            {
                ValidateSwitchFs(ctx, switchFs);
            }
        }
Exemple #26
0
        public static void Process(Context ctx)
        {
            SwitchFs switchFs;
            var      baseFs = new LocalFileSystem(ctx.Options.InFile);

            if (Directory.Exists(Path.Combine(ctx.Options.InFile, "Nintendo", "Contents", "registered")))
            {
                ctx.Logger.LogMessage("Treating path as SD card storage");
                switchFs = SwitchFs.OpenSdCard(ctx.Keyset, baseFs);
            }
            else if (Directory.Exists(Path.Combine(ctx.Options.InFile, "Contents", "registered")))
            {
                ctx.Logger.LogMessage("Treating path as NAND storage");
                switchFs = SwitchFs.OpenNandPartition(ctx.Keyset, baseFs);
            }
            else
            {
                ctx.Logger.LogMessage("Treating path as a directory of loose NCAs");
                switchFs = SwitchFs.OpenNcaDirectory(ctx.Keyset, baseFs);
            }

            if (ctx.Options.ListNcas)
            {
                ctx.Logger.LogMessage(ListNcas(switchFs));
            }

            if (ctx.Options.ListTitles)
            {
                ctx.Logger.LogMessage(ListTitles(switchFs));
            }

            if (ctx.Options.ListApps)
            {
                ctx.Logger.LogMessage(ListApplications(switchFs));
            }

            if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null)
            {
                ulong id = ctx.Options.TitleId;
                if (id == 0)
                {
                    ctx.Logger.LogMessage("Title ID must be specified to dump ExeFS");
                    return;
                }

                if (!switchFs.Titles.TryGetValue(id, out Title title))
                {
                    ctx.Logger.LogMessage($"Could not find title {id:X16}");
                    return;
                }

                if (title.MainNca == null)
                {
                    ctx.Logger.LogMessage($"Could not find main data for title {id:X16}");
                    return;
                }

                NcaSection section = title.MainNca.Sections[(int)ProgramPartitionType.Code];

                if (section == null)
                {
                    ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no ExeFS section");
                    return;
                }

                if (ctx.Options.ExefsOutDir != null)
                {
                    title.MainNca.ExtractSection(section.SectionNum, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
                }

                if (ctx.Options.ExefsOut != null)
                {
                    title.MainNca.ExportSection(section.SectionNum, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
                }
            }

            if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null)
            {
                ulong id = ctx.Options.TitleId;
                if (id == 0)
                {
                    ctx.Logger.LogMessage("Title ID must be specified to dump RomFS");
                    return;
                }

                if (!switchFs.Titles.TryGetValue(id, out Title title))
                {
                    ctx.Logger.LogMessage($"Could not find title {id:X16}");
                    return;
                }

                if (title.MainNca == null)
                {
                    ctx.Logger.LogMessage($"Could not find main data for title {id:X16}");
                    return;
                }

                NcaSection section = title.MainNca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs || x?.Type == SectionType.Bktr);

                if (section == null)
                {
                    ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no RomFS section");
                    return;
                }

                if (ctx.Options.RomfsOutDir != null)
                {
                    var romfs = new RomFsFileSystem(title.MainNca.OpenSection(section.SectionNum, false, ctx.Options.IntegrityLevel, true));
                    romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger);
                }

                if (ctx.Options.RomfsOut != null)
                {
                    title.MainNca.ExportSection(section.SectionNum, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
                }
            }

            if (ctx.Options.OutDir != null)
            {
                SaveTitle(ctx, switchFs);
            }

            if (ctx.Options.NspOut != null)
            {
                ProcessNsp.CreateNsp(ctx, switchFs);
            }

            if (ctx.Options.SaveOutDir != null)
            {
                ExportSdSaves(ctx, switchFs);
            }

            if (ctx.Options.Validate)
            {
                ValidateSwitchFs(ctx, switchFs);
            }
        }
Exemple #27
0
        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();
        }
Exemple #28
0
        public static void Process(Context ctx)
        {
            SwitchFs switchFs;
            var      baseFs = new LocalFileSystem(ctx.Options.InFile);

            if (Directory.Exists(Path.Combine(ctx.Options.InFile, "Nintendo", "Contents", "registered")))
            {
                ctx.Logger.LogMessage("Treating path as SD card storage");
                switchFs = SwitchFs.OpenSdCard(ctx.Keyset, baseFs);

                CheckForNcaFolders(ctx, switchFs);
            }
            else if (Directory.Exists(Path.Combine(ctx.Options.InFile, "Contents", "registered")))
            {
                ctx.Logger.LogMessage("Treating path as NAND storage");
                switchFs = SwitchFs.OpenNandPartition(ctx.Keyset, baseFs);

                CheckForNcaFolders(ctx, switchFs);
            }
            else
            {
                ctx.Logger.LogMessage("Treating path as a directory of loose NCAs");
                switchFs = SwitchFs.OpenNcaDirectory(ctx.Keyset, baseFs);
            }

            if (ctx.Options.ListNcas)
            {
                ctx.Logger.LogMessage(ListNcas(switchFs));
            }

            if (ctx.Options.ListTitles)
            {
                ctx.Logger.LogMessage(ListTitles(switchFs));
            }

            if (ctx.Options.ListApps)
            {
                ctx.Logger.LogMessage(ListApplications(switchFs));
            }

            if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null)
            {
                ulong id = ctx.Options.TitleId;
                if (id == 0)
                {
                    ctx.Logger.LogMessage("Title ID must be specified to dump ExeFS");
                    return;
                }

                if (!switchFs.Titles.TryGetValue(id, out Title title))
                {
                    ctx.Logger.LogMessage($"Could not find title {id:X16}");
                    return;
                }

                if (title.MainNca == null)
                {
                    ctx.Logger.LogMessage($"Could not find main data for title {id:X16}");
                    return;
                }

                if (!title.MainNca.Nca.SectionExists(NcaSectionType.Code))
                {
                    ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no ExeFS section");
                    return;
                }

                if (ctx.Options.ExefsOutDir != null)
                {
                    IFileSystem fs = title.MainNca.OpenFileSystem(NcaSectionType.Code, ctx.Options.IntegrityLevel);
                    fs.Extract(ctx.Options.ExefsOutDir, ctx.Logger);
                }

                if (ctx.Options.ExefsOut != null)
                {
                    title.MainNca.OpenStorage(NcaSectionType.Code, ctx.Options.IntegrityLevel).WriteAllBytes(ctx.Options.ExefsOut, ctx.Logger);
                }
            }

            if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null)
            {
                ulong id = ctx.Options.TitleId;
                if (id == 0)
                {
                    ctx.Logger.LogMessage("Title ID must be specified to dump RomFS");
                    return;
                }

                if (!switchFs.Titles.TryGetValue(id, out Title title))
                {
                    ctx.Logger.LogMessage($"Could not find title {id:X16}");
                    return;
                }

                if (title.MainNca == null)
                {
                    ctx.Logger.LogMessage($"Could not find main data for title {id:X16}");
                    return;
                }

                if (!title.MainNca.Nca.SectionExists(NcaSectionType.Data))
                {
                    ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no RomFS section");
                    return;
                }

                ProcessRomfs.Process(ctx, title.MainNca.OpenStorage(NcaSectionType.Data, ctx.Options.IntegrityLevel));
            }

            if (ctx.Options.OutDir != null)
            {
                SaveTitle(ctx, switchFs);
            }

            if (ctx.Options.NspOut != null)
            {
                ProcessPfs.CreateNsp(ctx, switchFs);
            }

            if (ctx.Options.SaveOutDir != null)
            {
                ExportSdSaves(ctx, switchFs);
            }

            if (ctx.Options.Validate)
            {
                ValidateSwitchFs(ctx, switchFs);
            }
        }
Exemple #29
0
        private void ImportGameDataClicked(object sender, RoutedEventArgs e)
        {
            string filter = @"
                Any game data (*.xci,*.nca,*.nsp)|*.xci;*.nca;*.nsp|
                NX Card Image (*.xci)|*.xci|
                Nintendo Content Archive (*.nca)|*.nca|
                Nintendo Installable Package (*.nsp)|*.nsp
            ".FilterMultilineString();

            FileInfo[] files = RequestOpenFilesFromUser(".*", filter, "Select game data...");

            if (files == null)
            {
                return;
            }

            TaskManagerPage.Current.Queue.Submit(new RunTask("Processing imported game data...", new Task(() =>
            {
                IEnumerable <FileInfo> ncas = files.Where((f) =>
                {
                    try
                    {
                        new Nca(HACGUIKeyset.Keyset, new LocalFile(f.FullName, OpenMode.Read).AsStorage());
                        return(true);
                    }
                    catch (Exception)
                    {
                        return(false);
                    }
                });
                IEnumerable <FileInfo> xcis = files.Except(ncas).Where((f) =>
                {
                    try
                    {
                        new Xci(HACGUIKeyset.Keyset, new LocalFile(f.FullName, OpenMode.Read).AsStorage());
                        return(true);
                    }
                    catch (Exception)
                    {
                        return(false);
                    }
                });
                IEnumerable <FileInfo> nsp = files.Except(ncas).Except(xcis).Where((f) =>
                {
                    try
                    {
                        new PartitionFileSystem(new LocalFile(f.FullName, OpenMode.Read).AsStorage());
                        return(true);
                    }
                    catch (Exception)
                    {
                        return(false);
                    }
                });

                List <SwitchFs> switchFilesystems = new List <SwitchFs>();

                PseudoFileSystem ncaFs = new PseudoFileSystem();
                foreach (FileInfo file in ncas)
                {
                    LocalFileSystem fs = new LocalFileSystem(file.Directory.FullName);

                    // clean up filename so it only ends with .nca, then map to actual name
                    string s = file.Name;
                    while (s.EndsWith(".nca"))
                    {
                        s = s.Substring(0, s.IndexOf(".nca"));
                    }
                    ncaFs.Add($"/{s}.nca", $"/{file.Name}", fs);
                }
                if (ncas.Any())
                {
                    switchFilesystems.Add(SwitchFs.OpenNcaDirectory(HACGUIKeyset.Keyset, ncaFs));
                }

                foreach (FileInfo file in xcis)
                {
                    Xci xci = new Xci(HACGUIKeyset.Keyset, new LocalFile(file.FullName, OpenMode.Read).AsStorage());
                    switchFilesystems.Add(SwitchFs.OpenNcaDirectory(HACGUIKeyset.Keyset, xci.OpenPartition(XciPartitionType.Secure)));
                }

                foreach (FileInfo file in nsp)
                {
                    PartitionFileSystem fs = new PartitionFileSystem(new LocalFile(file.FullName, OpenMode.Read).AsStorage());
                    switchFilesystems.Add(SwitchFs.OpenNcaDirectory(HACGUIKeyset.Keyset, fs));
                }

                foreach (SwitchFs fs in switchFilesystems)
                {
                    DeviceService.FsView.LoadFileSystemAsync("Opening imported data...", () => fs, FSView.TitleSource.Imported, false);
                }
            })));
        }
        public static void Start()
        {
            if (!Started)
            {
                Started = true;

                FsView = new FSView();

                int count = 0;
                FsView.Ready += (source) =>
                {
                    if (source == TitleSource.SD)
                    {
                        StatusService.SDStatus = StatusService.Status.OK;
                    }
                    else if (source == TitleSource.NAND)
                    {
                        count++;
                        if (count == 2)
                        {
                            StatusService.NANDStatus = StatusService.Status.OK;
                            Update();
                            count = 0;
                        }
                        return;
                    }
                    Update();
                };

                SDService.OnSDPluggedIn += (_) =>
                {
                    FsView.LoadFileSystemAsync("Opening SD filesystem...", () => SwitchFs.OpenSdCard(HACGUIKeyset.Keyset, new LocalFileSystem(SDService.SDEffectiveRoot.FullName)), TitleSource.SD, true);

                    StatusService.SDStatus = StatusService.Status.Progress;
                };

                SDService.OnSDRemoved += (drive) =>
                {
                    StatusService.SDStatus = StatusService.Status.Incorrect;
                    FsView.IndexedFilesystems[TitleSource.SD].Clear();
                    Update();
                };

                NANDService.OnNANDPluggedIn += () =>
                {
                    FsView.LoadFileSystemAsync("Opening NAND user filesystem...", () => SwitchFs.OpenNandPartition(HACGUIKeyset.Keyset, NANDService.NAND.OpenUserPartition()), TitleSource.NAND, false);
                    FsView.LoadFileSystemAsync("Opening NAND system filesystem...", () => SwitchFs.OpenNandPartition(HACGUIKeyset.Keyset, NANDService.NAND.OpenSystemPartition()), TitleSource.NAND, true);
                    TaskManagerPage.Current.Queue.Submit(new DecryptTicketsTask(Preferences.Current.DefaultConsoleName));
                    TaskManagerPage.Current.Queue.Submit(new SaveKeysetTask(Preferences.Current.DefaultConsoleName)); // TODO
                    TaskManagerPage.Current.Queue.Submit(new CopyAccountDataTask());

                    StatusService.NANDStatus = StatusService.Status.Progress;
                };

                NANDService.OnNANDRemoved += () =>
                {
                    StatusService.NANDStatus = StatusService.Status.Incorrect;
                    FsView.IndexedFilesystems[TitleSource.NAND].Clear();
                    Update();
                };

                SDService.Start();
                NANDService.Start();
            }
        }