internal static bool writeROM(NCSD NCSD, string SAVE_PATH, ProgressBar PB_Show = null, RichTextBox TB_Progress = null) { 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(NCSD.Data, 0, NCSD.Data.Length); updateTB(TB_Progress, "Writing NCCH..."); OutFileStream.Write(NCSD.NCCH_Array[0].header.Data, 0, NCSD.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, NCSD.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[NCSD.NCCH_Array[0].exheader.Data.Length + NCSD.NCCH_Array[0].exheader.AccessDescriptor.Length]; byte[] outEncExheader = new byte[NCSD.NCCH_Array[0].exheader.Data.Length + NCSD.NCCH_Array[0].exheader.AccessDescriptor.Length]; Array.Copy(NCSD.NCCH_Array[0].exheader.Data, inEncExheader, NCSD.NCCH_Array[0].exheader.Data.Length); Array.Copy(NCSD.NCCH_Array[0].exheader.AccessDescriptor, 0, inEncExheader, NCSD.NCCH_Array[0].exheader.Data.Length, NCSD.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 + NCSD.NCCH_Array[0].header.ExefsOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin); byte[] OutExefs = new byte[NCSD.NCCH_Array[0].exefs.Data.Length]; aesctr.TransformBlock(NCSD.NCCH_Array[0].exefs.Data, 0, NCSD.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 + NCSD.NCCH_Array[0].header.RomfsOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin); using (FileStream InFileStream = new FileStream(NCSD.NCCH_Array[0].romfs.FileName, FileMode.Open, FileAccess.Read)) { uint BUFFER_SIZE; ulong RomfsLen = NCSD.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 + NCSD.NCCH_Array[0].header.LogoOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin); OutFileStream.Write(NCSD.NCCH_Array[0].logo, 0, NCSD.NCCH_Array[0].logo.Length); if (NCSD.NCCH_Array[0].plainregion.Length > 0) { updateTB(TB_Progress, "Writing Plain Region..."); OutFileStream.Seek(0x4000 + NCSD.NCCH_Array[0].header.PlainRegionOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin); OutFileStream.Write(NCSD.NCCH_Array[0].plainregion, 0, NCSD.NCCH_Array[0].plainregion.Length); } //NCSD Padding OutFileStream.Seek(NCSD.header.OffsetSizeTable[NCSD.NCCH_Array.Count - 1].Offset * MEDIA_UNIT_SIZE + NCSD.header.OffsetSizeTable[NCSD.NCCH_Array.Count - 1].Size * MEDIA_UNIT_SIZE, SeekOrigin.Begin); ulong TotalLen = NCSD.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 (NCSD.NCCH_Array[0].romfs.isTempFile) { File.Delete(NCSD.NCCH_Array[0].romfs.FileName); } updateTB(TB_Progress, "Done!"); return(true); }
internal static bool writeROM(NCSD NCSD, string SAVE_PATH, ProgressBar PB_Show = null, RichTextBox TB_Progress = null) { 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(NCSD.Data, 0, NCSD.Data.Length); updateTB(TB_Progress, "Writing NCCH..."); OutFileStream.Write(NCSD.NCCH_Array[0].header.Data, 0, NCSD.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, NCSD.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[NCSD.NCCH_Array[0].exheader.Data.Length + NCSD.NCCH_Array[0].exheader.AccessDescriptor.Length]; byte[] outEncExheader = new byte[NCSD.NCCH_Array[0].exheader.Data.Length + NCSD.NCCH_Array[0].exheader.AccessDescriptor.Length]; Array.Copy(NCSD.NCCH_Array[0].exheader.Data, inEncExheader, NCSD.NCCH_Array[0].exheader.Data.Length); Array.Copy(NCSD.NCCH_Array[0].exheader.AccessDescriptor, 0, inEncExheader, NCSD.NCCH_Array[0].exheader.Data.Length, NCSD.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 + NCSD.NCCH_Array[0].header.ExefsOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin); byte[] OutExefs = new byte[NCSD.NCCH_Array[0].exefs.Data.Length]; aesctr.TransformBlock(NCSD.NCCH_Array[0].exefs.Data, 0, NCSD.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 + NCSD.NCCH_Array[0].header.RomfsOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin); using (FileStream InFileStream = new FileStream(NCSD.NCCH_Array[0].romfs.FileName, FileMode.Open, FileAccess.Read)) { uint BUFFER_SIZE; ulong RomfsLen = NCSD.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 + NCSD.NCCH_Array[0].header.LogoOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin); OutFileStream.Write(NCSD.NCCH_Array[0].logo, 0, NCSD.NCCH_Array[0].logo.Length); if (NCSD.NCCH_Array[0].plainregion.Length > 0) { updateTB(TB_Progress, "Writing Plain Region..."); OutFileStream.Seek(0x4000 + NCSD.NCCH_Array[0].header.PlainRegionOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin); OutFileStream.Write(NCSD.NCCH_Array[0].plainregion, 0, NCSD.NCCH_Array[0].plainregion.Length); } //NCSD Padding OutFileStream.Seek(NCSD.header.OffsetSizeTable[NCSD.NCCH_Array.Count - 1].Offset * MEDIA_UNIT_SIZE + NCSD.header.OffsetSizeTable[NCSD.NCCH_Array.Count - 1].Size * MEDIA_UNIT_SIZE, SeekOrigin.Begin); ulong TotalLen = NCSD.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 (NCSD.NCCH_Array[0].romfs.isTempFile) File.Delete(NCSD.NCCH_Array[0].romfs.FileName); updateTB(TB_Progress, "Done!"); return true; }