Example #1
0
        // Main wrapper that assembles the ROM based on the following specifications:
        internal static bool buildROM(bool Card2, string LOGO_NAME,
                                      string EXEFS_PATH, string ROMFS_PATH, string EXHEADER_PATH,
                                      string SERIAL_TEXT, string SAVE_PATH,
                                      ProgressBar PB_Show = null, RichTextBox TB_Progress = null)
        {
            PB_Show     = PB_Show ?? new ProgressBar();
            TB_Progress = TB_Progress ?? new RichTextBox();

            // Sanity check the input files.
            if (!
                ((File.Exists(EXEFS_PATH) || Directory.Exists(EXEFS_PATH)) &&
                 (File.Exists(ROMFS_PATH) || Directory.Exists(ROMFS_PATH)) &&
                 File.Exists(EXHEADER_PATH)))
            {
                return(false);
            }

            // If ExeFS and RomFS are not built, build.
            if (!File.Exists(EXEFS_PATH) && Directory.Exists(EXEFS_PATH))
            {
                ExeFS.set(Directory.GetFiles(EXEFS_PATH), EXEFS_PATH = "exefs.bin");
            }
            if (!File.Exists(ROMFS_PATH) && Directory.Exists(ROMFS_PATH))
            {
                RomFS.BuildRomFS(ROMFS_PATH, ROMFS_PATH = "romfs.bin", TB_Progress, PB_Show);
            }

            NCCH NCCH    = setNCCH(EXEFS_PATH, ROMFS_PATH, EXHEADER_PATH, SERIAL_TEXT, LOGO_NAME, PB_Show, TB_Progress);
            NCSD NCSD    = setNCSD(NCCH, Card2, PB_Show, TB_Progress);
            bool success = writeROM(NCSD, SAVE_PATH, PB_Show, TB_Progress);

            return(success);
        }
Example #2
0
        // Sub methods that drive the operation
        internal static NCCH setNCCH(string EXEFS_PATH, string ROMFS_PATH, string EXHEADER_PATH, string TB_Serial, string LOGO_NAME,
                                     ProgressBar PB_Show = null, RichTextBox TB_Progress = null)
        {
            PB_Show     = PB_Show ?? new ProgressBar();
            TB_Progress = TB_Progress ?? new RichTextBox();

            updateTB(TB_Progress, "Creating NCCH...");
            updateTB(TB_Progress, "Adding Exheader...");
            NCCH NCCH = new NCCH
            {
                exheader    = new Exheader(EXHEADER_PATH),
                plainregion = new byte[0]
            };

            if (NCCH.exheader.isPokemon())
            {
                updateTB(TB_Progress, "Detected Pokemon Game. Adding Plain Region...");
                if (NCCH.exheader.isXY())
                {
                    NCCH.plainregion = (byte[])Resources.ResourceManager.GetObject("XY");
                }
                else if (NCCH.exheader.isORAS())
                {
                    NCCH.plainregion = (byte[])Resources.ResourceManager.GetObject("ORAS");
                }
            }
            updateTB(TB_Progress, "Adding ExeFS...");
            NCCH.exefs = new ExeFS(EXEFS_PATH);
            updateTB(TB_Progress, "Adding RomFS...");
            NCCH.romfs = new RomFS(ROMFS_PATH);

            updateTB(TB_Progress, "Adding Logo...");
            NCCH.logo = (byte[])Resources.ResourceManager.GetObject(LOGO_NAME);
            updateTB(TB_Progress, "Assembling NCCH Header...");
            ulong Len = 0x200; //NCCH Signature + NCCH Header

            NCCH.header = new NCCH.Header {
                Signature = new byte[0x100], Magic = 0x4843434E
            };
            NCCH.header.TitleId       = NCCH.header.ProgramId = NCCH.exheader.TitleID;
            NCCH.header.MakerCode     = 0x3130; //01
            NCCH.header.FormatVersion = 0x2;    //Default
            NCCH.header.LogoHash      = new SHA256Managed().ComputeHash(NCCH.logo);
            NCCH.header.ProductCode   = Encoding.ASCII.GetBytes(TB_Serial);
            Array.Resize(ref NCCH.header.ProductCode, 0x10);
            NCCH.header.ExheaderHash = NCCH.exheader.GetSuperBlockHash();
            NCCH.header.ExheaderSize = (uint)NCCH.exheader.Data.Length;
            Len += NCCH.header.ExheaderSize + (uint)NCCH.exheader.AccessDescriptor.Length;
            NCCH.header.Flags = new byte[0x8];
            //FLAGS
            NCCH.header.Flags[3]   = 0;   // Crypto: 0 = <7.x, 1=7.x;
            NCCH.header.Flags[4]   = 1;   // Content Platform: 1 = CTR;
            NCCH.header.Flags[5]   = 0x3; // Content Type Bitflags: 1=Data, 2=Executable, 4=SysUpdate, 8=Manual, 0x10=Trial;
            NCCH.header.Flags[6]   = 0;   // MEDIA_UNIT_SIZE = 0x200*Math.Pow(2, Content.header.Flags[6]);
            NCCH.header.Flags[7]   = 1;   // FixedCrypto = 1, NoMountRomfs = 2; NoCrypto=4;
            NCCH.header.LogoOffset = (uint)(Len / MEDIA_UNIT_SIZE);
            NCCH.header.LogoSize   = (uint)(NCCH.logo.Length / MEDIA_UNIT_SIZE);
            Len += (uint)NCCH.logo.Length;
            NCCH.header.PlainRegionOffset = (uint)(NCCH.plainregion.Length > 0 ? Len / MEDIA_UNIT_SIZE : 0);
            NCCH.header.PlainRegionSize   = (uint)NCCH.plainregion.Length / MEDIA_UNIT_SIZE;
            Len += (uint)NCCH.plainregion.Length;
            NCCH.header.ExefsOffset         = (uint)(Len / MEDIA_UNIT_SIZE);
            NCCH.header.ExefsSize           = (uint)(NCCH.exefs.Data.Length / MEDIA_UNIT_SIZE);
            NCCH.header.ExefsSuperBlockSize = 0x200 / MEDIA_UNIT_SIZE; //Static 0x200 for exefs superblock
            Len += (uint)NCCH.exefs.Data.Length;
            Len  = (uint)Align(Len, 0x1000);                           //Romfs Start is aligned to 0x1000
            NCCH.header.RomfsOffset         = (uint)(Len / MEDIA_UNIT_SIZE);
            NCCH.header.RomfsSize           = (uint)(new FileInfo(NCCH.romfs.FileName).Length / MEDIA_UNIT_SIZE);
            NCCH.header.RomfsSuperBlockSize = NCCH.romfs.SuperBlockLen / MEDIA_UNIT_SIZE;
            Len += NCCH.header.RomfsSize * MEDIA_UNIT_SIZE;
            NCCH.header.ExefsHash = NCCH.exefs.SuperBlockHash;
            NCCH.header.RomfsHash = NCCH.romfs.SuperBlockHash;
            NCCH.header.Size      = (uint)(Len / MEDIA_UNIT_SIZE);
            //Build the Header byte[].
            updateTB(TB_Progress, "Building NCCH Header...");
            NCCH.header.BuildHeader();

            return(NCCH);
        }
Example #3
0
        internal static bool writeROM(NCSD Rom, string SAVE_PATH,
                                      ProgressBar PB_Show = null, RichTextBox TB_Progress = null)
        {
            NCCH Content = Rom.NCCH_Array[0];

            PB_Show     = PB_Show ?? new ProgressBar();
            TB_Progress = TB_Progress ?? new RichTextBox();
            using (FileStream OutFileStream = new FileStream(SAVE_PATH, FileMode.Create))
            {
                updateTB(TB_Progress, "Writing NCSD Header...");
                OutFileStream.Write(Rom.Data, 0, Rom.Data.Length);
                updateTB(TB_Progress, "Writing NCCH...");
                OutFileStream.Write(Rom.NCCH_Array[0].header.Data, 0, Rom.NCCH_Array[0].header.Data.Length); //Write NCCH header
                //AES time.
                byte[] key = new byte[0x10];                                                                 //Fixed-Crypto key is all zero.
                for (int i = 0; i < 3; i++)
                {
                    AesCtr aesctr = new AesCtr(key, Rom.NCCH_Array[0].header.ProgramId, ((ulong)(i + 1)) << 56); //CTR is ProgramID, section id<<88
                    switch (i)
                    {
                    case 0:     //Exheader + AccessDesc
                        updateTB(TB_Progress, "Writing Exheader...");
                        byte[] inEncExheader  = new byte[Rom.NCCH_Array[0].exheader.Data.Length + Rom.NCCH_Array[0].exheader.AccessDescriptor.Length];
                        byte[] outEncExheader = new byte[Rom.NCCH_Array[0].exheader.Data.Length + Rom.NCCH_Array[0].exheader.AccessDescriptor.Length];
                        Array.Copy(Rom.NCCH_Array[0].exheader.Data, inEncExheader, Rom.NCCH_Array[0].exheader.Data.Length);
                        Array.Copy(Rom.NCCH_Array[0].exheader.AccessDescriptor, 0, inEncExheader, Rom.NCCH_Array[0].exheader.Data.Length, Rom.NCCH_Array[0].exheader.AccessDescriptor.Length);
                        aesctr.TransformBlock(inEncExheader, 0, inEncExheader.Length, outEncExheader, 0);
                        OutFileStream.Write(outEncExheader, 0, outEncExheader.Length);     // Write Exheader
                        break;

                    case 1:     //Exefs
                        updateTB(TB_Progress, "Writing Exefs...");
                        OutFileStream.Seek(0x4000 + Rom.NCCH_Array[0].header.ExefsOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
                        byte[] OutExefs = new byte[Rom.NCCH_Array[0].exefs.Data.Length];
                        aesctr.TransformBlock(Rom.NCCH_Array[0].exefs.Data, 0, Rom.NCCH_Array[0].exefs.Data.Length, OutExefs, 0);
                        OutFileStream.Write(OutExefs, 0, OutExefs.Length);
                        break;

                    case 2:     //Romfs
                        updateTB(TB_Progress, "Writing Romfs...");
                        OutFileStream.Seek(0x4000 + Rom.NCCH_Array[0].header.RomfsOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
                        using (FileStream InFileStream = new FileStream(Rom.NCCH_Array[0].romfs.FileName, FileMode.Open, FileAccess.Read))
                        {
                            uint  BUFFER_SIZE = 0;
                            ulong RomfsLen    = Rom.NCCH_Array[0].header.RomfsSize * MEDIA_UNIT_SIZE;
                            PB_Show.Invoke((Action)(() =>
                            {
                                PB_Show.Minimum = 0;
                                PB_Show.Maximum = (int)(RomfsLen / 0x400000);
                                PB_Show.Value = 0;
                                PB_Show.Step = 1;
                            }));
                            for (ulong j = 0; j < (RomfsLen); j += BUFFER_SIZE)
                            {
                                BUFFER_SIZE = (RomfsLen - j) > 0x400000 ? 0x400000 : (uint)(RomfsLen - j);
                                byte[] buf    = new byte[BUFFER_SIZE];
                                byte[] outbuf = new byte[BUFFER_SIZE];
                                InFileStream.Read(buf, 0, (int)BUFFER_SIZE);
                                aesctr.TransformBlock(buf, 0, (int)BUFFER_SIZE, outbuf, 0);
                                OutFileStream.Write(outbuf, 0, (int)BUFFER_SIZE);
                                PB_Show.Invoke((Action)(PB_Show.PerformStep));
                            }
                        }
                        break;
                    }
                }
                updateTB(TB_Progress, "Writing Logo...");
                OutFileStream.Seek(0x4000 + Rom.NCCH_Array[0].header.LogoOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
                OutFileStream.Write(Rom.NCCH_Array[0].logo, 0, Rom.NCCH_Array[0].logo.Length);
                if (Rom.NCCH_Array[0].plainregion.Length > 0)
                {
                    updateTB(TB_Progress, "Writing Plain Region...");
                    OutFileStream.Seek(0x4000 + Rom.NCCH_Array[0].header.PlainRegionOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
                    OutFileStream.Write(Rom.NCCH_Array[0].plainregion, 0, Rom.NCCH_Array[0].plainregion.Length);
                }

                //NCSD Padding
                OutFileStream.Seek(Rom.header.OffsetSizeTable[Rom.NCCH_Array.Count - 1].Offset * MEDIA_UNIT_SIZE + Rom.header.OffsetSizeTable[Rom.NCCH_Array.Count - 1].Size * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
                ulong  TotalLen = Rom.header.MediaSize * MEDIA_UNIT_SIZE;
                byte[] Buffer   = Enumerable.Repeat((byte)0xFF, 0x400000).ToArray();
                updateTB(TB_Progress, "Writing NCSD Padding...");
                while ((ulong)OutFileStream.Position < TotalLen)
                {
                    int BUFFER_LEN = ((TotalLen - (ulong)OutFileStream.Position) < 0x400000) ? (int)(TotalLen - (ulong)OutFileStream.Position) : 0x400000;
                    OutFileStream.Write(Buffer, 0, BUFFER_LEN);
                }
            }

            //Delete Temporary Romfs File
            if (Content.romfs.isTempFile)
            {
                File.Delete(Content.romfs.FileName);
            }

            updateTB(TB_Progress, "Done!");
            return(true);
        }
Example #4
0
        internal static NCSD setNCSD(NCCH NCCH, bool Card2,
                                     ProgressBar PB_Show = null, RichTextBox TB_Progress = null)
        {
            PB_Show     = PB_Show ?? new ProgressBar();
            TB_Progress = TB_Progress ?? new RichTextBox();
            updateTB(TB_Progress, "Building NCSD Header...");
            NCSD NCSD = new NCSD
            {
                NCCH_Array = new List <NCCH> {
                    NCCH
                },
                Card2  = Card2,
                header = new NCSD.Header {
                    Signature = new byte[0x100], Magic = 0x4453434E
                }
            };
            ulong Length = 0x80 * 0x100000;                                 // 128 MB

            while (Length <= NCCH.header.Size * MEDIA_UNIT_SIZE + 0x400000) //Extra 4 MB for potential save data
            {
                Length *= 2;
            }
            NCSD.header.MediaSize       = (uint)(Length / MEDIA_UNIT_SIZE);
            NCSD.header.TitleId         = NCCH.exheader.TitleID;
            NCSD.header.OffsetSizeTable = new NCSD.NCCH_Meta[8];
            ulong OSOfs = 0x4000;

            for (int i = 0; i < NCSD.header.OffsetSizeTable.Length; i++)
            {
                NCSD.NCCH_Meta ncchm = new NCSD.NCCH_Meta();
                if (i < NCSD.NCCH_Array.Count)
                {
                    ncchm.Offset = (uint)(OSOfs / MEDIA_UNIT_SIZE);
                    ncchm.Size   = NCSD.NCCH_Array[i].header.Size;
                }
                else
                {
                    ncchm.Offset = 0;
                    ncchm.Size   = 0;
                }
                NCSD.header.OffsetSizeTable[i] = ncchm;
                OSOfs += ncchm.Size * MEDIA_UNIT_SIZE;
            }
            NCSD.header.flags       = new byte[0x8];
            NCSD.header.flags[0]    = 0;                          // 0-255 seconds of waiting for save writing.
            NCSD.header.flags[3]    = (byte)(NCSD.Card2 ? 2 : 1); // Media Card Device: 1 = NOR Flash, 2 = None, 3 = BT
            NCSD.header.flags[4]    = 1;                          // Media Platform Index: 1 = CTR
            NCSD.header.flags[5]    = (byte)(NCSD.Card2 ? 2 : 1); // Media Type Index: 0 = Inner Device, 1 = Card1, 2 = Card2, 3 = Extended Device
            NCSD.header.flags[6]    = 0;                          // Media Unit Size. Same as NCCH.
            NCSD.header.flags[7]    = 0;                          // Old Media Card Device.
            NCSD.header.NCCHIdTable = new ulong[8];
            for (int i = 0; i < NCSD.NCCH_Array.Count; i++)
            {
                NCSD.header.NCCHIdTable[i] = NCSD.NCCH_Array[i].header.TitleId;
            }
            NCSD.cardinfoheader = new NCSD.CardInfoHeader
            {
                WritableAddress = (uint)NCSD.GetWritableAddress(),
                CardInfoBitmask = 0,
                CIN             = new NCSD.CardInfoHeader.CardInfoNotes
                {
                    Reserved0        = new byte[0xF8],
                    MediaSizeUsed    = OSOfs,
                    Reserved1        = 0,
                    Unknown          = 0,
                    Reserved2        = new byte[0xC],
                    CVerTitleId      = 0,
                    CVerTitleVersion = 0,
                    Reserved3        = new byte[0xCD6]
                },
                NCCH0TitleId = NCSD.NCCH_Array[0].header.TitleId,
                Reserved0    = 0,
                InitialData  = new byte[0x30]
            };
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

            byte[] randbuffer = new byte[0x2C];
            rng.GetBytes(randbuffer);
            Array.Copy(randbuffer, NCSD.cardinfoheader.InitialData, randbuffer.Length);
            NCSD.cardinfoheader.Reserved1   = new byte[0xC0];
            NCSD.cardinfoheader.NCCH0Header = new byte[0x100];
            Array.Copy(NCSD.NCCH_Array[0].header.Data, 0x100, NCSD.cardinfoheader.NCCH0Header, 0, 0x100);

            NCSD.BuildHeader();

            //NCSD is Initialized
            return(NCSD);
        }
Example #5
0
        // Sub methods that drive the operation
        internal static NCCH setNCCH(string EXEFS_PATH, string ROMFS_PATH, string EXHEADER_PATH, string TB_Serial, string LOGO_NAME, string _patchDir, bool _useRam)
        {
            SHA256Managed sha     = new SHA256Managed();
            NCCH          Content = new NCCH();

            Console.WriteLine("Adding Exheader...");
            Content.exheader    = new Exheader(EXHEADER_PATH);
            Content.plainregion = new byte[0]; //No plain region by default.
            if (Content.exheader.isPokemon())
            {
                Console.WriteLine("Detected Pokemon Game. Adding Plain Region...");
                if (Content.exheader.isXY())
                {
                    Content.plainregion = (byte[])Resources.ResourceManager.GetObject("XY");
                }
                else if (Content.exheader.isORAS())
                {
                    Content.plainregion = (byte[])Resources.ResourceManager.GetObject("ORAS");
                }
            }
            Console.WriteLine("Adding ExeFS...");
            Content.exefs = new ExeFS(EXEFS_PATH);
            Console.WriteLine("Adding RomFS...");
            Content.romfs = new RomFS(ROMFS_PATH, _patchDir, _useRam);

            Console.WriteLine("Adding Logo...");
            Content.logo = (byte[])Resources.ResourceManager.GetObject(LOGO_NAME);
            Console.WriteLine("Building NCCH Header...");
            ulong Len = 0x200; //NCCH Signature + NCCH Header

            Content.header = new NCCH.Header {
                Signature = new byte[0x100], Magic = 0x4843434E
            };
            Content.header.TitleId       = Content.header.ProgramId = Content.exheader.TitleID;
            Content.header.MakerCode     = 0x3130; //01
            Content.header.FormatVersion = 0x2;    //Default
            Content.header.LogoHash      = sha.ComputeHash(Content.logo);
            Content.header.ProductCode   = Encoding.ASCII.GetBytes(TB_Serial);
            Array.Resize(ref Content.header.ProductCode, 0x10);
            Content.header.ExheaderHash = Content.exheader.GetSuperBlockHash();
            Content.header.ExheaderSize = (uint)(Content.exheader.Data.Length);
            Len += Content.header.ExheaderSize + (uint)Content.exheader.AccessDescriptor.Length;
            Content.header.Flags = new byte[0x8];
            //FLAGS
            Content.header.Flags[3]   = 0;   // Crypto: 0 = <7.x, 1=7.x;
            Content.header.Flags[4]   = 1;   // Content Platform: 1 = CTR;
            Content.header.Flags[5]   = 0x3; // Content Type Bitflags: 1=Data, 2=Executable, 4=SysUpdate, 8=Manual, 0x10=Trial;
            Content.header.Flags[6]   = 0;   // MEDIA_UNIT_SIZE = 0x200*Math.Pow(2, Content.header.Flags[6]);
            Content.header.Flags[7]   = 1;   // FixedCrypto = 1, NoMountRomfs = 2; NoCrypto=4;
            Content.header.LogoOffset = (uint)(Len / MEDIA_UNIT_SIZE);
            Content.header.LogoSize   = (uint)(Content.logo.Length / MEDIA_UNIT_SIZE);
            Len += (uint)Content.logo.Length;
            Content.header.PlainRegionOffset = (uint)((Content.plainregion.Length > 0) ? Len / MEDIA_UNIT_SIZE : 0);
            Content.header.PlainRegionSize   = (uint)Content.plainregion.Length / MEDIA_UNIT_SIZE;
            Len += (uint)Content.plainregion.Length;
            Content.header.ExefsOffset         = (uint)(Len / MEDIA_UNIT_SIZE);
            Content.header.ExefsSize           = (uint)(Content.exefs.Data.Length / MEDIA_UNIT_SIZE);
            Content.header.ExefsSuperBlockSize = 0x200 / MEDIA_UNIT_SIZE; //Static 0x200 for exefs superblock
            Len += (uint)Content.exefs.Data.Length;
            Len  = (uint)Align(Len, 0x1000);                              //Romfs Start is aligned to 0x1000
            Content.header.RomfsOffset         = (uint)(Len / MEDIA_UNIT_SIZE);
            Content.header.RomfsSize           = (uint)(Content.romfs.dataStream.Length / MEDIA_UNIT_SIZE);
            Content.header.RomfsSuperBlockSize = Content.romfs.SuperBlockLen / MEDIA_UNIT_SIZE;
            Len += Content.header.RomfsSize * MEDIA_UNIT_SIZE;
            Content.header.ExefsHash = Content.exefs.SuperBlockHash;
            Content.header.RomfsHash = Content.romfs.SuperBlockHash;
            Content.header.Size      = (uint)(Len / MEDIA_UNIT_SIZE);
            //Build the Header byte[].
            Content.header.BuildHeader();

            return(Content);
        }
Example #6
0
        internal static bool writeROM(NCSD Rom, string SAVE_PATH)
        {
            NCCH Content = Rom.NCCH_Array[0];

            using (FileStream OutFileStream = new FileStream(SAVE_PATH, FileMode.Create))
            {
                Console.WriteLine("Writing NCSD Header...");
                OutFileStream.Write(Rom.Data, 0, Rom.Data.Length);
                Console.WriteLine("Writing NCCH...");
                OutFileStream.Write(Rom.NCCH_Array[0].header.Data, 0, Rom.NCCH_Array[0].header.Data.Length); //Write NCCH header
                //NO AES time.
                for (int i = 0; i < 3; i++)
                {
                    switch (i)
                    {
                    case 0:     //Exheader + AccessDesc
                        Console.WriteLine("Writing Exheader...");
                        byte[] inEncExheader = new byte[Rom.NCCH_Array[0].exheader.Data.Length + Rom.NCCH_Array[0].exheader.AccessDescriptor.Length];
                        Array.Copy(Rom.NCCH_Array[0].exheader.Data, inEncExheader, Rom.NCCH_Array[0].exheader.Data.Length);
                        Array.Copy(Rom.NCCH_Array[0].exheader.AccessDescriptor, 0, inEncExheader, Rom.NCCH_Array[0].exheader.Data.Length, Rom.NCCH_Array[0].exheader.AccessDescriptor.Length);
                        OutFileStream.Write(inEncExheader, 0, inEncExheader.Length);     // Write Exheader
                        break;

                    case 1:     //Exefs
                        Console.WriteLine("Writing Exefs...");
                        OutFileStream.Seek(0x4000 + Rom.NCCH_Array[0].header.ExefsOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
                        OutFileStream.Write(Rom.NCCH_Array[0].exefs.Data, 0, Rom.NCCH_Array[0].exefs.Data.Length);
                        break;

                    case 2:     //Romfs
                        Console.WriteLine("Writing Romfs...");
                        OutFileStream.Seek(0x4000 + Rom.NCCH_Array[0].header.RomfsOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin);

                        Rom.NCCH_Array[0].romfs.dataStream.Seek(0, SeekOrigin.Begin);
                        Stream InFileStream = Rom.NCCH_Array[0].romfs.dataStream;

                        uint  BUFFER_SIZE = 0;
                        ulong RomfsLen    = Rom.NCCH_Array[0].header.RomfsSize * MEDIA_UNIT_SIZE;

                        for (ulong j = 0; j < (RomfsLen); j += BUFFER_SIZE)
                        {
                            BUFFER_SIZE = (RomfsLen - j) > 0x400000 ? 0x400000 : (uint)(RomfsLen - j);
                            byte[] buf = new byte[BUFFER_SIZE];
                            InFileStream.Read(buf, 0, (int)BUFFER_SIZE);
                            OutFileStream.Write(buf, 0, (int)BUFFER_SIZE);
                        }

                        break;
                    }
                }
                Console.WriteLine("Writing Logo...");
                OutFileStream.Seek(0x4000 + Rom.NCCH_Array[0].header.LogoOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
                OutFileStream.Write(Rom.NCCH_Array[0].logo, 0, Rom.NCCH_Array[0].logo.Length);
                if (Rom.NCCH_Array[0].plainregion.Length > 0)
                {
                    Console.WriteLine("Writing Plain Region...");
                    OutFileStream.Seek(0x4000 + Rom.NCCH_Array[0].header.PlainRegionOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
                    OutFileStream.Write(Rom.NCCH_Array[0].plainregion, 0, Rom.NCCH_Array[0].plainregion.Length);
                }

                //NCSD Padding
                OutFileStream.Seek(Rom.header.OffsetSizeTable[Rom.NCCH_Array.Count - 1].Offset * MEDIA_UNIT_SIZE + Rom.header.OffsetSizeTable[Rom.NCCH_Array.Count - 1].Size * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
                ulong  TotalLen = Rom.header.MediaSize * MEDIA_UNIT_SIZE;
                byte[] Buffer   = Enumerable.Repeat((byte)0xFF, 0x400000).ToArray();
                Console.WriteLine("Writing NCSD Padding...");
                while ((ulong)OutFileStream.Position < TotalLen)
                {
                    int BUFFER_LEN = ((TotalLen - (ulong)OutFileStream.Position) < 0x400000) ? (int)(TotalLen - (ulong)OutFileStream.Position) : 0x400000;
                    OutFileStream.Write(Buffer, 0, BUFFER_LEN);
                }
            }

            Content.romfs.dataStream.Dispose();

            //Delete Temporary Romfs File
            if (Content.romfs.isTempFile)
            {
                File.Delete(RomFS.TempFile);
            }

            Console.WriteLine("Done!");
            return(true);
        }
Example #7
0
        internal static NCSD setNCSD(NCCH Content, bool Card2
                                     )
        {
            NCSD Rom = new NCSD {
                NCCH_Array = new List <NCCH>()
            };

            Rom.NCCH_Array.Add(Content);
            Console.WriteLine("Building NCSD Header...");
            Rom.Card2  = Card2;
            Rom.header = new NCSD.Header {
                Signature = new byte[0x100], Magic = 0x4453434E
            };
            ulong Length = 0x80 * 0x100000;                                    // 128 MB

            while (Length <= Content.header.Size * MEDIA_UNIT_SIZE + 0x400000) //Extra 4 MB for potential save data
            {
                Length *= 2;
            }
            Rom.header.MediaSize       = (uint)(Length / MEDIA_UNIT_SIZE);
            Rom.header.TitleId         = Content.exheader.TitleID;
            Rom.header.OffsetSizeTable = new NCSD.NCCH_Meta[8];
            ulong OSOfs = 0x4000;

            for (int i = 0; i < Rom.header.OffsetSizeTable.Length; i++)
            {
                NCSD.NCCH_Meta ncchm = new NCSD.NCCH_Meta();
                if (i < Rom.NCCH_Array.Count)
                {
                    ncchm.Offset = (uint)(OSOfs / MEDIA_UNIT_SIZE);
                    ncchm.Size   = Rom.NCCH_Array[i].header.Size;
                }
                else
                {
                    ncchm.Offset = 0;
                    ncchm.Size   = 0;
                }
                Rom.header.OffsetSizeTable[i] = ncchm;
                OSOfs += ncchm.Size * MEDIA_UNIT_SIZE;
            }
            Rom.header.flags       = new byte[0x8];
            Rom.header.flags[0]    = 0;                         // 0-255 seconds of waiting for save writing.
            Rom.header.flags[3]    = (byte)(Rom.Card2 ? 2 : 1); // Media Card Device: 1 = NOR Flash, 2 = None, 3 = BT
            Rom.header.flags[4]    = 1;                         // Media Platform Index: 1 = CTR
            Rom.header.flags[5]    = (byte)(Rom.Card2 ? 2 : 1); // Media Type Index: 0 = Inner Device, 1 = Card1, 2 = Card2, 3 = Extended Device
            Rom.header.flags[6]    = 0;                         // Media Unit Size. Same as NCCH.
            Rom.header.flags[7]    = 0;                         // Old Media Card Device.
            Rom.header.NCCHIdTable = new ulong[8];
            for (int i = 0; i < Rom.NCCH_Array.Count; i++)
            {
                Rom.header.NCCHIdTable[i] = Rom.NCCH_Array[i].header.TitleId;
            }
            Rom.cardinfoheader = new NCSD.CardInfoHeader
            {
                WritableAddress = (uint)(Rom.GetWritableAddress()),
                CardInfoBitmask = 0,
                CIN             = new NCSD.CardInfoHeader.CardInfoNotes
                {
                    Reserved0        = new byte[0xF8],
                    MediaSizeUsed    = OSOfs,
                    Reserved1        = 0,
                    Unknown          = 0,
                    Reserved2        = new byte[0xC],
                    CVerTitleId      = 0,
                    CVerTitleVersion = 0,
                    Reserved3        = new byte[0xCD6]
                },
                NCCH0TitleId = Rom.NCCH_Array[0].header.TitleId,
                Reserved0    = 0,
                InitialData  = new byte[0x30]
            };
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

            byte[] randbuffer = new byte[0x2C];
            rng.GetBytes(randbuffer);
            Array.Copy(randbuffer, Rom.cardinfoheader.InitialData, randbuffer.Length);
            Rom.cardinfoheader.Reserved1   = new byte[0xC0];
            Rom.cardinfoheader.NCCH0Header = new byte[0x100];
            Array.Copy(Rom.NCCH_Array[0].header.Data, 0x100, Rom.cardinfoheader.NCCH0Header, 0, 0x100);

            Rom.BuildHeader();

            //NCSD is Initialized
            return(Rom);
        }
Example #8
0
        internal static NCSD setNCSD(NCCH NCCH, bool Card2,
            ProgressBar PB_Show = null, RichTextBox TB_Progress = null)
        {
            PB_Show = PB_Show ?? new ProgressBar();
            TB_Progress = TB_Progress ?? new RichTextBox();
            updateTB(TB_Progress, "Building NCSD Header...");
            NCSD NCSD = new NCSD
            {
                NCCH_Array = new List<NCCH> {NCCH},
                Card2 = Card2,
                header = new NCSD.Header {Signature = new byte[0x100], Magic = 0x4453434E}
            };
            ulong Length = 0x80 * 0x100000; // 128 MB
            while (Length <= NCCH.header.Size * MEDIA_UNIT_SIZE + 0x400000) //Extra 4 MB for potential save data
            {
                Length *= 2;
            }
            NCSD.header.MediaSize = (uint)(Length / MEDIA_UNIT_SIZE);
            NCSD.header.TitleId = NCCH.exheader.TitleID;
            NCSD.header.OffsetSizeTable = new NCSD.NCCH_Meta[8];
            ulong OSOfs = 0x4000;
            for (int i = 0; i < NCSD.header.OffsetSizeTable.Length; i++)
            {
                NCSD.NCCH_Meta ncchm = new NCSD.NCCH_Meta();
                if (i < NCSD.NCCH_Array.Count)
                {
                    ncchm.Offset = (uint)(OSOfs / MEDIA_UNIT_SIZE);
                    ncchm.Size = NCSD.NCCH_Array[i].header.Size;
                }
                else
                {
                    ncchm.Offset = 0;
                    ncchm.Size = 0;
                }
                NCSD.header.OffsetSizeTable[i] = ncchm;
                OSOfs += ncchm.Size * MEDIA_UNIT_SIZE;
            }
            NCSD.header.flags = new byte[0x8];
            NCSD.header.flags[0] = 0; // 0-255 seconds of waiting for save writing.
            NCSD.header.flags[3] = (byte)(NCSD.Card2 ? 2 : 1); // Media Card Device: 1 = NOR Flash, 2 = None, 3 = BT
            NCSD.header.flags[4] = 1; // Media Platform Index: 1 = CTR
            NCSD.header.flags[5] = (byte)(NCSD.Card2 ? 2 : 1); // Media Type Index: 0 = Inner Device, 1 = Card1, 2 = Card2, 3 = Extended Device
            NCSD.header.flags[6] = 0; // Media Unit Size. Same as NCCH.
            NCSD.header.flags[7] = 0; // Old Media Card Device.
            NCSD.header.NCCHIdTable = new ulong[8];
            for (int i = 0; i < NCSD.NCCH_Array.Count; i++)
            {
                NCSD.header.NCCHIdTable[i] = NCSD.NCCH_Array[i].header.TitleId;
            }
            NCSD.cardinfoheader = new NCSD.CardInfoHeader
            {
                WritableAddress = (uint)NCSD.GetWritableAddress(),
                CardInfoBitmask = 0,
                CIN = new NCSD.CardInfoHeader.CardInfoNotes
                {
                    Reserved0 = new byte[0xF8],
                    MediaSizeUsed = OSOfs,
                    Reserved1 = 0,
                    Unknown = 0,
                    Reserved2 = new byte[0xC],
                    CVerTitleId = 0,
                    CVerTitleVersion = 0,
                    Reserved3 = new byte[0xCD6]
                },
                NCCH0TitleId = NCSD.NCCH_Array[0].header.TitleId,
                Reserved0 = 0,
                InitialData = new byte[0x30]
            };
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            byte[] randbuffer = new byte[0x2C];
            rng.GetBytes(randbuffer);
            Array.Copy(randbuffer, NCSD.cardinfoheader.InitialData, randbuffer.Length);
            NCSD.cardinfoheader.Reserved1 = new byte[0xC0];
            NCSD.cardinfoheader.NCCH0Header = new byte[0x100];
            Array.Copy(NCSD.NCCH_Array[0].header.Data, 0x100, NCSD.cardinfoheader.NCCH0Header, 0, 0x100);

            NCSD.BuildHeader();

            //NCSD is Initialized
            return NCSD;
        }
Example #9
0
        // Sub methods that drive the operation
        internal static NCCH setNCCH(string EXEFS_PATH, string ROMFS_PATH, string EXHEADER_PATH, string TB_Serial, string LOGO_NAME,
            ProgressBar PB_Show = null, RichTextBox TB_Progress = null)
        {
            PB_Show = PB_Show ?? new ProgressBar();
            TB_Progress = TB_Progress ?? new RichTextBox();

            updateTB(TB_Progress, "Creating NCCH...");
            updateTB(TB_Progress, "Adding Exheader...");
            NCCH NCCH = new NCCH
            {
                exheader = new Exheader(EXHEADER_PATH),
                plainregion = new byte[0]
            };
            if (NCCH.exheader.isPokemon())
            {
                updateTB(TB_Progress, "Detected Pokemon Game. Adding Plain Region...");
                if (NCCH.exheader.isXY())
                    NCCH.plainregion = (byte[])Resources.ResourceManager.GetObject("XY");
                else if (NCCH.exheader.isORAS())
                    NCCH.plainregion = (byte[])Resources.ResourceManager.GetObject("ORAS");
            }
            updateTB(TB_Progress, "Adding ExeFS...");
            NCCH.exefs = new ExeFS(EXEFS_PATH);
            updateTB(TB_Progress, "Adding RomFS...");
            NCCH.romfs = new RomFS(ROMFS_PATH);

            updateTB(TB_Progress, "Adding Logo...");
            NCCH.logo = (byte[])Resources.ResourceManager.GetObject(LOGO_NAME);
            updateTB(TB_Progress, "Assembling NCCH Header...");
            ulong Len = 0x200; //NCCH Signature + NCCH Header
            NCCH.header = new NCCH.Header { Signature = new byte[0x100], Magic = 0x4843434E };
            NCCH.header.TitleId = NCCH.header.ProgramId = NCCH.exheader.TitleID;
            NCCH.header.MakerCode = 0x3130; //01
            NCCH.header.FormatVersion = 0x2; //Default
            NCCH.header.LogoHash = new SHA256Managed().ComputeHash(NCCH.logo);
            NCCH.header.ProductCode = Encoding.ASCII.GetBytes(TB_Serial);
            Array.Resize(ref NCCH.header.ProductCode, 0x10);
            NCCH.header.ExheaderHash = NCCH.exheader.GetSuperBlockHash();
            NCCH.header.ExheaderSize = (uint)NCCH.exheader.Data.Length;
            Len += NCCH.header.ExheaderSize + (uint)NCCH.exheader.AccessDescriptor.Length;
            NCCH.header.Flags = new byte[0x8];
            //FLAGS
            NCCH.header.Flags[3] = 0; // Crypto: 0 = <7.x, 1=7.x;
            NCCH.header.Flags[4] = 1; // Content Platform: 1 = CTR;
            NCCH.header.Flags[5] = 0x3; // Content Type Bitflags: 1=Data, 2=Executable, 4=SysUpdate, 8=Manual, 0x10=Trial;
            NCCH.header.Flags[6] = 0; // MEDIA_UNIT_SIZE = 0x200*Math.Pow(2, Content.header.Flags[6]);
            NCCH.header.Flags[7] = 1; // FixedCrypto = 1, NoMountRomfs = 2; NoCrypto=4;
            NCCH.header.LogoOffset = (uint)(Len / MEDIA_UNIT_SIZE);
            NCCH.header.LogoSize = (uint)(NCCH.logo.Length / MEDIA_UNIT_SIZE);
            Len += (uint)NCCH.logo.Length;
            NCCH.header.PlainRegionOffset = (uint)(NCCH.plainregion.Length > 0 ? Len / MEDIA_UNIT_SIZE : 0);
            NCCH.header.PlainRegionSize = (uint)NCCH.plainregion.Length / MEDIA_UNIT_SIZE;
            Len += (uint)NCCH.plainregion.Length;
            NCCH.header.ExefsOffset = (uint)(Len / MEDIA_UNIT_SIZE);
            NCCH.header.ExefsSize = (uint)(NCCH.exefs.Data.Length / MEDIA_UNIT_SIZE);
            NCCH.header.ExefsSuperBlockSize = 0x200 / MEDIA_UNIT_SIZE; //Static 0x200 for exefs superblock
            Len += (uint)NCCH.exefs.Data.Length;
            Len = (uint)Align(Len, 0x1000); //Romfs Start is aligned to 0x1000
            NCCH.header.RomfsOffset = (uint)(Len / MEDIA_UNIT_SIZE);
            NCCH.header.RomfsSize = (uint)(new FileInfo(NCCH.romfs.FileName).Length / MEDIA_UNIT_SIZE);
            NCCH.header.RomfsSuperBlockSize = NCCH.romfs.SuperBlockLen / MEDIA_UNIT_SIZE;
            Len += NCCH.header.RomfsSize * MEDIA_UNIT_SIZE;
            NCCH.header.ExefsHash = NCCH.exefs.SuperBlockHash;
            NCCH.header.RomfsHash = NCCH.romfs.SuperBlockHash;
            NCCH.header.Size = (uint)(Len / MEDIA_UNIT_SIZE);
            //Build the Header byte[].
            updateTB(TB_Progress, "Building NCCH Header...");
            NCCH.header.BuildHeader();

            return NCCH;
        }