Esempio n. 1
0
        private static void Main(string[] args)
        {
            var keyFile       = Environment.ExpandEnvironmentVariables("%USERPROFILE%/.switch/prod.keys");
            var keysInUserDir = true;

            var getDeltasOnly = false;

            #region Pre-execution checks
            if (!File.Exists(keyFile))
            {
                if (!File.Exists("prod.keys"))
                {
                    Console.Error.WriteLine("Error: prod.keys is missing!");
                    return;
                }
                else
                {
                    keysInUserDir = false;
                }
            }

            if (!File.Exists("edge.token"))
            {
                Console.Error.WriteLine("Error: Please add an edge token to a file named \"edge.token\".");
                return;
            }

            if (!File.Exists("device.id"))
            {
                Console.Error.WriteLine("Error: Please add your device ID in hexadecimal text form to a file named \"device.id\".");
                return;
            }

            if (!File.Exists("nx_tls_client_cert.pfx"))
            {
                Console.Error.WriteLine("Error: Please add your Switch certificate to a file named \"nx_tls_client_cert.pfx\".");
                return;
            }
            #endregion

            var deviceID = Convert.ToInt64(File.ReadAllText("device.id"), 16);
            var keys     = ExternalKeys.ReadKeyFile(keysInUserDir ? keyFile : "prod.keys");

            var sysID = "0100000000000816";

            // To-do: Clean up
            if (args[0] == "-s" || args[0] == sysID)
            {
                var JSON    = (string)GET(deviceID, SunUrl, true);
                var Version = args.Length > 1 ? args[1] : (string)JObject.Parse(JSON)["system_update_metas"][0]["title_version"];
                HEAD(deviceID, nMetaURL('s', sysID, Version, deviceID));
                var contentID = HEAD(deviceID, nMetaURL('s', sysID, Version, deviceID));

                using (var meta = (HttpWebResponse)GET(deviceID, nContentURL('s', contentID), false))
                    using (var rd = new BinaryReader(meta.GetResponseStream()))
                        using (var strm = new MemoryStorage(rd.ReadBytes((int)meta.ContentLength)))
                        {
                            Directory.CreateDirectory(sysID);
                            strm.WriteAllBytes($"{sysID}/{contentID}.cnmt.nca");
                            using (var nca = new Nca(keys, strm, false).OpenSection(0, false, IntegrityCheckLevel.None, false))
                            {
                                var pfs  = new Pfs(nca);
                                var cnmt = new Cnmt(pfs.OpenFile(pfs.Files[0]).AsStream());
                                foreach (var entry in cnmt.MetaEntries)
                                {
                                    var tid = $"{entry.TitleId:x16}";
                                    HEAD(deviceID, nMetaURL('a', tid, $"{entry.Version.Version}", deviceID));
                                    var cID = HEAD(deviceID, nMetaURL('a', tid, $"{entry.Version.Version}", deviceID));

                                    using (var met2 = (HttpWebResponse)GET(deviceID, nContentURL('a', cID), false))
                                        using (var rdr = new BinaryReader(met2.GetResponseStream()))
                                            using (var strm2 = new MemoryStorage(rdr.ReadBytes((int)meta.ContentLength)))
                                            {
                                                Directory.CreateDirectory($"{sysID}/{tid}");
                                                strm2.WriteAllBytes($"{sysID}/{tid}/{cID}.cnmt.nca");
                                                using (var nca2 = new Nca(keys, strm2, false).OpenSection(0, false, IntegrityCheckLevel.None, false))
                                                {
                                                    var pfs2  = new Pfs(nca2);
                                                    var cnmt2 = new Cnmt(pfs2.OpenFile(pfs2.Files[0]).AsStream());
                                                    foreach (var entry2 in cnmt2.ContentEntries)
                                                    {
                                                        string NCAID = entry2.NcaId.ToHexString().ToLower();
                                                        using (var Req = (HttpWebResponse)GET(deviceID, nContentURL('c', NCAID), false))
                                                            using (var Output = File.OpenWrite($"{sysID}/{tid}/{NCAID}.nca"))
                                                                Req.GetResponseStream().CopyTo(Output);
                                                    }
                                                }
                                            }
                                }
                            }
                        }

                return;
            }

            string id          = null,
                   idFirstReq  = null,
                   idSecondReq = null;

            List <string> tidTargets   = new List <string>(),
                          verTargets   = new List <string>(),
                          entryTargets = new List <string>();

            var numOfListings = 0;

            if (args.Length == 2)
            {
                if (args[1] == "-d")
                {
                    getDeltasOnly = true;
                }
                else if (args[0] == "-t")
                {
                    var rightsID = args[1];
                    using (var tikReq = (HttpWebResponse)GET(deviceID, CETKURL(rightsID), false))
                        using (var strm = tikReq.GetResponseStream())
                            using (var rd = new BinaryReader(strm))
                            {
                                File.WriteAllBytes($"{rightsID}.tik", rd.ReadBytes(0x2C0));
                                File.WriteAllBytes($"{rightsID}.cert", rd.ReadBytes(0x700));
                            }

                    return;
                }
            }

            GET(deviceID, Aqua(deviceID), false);

            if (args.Length == 3)
            {
                numOfListings = 2;
                if (args[0].Substring(13, 3) != "000" && args[0].Substring(13, 3) != "800")
                {
                    tidTargets.Add(null);
                    tidTargets.Add(args[0]);
                }
                else
                {
                    tidTargets.Add(null);
                    tidTargets.Add($"{args[0].Substring(0, 13)}800");
                }
                verTargets.Add(null);
                verTargets.Add(args[2]);
            }
            else
            {
                var Streq = (string)GET(deviceID, Superfly(GetBaseTID(args[0])), true);
                if (args[0].Substring(13, 3) == "000")
                {
                    foreach (JToken Listing in JArray.Parse(Streq))
                    {
                        if ((string)Listing["title_type"] != "AddOnContent")
                        {
                            numOfListings++;
                            tidTargets.Add(Listing["title_id"].ToString());
                            verTargets.Add(Listing["version"].ToString());
                        }
                    }
                }
                else
                {
                    foreach (JToken Listing in JArray.Parse(Streq))
                    {
                        if ((string)Listing["title_id"] == args[0])
                        {
                            numOfListings++;
                            tidTargets.Add(Listing["title_id"].ToString());
                            verTargets.Add(Listing["version"].ToString());
                        }
                    }
                }
            }

            if (args.Length == 1)
            {
                id = HEAD(deviceID, MetaURL('a', tidTargets[0], verTargets[0], deviceID));
            }

            if (args.Length == 1 && id != null)
            {
                GET(deviceID, ContentURL('a', id), true);
            }

            if (numOfListings >= 2)
            {
                idFirstReq = HEAD(deviceID, MetaURL('a', tidTargets[1], verTargets[1], deviceID));
            }

            if (args.Length == 1 && numOfListings >= 2)
            {
                GET(deviceID, ContentURL('a', idFirstReq), true);
            }

            if (numOfListings >= 2)
            {
                idSecondReq = HEAD(deviceID, MetaURL('a', tidTargets[1], verTargets[1], deviceID));
            }

            if (numOfListings >= 2)
            {
                GET(deviceID, ContentURL('a', idSecondReq), true);
            }

            if (args.Length == 1)
            {
                using (var meta = (HttpWebResponse)GET(deviceID, ContentURL('a', id), false))
                    using (var rd = new BinaryReader(meta.GetResponseStream()))
                        using (var strm = new MemoryStorage(rd.ReadBytes((int)meta.ContentLength)))
                        {
                            Directory.CreateDirectory(tidTargets[0]);
                            strm.WriteAllBytes($"{tidTargets[0]}/{id}.cnmt.nca");
                            using (var nca = new Nca(keys, strm, false).OpenSection(0, false, IntegrityCheckLevel.None, false))
                            {
                                var pfs  = new Pfs(nca);
                                var cnmt = new Cnmt(pfs.OpenFile(pfs.Files[0]).AsStream());
                                foreach (var entry in cnmt.ContentEntries)
                                {
                                    string NCAID = entry.NcaId.ToHexString().ToLower();
                                    using (var Req = (HttpWebResponse)GET(deviceID, ContentURL('c', NCAID), false))
                                        using (var Output = File.OpenWrite($"{tidTargets[0]}/{NCAID}.nca"))
                                            Req.GetResponseStream().CopyTo(Output);
                                }
                            }
                        }
            }

            if (numOfListings >= 2)
            {
                using (var meta = (HttpWebResponse)GET(deviceID, ContentURL('a', idSecondReq), false))
                    using (var read = new BinaryReader(meta.GetResponseStream()))
                        using (var metastrm = new MemoryStorage(read.ReadBytes((int)meta.ContentLength)))
                        {
                            Directory.CreateDirectory(tidTargets[1]);
                            metastrm.WriteAllBytes($"{tidTargets[1]}/{idSecondReq}.cnmt.nca");
                            using (var nca = new Nca(keys, metastrm, false).OpenSection(0, false, IntegrityCheckLevel.None, false))
                            {
                                var pfs  = new Pfs(nca);
                                var cnmt = new Cnmt(pfs.OpenFile(pfs.Files[0]).AsStream());
                                foreach (var entry in getDeltasOnly ?
                                         cnmt.ContentEntries.Where(e => e.Type == CnmtContentType.DeltaFragment) :
                                         cnmt.ContentEntries)
                                {
                                    var ncaID = entry.NcaId.ToHexString().ToLower();
                                    using (var request = (HttpWebResponse)GET(deviceID, ContentURL('c', ncaID), false))
                                        using (var output = File.OpenWrite($"{tidTargets[1]}/{ncaID}.nca"))
                                            request.GetResponseStream().CopyTo(output);

                                    if (entry.Type == CnmtContentType.Program)
                                    {
                                        var rightsID = new Nca(keys, new StreamStorage
                                                                   (File.OpenRead($"{tidTargets[1]}/{ncaID}.nca"), false), false)
                                                       .Header.RightsId.ToHexString().ToLower();

                                        using (var tikReq = (HttpWebResponse)GET(deviceID, CETKURL(rightsID), false))
                                            using (var strm = tikReq.GetResponseStream())
                                                using (var rd = new BinaryReader(strm))
                                                {
                                                    File.WriteAllBytes($"{tidTargets[1]}/{rightsID}.tik", rd.ReadBytes(0x2C0));
                                                    File.WriteAllBytes($"{tidTargets[1]}/{rightsID}.cert", rd.ReadBytes(0x700));
                                                }
                                    }
                                }
                            }
                        }
            }
        }
Esempio n. 2
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) &&
                        contentManager.TryGetFontFilename(name, out string fontFilename))
                    {
                        string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.NandSystem, NcaContentType.Data);
                        string fontPath    = _device.FileSystem.SwitchPathToSystemPath(contentPath);

                        if (!string.IsNullOrWhiteSpace(fontPath))
                        {
                            byte[] data;

                            using (IStorage ncaFileStream = new LocalStorage(fontPath, FileAccess.Read, FileMode.Open))
                            {
                                Nca         nca   = new Nca(_device.System.KeySet, ncaFileStream);
                                IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);

                                romfs.OpenFile(out IFile fontFile, ("/" + fontFilename).ToU8Span(), OpenMode.Read).ThrowIfFailure();

                                data = DecryptFont(fontFile.AsStream());
                            }

                            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).");
                }
            }
        }
Esempio n. 3
0
        public void LoadApplications(List <string> appDirs, Language desiredTitleLanguage)
        {
            int numApplicationsFound  = 0;
            int numApplicationsLoaded = 0;

            _desiredTitleLanguage = desiredTitleLanguage;

            // Builds the applications list with paths to found applications
            List <string> applications = new List <string>();

            foreach (string appDir in appDirs)
            {
                if (!Directory.Exists(appDir))
                {
                    Logger.Warning?.Print(LogClass.Application, $"The \"game_dirs\" section in \"Config.json\" contains an invalid directory: \"{appDir}\"");

                    continue;
                }

                foreach (string app in GetFilesInDirectory(appDir))
                {
                    if ((Path.GetExtension(app).ToLower() == ".nsp") ||
                        (Path.GetExtension(app).ToLower() == ".pfs0") ||
                        (Path.GetExtension(app).ToLower() == ".xci") ||
                        (Path.GetExtension(app).ToLower() == ".nca") ||
                        (Path.GetExtension(app).ToLower() == ".nro") ||
                        (Path.GetExtension(app).ToLower() == ".nso"))
                    {
                        applications.Add(app);
                        numApplicationsFound++;
                    }
                }
            }

            // Loops through applications list, creating a struct and then firing an event containing the struct for each application
            foreach (string applicationPath in applications)
            {
                double fileSize        = new FileInfo(applicationPath).Length * 0.000000000931;
                string titleName       = "Unknown";
                string titleId         = "0000000000000000";
                string developer       = "Unknown";
                string version         = "0";
                byte[] applicationIcon = null;

                BlitStruct <ApplicationControlProperty> controlHolder = new BlitStruct <ApplicationControlProperty>(1);

                try
                {
                    using (FileStream file = new FileStream(applicationPath, FileMode.Open, FileAccess.Read))
                    {
                        if ((Path.GetExtension(applicationPath).ToLower() == ".nsp") ||
                            (Path.GetExtension(applicationPath).ToLower() == ".pfs0") ||
                            (Path.GetExtension(applicationPath).ToLower() == ".xci"))
                        {
                            try
                            {
                                PartitionFileSystem pfs;

                                bool isExeFs = false;

                                if (Path.GetExtension(applicationPath).ToLower() == ".xci")
                                {
                                    Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage());

                                    pfs = xci.OpenPartition(XciPartitionType.Secure);
                                }
                                else
                                {
                                    pfs = new PartitionFileSystem(file.AsStorage());

                                    // If the NSP doesn't have a main NCA, decrement the number of applications found and then continue to the next application.
                                    bool hasMainNca = false;

                                    foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*"))
                                    {
                                        if (Path.GetExtension(fileEntry.FullPath).ToLower() == ".nca")
                                        {
                                            pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();

                                            Nca nca       = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
                                            int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);

                                            if (nca.Header.ContentType == NcaContentType.Program && !nca.Header.GetFsHeader(dataIndex).IsPatchSection())
                                            {
                                                hasMainNca = true;

                                                break;
                                            }
                                        }
                                        else if (Path.GetFileNameWithoutExtension(fileEntry.FullPath) == "main")
                                        {
                                            isExeFs = true;
                                        }
                                    }

                                    if (!hasMainNca && !isExeFs)
                                    {
                                        numApplicationsFound--;

                                        continue;
                                    }
                                }

                                if (isExeFs)
                                {
                                    applicationIcon = _nspIcon;

                                    Result result = pfs.OpenFile(out IFile npdmFile, "/main.npdm".ToU8Span(), OpenMode.Read);

                                    if (ResultFs.PathNotFound.Includes(result))
                                    {
                                        Npdm npdm = new Npdm(npdmFile.AsStream());

                                        titleName = npdm.TitleName;
                                        titleId   = npdm.Aci0.TitleId.ToString("x16");
                                    }
                                }
                                else
                                {
                                    // Store the ControlFS in variable called controlFs
                                    GetControlFsAndTitleId(pfs, out IFileSystem controlFs, out titleId);

                                    ReadControlData(controlFs, controlHolder.ByteSpan);

                                    // Get the title name, title ID, developer name and version number from the NACP
                                    version = IsUpdateApplied(titleId, out string updateVersion) ? updateVersion : controlHolder.Value.DisplayVersion.ToString();

                                    GetNameIdDeveloper(ref controlHolder.Value, out titleName, out _, out developer);

                                    // Read the icon from the ControlFS and store it as a byte array
                                    try
                                    {
                                        controlFs.OpenFile(out IFile icon, $"/icon_{_desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure();

                                        using (MemoryStream stream = new MemoryStream())
                                        {
                                            icon.AsStream().CopyTo(stream);
                                            applicationIcon = stream.ToArray();
                                        }
                                    }
                                    catch (HorizonResultException)
                                    {
                                        foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*"))
                                        {
                                            if (entry.Name == "control.nacp")
                                            {
                                                continue;
                                            }

                                            controlFs.OpenFile(out IFile icon, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();

                                            using (MemoryStream stream = new MemoryStream())
                                            {
                                                icon.AsStream().CopyTo(stream);
                                                applicationIcon = stream.ToArray();
                                            }

                                            if (applicationIcon != null)
                                            {
                                                break;
                                            }
                                        }

                                        if (applicationIcon == null)
                                        {
                                            applicationIcon = Path.GetExtension(applicationPath).ToLower() == ".xci" ? _xciIcon : _nspIcon;
                                        }
                                    }
                                }
                            }
                            catch (MissingKeyException exception)
                            {
                                applicationIcon = Path.GetExtension(applicationPath).ToLower() == ".xci" ? _xciIcon : _nspIcon;

                                Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}");
                            }
                            catch (InvalidDataException)
                            {
                                applicationIcon = Path.GetExtension(applicationPath).ToLower() == ".xci" ? _xciIcon : _nspIcon;

                                Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}");
                            }
                            catch (Exception exception)
                            {
                                Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. File: '{applicationPath}' Error: {exception}");

                                numApplicationsFound--;

                                continue;
                            }
                        }
                        else if (Path.GetExtension(applicationPath).ToLower() == ".nro")
                        {
                            BinaryReader reader = new BinaryReader(file);

                            byte[] Read(long position, int size)
                            {
                                file.Seek(position, SeekOrigin.Begin);

                                return(reader.ReadBytes(size));
                            }

                            try
                            {
                                file.Seek(24, SeekOrigin.Begin);

                                int assetOffset = reader.ReadInt32();

                                if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET")
                                {
                                    byte[] iconSectionInfo = Read(assetOffset + 8, 0x10);

                                    long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0);
                                    long iconSize   = BitConverter.ToInt64(iconSectionInfo, 8);

                                    ulong nacpOffset = reader.ReadUInt64();
                                    ulong nacpSize   = reader.ReadUInt64();

                                    // Reads and stores game icon as byte array
                                    applicationIcon = Read(assetOffset + iconOffset, (int)iconSize);

                                    // Read the NACP data
                                    Read(assetOffset + (int)nacpOffset, (int)nacpSize).AsSpan().CopyTo(controlHolder.ByteSpan);

                                    // Get the title name, title ID, developer name and version number from the NACP
                                    version = controlHolder.Value.DisplayVersion.ToString();

                                    GetNameIdDeveloper(ref controlHolder.Value, out titleName, out titleId, out developer);
                                }
                                else
                                {
                                    applicationIcon = _nroIcon;
                                    titleName       = Path.GetFileNameWithoutExtension(applicationPath);
                                }
                            }
                            catch
                            {
                                Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}");

                                numApplicationsFound--;

                                continue;
                            }
                        }
                        else if (Path.GetExtension(applicationPath).ToLower() == ".nca")
                        {
                            try
                            {
                                Nca nca       = new Nca(_virtualFileSystem.KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage());
                                int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);

                                if (nca.Header.ContentType != NcaContentType.Program || nca.Header.GetFsHeader(dataIndex).IsPatchSection())
                                {
                                    numApplicationsFound--;

                                    continue;
                                }
                            }
                            catch (InvalidDataException)
                            {
                                Logger.Warning?.Print(LogClass.Application, $"The NCA header content type check has failed. This is usually because the header key is incorrect or missing. Errored File: {applicationPath}");
                            }
                            catch
                            {
                                Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}");

                                numApplicationsFound--;

                                continue;
                            }

                            applicationIcon = _ncaIcon;
                            titleName       = Path.GetFileNameWithoutExtension(applicationPath);
                        }
                        // If its an NSO we just set defaults
                        else if (Path.GetExtension(applicationPath).ToLower() == ".nso")
                        {
                            applicationIcon = _nsoIcon;
                            titleName       = Path.GetFileNameWithoutExtension(applicationPath);
                        }
                    }
                }
                catch (IOException exception)
                {
                    Logger.Warning?.Print(LogClass.Application, exception.Message);

                    numApplicationsFound--;

                    continue;
                }

                ApplicationMetadata appMetadata = LoadAndSaveMetaData(titleId);

                if (appMetadata.LastPlayed != "Never" && !DateTime.TryParse(appMetadata.LastPlayed, out _))
                {
                    Logger.Warning?.Print(LogClass.Application, $"Last played datetime \"{appMetadata.LastPlayed}\" is invalid for current system culture, skipping (did current culture change?)");

                    appMetadata.LastPlayed = "Never";
                }

                ApplicationData data = new ApplicationData
                {
                    Favorite      = appMetadata.Favorite,
                    Icon          = applicationIcon,
                    TitleName     = titleName,
                    TitleId       = titleId,
                    Developer     = developer,
                    Version       = version,
                    TimePlayed    = ConvertSecondsToReadableString(appMetadata.TimePlayed),
                    LastPlayed    = appMetadata.LastPlayed,
                    FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0, 1),
                    FileSize      = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB",
                    Path          = applicationPath,
                    ControlHolder = controlHolder
                };

                numApplicationsLoaded++;

                OnApplicationAdded(new ApplicationAddedEventArgs()
                {
                    AppData = data
                });

                OnApplicationCountUpdated(new ApplicationCountUpdatedEventArgs()
                {
                    NumAppsFound  = numApplicationsFound,
                    NumAppsLoaded = numApplicationsLoaded
                });
            }

            OnApplicationCountUpdated(new ApplicationCountUpdatedEventArgs()
            {
                NumAppsFound  = numApplicationsFound,
                NumAppsLoaded = numApplicationsLoaded
            });
        }
Esempio n. 4
0
        private static void processControlNca(IStorage controlNca, ref Title title)
        {
            Nca nca = new Nca(keyset, controlNca, false);

            processControlNca(nca, ref title);
        }
Esempio n. 5
0
        private static (string, string) processCnmtNca(IStorage cnmtNca, ref Title title)
        {
            Nca nca = new Nca(keyset, cnmtNca, false);

            return(processCnmtNca(nca, ref title));
        }
Esempio n. 6
0
        public void LoadEntries(Switch device = null)
        {
            lock (_lock)
            {
                _contentDictionary = new SortedDictionary <(ulong, NcaContentType), string>();
                _locationEntries   = new Dictionary <StorageId, LinkedList <LocationEntry> >();

                foreach (StorageId storageId in Enum.GetValues(typeof(StorageId)))
                {
                    string contentDirectory    = null;
                    string contentPathString   = null;
                    string registeredDirectory = null;

                    try
                    {
                        contentPathString   = LocationHelper.GetContentRoot(storageId);
                        contentDirectory    = LocationHelper.GetRealPath(_virtualFileSystem, contentPathString);
                        registeredDirectory = Path.Combine(contentDirectory, "registered");
                    }
                    catch (NotSupportedException)
                    {
                        continue;
                    }

                    Directory.CreateDirectory(registeredDirectory);

                    LinkedList <LocationEntry> locationList = new LinkedList <LocationEntry>();

                    void AddEntry(LocationEntry entry)
                    {
                        locationList.AddLast(entry);
                    }

                    foreach (string directoryPath in Directory.EnumerateDirectories(registeredDirectory))
                    {
                        if (Directory.GetFiles(directoryPath).Length > 0)
                        {
                            string ncaName = new DirectoryInfo(directoryPath).Name.Replace(".nca", string.Empty);

                            using (FileStream ncaFile = File.OpenRead(Directory.GetFiles(directoryPath)[0]))
                            {
                                Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());

                                string switchPath = contentPathString + ":/" + ncaFile.Name.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);

                                // Change path format to switch's
                                switchPath = switchPath.Replace('\\', '/');

                                LocationEntry entry = new LocationEntry(switchPath,
                                                                        0,
                                                                        (long)nca.Header.TitleId,
                                                                        nca.Header.ContentType);

                                AddEntry(entry);

                                _contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
                            }
                        }
                    }

                    foreach (string filePath in Directory.EnumerateFiles(contentDirectory))
                    {
                        if (Path.GetExtension(filePath) == ".nca")
                        {
                            string ncaName = Path.GetFileNameWithoutExtension(filePath);

                            using (FileStream ncaFile = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                            {
                                Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());

                                string switchPath = contentPathString + ":/" + filePath.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);

                                // Change path format to switch's
                                switchPath = switchPath.Replace('\\', '/');

                                LocationEntry entry = new LocationEntry(switchPath,
                                                                        0,
                                                                        (long)nca.Header.TitleId,
                                                                        nca.Header.ContentType);

                                AddEntry(entry);

                                _contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
                            }
                        }
                    }

                    if (_locationEntries.ContainsKey(storageId) && _locationEntries[storageId]?.Count == 0)
                    {
                        _locationEntries.Remove(storageId);
                    }

                    if (!_locationEntries.ContainsKey(storageId))
                    {
                        _locationEntries.Add(storageId, locationList);
                    }
                }

                if (device != null)
                {
                    TimeManager.Instance.InitializeTimeZone(device);
                    device.System.Font.Initialize(this);
                }
            }
        }
Esempio n. 7
0
        public static void LoadApplications(List <string> appDirs, Keyset keySet, TitleLanguage desiredTitleLanguage)
        {
            int numApplicationsFound  = 0;
            int numApplicationsLoaded = 0;

            _keySet = keySet;
            _desiredTitleLanguage = desiredTitleLanguage;

            // Builds the applications list with paths to found applications
            List <string> applications = new List <string>();

            foreach (string appDir in appDirs)
            {
                if (Directory.Exists(appDir) == false)
                {
                    Logger.PrintWarning(LogClass.Application, $"The \"game_dirs\" section in \"Config.json\" contains an invalid directory: \"{appDir}\"");

                    continue;
                }

                foreach (string app in Directory.GetFiles(appDir, "*.*", SearchOption.AllDirectories))
                {
                    if ((Path.GetExtension(app) == ".xci") ||
                        (Path.GetExtension(app) == ".nro") ||
                        (Path.GetExtension(app) == ".nso") ||
                        (Path.GetFileName(app) == "hbl.nsp"))
                    {
                        applications.Add(app);
                        numApplicationsFound++;
                    }
                    else if ((Path.GetExtension(app) == ".nsp") || (Path.GetExtension(app) == ".pfs0"))
                    {
                        try
                        {
                            bool hasMainNca = false;

                            PartitionFileSystem nsp = new PartitionFileSystem(new FileStream(app, FileMode.Open, FileAccess.Read).AsStorage());
                            foreach (DirectoryEntryEx fileEntry in nsp.EnumerateEntries("/", "*.nca"))
                            {
                                nsp.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure();

                                Nca nca       = new Nca(_keySet, ncaFile.AsStorage());
                                int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);

                                if (nca.Header.ContentType == NcaContentType.Program && !nca.Header.GetFsHeader(dataIndex).IsPatchSection())
                                {
                                    hasMainNca = true;
                                }
                            }

                            if (!hasMainNca)
                            {
                                continue;
                            }
                        }
                        catch (InvalidDataException)
                        {
                            Logger.PrintWarning(LogClass.Application, $"{app}: The header key is incorrect or missing and therefore the NCA header content type check has failed.");
                        }

                        applications.Add(app);
                        numApplicationsFound++;
                    }
                    else if (Path.GetExtension(app) == ".nca")
                    {
                        try
                        {
                            Nca nca       = new Nca(_keySet, new FileStream(app, FileMode.Open, FileAccess.Read).AsStorage());
                            int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);

                            if (nca.Header.ContentType != NcaContentType.Program || nca.Header.GetFsHeader(dataIndex).IsPatchSection())
                            {
                                continue;
                            }
                        }
                        catch (InvalidDataException)
                        {
                            Logger.PrintWarning(LogClass.Application, $"{app}: The header key is incorrect or missing and therefore the NCA header content type check has failed.");
                        }

                        applications.Add(app);
                        numApplicationsFound++;
                    }
                }
            }

            // Loops through applications list, creating a struct and then firing an event containing the struct for each application
            foreach (string applicationPath in applications)
            {
                double fileSize        = new FileInfo(applicationPath).Length * 0.000000000931;
                string titleName       = "Unknown";
                string titleId         = "0000000000000000";
                string developer       = "Unknown";
                string version         = "0";
                byte[] applicationIcon = null;

                using (FileStream file = new FileStream(applicationPath, FileMode.Open, FileAccess.Read))
                {
                    if ((Path.GetExtension(applicationPath) == ".nsp") ||
                        (Path.GetExtension(applicationPath) == ".pfs0") ||
                        (Path.GetExtension(applicationPath) == ".xci"))
                    {
                        try
                        {
                            PartitionFileSystem pfs;

                            if (Path.GetExtension(applicationPath) == ".xci")
                            {
                                Xci xci = new Xci(_keySet, file.AsStorage());

                                pfs = xci.OpenPartition(XciPartitionType.Secure);
                            }
                            else
                            {
                                pfs = new PartitionFileSystem(file.AsStorage());
                            }

                            // Store the ControlFS in variable called controlFs
                            IFileSystem controlFs = GetControlFs(pfs);

                            // If this is null then this is probably not a normal NSP, it's probably an ExeFS as an NSP
                            if (controlFs == null)
                            {
                                applicationIcon = _nspIcon;

                                Result result = pfs.OpenFile(out IFile npdmFile, "/main.npdm", OpenMode.Read);

                                if (result != ResultFs.PathNotFound)
                                {
                                    Npdm npdm = new Npdm(npdmFile.AsStream());

                                    titleName = npdm.TitleName;
                                    titleId   = npdm.Aci0.TitleId.ToString("x16");
                                }
                            }
                            else
                            {
                                // Creates NACP class from the NACP file
                                controlFs.OpenFile(out IFile controlNacpFile, "/control.nacp", OpenMode.Read).ThrowIfFailure();

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

                                // Get the title name, title ID, developer name and version number from the NACP
                                version = controlData.DisplayVersion;

                                titleName = controlData.Descriptions[(int)_desiredTitleLanguage].Title;

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

                                titleId = controlData.PresenceGroupId.ToString("x16");

                                if (string.IsNullOrWhiteSpace(titleId))
                                {
                                    titleId = controlData.SaveDataOwnerId.ToString("x16");
                                }

                                if (string.IsNullOrWhiteSpace(titleId))
                                {
                                    titleId = (controlData.AddOnContentBaseId - 0x1000).ToString("x16");
                                }

                                developer = controlData.Descriptions[(int)_desiredTitleLanguage].Developer;

                                if (string.IsNullOrWhiteSpace(developer))
                                {
                                    developer = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Developer)).Developer;
                                }

                                // Read the icon from the ControlFS and store it as a byte array
                                try
                                {
                                    controlFs.OpenFile(out IFile icon, $"/icon_{_desiredTitleLanguage}.dat", OpenMode.Read).ThrowIfFailure();

                                    using (MemoryStream stream = new MemoryStream())
                                    {
                                        icon.AsStream().CopyTo(stream);
                                        applicationIcon = stream.ToArray();
                                    }
                                }
                                catch (HorizonResultException)
                                {
                                    foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*"))
                                    {
                                        if (entry.Name == "control.nacp")
                                        {
                                            continue;
                                        }

                                        controlFs.OpenFile(out IFile icon, entry.FullPath, OpenMode.Read).ThrowIfFailure();

                                        using (MemoryStream stream = new MemoryStream())
                                        {
                                            icon.AsStream().CopyTo(stream);
                                            applicationIcon = stream.ToArray();
                                        }

                                        if (applicationIcon != null)
                                        {
                                            break;
                                        }
                                    }

                                    if (applicationIcon == null)
                                    {
                                        applicationIcon = Path.GetExtension(applicationPath) == ".xci" ? _xciIcon : _nspIcon;
                                    }
                                }
                            }
                        }
                        catch (MissingKeyException exception)
                        {
                            applicationIcon = Path.GetExtension(applicationPath) == ".xci" ? _xciIcon : _nspIcon;

                            Logger.PrintWarning(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}");
                        }
                        catch (InvalidDataException)
                        {
                            applicationIcon = Path.GetExtension(applicationPath) == ".xci" ? _xciIcon : _nspIcon;

                            Logger.PrintWarning(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}");
                        }
                    }
                    else if (Path.GetExtension(applicationPath) == ".nro")
                    {
                        BinaryReader reader = new BinaryReader(file);

                        byte[] Read(long position, int size)
                        {
                            file.Seek(position, SeekOrigin.Begin);

                            return(reader.ReadBytes(size));
                        }

                        file.Seek(24, SeekOrigin.Begin);
                        int assetOffset = reader.ReadInt32();

                        if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET")
                        {
                            byte[] iconSectionInfo = Read(assetOffset + 8, 0x10);

                            long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0);
                            long iconSize   = BitConverter.ToInt64(iconSectionInfo, 8);

                            ulong nacpOffset = reader.ReadUInt64();
                            ulong nacpSize   = reader.ReadUInt64();

                            // Reads and stores game icon as byte array
                            applicationIcon = Read(assetOffset + iconOffset, (int)iconSize);

                            // Creates memory stream out of byte array which is the NACP
                            using (MemoryStream stream = new MemoryStream(Read(assetOffset + (int)nacpOffset, (int)nacpSize)))
                            {
                                // Creates NACP class from the memory stream
                                Nacp controlData = new Nacp(stream);

                                // Get the title name, title ID, developer name and version number from the NACP
                                version = controlData.DisplayVersion;

                                titleName = controlData.Descriptions[(int)_desiredTitleLanguage].Title;

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

                                titleId = controlData.PresenceGroupId.ToString("x16");

                                if (string.IsNullOrWhiteSpace(titleId))
                                {
                                    titleId = controlData.SaveDataOwnerId.ToString("x16");
                                }

                                if (string.IsNullOrWhiteSpace(titleId))
                                {
                                    titleId = (controlData.AddOnContentBaseId - 0x1000).ToString("x16");
                                }

                                developer = controlData.Descriptions[(int)_desiredTitleLanguage].Developer;

                                if (string.IsNullOrWhiteSpace(developer))
                                {
                                    developer = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Developer)).Developer;
                                }
                            }
                        }
                        else
                        {
                            applicationIcon = _nroIcon;
                        }
                    }
                    // If its an NCA or NSO we just set defaults
                    else if ((Path.GetExtension(applicationPath) == ".nca") || (Path.GetExtension(applicationPath) == ".nso"))
                    {
                        applicationIcon = Path.GetExtension(applicationPath) == ".nca" ? _ncaIcon : _nsoIcon;
                        titleName       = Path.GetFileNameWithoutExtension(applicationPath);
                    }
                }

                (bool favorite, string timePlayed, string lastPlayed) = GetMetadata(titleId);

                ApplicationData data = new ApplicationData()
                {
                    Favorite      = favorite,
                    Icon          = applicationIcon,
                    TitleName     = titleName,
                    TitleId       = titleId,
                    Developer     = developer,
                    Version       = version,
                    TimePlayed    = timePlayed,
                    LastPlayed    = lastPlayed,
                    FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0, 1),
                    FileSize      = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB",
                    Path          = applicationPath,
                };

                numApplicationsLoaded++;

                OnApplicationAdded(new ApplicationAddedEventArgs()
                {
                    AppData       = data,
                    NumAppsFound  = numApplicationsFound,
                    NumAppsLoaded = numApplicationsLoaded
                });
            }
        }
        public static void LoadApplications(List <string> appDirs, VirtualFileSystem virtualFileSystem, Language desiredTitleLanguage)
        {
            int numApplicationsFound  = 0;
            int numApplicationsLoaded = 0;

            _loadingError         = false;
            _virtualFileSystem    = virtualFileSystem;
            _desiredTitleLanguage = desiredTitleLanguage;

            // Builds the applications list with paths to found applications
            List <string> applications = new List <string>();

            foreach (string appDir in appDirs)
            {
                if (!Directory.Exists(appDir))
                {
                    Logger.PrintWarning(LogClass.Application, $"The \"game_dirs\" section in \"Config.json\" contains an invalid directory: \"{appDir}\"");

                    continue;
                }

                foreach (string app in Directory.GetFiles(appDir, "*.*", SearchOption.AllDirectories))
                {
                    if ((Path.GetExtension(app).ToLower() == ".nsp") ||
                        (Path.GetExtension(app).ToLower() == ".pfs0") ||
                        (Path.GetExtension(app).ToLower() == ".xci") ||
                        (Path.GetExtension(app).ToLower() == ".nca") ||
                        (Path.GetExtension(app).ToLower() == ".nro") ||
                        (Path.GetExtension(app).ToLower() == ".nso"))
                    {
                        applications.Add(app);
                        numApplicationsFound++;
                    }
                }
            }

            // Loops through applications list, creating a struct and then firing an event containing the struct for each application
            foreach (string applicationPath in applications)
            {
                double fileSize        = new FileInfo(applicationPath).Length * 0.000000000931;
                string titleName       = "Unknown";
                string titleId         = "0000000000000000";
                string developer       = "Unknown";
                string version         = "0";
                string saveDataPath    = null;
                byte[] applicationIcon = null;

                try
                {
                    using (FileStream file = new FileStream(applicationPath, FileMode.Open, FileAccess.Read))
                    {
                        if ((Path.GetExtension(applicationPath).ToLower() == ".nsp") ||
                            (Path.GetExtension(applicationPath).ToLower() == ".pfs0") ||
                            (Path.GetExtension(applicationPath).ToLower() == ".xci"))
                        {
                            try
                            {
                                PartitionFileSystem pfs;

                                bool isExeFs = false;

                                if (Path.GetExtension(applicationPath).ToLower() == ".xci")
                                {
                                    Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage());

                                    pfs = xci.OpenPartition(XciPartitionType.Secure);
                                }
                                else
                                {
                                    pfs = new PartitionFileSystem(file.AsStorage());

                                    // If the NSP doesn't have a main NCA, decrement the number of applications found and then continue to the next application.
                                    bool hasMainNca = false;

                                    foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*"))
                                    {
                                        if (Path.GetExtension(fileEntry.FullPath).ToLower() == ".nca")
                                        {
                                            pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure();

                                            Nca nca       = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
                                            int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);

                                            if (nca.Header.ContentType == NcaContentType.Program && !nca.Header.GetFsHeader(dataIndex).IsPatchSection())
                                            {
                                                hasMainNca = true;

                                                break;
                                            }
                                        }
                                        else if (Path.GetFileNameWithoutExtension(fileEntry.FullPath) == "main")
                                        {
                                            isExeFs = true;
                                        }
                                    }

                                    if (!hasMainNca && !isExeFs)
                                    {
                                        numApplicationsFound--;

                                        continue;
                                    }
                                }

                                if (isExeFs)
                                {
                                    applicationIcon = _nspIcon;

                                    Result result = pfs.OpenFile(out IFile npdmFile, "/main.npdm", OpenMode.Read);

                                    if (result != ResultFs.PathNotFound)
                                    {
                                        Npdm npdm = new Npdm(npdmFile.AsStream());

                                        titleName = npdm.TitleName;
                                        titleId   = npdm.Aci0.TitleId.ToString("x16");
                                    }
                                }
                                else
                                {
                                    // Store the ControlFS in variable called controlFs
                                    GetControlFsAndTitleId(pfs, out IFileSystem controlFs, out titleId);

                                    // Creates NACP class from the NACP file
                                    controlFs.OpenFile(out IFile controlNacpFile, "/control.nacp", OpenMode.Read).ThrowIfFailure();

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

                                    // Get the title name, title ID, developer name and version number from the NACP
                                    version = controlData.DisplayVersion;

                                    GetNameIdDeveloper(controlData, out titleName, out _, out developer);

                                    // Read the icon from the ControlFS and store it as a byte array
                                    try
                                    {
                                        controlFs.OpenFile(out IFile icon, $"/icon_{_desiredTitleLanguage}.dat", OpenMode.Read).ThrowIfFailure();

                                        using (MemoryStream stream = new MemoryStream())
                                        {
                                            icon.AsStream().CopyTo(stream);
                                            applicationIcon = stream.ToArray();
                                        }
                                    }
                                    catch (HorizonResultException)
                                    {
                                        foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*"))
                                        {
                                            if (entry.Name == "control.nacp")
                                            {
                                                continue;
                                            }

                                            controlFs.OpenFile(out IFile icon, entry.FullPath, OpenMode.Read).ThrowIfFailure();

                                            using (MemoryStream stream = new MemoryStream())
                                            {
                                                icon.AsStream().CopyTo(stream);
                                                applicationIcon = stream.ToArray();
                                            }

                                            if (applicationIcon != null)
                                            {
                                                break;
                                            }
                                        }

                                        if (applicationIcon == null)
                                        {
                                            applicationIcon = Path.GetExtension(applicationPath).ToLower() == ".xci" ? _xciIcon : _nspIcon;
                                        }
                                    }
                                }
                            }
                            catch (MissingKeyException exception)
                            {
                                applicationIcon = Path.GetExtension(applicationPath).ToLower() == ".xci" ? _xciIcon : _nspIcon;

                                Logger.PrintWarning(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}");
                            }
                            catch (InvalidDataException)
                            {
                                applicationIcon = Path.GetExtension(applicationPath).ToLower() == ".xci" ? _xciIcon : _nspIcon;

                                Logger.PrintWarning(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}");
                            }
                            catch (Exception exception)
                            {
                                Logger.PrintWarning(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}");
                                Logger.PrintDebug(LogClass.Application, exception.ToString());

                                numApplicationsFound--;
                                _loadingError = true;

                                continue;
                            }
                        }
                        else if (Path.GetExtension(applicationPath).ToLower() == ".nro")
                        {
                            BinaryReader reader = new BinaryReader(file);

                            byte[] Read(long position, int size)
                            {
                                file.Seek(position, SeekOrigin.Begin);

                                return(reader.ReadBytes(size));
                            }

                            try
                            {
                                file.Seek(24, SeekOrigin.Begin);

                                int assetOffset = reader.ReadInt32();

                                if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET")
                                {
                                    byte[] iconSectionInfo = Read(assetOffset + 8, 0x10);

                                    long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0);
                                    long iconSize   = BitConverter.ToInt64(iconSectionInfo, 8);

                                    ulong nacpOffset = reader.ReadUInt64();
                                    ulong nacpSize   = reader.ReadUInt64();

                                    // Reads and stores game icon as byte array
                                    applicationIcon = Read(assetOffset + iconOffset, (int)iconSize);

                                    // Creates memory stream out of byte array which is the NACP
                                    using (MemoryStream stream = new MemoryStream(Read(assetOffset + (int)nacpOffset, (int)nacpSize)))
                                    {
                                        // Creates NACP class from the memory stream
                                        Nacp controlData = new Nacp(stream);

                                        // Get the title name, title ID, developer name and version number from the NACP
                                        version = controlData.DisplayVersion;

                                        GetNameIdDeveloper(controlData, out titleName, out titleId, out developer);
                                    }
                                }
                                else
                                {
                                    applicationIcon = _nroIcon;
                                    titleName       = Path.GetFileNameWithoutExtension(applicationPath);
                                }
                            }
                            catch
                            {
                                Logger.PrintWarning(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}");

                                numApplicationsFound--;

                                continue;
                            }
                        }
                        else if (Path.GetExtension(applicationPath).ToLower() == ".nca")
                        {
                            try
                            {
                                Nca nca       = new Nca(_virtualFileSystem.KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage());
                                int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);

                                if (nca.Header.ContentType != NcaContentType.Program || nca.Header.GetFsHeader(dataIndex).IsPatchSection())
                                {
                                    numApplicationsFound--;

                                    continue;
                                }
                            }
                            catch (InvalidDataException)
                            {
                                Logger.PrintWarning(LogClass.Application, $"The NCA header content type check has failed. This is usually because the header key is incorrect or missing. Errored File: {applicationPath}");
                            }
                            catch
                            {
                                Logger.PrintWarning(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}");

                                numApplicationsFound--;
                                _loadingError = true;

                                continue;
                            }

                            applicationIcon = _ncaIcon;
                            titleName       = Path.GetFileNameWithoutExtension(applicationPath);
                        }
                        // If its an NSO we just set defaults
                        else if (Path.GetExtension(applicationPath).ToLower() == ".nso")
                        {
                            applicationIcon = _nsoIcon;
                            titleName       = Path.GetFileNameWithoutExtension(applicationPath);
                        }
                    }
                }
                catch (IOException exception)
                {
                    Logger.PrintWarning(LogClass.Application, exception.Message);

                    numApplicationsFound--;
                    _loadingError = true;

                    continue;
                }

                ApplicationMetadata appMetadata = LoadAndSaveMetaData(titleId);

                if (ulong.TryParse(titleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNum))
                {
                    SaveDataFilter filter = new SaveDataFilter();
                    filter.SetUserId(new UserId(1, 0));
                    filter.SetTitleId(new TitleId(titleIdNum));

                    Result result = virtualFileSystem.FsClient.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, ref filter);

                    if (result.IsSuccess())
                    {
                        saveDataPath = Path.Combine(virtualFileSystem.GetNandPath(), $"user/save/{saveDataInfo.SaveDataId:x16}");
                    }
                }

                ApplicationData data = new ApplicationData()
                {
                    Favorite      = appMetadata.Favorite,
                    Icon          = applicationIcon,
                    TitleName     = titleName,
                    TitleId       = titleId,
                    Developer     = developer,
                    Version       = version,
                    TimePlayed    = ConvertSecondsToReadableString(appMetadata.TimePlayed),
                    LastPlayed    = appMetadata.LastPlayed,
                    FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0, 1),
                    FileSize      = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB",
                    Path          = applicationPath,
                    SaveDataPath  = saveDataPath
                };

                numApplicationsLoaded++;

                OnApplicationAdded(new ApplicationAddedEventArgs()
                {
                    AppData = data
                });

                OnApplicationCountUpdated(new ApplicationCountUpdatedEventArgs()
                {
                    NumAppsFound  = numApplicationsFound,
                    NumAppsLoaded = numApplicationsLoaded
                });
            }

            OnApplicationCountUpdated(new ApplicationCountUpdatedEventArgs()
            {
                NumAppsFound  = numApplicationsFound,
                NumAppsLoaded = numApplicationsLoaded
            });

            if (_loadingError)
            {
                Gtk.Application.Invoke(delegate
                {
                    GtkDialog.CreateErrorDialog("One or more files encountered could not be loaded, check logs for more info.");
                });
            }
        }
Esempio n. 9
0
        private void Open()
        {
            treeView1.Nodes.Clear();

            string FileToOpen = null;

            if (Program.FileArg != null)
            {
                FileToOpen = Program.FileArg;
            }
            else
            {
                FileToOpen = openFileDialog1.FileName;
            }

            Program.FileArg = null;
            Stream Input = null;

            try
            {
                string ExpEnv(string In) => Environment.ExpandEnvironmentVariables(In);

                var ProdKeys  = ExpEnv(@"%USERPROFILE%\.switch\prod.keys");
                var TitleKeys = ExpEnv(@"%USERPROFILE%\.switch\title.keys");

                var Keys = ExternalKeys.ReadKeyFile(ProdKeys, TitleKeys);

                var Ext = (new FileInfo(FileToOpen).Extension);

                if (Ext == ".nsp")
                {
                    var InputPFS  = File.OpenRead(FileToOpen);
                    var Pfs       = new Pfs(InputPFS.AsStorage());
                    var CnmtNca   = new Nca(Keys, Pfs.OpenFile(Pfs.Files.FirstOrDefault(s => s.Name.Contains(".cnmt.nca"))), false);
                    var CnmtPfs   = new Pfs(CnmtNca.OpenSection(0, false, IntegrityCheckLevel.None, true));
                    var Cnmt      = new Cnmt(CnmtPfs.OpenFile(CnmtPfs.Files[0]).AsStream());
                    var Program   = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Program);
                    var CtrlEntry = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Control);
                    if (CtrlEntry != null)
                    {
                        Control = new Nca(Keys, Pfs.OpenFile($"{CtrlEntry.NcaId.ToHexString().ToLower()}.nca"), false);
                    }
                    Input = Pfs.OpenFile($"{Program.NcaId.ToHexString().ToLower()}.nca").AsStream();
                }
                else if (Ext == ".xci")
                {
                    var InputPFS  = File.OpenRead(FileToOpen);
                    var Xci       = new Xci(Keys, InputPFS.AsStorage());
                    var CnmtNca   = new Nca(Keys, Xci.SecurePartition.OpenFile(Xci.SecurePartition.Files.FirstOrDefault(s => s.Name.Contains(".cnmt.nca"))), false);
                    var CnmtPfs   = new Pfs(CnmtNca.OpenSection(0, false, IntegrityCheckLevel.None, true));
                    var Cnmt      = new Cnmt(CnmtPfs.OpenFile(CnmtPfs.Files[0]).AsStream());
                    var Program   = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Program);
                    var CtrlEntry = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Control);
                    if (CtrlEntry != null)
                    {
                        Control = new Nca(Keys, Xci.SecurePartition.OpenFile($"{CtrlEntry.NcaId.ToHexString().ToLower()}.nca"), false);
                    }
                    Input = Xci.SecurePartition.OpenFile($"{Program.NcaId.ToHexString().ToLower()}.nca").AsStream();
                }
                else if (FileToOpen.Split('.')[1] == "cnmt" && Ext == ".nca")
                {
                    var TargetFile = File.OpenRead(FileToOpen);
                    var CnmtNca    = new Nca(Keys, TargetFile.AsStorage(), false);
                    var CnmtPfs    = new Pfs(CnmtNca.OpenSection(0, false, IntegrityCheckLevel.None, true));
                    var Cnmt       = new Cnmt(CnmtPfs.OpenFile(CnmtPfs.Files[0]).AsStream());
                    var Program    = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Program);
                    var CtrlEntry  = Cnmt.ContentEntries.FirstOrDefault(c => c.Type == CnmtContentType.Control);
                    if (CtrlEntry != null)
                    {
                        Control = new Nca(Keys, File.OpenRead($"{CtrlEntry.NcaId.ToHexString().ToLower()}.nca").AsStorage(), false);
                    }
                    Input = File.OpenRead($"{Program.NcaId.ToHexString().ToLower()}.nca");
                }
                else
                {
                    Input = File.OpenRead(FileToOpen);
                }

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

                    if (Nca.HasRightsId && !Keys.TitleKeys.Keys.Any(k => k.SequenceEqual(Nca.Header.RightsId)))
                    {
                        MessageBox.Show($"Error: the titlekey for {Nca.Header.RightsId.ToHexString().ToLower()} is not present in your key file.");
                    }
                    else
                    {
                        var isUpdateNca = false;

                        if (Nca.Sections.Any(s => s?.Type == SectionType.Bktr))
                        {
                            isUpdateNca = true;
                        }

                        if (isUpdateNca)
                        {
                            openFileDialog1.Title = "Select base Nca";
                            openFileDialog1.ShowDialog();
                            var Input2 = File.OpenRead(openFileDialog1.FileName);
                            Patch = new Nca(Keys, Input2.AsStorage(), true);
                            Nca.SetBaseNca(Patch);
                        }

                        new Thread
                            (() =>
                        {
                            Thread.CurrentThread.IsBackground = true;
                            var Info = GetTitleMeta($"{Nca.Header.TitleId:x16}");
                            label2.Invoke(new Action(() => { label2.Text = Info[0]; label3.Text = Info[1]; }));
                        }).Start();

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

                        IO.PopulateTreeView(treeView1.Nodes, Rom.RootDir);
                    }
                }
                catch { MessageBox.Show("There was an error reading the NCA. Are you sure the correct keys are present in your keyfiles?"); }
            }
            catch (ArgumentNullException) { MessageBox.Show("Error: key files are missing!"); }
        }
Esempio n. 10
0
        private (Nca Main, Nca Control) GetXciGameData(Xci Xci)
        {
            if (Xci.SecurePartition == null)
            {
                throw new InvalidDataException("Could not find XCI secure partition");
            }

            Nca MainNca    = null;
            Nca PatchNca   = null;
            Nca ControlNca = null;

            foreach (PfsFileEntry TicketEntry in Xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".tik")))
            {
                Ticket ticket = new Ticket(Xci.SecurePartition.OpenFile(TicketEntry));

                if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId))
                {
                    KeySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(KeySet));
                }
            }

            foreach (PfsFileEntry FileEntry in Xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".nca")))
            {
                Stream NcaStream = Xci.SecurePartition.OpenFile(FileEntry);

                Nca Nca = new Nca(KeySet, NcaStream, true);

                if (Nca.Header.ContentType == ContentType.Program)
                {
                    if (Nca.Sections.Any(x => x?.Type == SectionType.Romfs))
                    {
                        MainNca = Nca;
                    }
                    else if (Nca.Sections.Any(x => x?.Type == SectionType.Bktr))
                    {
                        PatchNca = Nca;
                    }
                }
                else if (Nca.Header.ContentType == ContentType.Control)
                {
                    ControlNca = Nca;
                }
            }

            if (MainNca == null)
            {
                Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided XCI file");
            }

            MainNca.SetBaseNca(PatchNca);

            if (ControlNca != null)
            {
                ReadControlData(ControlNca);
            }

            if (PatchNca != null)
            {
                PatchNca.SetBaseNca(MainNca);

                return(PatchNca, ControlNca);
            }

            return(MainNca, ControlNca);
        }
Esempio n. 11
0
        static void Main(string[] args)
        {
            Console.WriteLine("Nintendo Switch NSP Verifier v1.00");
            Console.WriteLine("Copyright 2018 CaitSith2");
            Console.WriteLine("");

            _path = args.Length >= 1
                ? string.Join(" ", args)
                : Environment.CurrentDirectory;

            if (new[] { "--help", "-h" }.Any(x => x.Equals(_path, StringComparison.InvariantCultureIgnoreCase)))
            {
                Console.WriteLine("Usage: NSPVerify [path to NSP directory]");
                Console.WriteLine("");
                Console.WriteLine("If the tool is run without specifying a path, it will look for NSPs in the current directory and ALL sub-directories of current directory");
                return;
            }



            if (!Directory.Exists(_path))
            {
                Console.WriteLine("ERROR: Specified directory does not exist.  specify --help for usage information.");
                return;
            }

            IFileSystem fs = new LocalFileSystem(_path);

            var keys = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch", "prod.keys");

            if (File.Exists("keys.txt"))
            {
                keys = "keys.txt";
            }

            if (!File.Exists(keys))
            {
                Console.WriteLine($"Cannot verify NSPs without keys.txt. Either put it in the same directory as this tool,");
                Console.WriteLine($"or place it in \"{Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch")}\" named as prod.keys");
                PressAnyKey();
                return;
            }

            var keyset        = ExternalKeys.ReadKeyFile(keys);
            var badlist       = new List <string>();
            var exceptionlist = new List <string>();

            var files = new List <DirectoryEntry>();

            files.AddRange(fs.EnumerateEntries("*.nsp", SearchOptions.RecurseSubdirectories));
            files.AddRange(fs.EnumerateEntries("*.nsx", SearchOptions.RecurseSubdirectories));

            if (files.Count == 0)
            {
                Console.WriteLine("Error: No NSP/NSX files in specified directory");
                PressAnyKey();
                return;
            }

            foreach (DirectoryEntry dentry in files)
            {
                var file             = dentry.FullPath;
                var filename         = Path.GetFileName(file);
                var relativefilename = Util.GetRelativePath(file, "/");
                Console.Write($"Checking {filename}: ");
                try
                {
                    bool ok = true;
                    using (var nspfile = fs.OpenFile(file, OpenMode.Read))
                    {
                        var nspdata  = new PartitionFileSystem(new FileStorage(nspfile));
                        var cnmtfile = nspdata.Files.FirstOrDefault(x => x.Name.ToLowerInvariant().EndsWith(".cnmt.nca"));
                        if (cnmtfile == null)
                        {
                            Console.WriteLine($"\rChecking {filename}: No cnmt.nca file present");
                            badlist.Add(relativefilename);
                            continue;
                        }

                        var  cnmtdata = nspdata.OpenFile(cnmtfile, OpenMode.Read);
                        Cnmt cnmt;
                        using (var sr = new BinaryReader(cnmtdata.AsStream()))
                        {
                            var cnmthash = SHA256.Create().ComputeHash(sr.ReadBytes((int)cnmtdata.GetSize()));
                            if (!cnmtfile.Name.ToLowerInvariant().Contains(cnmthash.Take(16).ToArray().ToHexString()))
                            {
                                //Put failure here
                                Console.WriteLine($"\rChecking {filename}: cnmt.nca file is corrupted");
                                badlist.Add(relativefilename);
                                cnmtdata.Dispose();
                                continue;
                            }

                            sr.BaseStream.Position = 0;
                            var cnmtnca    = new Nca(keyset, new FileStorage(cnmtdata));
                            var section    = cnmtnca.OpenStorage(0, IntegrityCheckLevel.ErrorOnInvalid);
                            var sectionpfs = new PartitionFileSystem(section);
                            cnmt = new Cnmt(sectionpfs.OpenFile(sectionpfs.Files[0], OpenMode.Read).AsStream());
                        }

                        foreach (var entry in cnmt.ContentEntries)
                        {
                            var entryfile = nspdata.Files.FirstOrDefault(x => x.Name.ToLowerInvariant().EndsWith(entry.NcaId.ToHexString() + ".nca"));
                            if (entryfile == null)
                            {
                                if (entry.Type != CnmtContentType.DeltaFragment)
                                {
                                    //Put failure here
                                    Console.WriteLine($"\rChecking {filename}: one of the entries required by the cnmt.nca is missing.");
                                    badlist.Add(relativefilename);
                                    break;
                                }

                                continue;
                            }

                            using (var entrynca = nspdata.OpenFile(entryfile, OpenMode.Read))
                            {
                                var hash = SHA256.Create();

                                using (var sr = new BinaryReader(entrynca.AsStream()))
                                {
                                    while (entrynca.GetSize() != sr.BaseStream.Position)
                                    {
                                        var entryncadata = sr.ReadBytes(0x100000);
                                        hash.TransformBlock(entryncadata, 0, entryncadata.Length, entryncadata, 0);
                                        Console.Write($"\rChecking {filename}: {((sr.BaseStream.Position * 100.0) / entrynca.GetSize()):0.0}%");
                                    }

                                    hash.TransformFinalBlock(new byte[0], 0, 0);
                                }

                                if (hash.Hash.ToHexString().Equals(entry.Hash.ToHexString()))
                                {
                                    Console.Write($"\rChecking {filename}: {100:0.0}%");
                                    continue;
                                }

                                //Put failure here
                                Console.WriteLine($"\rChecking {filename}: one of the entries required by the cnmt.nca is corrupted");
                                badlist.Add(relativefilename);
                                ok = false;
                                break;
                            }
                        }

                        if (ok)
                        {
                            Console.WriteLine($"\rChecking {filename}: OK        ");
                        }
                        //Put Success here
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    Console.WriteLine(ex.StackTrace);
                    exceptionlist.Add($"{relativefilename}{Environment.NewLine}Exception: \"{ex.GetType()}\" {ex.Message}{Environment.NewLine}Stack Trace: {ex.StackTrace}{Environment.NewLine}");
                }
            }

            badlist.Insert(0, badlist.Count == 0
                ? "None of the files are corrupted. :)"
                : "The following NSP/NSX files are corrupted:");

            exceptionlist.Insert(0, exceptionlist.Count == 0
                ? "No exceptions to log. :)"
                : "Exceptions caused while parsing the following NSP/NSX files:");

            try
            {
                File.WriteAllText("Corrupted NSPs.txt", string.Join(Environment.NewLine, badlist));
                File.WriteAllText("Exception Log.txt", string.Join(Environment.NewLine, exceptionlist));
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Could not write the output files \"Corrupted NSPs.txt\" and \"Exception Log.txt\" due to the following exception.");
                Console.WriteLine($"Exception: \"{ex.GetType()}\" {ex.Message}");
                Console.WriteLine($"Stack Trace: {ex.StackTrace}{Environment.NewLine}");

                Console.WriteLine(string.Join(Environment.NewLine, badlist));
                Console.WriteLine();
                Console.WriteLine(string.Join(Environment.NewLine, exceptionlist));
                Console.WriteLine();
            }

            Console.WriteLine("Done.");
            PressAnyKey();
        }
Esempio n. 12
0
        public void LoadNca(Nca mainNca, Nca patchNca, Nca controlNca)
        {
            if (mainNca.Header.ContentType != NcaContentType.Program)
            {
                Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA");

                return;
            }

            IStorage    dataStorage = null;
            IFileSystem codeFs      = null;

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

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

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

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

                return;
            }

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

            LoadExeFs(codeFs, out Npdm metaData);

            TitleId = metaData.Aci0.TitleId;

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

            if (TitleId != 0)
            {
                EnsureSaveData(new TitleId(TitleId));
            }
        }
Esempio n. 13
0
        private (Nca Main, Nca patch, Nca Control) GetXciGameData(Xci xci)
        {
            if (!xci.HasPartition(XciPartitionType.Secure))
            {
                throw new InvalidDataException("Could not find XCI secure partition");
            }

            Nca mainNca    = null;
            Nca patchNca   = null;
            Nca controlNca = null;

            XciPartition securePartition = xci.OpenPartition(XciPartitionType.Secure);

            foreach (DirectoryEntryEx ticketEntry in securePartition.EnumerateEntries("/", "*.tik"))
            {
                Result result = securePartition.OpenFile(out IFile ticketFile, ticketEntry.FullPath.ToU8Span(), OpenMode.Read);

                if (result.IsSuccess())
                {
                    Ticket ticket = new Ticket(ticketFile.AsStream());

                    KeySet.ExternalKeySet.Add(new RightsId(ticket.RightsId), new AccessKey(ticket.GetTitleKey(KeySet)));
                }
            }

            foreach (DirectoryEntryEx fileEntry in securePartition.EnumerateEntries("/", "*.nca"))
            {
                Result result = securePartition.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read);
                if (result.IsFailure())
                {
                    continue;
                }

                Nca nca = new Nca(KeySet, ncaFile.AsStorage());

                if (nca.Header.ContentType == NcaContentType.Program)
                {
                    int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);

                    if (nca.Header.GetFsHeader(dataIndex).IsPatchSection())
                    {
                        patchNca = nca;
                    }
                    else
                    {
                        mainNca = nca;
                    }
                }
                else if (nca.Header.ContentType == NcaContentType.Control)
                {
                    controlNca = nca;
                }
            }

            if (mainNca == null)
            {
                Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided XCI file");
            }

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

            return(mainNca, patchNca, controlNca);
        }
Esempio n. 14
0
        private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetObject("_dlcWindow").Handle)
        {
            builder.Autoconnect(this);

            _titleId                 = titleId;
            _virtualFileSystem       = virtualFileSystem;
            _dlcJsonPath             = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "dlc.json");
            _baseTitleInfoLabel.Text = $"DLC Available for {titleName} [{titleId.ToUpper()}]";

            try
            {
                _dlcContainerList = JsonHelper.DeserializeFromFile <List <DlcContainer> >(_dlcJsonPath);
            }
            catch
            {
                _dlcContainerList = new List <DlcContainer>();
            }

            _dlcTreeView.Model = new TreeStore(typeof(bool), typeof(string), typeof(string));

            CellRendererToggle enableToggle = new CellRendererToggle();

            enableToggle.Toggled += (sender, args) =>
            {
                _dlcTreeView.Model.GetIter(out TreeIter treeIter, new TreePath(args.Path));
                bool newValue = !(bool)_dlcTreeView.Model.GetValue(treeIter, 0);
                _dlcTreeView.Model.SetValue(treeIter, 0, newValue);

                if (_dlcTreeView.Model.IterChildren(out TreeIter childIter, treeIter))
                {
                    do
                    {
                        _dlcTreeView.Model.SetValue(childIter, 0, newValue);
                    }while (_dlcTreeView.Model.IterNext(ref childIter));
                }
            };

            _dlcTreeView.AppendColumn("Enabled", enableToggle, "active", 0);
            _dlcTreeView.AppendColumn("TitleId", new CellRendererText(), "text", 1);
            _dlcTreeView.AppendColumn("Path", new CellRendererText(), "text", 2);

            foreach (DlcContainer dlcContainer in _dlcContainerList)
            {
                TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(false, "", dlcContainer.Path);

                using FileStream containerFile = File.OpenRead(dlcContainer.Path);
                PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
                _virtualFileSystem.ImportTickets(pfs);

                foreach (DlcNca dlcNca in dlcContainer.DlcNcaList)
                {
                    pfs.OpenFile(out IFile ncaFile, dlcNca.Path.ToU8Span(), OpenMode.Read).ThrowIfFailure();
                    Nca nca = TryCreateNca(ncaFile.AsStorage(), dlcContainer.Path);

                    if (nca != null)
                    {
                        ((TreeStore)_dlcTreeView.Model).AppendValues(parentIter, dlcNca.Enabled, nca.Header.TitleId.ToString("X16"), dlcNca.Path);
                    }
                }
            }
        }
Esempio n. 15
0
        // OpenDataStorageByDataId(u8 storageId, nn::ApplicationId tid) -> object<nn::fssrv::sf::IStorage> dataStorage
        public ResultCode OpenDataStorageByDataId(ServiceCtx context)
        {
            StorageId storageId = (StorageId)context.RequestData.ReadByte();

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

            // We do a mitm here to find if the request is for an AOC.
            // This is because AOC can be distributed over multiple containers in the emulator.
            if (context.Device.System.ContentManager.GetAocDataStorage((ulong)titleId, out LibHac.Fs.IStorage aocStorage))
            {
                Logger.Info?.Print(LogClass.Loader, $"Opened AddOnContent Data TitleID={titleId:X16}");

                MakeObject(context, new FileSystemProxy.IStorage(context.Device.FileSystem.ModLoader.ApplyRomFsMods((ulong)titleId, aocStorage)));

                return(ResultCode.Success);
            }

            NcaContentType contentType = NcaContentType.Data;

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

            if (installedStorage == StorageId.None)
            {
                contentType = NcaContentType.PublicData;

                installedStorage = context.Device.System.ContentManager.GetInstalledStorage(titleId, contentType, storageId);
            }

            if (installedStorage != StorageId.None)
            {
                string contentPath = context.Device.System.ContentManager.GetInstalledContentPath(titleId, storageId, contentType);
                string installPath = context.Device.FileSystem.SwitchPathToSystemPath(contentPath);

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

                    if (File.Exists(ncaPath))
                    {
                        try
                        {
                            LibHac.Fs.IStorage ncaStorage = new LocalStorage(ncaPath, FileAccess.Read, FileMode.Open);
                            Nca nca = new Nca(context.Device.System.KeySet, ncaStorage);
                            LibHac.Fs.IStorage romfsStorage = nca.OpenStorage(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel);

                            MakeObject(context, new FileSystemProxy.IStorage(romfsStorage));
                        }
                        catch (HorizonResultException ex)
                        {
                            return((ResultCode)ex.ResultValue.Value);
                        }

                        return(ResultCode.Success);
                    }
                    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}.");
        }
Esempio n. 16
0
        private void AddButton_Clicked(object sender, EventArgs args)
        {
            FileChooserNative fileChooser = new FileChooserNative("Select DLC files", this, FileChooserAction.Open, "Add", "Cancel")
            {
                SelectMultiple = true
            };

            FileFilter filter = new FileFilter()
            {
                Name = "Switch Game DLCs"
            };

            filter.AddPattern("*.nsp");

            fileChooser.AddFilter(filter);

            if (fileChooser.Run() == (int)ResponseType.Accept)
            {
                foreach (string containerPath in fileChooser.Filenames)
                {
                    if (!File.Exists(containerPath))
                    {
                        return;
                    }

                    using (FileStream containerFile = File.OpenRead(containerPath))
                    {
                        PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
                        bool containsDlc        = false;

                        _virtualFileSystem.ImportTickets(pfs);

                        TreeIter?parentIter = null;

                        foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
                        {
                            using var ncaFile = new UniqueRef <IFile>();

                            pfs.OpenFile(ref ncaFile.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();

                            Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), containerPath);

                            if (nca == null)
                            {
                                continue;
                            }

                            if (nca.Header.ContentType == NcaContentType.PublicData)
                            {
                                if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000).ToString("x16") != _titleId)
                                {
                                    break;
                                }

                                parentIter ??= ((TreeStore)_dlcTreeView.Model).AppendValues(true, "", containerPath);

                                ((TreeStore)_dlcTreeView.Model).AppendValues(parentIter.Value, true, nca.Header.TitleId.ToString("X16"), fileEntry.FullPath);
                                containsDlc = true;
                            }
                        }

                        if (!containsDlc)
                        {
                            GtkDialog.CreateErrorDialog("The specified file does not contain DLC for the selected title!");
                        }
                    }
                }
            }

            fileChooser.Dispose();
        }
Esempio n. 17
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)
            {
                Device.Log.PrintError(LogClass.Loader, "No ExeFS found in NCA");

                return;
            }

            if (RomfsSection == null)
            {
                Device.Log.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"))
            {
                Device.Log.PrintInfo(LogClass.Loader, "Loading main.npdm...");

                MetaData = new Npdm(Exefs.OpenFile("main.npdm"));
            }
            else
            {
                Device.Log.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;
                    }

                    Device.Log.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();
        }
Esempio n. 18
0
        private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetObject("_dlcWindow").Handle)
        {
            builder.Autoconnect(this);

            _titleId                 = titleId;
            _virtualFileSystem       = virtualFileSystem;
            _dlcJsonPath             = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "dlc.json");
            _baseTitleInfoLabel.Text = $"DLC Available for {titleName} [{titleId.ToUpper()}]";

            try
            {
                _dlcContainerList = JsonHelper.DeserializeFromFile <List <DownloadableContentContainer> >(_dlcJsonPath);
            }
            catch
            {
                _dlcContainerList = new List <DownloadableContentContainer>();
            }

            _dlcTreeView.Model = new TreeStore(typeof(bool), typeof(string), typeof(string));

            CellRendererToggle enableToggle = new CellRendererToggle();

            enableToggle.Toggled += (sender, args) =>
            {
                _dlcTreeView.Model.GetIter(out TreeIter treeIter, new TreePath(args.Path));
                bool newValue = !(bool)_dlcTreeView.Model.GetValue(treeIter, 0);
                _dlcTreeView.Model.SetValue(treeIter, 0, newValue);

                if (_dlcTreeView.Model.IterChildren(out TreeIter childIter, treeIter))
                {
                    do
                    {
                        _dlcTreeView.Model.SetValue(childIter, 0, newValue);
                    }while (_dlcTreeView.Model.IterNext(ref childIter));
                }
            };

            _dlcTreeView.AppendColumn("Enabled", enableToggle, "active", 0);
            _dlcTreeView.AppendColumn("TitleId", new CellRendererText(), "text", 1);
            _dlcTreeView.AppendColumn("Path", new CellRendererText(), "text", 2);

            foreach (DownloadableContentContainer dlcContainer in _dlcContainerList)
            {
                if (File.Exists(dlcContainer.ContainerPath))
                {
                    // The parent tree item has its own "enabled" check box, but it's the actual
                    // nca entries that store the enabled / disabled state. A bit of a UI inconsistency.
                    // Maybe a tri-state check box would be better, but for now we check the parent
                    // "enabled" box if all child NCAs are enabled. Usually fine since each nsp has only one nca.
                    bool     areAllContentPacksEnabled = dlcContainer.DownloadableContentNcaList.TrueForAll((nca) => nca.Enabled);
                    TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(areAllContentPacksEnabled, "", dlcContainer.ContainerPath);
                    using FileStream containerFile = File.OpenRead(dlcContainer.ContainerPath);
                    PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
                    _virtualFileSystem.ImportTickets(pfs);

                    foreach (DownloadableContentNca dlcNca in dlcContainer.DownloadableContentNcaList)
                    {
                        using var ncaFile = new UniqueRef <IFile>();

                        pfs.OpenFile(ref ncaFile.Ref(), dlcNca.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
                        Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), dlcContainer.ContainerPath);

                        if (nca != null)
                        {
                            ((TreeStore)_dlcTreeView.Model).AppendValues(parentIter, dlcNca.Enabled, nca.Header.TitleId.ToString("X16"), dlcNca.FullPath);
                        }
                    }
                }
                else
                {
                    // DLC file moved or renamed. Allow the user to remove it without crashing the whole dialog.
                    TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(false, "", $"(MISSING) {dlcContainer.ContainerPath}");
                }
            }
        }
Esempio n. 19
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).");
                }
            }
        }
Esempio n. 20
0
        public void LoadNca(Nca mainNca, Nca patchNca, Nca controlNca)
        {
            if (mainNca.Header.ContentType != ContentType.Program)
            {
                Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA");

                return;
            }

            IStorage    dataStorage = null;
            IFileSystem codeFs      = null;

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

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

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

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

                return;
            }

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

            LoadExeFs(codeFs, out Npdm metaData);

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

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

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

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

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

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

                return(controlData);
            }

            if (controlNca != null)
            {
                ReadControlData();
            }
            else
            {
                TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
            }
        }
Esempio n. 21
0
        private static void processBiggestNca(IStorage biggestNca, ref Title title)
        {
            Nca nca = new Nca(keyset, biggestNca, false);

            processBiggestNca(nca, ref title);
        }
        private void ExtractSection(NcaSectionType ncaSectionType)
        {
            FileChooserDialog fileChooser = new FileChooserDialog("Choose the folder to extract into", null, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Extract", ResponseType.Accept);

            fileChooser.SetPosition(WindowPosition.Center);

            int    response    = fileChooser.Run();
            string destination = fileChooser.Filename;

            fileChooser.Dispose();

            if (response == (int)ResponseType.Accept)
            {
                Thread extractorThread = new Thread(() =>
                {
                    string sourceFile = _gameTableStore.GetValue(_rowIter, 9).ToString();

                    Gtk.Application.Invoke(delegate
                    {
                        _dialog = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Cancel, null)
                        {
                            Title          = "Ryujinx - NCA Section Extractor",
                            Icon           = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"),
                            SecondaryText  = $"Extracting {ncaSectionType} section from {System.IO.Path.GetFileName(sourceFile)}...",
                            WindowPosition = WindowPosition.Center
                        };

                        int dialogResponse = _dialog.Run();
                        if (dialogResponse == (int)ResponseType.Cancel || dialogResponse == (int)ResponseType.DeleteEvent)
                        {
                            _cancel = true;
                            _dialog.Dispose();
                        }
                    });

                    using (FileStream file = new FileStream(sourceFile, FileMode.Open, FileAccess.Read))
                    {
                        Nca mainNca  = null;
                        Nca patchNca = null;

                        if ((System.IO.Path.GetExtension(sourceFile).ToLower() == ".nsp") ||
                            (System.IO.Path.GetExtension(sourceFile).ToLower() == ".pfs0") ||
                            (System.IO.Path.GetExtension(sourceFile).ToLower() == ".xci"))
                        {
                            PartitionFileSystem pfs;

                            if (System.IO.Path.GetExtension(sourceFile) == ".xci")
                            {
                                Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage());

                                pfs = xci.OpenPartition(XciPartitionType.Secure);
                            }
                            else
                            {
                                pfs = new PartitionFileSystem(file.AsStorage());
                            }

                            foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
                            {
                                pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure();

                                Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());

                                if (nca.Header.ContentType == NcaContentType.Program)
                                {
                                    int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);

                                    if (nca.Header.GetFsHeader(dataIndex).IsPatchSection())
                                    {
                                        patchNca = nca;
                                    }
                                    else
                                    {
                                        mainNca = nca;
                                    }
                                }
                            }
                        }
                        else if (System.IO.Path.GetExtension(sourceFile).ToLower() == ".nca")
                        {
                            mainNca = new Nca(_virtualFileSystem.KeySet, file.AsStorage());
                        }

                        if (mainNca == null)
                        {
                            Logger.PrintError(LogClass.Application, "Extraction failed. The main NCA was not present in the selected file.");

                            Gtk.Application.Invoke(delegate
                            {
                                GtkDialog.CreateErrorDialog("Extraction failed. The main NCA was not present in the selected file.");
                            });

                            return;
                        }

                        int index = Nca.GetSectionIndexFromType(ncaSectionType, mainNca.Header.ContentType);

                        IFileSystem ncaFileSystem = patchNca != null ? mainNca.OpenFileSystemWithPatch(patchNca, index, IntegrityCheckLevel.ErrorOnInvalid)
                                                                     : mainNca.OpenFileSystem(index, IntegrityCheckLevel.ErrorOnInvalid);

                        FileSystemClient fsClient = _virtualFileSystem.FsClient;

                        string source = DateTime.Now.ToFileTime().ToString().Substring(10);
                        string output = DateTime.Now.ToFileTime().ToString().Substring(10);

                        fsClient.Register(source.ToU8Span(), ncaFileSystem);
                        fsClient.Register(output.ToU8Span(), new LocalFileSystem(destination));

                        (Result? resultCode, bool canceled) = CopyDirectory(fsClient, $"{source}:/", $"{output}:/");

                        if (!canceled)
                        {
                            if (resultCode.Value.IsFailure())
                            {
                                Logger.PrintError(LogClass.Application, $"LibHac returned error code: {resultCode.Value.ErrorCode}");

                                Gtk.Application.Invoke(delegate
                                {
                                    _dialog?.Dispose();

                                    GtkDialog.CreateErrorDialog("Extraction failed. Read the log file for further information.");
                                });
                            }
                            else if (resultCode.Value.IsSuccess())
                            {
                                Gtk.Application.Invoke(delegate
                                {
                                    _dialog?.Dispose();

                                    MessageDialog dialog = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null)
                                    {
                                        Title          = "Ryujinx - NCA Section Extractor",
                                        Icon           = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"),
                                        SecondaryText  = "Extraction has completed successfully.",
                                        WindowPosition = WindowPosition.Center
                                    };

                                    dialog.Run();
                                    dialog.Dispose();
                                });
                            }
                        }

                        fsClient.Unmount(source);
                        fsClient.Unmount(output);
                    }
                });

                extractorThread.Name         = "GUI.NcaSectionExtractorThread";
                extractorThread.IsBackground = true;
                extractorThread.Start();
            }
        }
Esempio n. 23
0
        private static (string, string) processCnmtNca(Nca nca, ref Title title, bool cnmtContent = true)
        {
            string biggestNca = null, controlNca = null;

            log?.WriteLine("Processing CNMT NCA");

            try
            {
                Pfs ncaPfs = new Pfs(nca.OpenSection(0, false, IntegrityCheckLevel.ErrorOnInvalid, true));

                PfsFileEntry[] ncaFileEntries = ncaPfs.Files;
                foreach (PfsFileEntry pfsEntry in ncaFileEntries)
                {
                    Cnmt cnmt = new Cnmt(ncaPfs.OpenFile(pfsEntry).AsStream());

                    if (title.version == unchecked ((uint)-1) || cnmt.TitleVersion?.Version > title.version)
                    {
                        title.type = cnmt.Type;

                        title.titleID     = String.Format("{0:X16}", cnmt.TitleId);
                        title.baseTitleID = String.Format("{0:X16}", cnmt.ApplicationTitleId);
                        title.version     = cnmt.TitleVersion?.Version ?? title.version;

                        title.systemVersion      = cnmt.MinimumSystemVersion?.Version ?? unchecked ((uint)-1);
                        title.applicationVersion = cnmt.MinimumApplicationVersion?.Version ?? unchecked ((uint)-1);

                        if (cnmtContent)
                        {
                            CnmtContentEntry[] contentEntries = cnmt.ContentEntries;
                            foreach (CnmtContentEntry contentEntry in contentEntries)
                            {
                                if (title.type == TitleType.Application || title.type == TitleType.Patch)
                                {
                                    if (contentEntry.Type == CnmtContentType.Program)
                                    {
                                        biggestNca = BitConverter.ToString(contentEntry.NcaId).Replace("-", "").ToLower() + ".nca";

                                        log?.WriteLine("Found Biggest NCA {0}", biggestNca);
                                    }
                                    else if (contentEntry.Type == CnmtContentType.Control)
                                    {
                                        controlNca = BitConverter.ToString(contentEntry.NcaId).Replace("-", "").ToLower() + ".nca";

                                        log?.WriteLine("Found Control NCA {0}", controlNca);
                                    }
                                }
                                else if (title.type == TitleType.AddOnContent)
                                {
                                    if (contentEntry.Type == CnmtContentType.Data)
                                    {
                                        biggestNca = BitConverter.ToString(contentEntry.NcaId).Replace("-", "").ToLower() + ".nca";

                                        log?.WriteLine("Found Biggest NCA {0}", biggestNca);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (MissingKeyException ex)
            {
                title.error = String.Format("Missing {0}: {1}", ex.Type == KeyType.Title ? "Title Key" : "Key", ex.Name.Replace("key_area_key_application", "master_key"));

                log?.WriteLine(title.error);
            }
            catch (FileNotFoundException) { }

            return(biggestNca, controlNca);
        }
Esempio n. 24
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());
            }
        }
Esempio n. 25
0
        private static void processBiggestNca(Nca nca, ref Title title)
        {
            log?.WriteLine("Processing Biggest NCA");

            if (((title.type == TitleType.Application || title.type == TitleType.Patch) && nca.Header.ContentType == ContentType.Program) ||
                (title.type == TitleType.Patch && nca.Header.ContentType == ContentType.Data) ||
                (title.type == TitleType.AddOnContent && nca.Header.ContentType == ContentType.AocData))
            {
                title.signature = (nca.Header.FixedSigValidity == Validity.Valid);
            }

            if (nca.HasRightsId)
            {
                if (keyset.TitleNames.TryGetValue(nca.Header.RightsId, out string titleName))
                {
                    title.titleName = titleName;
                }
                else if (keyset.TitleNames.TryGetValue(BitConverter.GetBytes(nca.Header.TitleId).Concat(new byte[8]).ToArray(), out titleName))
                {
                    title.titleName = titleName;
                }
                if (keyset.TitleVersions.TryGetValue(nca.Header.RightsId, out uint titleVersion))
                {
                    title.latestVersion = titleVersion;
                }
                else if (keyset.TitleVersions.TryGetValue(BitConverter.GetBytes(nca.Header.TitleId).Concat(new byte[8]).ToArray(), out titleVersion))
                {
                    title.latestVersion = titleVersion;
                }
            }

            if (String.IsNullOrEmpty(title.titleName))
            {
                if (titleNames.TryGetValue(title.titleID, out string titleName))
                {
                    title.titleName = titleName;
                }
                else if (titleNames.TryGetValue(title.baseTitleID, out titleName))
                {
                    title.titleName = titleName;

                    if (title.type == TitleType.AddOnContent)
                    {
                        title.titleName += " [DLC]";
                    }
                }
                if (titleVersions.TryGetValue(title.titleID, out uint titleVersion))
                {
                    title.latestVersion = titleVersion;
                }
            }

            if (((title.type == TitleType.Application || title.type == TitleType.Patch) && nca.Header.ContentType == ContentType.Program) ||
                (title.type == TitleType.Patch && nca.Header.ContentType == ContentType.Data) ||
                (title.type == TitleType.AddOnContent && nca.Header.ContentType == ContentType.AocData))
            {
                title.masterkey = (uint)nca.Header.CryptoType == 2 ? (uint)Math.Max(nca.Header.CryptoType2 - 1, 0) : 0;

                if (nca.Header.ContentType == ContentType.Program)
                {
                    processNpdm(nca, ref title);
                }
            }
        }
Esempio n. 26
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}");
            }
        }
Esempio n. 27
0
        public void EnsureInitialized(ContentManager contentManager)
        {
            if (_fontData == null)
            {
                _device.Memory.ZeroFill(_physicalAddress, Horizon.FontSize);

                uint fontOffset = 0;

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

                        if (!string.IsNullOrWhiteSpace(fontPath))
                        {
                            byte[] data;

                            using (IStorage ncaFileStream = new LocalStorage(fontPath, FileAccess.Read, FileMode.Open))
                            {
                                Nca         nca   = new Nca(_device.System.KeySet, ncaFileStream);
                                IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);

                                romfs.OpenFile(out IFile fontFile, ("/" + fontFilename).ToU8Span(), OpenMode.Read).ThrowIfFailure();

                                data = DecryptFont(fontFile.AsStream());
                            }

                            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.Write(_physicalAddress + fontOffset, data[fontOffset - start]);
                            }

                            return(info);
                        }
                        else
                        {
                            if (!contentManager.TryGetSystemTitlesName(fontTitle, out string titleName))
                            {
                                titleName = "Unknown";
                            }

                            throw new InvalidSystemResourceException($"{titleName} ({fontTitle:x8}) system title not found! This font will not work, provide the system archive to fix this error. (See https://github.com/Ryujinx/Ryujinx#requirements for more information)");
                        }
                    }
                    else
                    {
                        throw new ArgumentException($"Unknown font \"{name}\"!");
                    }
                }

                _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).");
                }
            }
        }
Esempio n. 28
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;

                case 0x0100000000000024:     // ssl
                    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.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);
                        byte[] key3 = new byte[0x10];
                        Crypto.DecryptEcb(key2, SslRsaKeyY, HACGUIKeyset.Keyset.SslRsaKek, 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.GetTitleKey(HACGUIKeyset.Keyset), HACGUIKeyset.Keyset.TitleKeys[ticket.RightsId], 0x10);
            }
            NANDService.Stop();

            Stream prodKeys = HACGUIKeyset.ProductionKeysFileInfo.Create();

            prodKeys.WriteString(HACGUIKeyset.PrintCommonKeys(HACGUIKeyset.Keyset, true));
            Stream extraKeys = HACGUIKeyset.ExtraKeysFileInfo.Create();

            extraKeys.WriteString(HACGUIKeyset.PrintCommonWithoutFriendlyKeys(HACGUIKeyset.Keyset));
            Stream consoleKeys = HACGUIKeyset.ConsoleKeysFileInfo.Create();

            consoleKeys.WriteString(ExternalKeys.PrintUniqueKeys(HACGUIKeyset.Keyset));
            Stream specificConsoleKeys = HACGUIKeyset.GetConsoleKeysFileInfoByName(PickConsole.ConsoleName).Create();

            specificConsoleKeys.WriteString(ExternalKeys.PrintUniqueKeys(HACGUIKeyset.Keyset));
            Stream titleKeys = HACGUIKeyset.TitleKeysFileInfo.Create();

            titleKeys.WriteString(ExternalKeys.PrintTitleKeys(HACGUIKeyset.Keyset));
            prodKeys.Close();
            extraKeys.Close();
            consoleKeys.Close();
            specificConsoleKeys.Close();
            titleKeys.Close();
        }
Esempio n. 29
0
 public NcaItem(Nca nca, PartitionFileEntry partitionFileEntry, IFile file, PartitionFileSystemItemBase parentItem)
     : base(partitionFileEntry, file, parentItem)
 {
     Nca = nca ?? throw new ArgumentNullException(nameof(nca));
     Id  = PartitionFileEntry.Name.Split('.', 2)[0];
 }
Esempio n. 30
0
        private static string Print(this NcaHolder ncaHolder)
        {
            Nca nca       = ncaHolder.Nca;
            int masterKey = GetMasterKeyRevisionFromKeyGeneration(nca.Header.KeyGeneration);

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

            sb.AppendLine();

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

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

            if (nca.Header.HasRightsId)
            {
                PrintItem(sb, colLen, "Rights ID:", nca.Header.RightsId.ToArray());
            }
            else
            {
                PrintKeyArea();
            }

            PrintSections();

            return(sb.ToString());

            void PrintKeyArea()
            {
                NcaVersion version = nca.Header.FormatVersion;

                if (version == NcaVersion.Nca0RsaOaep)
                {
                    sb.AppendLine("Key Area (Encrypted):");
                    PrintItem(sb, colLen, "Key (RSA-OAEP Encrypted):", nca.Header.GetKeyArea().ToArray());

                    sb.AppendLine("Key Area (Decrypted):");
                    for (int i = 0; i < 2; i++)
                    {
                        PrintItem(sb, colLen, $"    Key {i} (Decrypted):", nca.GetDecryptedKey(i));
                    }
                }
                else if (version == NcaVersion.Nca0FixedKey)
                {
                    sb.AppendLine("Key Area:");
                    for (int i = 0; i < 2; i++)
                    {
                        PrintItem(sb, colLen, $"    Key {i}:", nca.Header.GetEncryptedKey(i).ToArray());
                    }
                }
                else
                {
                    int keyCount = version == NcaVersion.Nca0 ? 2 : 4;

                    PrintItem(sb, colLen, "Key Area Encryption Key:", nca.Header.KeyAreaKeyIndex);
                    sb.AppendLine("Key Area (Encrypted):");
                    for (int i = 0; i < keyCount; i++)
                    {
                        PrintItem(sb, colLen, $"    Key {i} (Encrypted):", nca.Header.GetEncryptedKey(i).ToArray());
                    }

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

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

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

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

                    sb.AppendLine($"    Section {i}:");
                    PrintItem(sb, colLen, "        Offset:", $"0x{nca.Header.GetSectionStartOffset(i):x12}");
                    PrintItem(sb, colLen, "        Size:", $"0x{nca.Header.GetSectionSize(i):x12}");
                    PrintItem(sb, colLen, "        Partition Type:", GetPartitionType(sectHeader, isExefs, nca.Header.IsNca0()));
                    PrintItem(sb, colLen, "        Section CTR:", $"{sectHeader.Counter:x16}");
                    PrintItem(sb, colLen, "        Section Validity:", $"{ncaHolder.Validities[i].Print()}");

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

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

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

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