Beispiel #1
0
        /// <summary>
        /// Process the extended header, if it exists
        /// </summary>
        /// <param name="ncchHeader">NCCH header representing the partition</param>
        /// <param name="reader">BinaryReader representing the input stream</param>
        /// <param name="writer">BinaryWriter representing the output stream</param>
        private void ProcessExeFSFileEntries(NCCHHeader ncchHeader, BinaryReader reader, BinaryWriter writer)
        {
            // TODO: Determine how to figure out the MediaUnitSize without an NCSD header. Is it a default value?
            uint mediaUnitSize = 0x200; // mediaUnitSize;

            reader.BaseStream.Seek((ncchHeader.Entry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
            ExeFSHeader exefsHeader = ExeFSHeader.Read(reader);

            // If the header failed to read, log and return
            if (exefsHeader == null)
            {
                Console.WriteLine($"Partition {ncchHeader.PartitionNumber} ExeFS header could not be read. Skipping...");
                return;
            }

            foreach (ExeFSFileHeader fileHeader in exefsHeader.FileHeaders)
            {
                // Only decrypt a file if it's a code binary
                if (!fileHeader.IsCodeBinary)
                {
                    continue;
                }

                uint datalenM  = ((fileHeader.FileSize) / (1024 * 1024));
                uint datalenB  = ((fileHeader.FileSize) % (1024 * 1024));
                uint ctroffset = ((fileHeader.FileOffset + mediaUnitSize) / 0x10);

                byte[] exefsIVWithOffsetForHeader = AddToByteArray(ncchHeader.ExeFSIV, (int)ctroffset);

                var firstCipher  = CreateAESCipher(ncchHeader.NormalKey, exefsIVWithOffsetForHeader, decryptArgs.Encrypt);
                var secondCipher = CreateAESCipher(ncchHeader.NormalKey2C, exefsIVWithOffsetForHeader, !decryptArgs.Encrypt);

                reader.BaseStream.Seek((((ncchHeader.Entry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) + 1) * mediaUnitSize) + fileHeader.FileOffset, SeekOrigin.Begin);
                writer.BaseStream.Seek((((ncchHeader.Entry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) + 1) * mediaUnitSize) + fileHeader.FileOffset, SeekOrigin.Begin);

                if (datalenM > 0)
                {
                    for (int i = 0; i < datalenM; i++)
                    {
                        writer.Write(secondCipher.ProcessBytes(firstCipher.ProcessBytes(reader.ReadBytes(1024 * 1024))));
                        writer.Flush();
                        Console.Write($"\rPartition {ncchHeader.PartitionNumber} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.ReadableFileName}... {i} / {datalenM + 1} mb...");
                    }
                }

                if (datalenB > 0)
                {
                    writer.Write(secondCipher.DoFinal(firstCipher.DoFinal(reader.ReadBytes((int)datalenB))));
                    writer.Flush();
                }

                Console.Write($"\rPartition {ncchHeader.PartitionNumber} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.ReadableFileName}... {datalenM + 1} / {datalenM + 1} mb... Done!\r\n");
            }
        }
Beispiel #2
0
        static void Main(string[] args)
        {
            // string path = @"D:\Games\3DS\LEGO Star Wars III (USA).3ds";
            string path = args[0];
            // string path = @"D:\Games\3DS\Mario Kart 7 (USA).3ds";

            FileStream fs         = File.Open(path, FileMode.Open);
            NCSDHeader ncsdHeader = new NCSDHeader(IO.ReadData(fs, 512));

            System.Console.WriteLine(ncsdHeader);

            int partition = 1;

            if (args.Length > 1)
            {
                partition = int.Parse(args[1]);
            }
            else
            {
                System.Console.Write("Partition: ");
                partition = int.Parse(System.Console.ReadLine());
            }
            long offset = ncsdHeader.PartitionTable.partitions[partition].Offset;

            fs.Seek(offset, SeekOrigin.Begin);
            NCCHHeader ncchHeader = new NCCHHeader(IO.ReadData(fs, 512), offset);

            System.Console.WriteLine(ncchHeader);

            fs.Seek(ncchHeader.ExeFSOffset, SeekOrigin.Begin);
            ExeFSHeader exeFSHeader = new ExeFSHeader(IO.ReadData(fs, 512), ncchHeader.ExeFSOffset);

            System.Console.WriteLine($"\nExeFS Header\n{exeFSHeader}");

            fs.Seek(ncchHeader.RomFSOffset, SeekOrigin.Begin);
            IVFCHeader ivfcHeader = new IVFCHeader(IO.ReadData(fs, 92), ncchHeader.RomFSOffset);

            System.Console.WriteLine($"\nIVFC Header (RomFS)\n{ivfcHeader}");

            L3Partition l3Partition = new L3Partition(fs, ncchHeader.RomFSOffset + 0x1000);

            System.Console.WriteLine($"\nL3 Header (RomFS)\n{l3Partition.Header}");
            // System.Console.WriteLine($"\nL3 Partition Directory Metadata Table (RomFS)\n{l3Partition.DirectoryMetadataTable}");
            // System.Console.WriteLine($"\nL3 Partition Files Metadata Table (RomFS)\n{l3Partition.FileMetadataTable}");
            System.Console.WriteLine($"\nL3 Partition Structure (RomFS)\n{l3Partition}");
        }