Example #1
0
        private static void PrintPartition(StringBuilder sb, int colLen, XciPartition partition, XciPartitionType type)
        {
            const int fileNameLen = 57;

            sb.AppendLine($"{type.ToString()} Partition:{partition.HashValidity.GetValidityString()}");
            PrintItem(sb, colLen, "    Magic:", partition.Header.Magic);
            PrintItem(sb, colLen, "    Offset:", $"{partition.Offset:x12}");
            PrintItem(sb, colLen, "    Number of files:", partition.Files.Length);

            string name = type.GetFileName();

            if (partition.Files.Length > 0 && partition.Files.Length < 100)
            {
                for (int i = 0; i < partition.Files.Length; i++)
                {
                    PartitionFileEntry file = partition.Files[i];

                    string label   = i == 0 ? "    Files:" : "";
                    string offsets = $"{file.Offset:x12}-{file.Offset + file.Size:x12}{file.HashValidity.GetValidityString()}";
                    string data    = $"{name}:/{file.Name}".PadRight(fileNameLen) + offsets;

                    PrintItem(sb, colLen, label, data);
                }
            }
        }
Example #2
0
        public static IStorage ProcessXci(IStorage xciStorage, bool compress)
        {
            Xci      xci = new Xci(KeySet, xciStorage);
            IStorage xciHeaderStorage = new MemoryStorage(new byte[0x200]);

            xciStorage.CopyTo(xciHeaderStorage);

            XciPartition securePartition          = xci.OpenPartition(XciPartitionType.Secure);
            IStorage     processedSecurePartition = ProcessPartitionFileSystem(securePartition, PartitionFileSystemType.Hashed, compress);

            PartitionFileSystemBuilder rootPartitionBuilder = new PartitionFileSystemBuilder();

            rootPartitionBuilder.AddFile("secure", processedSecurePartition.AsFile(OpenMode.Read));
            IStorage rootPartitionStorage = rootPartitionBuilder.Build(PartitionFileSystemType.Hashed);

            using (BinaryReader reader = new BinaryReader(rootPartitionStorage.AsStream()))
            {
                PartitionFileSystemHeader pfsHeader = new PartitionFileSystemHeader(reader);
                Span <byte> pfsHeaderBytes          = stackalloc byte[pfsHeader.HeaderSize];
                Span <byte> pfsHeaderHash           = stackalloc byte[0x20];
                rootPartitionStorage.Read(0, pfsHeaderBytes);
                Sha256.GenerateSha256Hash(pfsHeaderBytes, pfsHeaderHash);

                xciHeaderStorage.Write(0x138, BitConverter.GetBytes(pfsHeader.HeaderSize));
                xciHeaderStorage.Write(0x140, pfsHeaderHash);
            }

            return(new ConcatenationStorage(new[]
            {
                xciHeaderStorage,
                new MemoryStorage(new byte[xci.Header.RootPartitionOffset - 0x200]), // Cert and padding
                rootPartitionStorage
            }, false));
        }
Example #3
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 (DirectoryEntry ticketEntry in securePartition.EnumerateEntries("*.tik"))
            {
                Ticket ticket = new Ticket(securePartition.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream());

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

            foreach (DirectoryEntry fileEntry in securePartition.EnumerateEntries("*.nca"))
            {
                IStorage ncaStorage = securePartition.OpenFile(fileEntry.FullPath, OpenMode.Read).AsStorage();

                Nca nca = new Nca(KeySet, ncaStorage);

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

                    if (nca.Header.GetFsHeader(dataIndex).IsPatchSection())
                    {
                        patchNca = nca;
                    }
                    else
                    {
                        mainNca = 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");
            }

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

            return(mainNca, patchNca, controlNca);
        }
Example #4
0
        private static string Print(this Xci xci)
        {
            const int colLen = 36;

            var sb = new StringBuilder();

            sb.AppendLine();

            sb.AppendLine("XCI:");

            PrintItem(sb, colLen, "Magic:", xci.Header.Magic);
            PrintItem(sb, colLen, $"Header Signature{xci.Header.SignatureValidity.GetValidityString()}:", xci.Header.Signature);
            PrintItem(sb, colLen, $"Header Hash{xci.Header.PartitionFsHeaderValidity.GetValidityString()}:", xci.Header.RootPartitionHeaderHash);
            PrintItem(sb, colLen, "Cartridge Type:", GetCartridgeType(xci.Header.GameCardSize));
            PrintItem(sb, colLen, "Cartridge Size:", $"0x{Utilities.MediaToReal(xci.Header.ValidDataEndPage + 1):x12}");
            PrintItem(sb, colLen, "Header IV:", xci.Header.AesCbcIv);

            PrintPartition(sb, colLen, xci.OpenPartition(XciPartitionType.Root), XciPartitionType.Root);

            foreach (XciPartitionType type in Enum.GetValues(typeof(XciPartitionType)))
            {
                if (type == XciPartitionType.Root || !xci.HasPartition(type))
                {
                    continue;
                }

                XciPartition partition = xci.OpenPartition(type);
                PrintPartition(sb, colLen, partition, type);
            }

            return(sb.ToString());
        }
Example #5
0
        private static Nca GetXciMainNca(Xci xci, Context ctx)
        {
            XciPartition partition = xci.OpenPartition(XciPartitionType.Secure);

            if (partition == null)
            {
                ctx.Logger.LogMessage("Could not find secure partition");
                return(null);
            }

            Nca mainNca = null;

            foreach (PartitionFileEntry fileEntry in partition.Files.Where(x => x.Name.EndsWith(".nca")))
            {
                IStorage ncaStorage = partition.OpenFile(fileEntry, OpenMode.Read).AsStorage();
                var      nca        = new Nca(ctx.Keyset, ncaStorage);

                if (nca.Header.ContentType == NcaContentType.Program)
                {
                    mainNca = nca;
                }
            }

            return(mainNca);
        }
 public XciPartitionItem(XciPartition xciPartition, XciPartitionType xciPartitionType, XciItem parentItem)
     : base(xciPartition)
 {
     XciPartition     = xciPartition ?? throw new ArgumentNullException(nameof(xciPartition));
     XciPartitionType = xciPartitionType;
     ParentItem       = parentItem ?? throw new ArgumentNullException(nameof(parentItem));
 }
Example #7
0
        public Result Create(out ReferenceCountedDisposable <IFileSystem> fileSystem, GameCardHandle handle, GameCardPartition partitionType)
        {
            // Use the old xci code temporarily

            UnsafeHelpers.SkipParamInit(out fileSystem);

            Result rc = GameCard.GetXci(out Xci xci, handle);

            if (rc.IsFailure())
            {
                return(rc);
            }

            if (!xci.HasPartition((XciPartitionType)partitionType))
            {
                return(ResultFs.PartitionNotFound.Log());
            }

            XciPartition fs = xci.OpenPartition((XciPartitionType)partitionType);

            fileSystem = new ReferenceCountedDisposable <IFileSystem>(fs);
            return(Result.Success);
        }
Example #8
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, 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, 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);
        }
Example #9
0
        static void Main(string[] args)
        {
            Console.Title = "XCIRepacker v0.1 by Ac_K";

            Console.WriteLine(Environment.NewLine +
                              " XCIRepacker v0.1 by Ac_K" +
                              Environment.NewLine +
                              Environment.NewLine +
                              " Provide with the courtesy of the mob." +
                              Environment.NewLine +
                              Environment.NewLine +
                              "---------------------------------------" +
                              Environment.NewLine);

            if (args.Length == 1)
            {
                Keyset keySet = OpenKeyset();

                if (keySet != null)
                {
                    if (File.Exists(args[0]))
                    {
                        try
                        {
                            Xci xciFile = new Xci(keySet, new LocalStorage(args[0], FileAccess.Read));

                            if (xciFile.HasPartition(XciPartitionType.Secure))
                            {
                                XciPartition xciPartition = xciFile.OpenPartition(XciPartitionType.Root);

                                IFile ncaStorage = xciPartition.OpenFile("secure", OpenMode.Read);

                                string outputPath = Path.GetDirectoryName(args[0]) + Path.GetFileNameWithoutExtension(args[0]) + ".nsp";

                                Console.WriteLine($" Input  File Path: {args[0]}");
                                Console.WriteLine($" Output File Path: {outputPath}" + Environment.NewLine);

                                using (Stream dataInput = ncaStorage.AsStream())
                                    using (FileStream fileOutput = new FileStream(outputPath, FileMode.Create, FileAccess.ReadWrite))
                                        using (BinaryReader reader = new BinaryReader(fileOutput))
                                            using (BinaryWriter writer = new BinaryWriter(fileOutput))
                                            {
                                                int  bytesRead  = -1;
                                                long totalReads = 0;
                                                long totalBytes = dataInput.Length;

                                                byte[] bytes = new byte[_bufferSize];

                                                Console.WriteLine(" Extracting Secure partition..." + Environment.NewLine);

                                                while ((bytesRead = dataInput.Read(bytes, 0, _bufferSize)) > 0)
                                                {
                                                    fileOutput.Write(bytes, 0, bytesRead);
                                                    totalReads += bytesRead;

                                                    DrawTextProgressBar(totalReads, totalBytes);
                                                }

                                                Console.WriteLine(Environment.NewLine +
                                                                  Environment.NewLine +
                                                                  " Secure partition extracted!" +
                                                                  Environment.NewLine +
                                                                  Environment.NewLine +
                                                                  "---------------------------------------" +
                                                                  Environment.NewLine);

                                                Console.Write(" Patching HFS0 Header to PFS0...");

                                                fileOutput.Position = 0;

                                                string Magic = Encoding.ASCII.GetString(reader.ReadBytes(0x04));

                                                if (Magic == "HFS0")
                                                {
                                                    fileOutput.Seek(0x00, SeekOrigin.Begin);

                                                    writer.Write(new byte[] { 0x50, 0x46, 0x53, 0x30 }); // PFS0

                                                    int filesNumber    = reader.ReadInt32();             // Skip write files number because is at same offset
                                                    int filesNamesSize = reader.ReadInt32();

                                                    reader.ReadInt32(); // Skip reserved

                                                    long HFS0HeaderSize = filesNamesSize + 0x10;

                                                    for (int i = 0; i < filesNumber; i++)
                                                    {
                                                        fileOutput.Seek((i * 0x40) + 0x10, SeekOrigin.Begin);

                                                        long fileOffset     = reader.ReadInt64();
                                                        long fileSize       = reader.ReadInt64();
                                                        int  fileNameOffset = reader.ReadInt32();
                                                        int  hashedSize     = reader.ReadInt32();

                                                        reader.ReadInt64(); // reserved

                                                        reader.ReadBytes(0x20);

                                                        HFS0HeaderSize += 0x40;

                                                        fileOutput.Seek((i * 0x18) + 0x10, SeekOrigin.Begin);

                                                        writer.Write(fileOffset);
                                                        writer.Write(fileSize);
                                                        writer.Write(fileNameOffset);
                                                        writer.Write(0x00); // reserved
                                                    }

                                                    long endPatchedHeader = fileOutput.Position;

                                                    fileOutput.Seek((4 * 0x40) + 0x10, SeekOrigin.Begin);

                                                    byte[] filesNamesTable = reader.ReadBytes(filesNamesSize);

                                                    fileOutput.Seek(endPatchedHeader, SeekOrigin.Begin);

                                                    writer.Write(filesNamesTable);

                                                    int shiftSize = (int)(HFS0HeaderSize - fileOutput.Position);

                                                    writer.Write(new byte[shiftSize]);

                                                    fileOutput.Seek(0x08, SeekOrigin.Begin);

                                                    writer.Write(filesNamesSize + shiftSize);

                                                    Console.WriteLine(" Done!");
                                                }
                                                else
                                                {
                                                    Console.WriteLine(" ERROR: Extracted file isn't HFS0!");
                                                }
                                            }
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($" ERROR: {ex.Message}");
                        }
                    }
                    else
                    {
                        Console.WriteLine(" ERROR: XCI file not found!");
                    }
                }
                else
                {
                    Console.WriteLine(" ERROR: Keys file not found!");
                }
            }
            else
            {
                Console.WriteLine(" USAGE: XCIRepacker.exe \"PathOfFile.xci\"");
            }

            Console.ReadKey();
        }
Example #10
0
        public static void Process(Context ctx)
        {
            using (var file = new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.Read))
            {
                var xci = new Xci(ctx.Keyset, file.AsStorage());

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    if (ctx.Options.RomfsOut != null)
                    {
                        mainNca.ExportSection(romfsSection.SectionNum, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
                    }
                }
            }
        }
Example #11
0
        public static void Process(Context ctx)
        {
            using (var file = new LocalStorage(ctx.Options.InFile, FileAccess.Read))
            {
                var xci = new Xci(ctx.Keyset, file);

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

                if (ctx.Options.RootDir != null)
                {
                    xci.OpenPartition(XciPartitionType.Root).Extract(ctx.Options.RootDir, ctx.Logger);
                }

                if (ctx.Options.UpdateDir != null && xci.HasPartition(XciPartitionType.Update))
                {
                    xci.OpenPartition(XciPartitionType.Update).Extract(ctx.Options.UpdateDir, ctx.Logger);
                }

                if (ctx.Options.NormalDir != null && xci.HasPartition(XciPartitionType.Normal))
                {
                    xci.OpenPartition(XciPartitionType.Normal).Extract(ctx.Options.NormalDir, ctx.Logger);
                }

                if (ctx.Options.SecureDir != null && xci.HasPartition(XciPartitionType.Secure))
                {
                    xci.OpenPartition(XciPartitionType.Secure).Extract(ctx.Options.SecureDir, ctx.Logger);
                }

                if (ctx.Options.LogoDir != null && xci.HasPartition(XciPartitionType.Logo))
                {
                    xci.OpenPartition(XciPartitionType.Logo).Extract(ctx.Options.LogoDir, ctx.Logger);
                }

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

                    foreach (PartitionFileEntry sub in root.Files)
                    {
                        var    subPfs = new PartitionFileSystem(root.OpenFile(sub, OpenMode.Read).AsStorage());
                        string subDir = Path.Combine(ctx.Options.OutDir, sub.Name);

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

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

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

                    if (!mainNca.SectionExists(NcaSectionType.Code))
                    {
                        ctx.Logger.LogMessage("NCA has no ExeFS section");
                        return;
                    }

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

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

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

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

                    if (!mainNca.SectionExists(NcaSectionType.Data))
                    {
                        ctx.Logger.LogMessage("NCA has no RomFS section");
                        return;
                    }

                    ProcessRomfs.Process(ctx, mainNca.OpenStorage(NcaSectionType.Data, ctx.Options.IntegrityLevel, false));
                }
            }
        }