示例#1
0
        private long OpenNcaFs(ServiceCtx Context, string NcaPath, Stream NcaStream)
        {
            Nca Nca = new Nca(Context.Device.System.KeySet, NcaStream, false);

            NcaSection RomfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
            NcaSection PfsSection   = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Pfs0);

            if (RomfsSection != null)
            {
                Stream      RomfsStream   = Nca.OpenSection(RomfsSection.SectionNum, false, Context.Device.System.FsIntegrityCheckLevel);
                IFileSystem NcaFileSystem = new IFileSystem(NcaPath, new RomFsProvider(RomfsStream));

                MakeObject(Context, NcaFileSystem);
            }
            else if (PfsSection != null)
            {
                Stream      PfsStream     = Nca.OpenSection(PfsSection.SectionNum, false, Context.Device.System.FsIntegrityCheckLevel);
                Pfs         Pfs           = new Pfs(PfsStream);
                IFileSystem NcaFileSystem = new IFileSystem(NcaPath, new PFsProvider(Pfs));

                MakeObject(Context, NcaFileSystem);
            }
            else
            {
                return(MakeError(ErrorModule.Fs, FsErr.PartitionNotFound));
            }

            return(0);
        }
示例#2
0
        public Task <ImageSource> FindTitleIcon(Title title)
        {
            if (title.ControlNca != null)
            {
                NcaSection      meta      = title.ControlNca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
                RomFsFileSystem controlFS = new RomFsFileSystem(title.ControlNca.OpenSection(meta.SectionNum, false, IntegrityCheckLevel.ErrorOnInvalid, false));
                DirectoryEntry  file      = controlFS.EnumerateEntries("icon_*.dat").FirstOrDefault();

                if (file != null)
                {
                    return(new Task <ImageSource>(() =>
                    {
                        try
                        {
                            JpegBitmapDecoder decoder = new JpegBitmapDecoder(controlFS.OpenFile(file.FullPath, OpenMode.Read).AsStream(), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                            decoder.Frames[0].Freeze();
                            return decoder.Frames[0];
                        } catch (Exception)
                        {
                            return null;
                        }
                    }));
                }
            }
            return(null);
        }
示例#3
0
        public static void ExtractSection(this Nca nca, int index, string outputDir, bool verify = false, IProgressReport logger = null)
        {
            if (index < 0 || index > 3)
            {
                throw new IndexOutOfRangeException();
            }
            if (nca.Sections[index] == null)
            {
                return;
            }

            NcaSection section = nca.Sections[index];
            Stream     stream  = nca.OpenSection(index, false, verify);

            switch (section.Type)
            {
            case SectionType.Invalid:
                break;

            case SectionType.Pfs0:
                var pfs0 = new Pfs(stream);
                pfs0.Extract(outputDir, logger);
                break;

            case SectionType.Romfs:
                var romfs = new Romfs(stream);
                romfs.Extract(outputDir, logger);
                break;

            case SectionType.Bktr:
                break;
            }
        }
示例#4
0
        private long OpenNcaFs(ServiceCtx context, string ncaPath, LibHac.IO.IStorage ncaStorage)
        {
            Nca nca = new Nca(context.Device.System.KeySet, ncaStorage, false);

            NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
            NcaSection pfsSection   = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Pfs0);

            if (romfsSection != null)
            {
                LibHac.IO.IStorage romfsStorage  = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel, false);
                IFileSystem        ncaFileSystem = new IFileSystem(ncaPath, new RomFsProvider(romfsStorage));

                MakeObject(context, ncaFileSystem);
            }
            else if (pfsSection != null)
            {
                LibHac.IO.IStorage pfsStorage = nca.OpenSection(pfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel, false);
                Pfs         pfs           = new Pfs(pfsStorage);
                IFileSystem ncaFileSystem = new IFileSystem(ncaPath, new PFsProvider(pfs));

                MakeObject(context, ncaFileSystem);
            }
            else
            {
                return(MakeError(ErrorModule.Fs, FsErr.PartitionNotFound));
            }

            return(0);
        }
示例#5
0
        // OpenDataStorageByDataId(u8 storageId, nn::ApplicationId tid) -> object<nn::fssrv::sf::IStorage> dataStorage
        public long OpenDataStorageByDataId(ServiceCtx Context)
        {
            StorageId StorageId = (StorageId)Context.RequestData.ReadByte();

            byte[] Padding = Context.RequestData.ReadBytes(7);
            long   TitleId = Context.RequestData.ReadInt64();

            StorageId InstalledStorage =
                Context.Device.System.ContentManager.GetInstalledStorage(TitleId, ContentType.Data, StorageId);

            if (InstalledStorage == StorageId.None)
            {
                InstalledStorage =
                    Context.Device.System.ContentManager.GetInstalledStorage(TitleId, ContentType.AocData, StorageId);
            }

            if (InstalledStorage != StorageId.None)
            {
                string ContentPath = Context.Device.System.ContentManager.GetInstalledContentPath(TitleId, StorageId, ContentType.AocData);

                if (string.IsNullOrWhiteSpace(ContentPath))
                {
                    ContentPath = Context.Device.System.ContentManager.GetInstalledContentPath(TitleId, StorageId, ContentType.AocData);
                }

                string InstallPath = Context.Device.FileSystem.SwitchPathToSystemPath(ContentPath);

                if (!string.IsNullOrWhiteSpace(InstallPath))
                {
                    string NcaPath = InstallPath;

                    if (File.Exists(NcaPath))
                    {
                        FileStream NcaStream    = new FileStream(NcaPath, FileMode.Open, FileAccess.Read);
                        Nca        Nca          = new Nca(Context.Device.System.KeySet, NcaStream, false);
                        NcaSection RomfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
                        Stream     RomfsStream  = Nca.OpenSection(RomfsSection.SectionNum, false, Context.Device.System.FsIntegrityCheckLevel);

                        MakeObject(Context, new IStorage(RomfsStream));

                        return(0);
                    }
                    else
                    {
                        throw new FileNotFoundException($"No Nca found in Path `{NcaPath}`.");
                    }
                }
                else
                {
                    throw new DirectoryNotFoundException($"Path for title id {TitleId:x16} on Storage {StorageId} was not found in Path {InstallPath}.");
                }
            }

            throw new FileNotFoundException($"System archive with titleid {TitleId:x16} was not found on Storage {StorageId}. Found in {InstalledStorage}.");
        }
示例#6
0
        // OpenDataStorageByDataId(u8 storageId, nn::ApplicationId tid) -> object<nn::fssrv::sf::IStorage> dataStorage
        public long OpenDataStorageByDataId(ServiceCtx context)
        {
            StorageId storageId = (StorageId)context.RequestData.ReadByte();

            byte[] padding = context.RequestData.ReadBytes(7);
            long   titleId = context.RequestData.ReadInt64();

            StorageId installedStorage =
                context.Device.System.ContentManager.GetInstalledStorage(titleId, ContentType.Data, storageId);

            if (installedStorage == StorageId.None)
            {
                installedStorage =
                    context.Device.System.ContentManager.GetInstalledStorage(titleId, ContentType.AocData, storageId);
            }

            if (installedStorage != StorageId.None)
            {
                string contentPath = context.Device.System.ContentManager.GetInstalledContentPath(titleId, storageId, ContentType.AocData);

                if (string.IsNullOrWhiteSpace(contentPath))
                {
                    contentPath = context.Device.System.ContentManager.GetInstalledContentPath(titleId, storageId, ContentType.AocData);
                }

                string installPath = context.Device.FileSystem.SwitchPathToSystemPath(contentPath);

                if (!string.IsNullOrWhiteSpace(installPath))
                {
                    string ncaPath = installPath;

                    if (File.Exists(ncaPath))
                    {
                        FileStream ncaStream    = new FileStream(ncaPath, FileMode.Open, FileAccess.Read);
                        Nca        nca          = new Nca(context.Device.System.KeySet, ncaStream, false);
                        NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
                        Stream     romfsStream  = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel);

                        MakeObject(context, new IStorage(romfsStream));

                        return(0);
                    }
                    else
                    {
                        throw new FileNotFoundException($"No Nca found in Path `{ncaPath}`.");
                    }
                }
                else
                {
                    throw new DirectoryNotFoundException($"Path for title id {titleId:x16} on Storage {storageId} was not found in Path {installPath}.");
                }
            }

            throw new FileNotFoundException($"System archive with titleid {titleId:x16} was not found on Storage {storageId}. Found in {installedStorage}.");
        }
示例#7
0
        public static NcaSection ParseSection(NcaHeader Header, int index)
        {
            var entry  = Header.SectionEntries[index];
            var header = Header.FsHeaders[index];

            if (entry.MediaStartOffset == 0)
            {
                return(null);
            }

            var sect = new NcaSection();

            sect.SectionNum = index;
            sect.Offset     = Utils.MediaToReal(entry.MediaStartOffset);
            sect.Size       = Utils.MediaToReal(entry.MediaEndOffset) - sect.Offset;
            sect.Header     = header;
            sect.Type       = header.Type;

            return(sect);
        }
示例#8
0
        public static Validity VerifySection(this Nca nca, int index, IProgressReport logger = null, bool quiet = false)
        {
            if (nca.Sections[index] == null)
            {
                throw new ArgumentOutOfRangeException(nameof(index));
            }

            NcaSection  sect     = nca.Sections[index];
            NcaHashType hashType = sect.Header.HashType;

            if (hashType != NcaHashType.Sha256 && hashType != NcaHashType.Ivfc)
            {
                return(Validity.Unchecked);
            }

            var stream = nca.OpenStorage(index, IntegrityCheckLevel.IgnoreOnInvalid, false)
                         as HierarchicalIntegrityVerificationStorage;

            if (stream == null)
            {
                return(Validity.Unchecked);
            }

            if (!quiet)
            {
                logger?.LogMessage($"Verifying section {index}...");
            }
            Validity validity = stream.Validate(true, logger);

            if (hashType == NcaHashType.Ivfc)
            {
                stream.SetLevelValidities(sect.Header.IvfcInfo);
            }
            else if (hashType == NcaHashType.Sha256)
            {
                sect.Header.Sha256Info.HashValidity = validity;
            }

            return(validity);
        }
示例#9
0
        public Bktr(Stream patchRomfs, Stream baseRomfs, NcaSection section)
        {
            if (section.Header.EncryptionType != NcaEncryptionType.AesCtrEx)
            {
                throw new ArgumentException("Section is not of type BKTR");
            }
            Patch = patchRomfs ?? throw new NullReferenceException($"{nameof(patchRomfs)} cannot be null");
            Base  = baseRomfs ?? throw new NullReferenceException($"{nameof(baseRomfs)} cannot be null");

            IvfcLevelHeader level5 = section.Header.IvfcInfo.LevelHeaders[5];

            Length = level5.LogicalOffset + level5.HashDataSize;

            using (var reader = new BinaryReader(patchRomfs, Encoding.Default, true))
            {
                patchRomfs.Position = section.Header.BktrInfo.RelocationHeader.Offset;
                RelocationBlock     = new RelocationBlock(reader);
            }

            foreach (RelocationBucket bucket in RelocationBlock.Buckets)
            {
                RelocationEntries.AddRange(bucket.Entries);
            }

            for (int i = 0; i < RelocationEntries.Count - 1; i++)
            {
                RelocationEntries[i].Next          = RelocationEntries[i + 1];
                RelocationEntries[i].VirtOffsetEnd = RelocationEntries[i + 1].VirtOffset;
            }

            RelocationEntries[RelocationEntries.Count - 1].VirtOffsetEnd = level5.LogicalOffset + level5.HashDataSize;
            RelocationOffsets = RelocationEntries.Select(x => x.VirtOffset).ToList();

            CurrentEntry = GetRelocationEntry(0);
            UpdateSourceStreamPositions();
        }
示例#10
0
        private static string Print(this Nca nca)
        {
            int colLen = 36;
            var sb     = new StringBuilder();

            sb.AppendLine();

            sb.AppendLine("NCA:");
            PrintItem(sb, colLen, "Magic:", nca.Header.Magic);
            PrintItem(sb, colLen, $"Fixed-Key Signature{nca.Header.FixedSigValidity.GetValidityString()}:", nca.Header.Signature1);
            PrintItem(sb, colLen, $"NPDM Signature{nca.Header.NpdmSigValidity.GetValidityString()}:", nca.Header.Signature2);
            PrintItem(sb, colLen, "Content Size:", $"0x{nca.Header.NcaSize:x12}");
            PrintItem(sb, colLen, "TitleID:", $"{nca.Header.TitleId:X16}");
            PrintItem(sb, colLen, "SDK Version:", nca.Header.SdkVersion);
            PrintItem(sb, colLen, "Distribution type:", nca.Header.Distribution);
            PrintItem(sb, colLen, "Content Type:", nca.Header.ContentType);
            PrintItem(sb, colLen, "Master Key Revision:", $"{nca.CryptoType} ({Util.GetKeyRevisionSummary(nca.CryptoType)})");
            PrintItem(sb, colLen, "Encryption Type:", $"{(nca.HasRightsId ? "Titlekey crypto" : "Standard crypto")}");

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

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

            PrintSections();

            return(sb.ToString());

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

                for (int i = 0; i < 4; i++)
                {
                    NcaSection sect = nca.Sections[i];
                    if (sect == null)
                    {
                        continue;
                    }

                    bool isExefs = nca.Header.ContentType == ContentType.Program && i == (int)ProgramPartitionType.Code;

                    sb.AppendLine($"    Section {i}:");
                    PrintItem(sb, colLen, "        Offset:", $"0x{sect.Offset:x12}");
                    PrintItem(sb, colLen, "        Size:", $"0x{sect.Size:x12}");
                    PrintItem(sb, colLen, "        Partition Type:", isExefs ? "ExeFS" : sect.Type.ToString());
                    PrintItem(sb, colLen, "        Section CTR:", sect.Header.Ctr);

                    switch (sect.Header.HashType)
                    {
                    case NcaHashType.Sha256:
                        PrintSha256Hash(sect);
                        break;

                    case NcaHashType.Ivfc:
                        PrintIvfcHash(sb, colLen, 8, sect.Header.IvfcInfo, IntegrityStorageType.RomFs);
                        break;

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

            void PrintSha256Hash(NcaSection sect)
            {
                Sha256Info hashInfo = sect.Header.Sha256Info;

                PrintItem(sb, colLen, $"        Master Hash{sect.MasterHashValidity.GetValidityString()}:", hashInfo.MasterHash);
                sb.AppendLine($"        Hash Table{sect.Header.Sha256Info.HashValidity.GetValidityString()}:");

                PrintItem(sb, colLen, "            Offset:", $"0x{hashInfo.HashTableOffset:x12}");
                PrintItem(sb, colLen, "            Size:", $"0x{hashInfo.HashTableSize:x12}");
                PrintItem(sb, colLen, "            Block Size:", $"0x{hashInfo.BlockSize:x}");
                PrintItem(sb, colLen, "        PFS0 Offset:", $"0x{hashInfo.DataOffset:x12}");
                PrintItem(sb, colLen, "        PFS0 Size:", $"0x{hashInfo.DataSize:x12}");
            }
        }
示例#11
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);
                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.Sections[i] != null)
                    {
                        nca.VerifySection(i, ctx.Logger);
                    }
                }

                if (ctx.Options.ListRomFs && nca.Sections[1] != null)
                {
                    var romfs = new RomFsFileSystem(nca.OpenSection(1, false, ctx.Options.IntegrityLevel, true));

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

                if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null || ctx.Options.ReadBench)
                {
                    NcaSection section = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs || x?.Type == SectionType.Bktr);

                    if (section == null)
                    {
                        ctx.Logger.LogMessage("NCA has no RomFS section");
                        return;
                    }

                    if (section.Type == SectionType.Bktr && ctx.Options.BaseNca == null)
                    {
                        ctx.Logger.LogMessage("Cannot save BKTR section without base RomFS");
                        return;
                    }

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

                    if (ctx.Options.RomfsOutDir != null)
                    {
                        IFileSystem romfs = nca.OpenSectionFileSystem(section.SectionNum, ctx.Options.IntegrityLevel);
                        romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger);
                    }

                    if (ctx.Options.ReadBench)
                    {
                        long     bytesToRead = 1024L * 1024 * 1024 * 5;
                        IStorage storage     = nca.OpenSection(section.SectionNum, false, ctx.Options.IntegrityLevel, true);
                        var      dest        = new NullStorage(storage.Length);

                        int iterations = (int)(bytesToRead / storage.Length) + 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;
                    }

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

                    if (section == null)
                    {
                        ctx.Logger.LogMessage("Could not find an ExeFS section");
                        return;
                    }

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

                    if (ctx.Options.ExefsOutDir != null)
                    {
                        IFileSystem pfs = nca.OpenSectionFileSystem(section.SectionNum, ctx.Options.IntegrityLevel);
                        pfs.Extract(ctx.Options.ExefsOutDir, ctx.Logger);
                    }
                }

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

                if (!ctx.Options.ReadBench)
                {
                    ctx.Logger.LogMessage(nca.Print());
                }
            }
        }
示例#12
0
        public static void EncryptFunct(
            Stream Input, Stream Output, string ncaFilename,
            bool verifyEncrypted, Keyset keyset, Output Out)
        {
            var DecryptedKeys = Utils.CreateJaggedArray <byte[][]>(4, 0x10);
            var HeaderKey1    = new byte[16];
            var HeaderKey2    = new byte[16];

            Buffer.BlockCopy(keyset.HeaderKey, 0, HeaderKey1, 0, 16);
            Buffer.BlockCopy(keyset.HeaderKey, 16, HeaderKey2, 0, 16);

            var DecryptedHeader = new byte[0xC00];

            Input.Read(DecryptedHeader, 0, 0xC00);

            var Header     = new NcaHeader(new BinaryReader(new MemoryStream(DecryptedHeader)), keyset);
            var CryptoType = Math.Max(Header.CryptoType, Header.CryptoType2);

            if (CryptoType > 0)
            {
                CryptoType--;
            }

            var HasRightsId = !Header.RightsId.IsEmpty();

            if (!HasRightsId)
            {
                Out.Log("Key Area (Encrypted):\r\n");
                if (keyset.KeyAreaKeys[CryptoType][Header.KaekInd].IsEmpty())
                {
                    throw new ArgumentException($"key_area_key_{KakNames[Header.KaekInd]}_{CryptoType:x2}",
                                                "Missing area key!");
                }

                Out.Log(
                    $"key_area_key_{KakNames[Header.KaekInd]}_{CryptoType:x2}: {Utils.BytesToString(keyset.KeyAreaKeys[CryptoType][Header.KaekInd])}\r\n");
                for (var i = 0; i < 4; ++i)
                {
                    LibHac.Crypto.DecryptEcb(keyset.KeyAreaKeys[CryptoType][Header.KaekInd], Header.EncryptedKeys[i],
                                             DecryptedKeys[i], 0x10);
                    Out.Log($"Key {i} (Encrypted): {Utils.BytesToString(Header.EncryptedKeys[i])}\r\n");
                    Out.Log($"Key {i} (Decrypted): {Utils.BytesToString(DecryptedKeys[i])}\r\n");
                }
            }
            else
            {
                var titleKey    = keyset.TitleKeys[Header.RightsId];
                var TitleKeyDec = new byte[0x10];
                LibHac.Crypto.DecryptEcb(keyset.TitleKeks[CryptoType], titleKey, TitleKeyDec, 0x10);
                Out.Log($"titleKey: {Utils.BytesToString(titleKey)}\r\n");
                Out.Log($"TitleKeyDec: {Utils.BytesToString(TitleKeyDec)}\r\n");
                DecryptedKeys[2] = TitleKeyDec;
            }

            var Sections         = new NcaSection[4];
            var SectionsByOffset = new Dictionary <long, int>();
            var lowestOffset     = long.MaxValue;

            for (var i = 0; i < 4; ++i)
            {
                var section = NcaParseSection.ParseSection(Header, i);
                if (section == null)
                {
                    continue;
                }

                SectionsByOffset.Add(section.Offset, i);
                if (section.Offset < lowestOffset)
                {
                    lowestOffset = section.Offset;
                }

                Sections[i] = section;
            }

            Out.Log($"HeaderKey: {Utils.BytesToString(keyset.HeaderKey)}\r\n");
            Out.Log("Encrypting and writing header to NCA...\r\n");
            SHA256Cng sha256NCA = null;

            if (verifyEncrypted)
            {
                sha256NCA = new SHA256Cng();
                sha256NCA.Initialize();
            }

            var encryptedHeader = CryptoInitialisers.AES_XTS(HeaderKey1, HeaderKey2, 0x200, DecryptedHeader, 0);

            if (Output != null)
            {
                Output.Write(encryptedHeader, 0, DecryptedHeader.Length);
            }

            if (verifyEncrypted)
            {
                sha256NCA.TransformBlock(encryptedHeader, 0, DecryptedHeader.Length, null, 0);
            }

            var   dummyHeader       = new byte[0xC00];
            ulong dummyHeaderSector = 6;
            long  dummyHeaderPos;

            for (dummyHeaderPos = 0xC00; dummyHeaderPos < lowestOffset; dummyHeaderPos += 0xC00)
            {
                var dummyHeaderWriteCount = (int)Math.Min(lowestOffset - dummyHeaderPos, DecryptedHeader.Length);
                Input.Read(dummyHeader, 0, dummyHeaderWriteCount);
                var dummyHeaderEncrypted =
                    CryptoInitialisers.AES_XTS(HeaderKey1, HeaderKey2, 0x200, dummyHeader, dummyHeaderSector);
                if (Output != null)
                {
                    Output.Write(dummyHeaderEncrypted, 0, dummyHeaderWriteCount);
                }

                if (verifyEncrypted)
                {
                    sha256NCA.TransformBlock(dummyHeaderEncrypted, 0, dummyHeaderWriteCount, null, 0);
                }

                dummyHeaderSector += 6;
            }

            Out.Log("Encrypting and writing sectors to NCA...\r\n");
            Out.Log("Sections:\r\n");
            foreach (var i in SectionsByOffset.OrderBy(i => i.Key).Select(item => item.Value))
            {
                var sect = Sections[i];
                if (sect == null)
                {
                    continue;
                }

                var isExefs       = Header.ContentType == ContentType.Program && i == (int)ProgramPartitionType.Code;
                var PartitionType = isExefs ? "ExeFS" : sect.Type.ToString();
                Out.Log($"    Section {i}:\r\n");
                Out.Log($"        Offset: 0x{sect.Offset:x12}\r\n");
                Out.Log($"        Size: 0x{sect.Size:x12}\r\n");
                Out.Log($"        Partition Type: {PartitionType}\r\n");
                Out.Log($"        Section CTR: {Utils.BytesToString(sect.Header.Ctr)}\r\n");
                var initialCounter = new byte[0x10];


                if (sect.Header.Ctr != null)
                {
                    Array.Copy(sect.Header.Ctr, initialCounter, 8);
                }

                Out.Log($"initialCounter: {Utils.BytesToString(initialCounter)}\r\n");

                if (Input.Position != sect.Offset)
                {
                    //Input.Seek(sect.Offset, SeekOrigin.Begin);
                    //Output.Seek(sect.Offset, SeekOrigin.Begin);
                    //Todo: sha256NCA Gap support
                    throw new NotImplementedException("Gaps between NCA sections aren't implemented yet!");
                }

                const int maxBS = 10485760;                 //10 MB
                int       bs;
                var       DecryptedSectionBlock = new byte[maxBS];
                var       sectOffsetEnd         = sect.Offset + sect.Size;
                var       AesCtrEncrypter       = new Aes128CtrTransform(DecryptedKeys[2], initialCounter);
                switch (sect.Header.EncryptionType)
                {
                case NcaEncryptionType.None:
                    while (Input.Position < sectOffsetEnd)
                    {
                        bs = (int)Math.Min(sectOffsetEnd - Input.Position, maxBS);
                        Out.Print($"Encrypted: {Input.Position / 0x100000} MB\r\n");
                        Input.Read(DecryptedSectionBlock, 0, bs);
                        if (Output != null)
                        {
                            Output.Write(DecryptedSectionBlock, 0, bs);
                        }

                        if (verifyEncrypted)
                        {
                            sha256NCA.TransformBlock(DecryptedSectionBlock, 0, bs, null, 0);
                        }
                    }

                    break;

                case NcaEncryptionType.AesCtr:

                    while (Input.Position < sectOffsetEnd)
                    {
                        SetCtrOffset(initialCounter, Input.Position);
                        bs = (int)Math.Min(sectOffsetEnd - Input.Position, maxBS);
                        Out.Print($"Encrypted: {Input.Position / 0x100000} MB\r\n");
                        Input.Read(DecryptedSectionBlock, 0, bs);
                        AesCtrEncrypter.Counter = initialCounter;
                        AesCtrEncrypter.TransformBlock(DecryptedSectionBlock);

                        if (Output != null)
                        {
                            Output.Write(DecryptedSectionBlock, 0, bs);
                        }

                        if (verifyEncrypted)
                        {
                            sha256NCA.TransformBlock(DecryptedSectionBlock, 0, bs, null, 0);
                        }
                    }

                    break;

                case NcaEncryptionType.AesCtrEx:
                    var info         = sect.Header.BktrInfo;
                    var MyBucketTree = new MyBucketTree <AesSubsectionEntry>(
                        new MemoryStream(sect.Header.BktrInfo.EncryptionHeader.Header), Input,
                        sect.Offset + info.EncryptionHeader.Offset);
                    var SubsectionEntries = MyBucketTree.GetEntryList();
                    var SubsectionOffsets = SubsectionEntries.Select(x => x.Offset).ToList();

                    var subsectionEntryCounter = new byte[0x10];
                    Array.Copy(initialCounter, subsectionEntryCounter, 0x10);
                    foreach (var entry in SubsectionEntries)
                    {
                        do
                        {
                            bs = (int)Math.Min((sect.Offset + entry.OffsetEnd) - Input.Position, maxBS);

                            SetCtrOffset(subsectionEntryCounter, Input.Position);
                            subsectionEntryCounter[7] = (byte)entry.Counter;
                            subsectionEntryCounter[6] = (byte)(entry.Counter >> 8);
                            subsectionEntryCounter[5] = (byte)(entry.Counter >> 16);
                            subsectionEntryCounter[4] = (byte)(entry.Counter >> 24);

                            var DecryptedSectionBlockLUL = new byte[bs];
                            Out.Print($"Encrypted: {Input.Position / 0x100000} MB\r\n");
                            Out.Log($"{Input.Position}: {Utils.BytesToString(subsectionEntryCounter)}\r\n");
                            Input.Read(DecryptedSectionBlockLUL, 0, bs);
                            AesCtrEncrypter.Counter = subsectionEntryCounter;
                            AesCtrEncrypter.TransformBlock(DecryptedSectionBlockLUL);
                            if (Output != null)
                            {
                                Output.Write(DecryptedSectionBlockLUL, 0, bs);
                            }

                            if (verifyEncrypted)
                            {
                                sha256NCA.TransformBlock(DecryptedSectionBlockLUL, 0, bs, null, 0);
                            }
                        } while (Input.Position < entry.OffsetEnd);
                    }

                    while (Input.Position < sectOffsetEnd)
                    {
                        SetCtrOffset(subsectionEntryCounter, Input.Position);
                        bs = (int)Math.Min(sectOffsetEnd - Input.Position, maxBS);
                        Out.Print($"EncryptedAfter: {Input.Position / 0x100000} MB\r\n");
                        Input.Read(DecryptedSectionBlock, 0, bs);
                        Out.Log($"{Input.Position}: {Utils.BytesToString(subsectionEntryCounter)}\r\n");
                        AesCtrEncrypter.Counter = subsectionEntryCounter;
                        AesCtrEncrypter.TransformBlock(DecryptedSectionBlock);
                        if (Output != null)
                        {
                            Output.Write(DecryptedSectionBlock, 0, bs);
                        }

                        if (verifyEncrypted)
                        {
                            sha256NCA.TransformBlock(DecryptedSectionBlock, 0, bs, null, 0);
                        }
                    }

                    break;

                default:
                    throw new NotImplementedException();
                }
            }

            if (verifyEncrypted)
            {
                sha256NCA.TransformFinalBlock(new byte[0], 0, 0);
                var sha256NCAHashString = Utils.BytesToString(sha256NCA.Hash).ToLower();
                if (sha256NCAHashString.StartsWith(ncaFilename.Split('.')[0].ToLower()))
                {
                    Out.Log($"[VERIFIED] {sha256NCAHashString}\r\n");
                }
                else
                {
                    throw new Exception($"[INVALID HASH] sha256({ncaFilename}) = {sha256NCAHashString}\r\n");
                }
            }
        }
示例#13
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));
        }
示例#14
0
        public static void Process(Context ctx)
        {
            using (var file = new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.Read))
            {
                var xci = new Xci(ctx.Keyset, file.AsStorage());

                ctx.Logger.LogMessage(xci.Print());

                if (ctx.Options.RootDir != null)
                {
                    xci.RootPartition?.Extract(ctx.Options.RootDir, ctx.Logger);
                }

                if (ctx.Options.UpdateDir != null)
                {
                    xci.UpdatePartition?.Extract(ctx.Options.UpdateDir, ctx.Logger);
                }

                if (ctx.Options.NormalDir != null)
                {
                    xci.NormalPartition?.Extract(ctx.Options.NormalDir, ctx.Logger);
                }

                if (ctx.Options.SecureDir != null)
                {
                    xci.SecurePartition?.Extract(ctx.Options.SecureDir, ctx.Logger);
                }

                if (ctx.Options.LogoDir != null)
                {
                    xci.LogoPartition?.Extract(ctx.Options.LogoDir, ctx.Logger);
                }

                if (ctx.Options.OutDir != null && xci.RootPartition != null)
                {
                    XciPartition root = xci.RootPartition;
                    if (root == null)
                    {
                        ctx.Logger.LogMessage("Could not find root partition");
                        return;
                    }

                    foreach (PfsFileEntry sub in root.Files)
                    {
                        var    subPfs = new Pfs(root.OpenFile(sub));
                        string subDir = Path.Combine(ctx.Options.OutDir, sub.Name);

                        subPfs.Extract(subDir, ctx.Logger);
                    }
                }

                if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null)
                {
                    Nca mainNca = GetXciMainNca(xci, ctx);

                    if (mainNca == null)
                    {
                        ctx.Logger.LogMessage("Could not find Program NCA");
                        return;
                    }

                    NcaSection exefsSection = mainNca.Sections[(int)ProgramPartitionType.Code];

                    if (exefsSection == null)
                    {
                        ctx.Logger.LogMessage("NCA has no ExeFS section");
                        return;
                    }

                    if (ctx.Options.ExefsOutDir != null)
                    {
                        mainNca.ExtractSection(exefsSection.SectionNum, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
                    }

                    if (ctx.Options.ExefsOut != null)
                    {
                        mainNca.ExportSection(exefsSection.SectionNum, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
                    }
                }

                if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null)
                {
                    Nca mainNca = GetXciMainNca(xci, ctx);

                    if (mainNca == null)
                    {
                        ctx.Logger.LogMessage("Could not find Program NCA");
                        return;
                    }

                    NcaSection romfsSection = mainNca.Sections.FirstOrDefault(x => x.Type == SectionType.Romfs);

                    if (romfsSection == null)
                    {
                        ctx.Logger.LogMessage("NCA has no RomFS section");
                        return;
                    }

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

                    if (ctx.Options.RomfsOut != null)
                    {
                        mainNca.ExportSection(romfsSection.SectionNum, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
                    }
                }
            }
        }
示例#15
0
        public void LoadNca(Nca MainNca, Nca ControlNca)
        {
            NcaSection RomfsSection = MainNca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs || x?.Type == SectionType.Bktr);
            NcaSection ExefsSection = MainNca.Sections.FirstOrDefault(x => x?.IsExefs == true);

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

                return;
            }

            if (RomfsSection == null)
            {
                Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA");
            }
            else
            {
                Stream RomfsStream = MainNca.OpenSection(RomfsSection.SectionNum, false, EnableFsIntegrityChecks);

                Device.FileSystem.SetRomFs(RomfsStream);
            }

            Stream ExefsStream = MainNca.OpenSection(ExefsSection.SectionNum, false, EnableFsIntegrityChecks);

            Pfs Exefs = new Pfs(ExefsStream);

            Npdm MetaData = null;

            if (Exefs.FileExists("main.npdm"))
            {
                Logger.PrintInfo(LogClass.Loader, "Loading main.npdm...");

                MetaData = new Npdm(Exefs.OpenFile("main.npdm"));
            }
            else
            {
                Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
            }

            Process MainProcess = MakeProcess(MetaData);

            void LoadNso(string Filename)
            {
                foreach (PfsFileEntry File in Exefs.Files.Where(x => x.Name.StartsWith(Filename)))
                {
                    if (Path.GetExtension(File.Name) != string.Empty)
                    {
                        continue;
                    }

                    Logger.PrintInfo(LogClass.Loader, $"Loading {Filename}...");

                    string Name = Path.GetFileNameWithoutExtension(File.Name);

                    Nso Program = new Nso(Exefs.OpenFile(File), Name);

                    MainProcess.LoadProgram(Program);
                }
            }

            Nacp ReadControlData()
            {
                Romfs ControlRomfs = new Romfs(ControlNca.OpenSection(0, false, EnableFsIntegrityChecks));

                byte[] ControlFile = ControlRomfs.GetFile("/control.nacp");

                BinaryReader Reader = new BinaryReader(new MemoryStream(ControlFile));

                Nacp ControlData = new Nacp(Reader);

                CurrentTitle = ControlData.Languages[(int)State.DesiredTitleLanguage].Title;

                if (string.IsNullOrWhiteSpace(CurrentTitle))
                {
                    CurrentTitle = ControlData.Languages.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title;
                }

                return(ControlData);
            }

            if (ControlNca != null)
            {
                MainProcess.ControlData = ReadControlData();
            }
            else
            {
                CurrentTitle = MainProcess.MetaData.ACI0.TitleId.ToString("x16");
            }

            if (!MainProcess.MetaData.Is64Bits)
            {
                throw new NotImplementedException("32-bit titles are unsupported!");
            }

            LoadNso("rtld");

            MainProcess.SetEmptyArgs();

            LoadNso("main");
            LoadNso("subsdk");
            LoadNso("sdk");

            MainProcess.Run();
        }
示例#16
0
        public void EnsureInitialized(ContentManager ContentManager)
        {
            if (FontData == null)
            {
                Device.Memory.FillWithZeros(PhysicalAddress, Horizon.FontSize);

                uint FontOffset = 0;

                FontInfo CreateFont(string Name)
                {
                    if (ContentManager.TryGetFontTitle(Name, out long FontTitle))
                    {
                        string ContentPath = ContentManager.GetInstalledContentPath(FontTitle, StorageId.NandSystem, ContentType.Data);
                        string FontPath    = Device.FileSystem.SwitchPathToSystemPath(ContentPath);

                        if (!string.IsNullOrWhiteSpace(FontPath))
                        {
                            int FileIndex = 0;

                            //Use second file in Chinese Font title for standard
                            if (Name == "FontChineseSimplified")
                            {
                                FileIndex = 1;
                            }

                            FileStream NcaFileStream = new FileStream(FontPath, FileMode.Open, FileAccess.Read);
                            Nca        Nca           = new Nca(Device.System.KeySet, NcaFileStream, false);
                            NcaSection RomfsSection  = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
                            Romfs      Romfs         = new Romfs(Nca.OpenSection(RomfsSection.SectionNum, false, Device.System.FsIntegrityCheckLevel));
                            Stream     FontFile      = Romfs.OpenFile(Romfs.Files[FileIndex]);

                            byte[] Data = DecryptFont(FontFile);

                            FontInfo Info = new FontInfo((int)FontOffset, Data.Length);

                            WriteMagicAndSize(PhysicalAddress + FontOffset, Data.Length);

                            FontOffset += 8;

                            uint Start = FontOffset;

                            for (; FontOffset - Start < Data.Length; FontOffset++)
                            {
                                Device.Memory.WriteByte(PhysicalAddress + FontOffset, Data[FontOffset - Start]);
                            }

                            NcaFileStream.Dispose();
                            Nca.Dispose();

                            return(Info);
                        }
                    }

                    string FontFilePath = Path.Combine(FontsPath, Name + ".ttf");

                    if (File.Exists(FontFilePath))
                    {
                        byte[] Data = File.ReadAllBytes(FontFilePath);

                        FontInfo Info = new FontInfo((int)FontOffset, Data.Length);

                        WriteMagicAndSize(PhysicalAddress + FontOffset, Data.Length);

                        FontOffset += 8;

                        uint Start = FontOffset;

                        for (; FontOffset - Start < Data.Length; FontOffset++)
                        {
                            Device.Memory.WriteByte(PhysicalAddress + FontOffset, Data[FontOffset - Start]);
                        }

                        return(Info);
                    }
                    else
                    {
                        throw new InvalidSystemResourceException($"Font \"{Name}.ttf\" not found. Please provide it in \"{FontsPath}\".");
                    }
                }

                FontData = new Dictionary <SharedFontType, FontInfo>()
                {
                    { SharedFontType.JapanUsEurope, CreateFont("FontStandard") },
                    { SharedFontType.SimplifiedChinese, CreateFont("FontChineseSimplified") },
                    { SharedFontType.SimplifiedChineseEx, CreateFont("FontExtendedChineseSimplified") },
                    { SharedFontType.TraditionalChinese, CreateFont("FontChineseTraditional") },
                    { SharedFontType.Korean, CreateFont("FontKorean") },
                    { SharedFontType.NintendoEx, CreateFont("FontNintendoExtended") }
                };

                if (FontOffset > Horizon.FontSize)
                {
                    throw new InvalidSystemResourceException(
                              $"The sum of all fonts size exceed the shared memory size. " +
                              $"Please make sure that the fonts don't exceed {Horizon.FontSize} bytes in total. " +
                              $"(actual size: {FontOffset} bytes).");
                }
            }
        }
示例#17
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);
            }
        }
示例#18
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);
            }
        }
示例#19
0
        public static void Process(Context ctx)
        {
            using (var file = new StreamStorage(new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.Read), false))
            {
                var nca = new Nca(ctx.Keyset, file, false);
                nca.ValidateMasterHashes();
                nca.ParseNpdm();

                if (ctx.Options.BaseNca != null)
                {
                    var baseFile = new StreamStorage(new FileStream(ctx.Options.BaseNca, FileMode.Open, FileAccess.Read), false);
                    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.Sections[i] != null)
                    {
                        nca.VerifySection(i, ctx.Logger);
                    }
                }

                if (ctx.Options.ListRomFs && nca.Sections[1] != null)
                {
                    var romfs = new Romfs(nca.OpenSection(1, false, ctx.Options.IntegrityLevel, true));

                    foreach (RomfsFile romfsFile in romfs.Files)
                    {
                        ctx.Logger.LogMessage(romfsFile.FullPath);
                    }
                }

                if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null)
                {
                    NcaSection section = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs || x?.Type == SectionType.Bktr);

                    if (section == null)
                    {
                        ctx.Logger.LogMessage("NCA has no RomFS section");
                        return;
                    }

                    if (section.Type == SectionType.Bktr && ctx.Options.BaseNca == null)
                    {
                        ctx.Logger.LogMessage("Cannot save BKTR section without base RomFS");
                        return;
                    }

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

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

                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;
                    }

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

                    if (section == null)
                    {
                        ctx.Logger.LogMessage("Could not find an ExeFS section");
                        return;
                    }

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

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

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

                ctx.Logger.LogMessage(nca.Print());
            }
        }
示例#20
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();
        }
示例#21
0
        public void EnsureInitialized(ContentManager contentManager)
        {
            if (_fontData == null)
            {
                _device.Memory.FillWithZeros(_physicalAddress, Horizon.FontSize);

                uint fontOffset = 0;

                FontInfo CreateFont(string name)
                {
                    if (contentManager.TryGetFontTitle(name, out long fontTitle))
                    {
                        string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.NandSystem, ContentType.Data);
                        string fontPath    = _device.FileSystem.SwitchPathToSystemPath(contentPath);

                        if (!string.IsNullOrWhiteSpace(fontPath))
                        {
                            int fileIndex = 0;

                            //Use second file in Chinese Font title for standard
                            if (name == "FontChineseSimplified")
                            {
                                fileIndex = 1;
                            }

                            byte[] data;

                            using (FileStream ncaFileStream = new FileStream(fontPath, FileMode.Open, FileAccess.Read))
                            {
                                Nca        nca          = new Nca(_device.System.KeySet, ncaFileStream.AsStorage(), false);
                                NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
                                Romfs      romfs        = new Romfs(nca.OpenSection(romfsSection.SectionNum, false, _device.System.FsIntegrityCheckLevel, false));
                                Stream     fontFile     = romfs.OpenFile(romfs.Files[fileIndex]).AsStream();

                                data = DecryptFont(fontFile);
                            }

                            FontInfo info = new FontInfo((int)fontOffset, data.Length);

                            WriteMagicAndSize(_physicalAddress + fontOffset, data.Length);

                            fontOffset += 8;

                            uint start = fontOffset;

                            for (; fontOffset - start < data.Length; fontOffset++)
                            {
                                _device.Memory.WriteByte(_physicalAddress + fontOffset, data[fontOffset - start]);
                            }

                            return(info);
                        }
                    }

                    string fontFilePath = Path.Combine(_fontsPath, name + ".ttf");

                    if (File.Exists(fontFilePath))
                    {
                        byte[] data = File.ReadAllBytes(fontFilePath);

                        FontInfo info = new FontInfo((int)fontOffset, data.Length);

                        WriteMagicAndSize(_physicalAddress + fontOffset, data.Length);

                        fontOffset += 8;

                        uint start = fontOffset;

                        for (; fontOffset - start < data.Length; fontOffset++)
                        {
                            _device.Memory.WriteByte(_physicalAddress + fontOffset, data[fontOffset - start]);
                        }

                        return(info);
                    }
                    else
                    {
                        throw new InvalidSystemResourceException($"Font \"{name}.ttf\" not found. Please provide it in \"{_fontsPath}\".");
                    }
                }

                _fontData = new Dictionary <SharedFontType, FontInfo>
                {
                    { SharedFontType.JapanUsEurope, CreateFont("FontStandard") },
                    { SharedFontType.SimplifiedChinese, CreateFont("FontChineseSimplified") },
                    { SharedFontType.SimplifiedChineseEx, CreateFont("FontExtendedChineseSimplified") },
                    { SharedFontType.TraditionalChinese, CreateFont("FontChineseTraditional") },
                    { SharedFontType.Korean, CreateFont("FontKorean") },
                    { SharedFontType.NintendoEx, CreateFont("FontNintendoExtended") }
                };

                if (fontOffset > Horizon.FontSize)
                {
                    throw new InvalidSystemResourceException(
                              $"The sum of all fonts size exceed the shared memory size. " +
                              $"Please make sure that the fonts don't exceed {Horizon.FontSize} bytes in total. " +
                              $"(actual size: {fontOffset} bytes).");
                }
            }
        }