Beispiel #1
0
        public byte[] GetFirmwareData(Switch device)
        {
            const ulong SystemVersionTitleId = 0x0100000000000809;

            string contentPath = device.System.ContentManager.GetInstalledContentPath(SystemVersionTitleId, StorageId.BuiltInSystem, NcaContentType.Data);

            if (string.IsNullOrWhiteSpace(contentPath))
            {
                return(null);
            }

            string firmwareTitlePath = device.FileSystem.SwitchPathToSystemPath(contentPath);

            using (IStorage firmwareStorage = new LocalStorage(firmwareTitlePath, FileAccess.Read))
            {
                Nca firmwareContent = new Nca(device.System.KeySet, firmwareStorage);

                if (!firmwareContent.CanOpenSection(NcaSectionType.Data))
                {
                    return(null);
                }

                IFileSystem firmwareRomFs = firmwareContent.OpenFileSystem(NcaSectionType.Data, device.System.FsIntegrityCheckLevel);

                using var firmwareFile = new UniqueRef <IFile>();

                Result result = firmwareRomFs.OpenFile(ref firmwareFile.Ref(), "/file".ToU8Span(), OpenMode.Read);
                if (result.IsFailure())
                {
                    return(null);
                }

                result = firmwareFile.Get.GetSize(out long fileSize);
                if (result.IsFailure())
                {
                    return(null);
                }

                byte[] data = new byte[fileSize];

                result = firmwareFile.Get.Read(out _, 0, data);
                if (result.IsFailure())
                {
                    return(null);
                }

                return(data);
            }
        }
Beispiel #2
0
        public void Load(System.IO.Stream stream)
        {
            var Keys = Forms.SwitchKeySelectionForm.ShowKeySelector();

            if (Keys == null)
            {
                throw new Exception("Failed to get keys. Please select valid paths!");
            }

            Stream Input;

            var Pfs       = new Pfs(stream.AsStorage());
            var CnmtNca   = new Nca(Keys, Pfs.OpenFile(Pfs.Files.FirstOrDefault(s => s.Name.Contains(".cnmt.nca"))), false);
            var CnmtPfs   = new Pfs(CnmtNca.OpenSection(0, false, IntegrityCheckLevel.None, true));
            var Cnmt      = new Cnmt(CnmtPfs.OpenFile(CnmtPfs.Files[0]).AsStream());
            var Program   = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Program);
            var CtrlEntry = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Control);

            if (CtrlEntry != null)
            {
                Control = new Nca(Keys, Pfs.OpenFile($"{CtrlEntry.NcaId.ToHexString().ToLower()}.nca"), false);
            }
            Input = Pfs.OpenFile($"{Program.NcaId.ToHexString().ToLower()}.nca").AsStream();

            var Nca = new Nca(Keys, Input.AsStorage(), true);

            Romfs romfs = new Romfs(
                Nca.OpenSection(Nca.Sections.FirstOrDefault
                                    (s => s?.Type == SectionType.Romfs || s?.Type == SectionType.Bktr)
                                .SectionNum, false, IntegrityCheckLevel.None, true));

            if (Nca.CanOpenSection((int)ProgramPartitionType.Code))
            {
                var exefs = new Pfs(Nca.OpenSection((int)ProgramPartitionType.Code,
                                                    false, IntegrityCheckLevel.None, true));

                foreach (var file in exefs.Files)
                {
                    files.Add(new ExefsEntry(exefs, file));
                }
            }

            for (int i = 0; i < romfs.Files.Count; i++)
            {
                files.Add(new FileEntry(romfs, romfs.Files[i]));
            }
        }
Beispiel #3
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
                            }
                        }
                    }
                }
            }
        }
Beispiel #4
0
        public void LoadNca(Nca mainNca, Nca patchNca, Nca controlNca)
        {
            if (mainNca.Header.ContentType != NcaContentType.Program)
            {
                Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA");

                return;
            }

            IStorage    dataStorage = null;
            IFileSystem codeFs      = null;

            if (patchNca == null)
            {
                if (mainNca.CanOpenSection(NcaSectionType.Data))
                {
                    dataStorage = mainNca.OpenStorage(NcaSectionType.Data, FsIntegrityCheckLevel);
                }

                if (mainNca.CanOpenSection(NcaSectionType.Code))
                {
                    codeFs = mainNca.OpenFileSystem(NcaSectionType.Code, FsIntegrityCheckLevel);
                }
            }
            else
            {
                if (patchNca.CanOpenSection(NcaSectionType.Data))
                {
                    dataStorage = mainNca.OpenStorageWithPatch(patchNca, NcaSectionType.Data, FsIntegrityCheckLevel);
                }

                if (patchNca.CanOpenSection(NcaSectionType.Code))
                {
                    codeFs = mainNca.OpenFileSystemWithPatch(patchNca, NcaSectionType.Code, FsIntegrityCheckLevel);
                }
            }

            if (codeFs == null)
            {
                Logger.PrintError(LogClass.Loader, "No ExeFS found in NCA");

                return;
            }

            if (dataStorage == null)
            {
                Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA");
            }
            else
            {
                Device.FileSystem.SetRomFs(dataStorage.AsStream(FileAccess.Read));
            }

            LoadExeFs(codeFs, out Npdm metaData);

            TitleId = metaData.Aci0.TitleId;

            if (controlNca != null)
            {
                ReadControlData(controlNca);
            }
            else
            {
                ControlData.ByteSpan.Clear();
            }

            if (TitleId != 0)
            {
                EnsureSaveData(new TitleId(TitleId));
            }
        }
Beispiel #5
0
        public void LoadNca(Nca mainNca, Nca patchNca, Nca controlNca)
        {
            if (mainNca.Header.ContentType != ContentType.Program)
            {
                Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA");

                return;
            }

            IStorage    dataStorage = null;
            IFileSystem codeFs      = null;

            if (patchNca == null)
            {
                if (mainNca.CanOpenSection(NcaSectionType.Data))
                {
                    dataStorage = mainNca.OpenStorage(NcaSectionType.Data, FsIntegrityCheckLevel);
                }

                if (mainNca.CanOpenSection(NcaSectionType.Code))
                {
                    codeFs = mainNca.OpenFileSystem(NcaSectionType.Code, FsIntegrityCheckLevel);
                }
            }
            else
            {
                if (patchNca.CanOpenSection(NcaSectionType.Data))
                {
                    dataStorage = mainNca.OpenStorageWithPatch(patchNca, NcaSectionType.Data, FsIntegrityCheckLevel);
                }

                if (patchNca.CanOpenSection(NcaSectionType.Code))
                {
                    codeFs = mainNca.OpenFileSystemWithPatch(patchNca, NcaSectionType.Code, FsIntegrityCheckLevel);
                }
            }

            if (codeFs == null)
            {
                Logger.PrintError(LogClass.Loader, "No ExeFS found in NCA");

                return;
            }

            if (dataStorage == null)
            {
                Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA");
            }
            else
            {
                Device.FileSystem.SetRomFs(dataStorage.AsStream(FileAccess.Read));
            }

            LoadExeFs(codeFs, out Npdm metaData);

            Nacp ReadControlData()
            {
                IFileSystem controlRomfs = controlNca.OpenFileSystem(NcaSectionType.Data, FsIntegrityCheckLevel);

                IFile controlFile = controlRomfs.OpenFile("/control.nacp", OpenMode.Read);

                Nacp controlData = new Nacp(controlFile.AsStream());

                TitleName = CurrentTitle = controlData.Descriptions[(int)State.DesiredTitleLanguage].Title;
                TitleID   = metaData.Aci0.TitleId.ToString("x16");

                CurrentTitle = controlData.Descriptions[(int)State.DesiredTitleLanguage].Title;

                if (string.IsNullOrWhiteSpace(CurrentTitle))
                {
                    TitleName = CurrentTitle = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title;
                }

                return(controlData);
            }

            if (controlNca != null)
            {
                ReadControlData();
            }
            else
            {
                TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
            }
        }
Beispiel #6
0
        private static string Print(this NcaHolder ncaHolder)
        {
            Nca nca       = ncaHolder.Nca;
            int masterKey = Keyset.GetMasterKeyRevisionFromKeyGeneration(nca.Header.KeyGeneration);

            int colLen = 36;
            var sb     = new StringBuilder();

            sb.AppendLine();

            sb.AppendLine("NCA:");
            PrintItem(sb, colLen, "Magic:", MagicToString(nca.Header.Magic));
            PrintItem(sb, colLen, $"Fixed-Key Signature{nca.VerifyHeaderSignature().GetValidityString()}:", nca.Header.Signature1.ToArray());
            PrintItem(sb, colLen, $"NPDM Signature{nca.VerifySignature2().GetValidityString()}:", nca.Header.Signature2.ToArray());
            PrintItem(sb, colLen, "Content Size:", $"0x{nca.Header.NcaSize:x12}");
            PrintItem(sb, colLen, "TitleID:", $"{nca.Header.TitleId:X16}");
            if (nca.CanOpenSection(NcaSectionType.Code))
            {
                IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.None);
                Result      r  = fs.OpenFile(out IFile file, "/main.npdm".ToU8String(), OpenMode.Read);
                if (r.IsSuccess())
                {
                    var npdm = new NpdmBinary(file.AsStream(), null);
                    PrintItem(sb, colLen, "Title Name:", npdm.TitleName);
                }
            }

            PrintItem(sb, colLen, "SDK Version:", nca.Header.SdkVersion);
            PrintItem(sb, colLen, "Distribution type:", nca.Header.DistributionType);
            PrintItem(sb, colLen, "Content Type:", nca.Header.ContentType);
            PrintItem(sb, colLen, "Master Key Revision:", $"{masterKey} ({Utilities.GetKeyRevisionSummary(masterKey)})");
            PrintItem(sb, colLen, "Encryption Type:", $"{(nca.Header.HasRightsId ? "Titlekey crypto" : "Standard crypto")}");

            if (nca.Header.HasRightsId)
            {
                PrintItem(sb, colLen, "Rights ID:", nca.Header.RightsId.ToArray());
            }
            else
            {
                PrintItem(sb, colLen, "Key Area Encryption Key:", nca.Header.KeyAreaKeyIndex);
                sb.AppendLine("Key Area (Encrypted):");
                for (int i = 0; i < 4; i++)
                {
                    PrintItem(sb, colLen, $"    Key {i} (Encrypted):", nca.Header.GetEncryptedKey(i).ToArray());
                }

                sb.AppendLine("Key Area (Decrypted):");
                for (int i = 0; i < 4; i++)
                {
                    PrintItem(sb, colLen, $"    Key {i} (Decrypted):", nca.GetDecryptedKey(i));
                }
            }

            PrintSections();

            return(sb.ToString());

            void PrintSections()
            {
                sb.AppendLine("Sections:");

                for (int i = 0; i < 4; i++)
                {
                    if (!nca.Header.IsSectionEnabled(i))
                    {
                        continue;
                    }

                    NcaFsHeader sectHeader = nca.Header.GetFsHeader(i);
                    bool        isExefs    = nca.Header.ContentType == NcaContentType.Program && i == 0;

                    sb.AppendLine($"    Section {i}:");
                    PrintItem(sb, colLen, "        Offset:", $"0x{nca.Header.GetSectionStartOffset(i):x12}");
                    PrintItem(sb, colLen, "        Size:", $"0x{nca.Header.GetSectionSize(i):x12}");
                    PrintItem(sb, colLen, "        Partition Type:", (isExefs ? "ExeFS" : sectHeader.FormatType.ToString()) + (sectHeader.IsPatchSection() ? " patch" : ""));
                    PrintItem(sb, colLen, "        Section CTR:", $"{sectHeader.Counter:x16}");
                    PrintItem(sb, colLen, "        Section Validity:", $"{ncaHolder.Validities[i]}");

                    switch (sectHeader.HashType)
                    {
                    case NcaHashType.Sha256:
                        PrintSha256Hash(sectHeader, i);
                        break;

                    case NcaHashType.Ivfc:
                        Validity masterHashValidity = nca.ValidateSectionMasterHash(i);

                        PrintIvfcHashNew(sb, colLen, 8, sectHeader.GetIntegrityInfoIvfc(), IntegrityStorageType.RomFs, masterHashValidity);
                        break;

                    default:
                        sb.AppendLine("        Unknown/invalid superblock!");
                        break;
                    }
                }
            }

            void PrintSha256Hash(NcaFsHeader sect, int index)
            {
                NcaFsIntegrityInfoSha256 hashInfo = sect.GetIntegrityInfoSha256();

                PrintItem(sb, colLen, $"        Master Hash{nca.ValidateSectionMasterHash(index).GetValidityString()}:", hashInfo.MasterHash.ToArray());
                sb.AppendLine($"        Hash Table:");

                PrintItem(sb, colLen, "            Offset:", $"0x{hashInfo.GetLevelOffset(0):x12}");
                PrintItem(sb, colLen, "            Size:", $"0x{hashInfo.GetLevelSize(0):x12}");
                PrintItem(sb, colLen, "            Block Size:", $"0x{hashInfo.BlockSize:x}");
                PrintItem(sb, colLen, "        PFS0 Offset:", $"0x{hashInfo.GetLevelOffset(1):x12}");
                PrintItem(sb, colLen, "        PFS0 Size:", $"0x{hashInfo.GetLevelSize(1):x12}");
            }
        }
Beispiel #7
0
        public static void Process(Context ctx)
        {
            using (IStorage file = new LocalStorage(ctx.Options.InFile, FileAccess.Read))
            {
                var nca     = new Nca(ctx.Keyset, file);
                Nca baseNca = null;

                var ncaHolder = new NcaHolder {
                    Nca = nca
                };

                if (ctx.Options.HeaderOut != null)
                {
                    using (var outHeader = new FileStream(ctx.Options.HeaderOut, FileMode.Create, FileAccess.ReadWrite))
                    {
                        nca.OpenDecryptedHeaderStorage().Slice(0, 0xc00).CopyToStream(outHeader);
                    }
                }

                if (ctx.Options.BaseNca != null)
                {
                    IStorage baseFile = new LocalStorage(ctx.Options.BaseNca, FileAccess.Read);
                    baseNca = new Nca(ctx.Keyset, baseFile);
                }

                for (int i = 0; i < 3; i++)
                {
                    if (ctx.Options.SectionOut[i] != null)
                    {
                        OpenStorage(i).WriteAllBytes(ctx.Options.SectionOut[i], ctx.Logger);
                    }

                    if (ctx.Options.SectionOutDir[i] != null)
                    {
                        FileSystemClient fs = ctx.FsClient;

                        string mountName = $"section{i}";

                        fs.Register(mountName.ToU8Span(), OpenFileSystem(i));
                        fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.SectionOutDir[i]));

                        FsUtils.CopyDirectoryWithProgress(fs, (mountName + ":/").ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure();

                        fs.Unmount(mountName.ToU8Span());
                        fs.Unmount("output".ToU8Span());
                    }

                    if (ctx.Options.Validate && nca.SectionExists(i))
                    {
                        if (nca.Header.GetFsHeader(i).IsPatchSection() && baseNca != null)
                        {
                            ncaHolder.Validities[i] = baseNca.VerifySection(nca, i, ctx.Logger);
                        }
                        else
                        {
                            ncaHolder.Validities[i] = nca.VerifySection(i, ctx.Logger);
                        }
                    }
                }

                if (ctx.Options.ListRomFs && nca.CanOpenSection(NcaSectionType.Data))
                {
                    IFileSystem romfs = OpenFileSystemByType(NcaSectionType.Data);

                    foreach (DirectoryEntryEx entry in romfs.EnumerateEntries())
                    {
                        ctx.Logger.LogMessage(entry.FullPath);
                    }
                }

                if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null || ctx.Options.ReadBench)
                {
                    if (!nca.SectionExists(NcaSectionType.Data))
                    {
                        ctx.Logger.LogMessage("NCA has no RomFS section");
                        return;
                    }

                    if (ctx.Options.RomfsOut != null)
                    {
                        OpenStorageByType(NcaSectionType.Data).WriteAllBytes(ctx.Options.RomfsOut, ctx.Logger);
                    }

                    if (ctx.Options.RomfsOutDir != null)
                    {
                        FileSystemClient fs = ctx.FsClient;

                        fs.Register("rom".ToU8Span(), OpenFileSystemByType(NcaSectionType.Data));
                        fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.RomfsOutDir));

                        FsUtils.CopyDirectoryWithProgress(fs, "rom:/".ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure();

                        fs.Unmount("rom".ToU8Span());
                        fs.Unmount("output".ToU8Span());
                    }

                    if (ctx.Options.ReadBench)
                    {
                        long     bytesToRead = 1024L * 1024 * 1024 * 5;
                        IStorage storage     = OpenStorageByType(NcaSectionType.Data);

                        storage.GetSize(out long sectionSize).ThrowIfFailure();

                        var dest = new NullStorage(sectionSize);

                        int iterations = (int)(bytesToRead / sectionSize) + 1;
                        ctx.Logger.LogMessage(iterations.ToString());

                        ctx.Logger.StartNewStopWatch();

                        for (int i = 0; i < iterations; i++)
                        {
                            storage.CopyTo(dest, ctx.Logger);
                            ctx.Logger.LogMessage(ctx.Logger.GetRateString());
                        }

                        ctx.Logger.PauseStopWatch();
                        ctx.Logger.LogMessage(ctx.Logger.GetRateString());
                    }
                }

                if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null)
                {
                    if (nca.Header.ContentType != NcaContentType.Program)
                    {
                        ctx.Logger.LogMessage("NCA's content type is not \"Program\"");
                        return;
                    }

                    if (!nca.SectionExists(NcaSectionType.Code))
                    {
                        ctx.Logger.LogMessage("Could not find an ExeFS section");
                        return;
                    }

                    if (ctx.Options.ExefsOut != null)
                    {
                        OpenStorageByType(NcaSectionType.Code).WriteAllBytes(ctx.Options.ExefsOut, ctx.Logger);
                    }

                    if (ctx.Options.ExefsOutDir != null)
                    {
                        FileSystemClient fs = ctx.FsClient;

                        fs.Register("code".ToU8Span(), OpenFileSystemByType(NcaSectionType.Code));
                        fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.ExefsOutDir));

                        FsUtils.CopyDirectoryWithProgress(fs, "code:/".ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure();

                        fs.Unmount("code".ToU8Span());
                        fs.Unmount("output".ToU8Span());
                    }
                }

                if (ctx.Options.PlaintextOut != null)
                {
                    nca.OpenDecryptedNca().WriteAllBytes(ctx.Options.PlaintextOut, ctx.Logger);
                }

                if (!ctx.Options.ReadBench)
                {
                    ctx.Logger.LogMessage(ncaHolder.Print());
                }

                IStorage OpenStorage(int index)
                {
                    if (ctx.Options.Raw)
                    {
                        if (baseNca != null)
                        {
                            return(baseNca.OpenRawStorageWithPatch(nca, index));
                        }

                        return(nca.OpenRawStorage(index));
                    }

                    if (baseNca != null)
                    {
                        return(baseNca.OpenStorageWithPatch(nca, index, ctx.Options.IntegrityLevel));
                    }

                    return(nca.OpenStorage(index, ctx.Options.IntegrityLevel));
                }

                IFileSystem OpenFileSystem(int index)
                {
                    if (baseNca != null)
                    {
                        return(baseNca.OpenFileSystemWithPatch(nca, index, ctx.Options.IntegrityLevel));
                    }

                    return(nca.OpenFileSystem(index, ctx.Options.IntegrityLevel));
                }

                IStorage OpenStorageByType(NcaSectionType type)
                {
                    return(OpenStorage(Nca.GetSectionIndexFromType(type, nca.Header.ContentType)));
                }

                IFileSystem OpenFileSystemByType(NcaSectionType type)
                {
                    return(OpenFileSystem(Nca.GetSectionIndexFromType(type, nca.Header.ContentType)));
                }
            }
        }
Beispiel #8
0
        public static void Process(Context ctx)
        {
            using (IStorage file = new LocalStorage(ctx.Options.InFile, FileAccess.Read))
            {
                var nca = new Nca(ctx.Keyset, file, false);

                if (ctx.Options.HeaderOut != null)
                {
                    using (var outHeader = new FileStream(ctx.Options.HeaderOut, FileMode.Create, FileAccess.ReadWrite))
                    {
                        nca.OpenHeaderStorage().Slice(0, 0xc00).CopyToStream(outHeader);
                    }
                }

                nca.ValidateMasterHashes();
                nca.ParseNpdm();

                if (ctx.Options.BaseNca != null)
                {
                    IStorage baseFile = new LocalStorage(ctx.Options.BaseNca, FileAccess.Read);
                    var      baseNca  = new Nca(ctx.Keyset, baseFile, false);
                    nca.SetBaseNca(baseNca);
                }

                for (int i = 0; i < 3; i++)
                {
                    if (ctx.Options.SectionOut[i] != null)
                    {
                        nca.ExportSection(i, ctx.Options.SectionOut[i], ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
                    }

                    if (ctx.Options.SectionOutDir[i] != null)
                    {
                        nca.ExtractSection(i, ctx.Options.SectionOutDir[i], ctx.Options.IntegrityLevel, ctx.Logger);
                    }

                    if (ctx.Options.Validate && nca.SectionExists(i))
                    {
                        nca.VerifySection(i, ctx.Logger);
                    }
                }

                if (ctx.Options.ListRomFs && nca.CanOpenSection(NcaSectionType.Data))
                {
                    IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, ctx.Options.IntegrityLevel);

                    foreach (DirectoryEntry entry in romfs.EnumerateEntries())
                    {
                        ctx.Logger.LogMessage(entry.FullPath);
                    }
                }

                if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null || ctx.Options.ReadBench)
                {
                    if (!nca.SectionExists(NcaSectionType.Data))
                    {
                        ctx.Logger.LogMessage("NCA has no RomFS section");
                        return;
                    }

                    if (ctx.Options.RomfsOut != null)
                    {
                        nca.ExportSection(NcaSectionType.Data, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
                    }

                    if (ctx.Options.RomfsOutDir != null)
                    {
                        nca.ExtractSection(NcaSectionType.Data, ctx.Options.RomfsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
                    }

                    if (ctx.Options.ReadBench)
                    {
                        long     bytesToRead = 1024L * 1024 * 1024 * 5;
                        IStorage storage     = nca.OpenStorage(NcaSectionType.Data, ctx.Options.IntegrityLevel);
                        var      dest        = new NullStorage(storage.GetSize());

                        int iterations = (int)(bytesToRead / storage.GetSize()) + 1;
                        ctx.Logger.LogMessage(iterations.ToString());

                        ctx.Logger.StartNewStopWatch();

                        for (int i = 0; i < iterations; i++)
                        {
                            storage.CopyTo(dest, ctx.Logger);
                            ctx.Logger.LogMessage(ctx.Logger.GetRateString());
                        }

                        ctx.Logger.PauseStopWatch();
                        ctx.Logger.LogMessage(ctx.Logger.GetRateString());
                    }
                }

                if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null)
                {
                    if (nca.Header.ContentType != ContentType.Program)
                    {
                        ctx.Logger.LogMessage("NCA's content type is not \"Program\"");
                        return;
                    }

                    if (!nca.SectionExists(NcaSectionType.Code))
                    {
                        ctx.Logger.LogMessage("Could not find an ExeFS section");
                        return;
                    }

                    if (ctx.Options.ExefsOut != null)
                    {
                        nca.ExportSection(NcaSectionType.Code, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
                    }

                    if (ctx.Options.ExefsOutDir != null)
                    {
                        nca.ExtractSection(NcaSectionType.Code, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
                    }
                }

                if (ctx.Options.PlaintextOut != null)
                {
                    nca.OpenDecryptedNca().WriteAllBytes(ctx.Options.PlaintextOut, ctx.Logger);
                }

                if (!ctx.Options.ReadBench)
                {
                    ctx.Logger.LogMessage(nca.Print());
                }
            }
        }
Beispiel #9
0
        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();
        }