Example #1
0
 public void WriteBinary(string tempFile, string outFile)
 {
     using (FileStream fs = new FileStream(outFile, FileMode.Create))
     {
         using (BinaryWriter writer = new BinaryWriter(fs))
         {
             using (FileStream fileStream = new FileStream(tempFile, FileMode.Open, FileAccess.Read))
             {
                 uint BUFFER_SIZE = 0x400000; // 4MB Buffer
                 PB_Show.Invoke((Action)(() =>
                 {
                     PB_Show.Minimum = 0;
                     PB_Show.Maximum = (int)(fileStream.Length / BUFFER_SIZE);
                     PB_Show.Value = 0;
                     PB_Show.Step = 1;
                 }));
                 byte[] buffer = new byte[BUFFER_SIZE];
                 while (true)
                 {
                     int count = fileStream.Read(buffer, 0, buffer.Length);
                     if (count != 0)
                     {
                         writer.Write(buffer, 0, count);
                         PB_Show.Invoke((Action)(() => PB_Show.PerformStep()));
                     }
                     else
                     {
                         break;
                     }
                 }
             }
             writer.Flush();
         }
     }
     File.Delete(TempFile);
     Invoke((Action)(() =>
     {
         MessageBox.Show("Wrote RomFS to " + outFile + ".");
     }));
 }
Example #2
0
        public static bool rehashCRR(string PATH_CRR, string PATH_CRO, bool saveCRO = true, bool saveCRR = true, RichTextBox TB_Progress = null, ProgressBar PB_Show = null)
        {
            // Get CRO files
            string[] CROFiles = Directory.GetFiles(PATH_CRO);

            // Weed out anything that isn't a .cro
            CROFiles = CROFiles.Where(t => Path.GetExtension(t) == ".cro").ToArray();
            // Open the CRR
            byte[] CRR             = File.ReadAllBytes(PATH_CRR);
            int    hashTableOffset = BitConverter.ToInt32(CRR, 0x350);
            int    hashCount       = BitConverter.ToInt32(CRR, 0x354);

            // A little validation...
            if (hashCount != CROFiles.Length)
            {
                updateTB(TB_Progress,
                         $"Amount of input file-hashes does not equal the hash count in CRR. Expected {hashCount}, got {CROFiles.Length}.");
                updateTB(TB_Progress, "Did not modify files. Aborting.");
                return(false);
            }

            // Initialize Update Display
            if (TB_Progress == null)
            {
                TB_Progress = new RichTextBox();
            }
            if (PB_Show == null)
            {
                PB_Show = new ProgressBar();
            }
            if (PB_Show.InvokeRequired)
            {
                PB_Show.Invoke((MethodInvoker) delegate { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = CROFiles.Length; });
            }
            else
            {
                PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = CROFiles.Length;
            }
            updateTB(TB_Progress, "");
            updateTB(TB_Progress, "Computing hashes for " + CROFiles.Length + " CRO files.");

            // Store Hashes as Strings (hacky way to sort byte[]'s against eachother
            string[] hashes = new string[CROFiles.Length];
            for (int i = 0; i < hashes.Length; i++)
            {
                byte[] data = File.ReadAllBytes(CROFiles[i]);
                byte[] hash = hashCRO(ref data);
                hashes[i] = getHexString(hash).ToUpper();
                if (saveCRO)
                {
                    File.WriteAllBytes(CROFiles[i], data);
                }

                if (PB_Show.InvokeRequired)
                {
                    PB_Show.Invoke((MethodInvoker)(() => PB_Show.PerformStep()));
                }
                else
                {
                    PB_Show.PerformStep();
                }
            }
            updateTB(TB_Progress, "Hashes computed, now sorting."); // Don't need to fiddle the ProgressBar because this should be quite quick.
            string[] hashCopy = (string[])hashes.Clone();           // Store an unsorted list for later.
            Array.Sort(hashes, string.Compare);
            // Convert Hash Strings to Bytes
            byte[][] hashData = new byte[hashes.Length][];
            for (int i = 0; i < hashes.Length; i++)
            {
                hashData[i] = StringToByteArray(hashes[i]);
            }

            updateTB(TB_Progress, "Hashes sorted, writing hashes to CRR.");

            // Loop to check which CROs have to be updated. Do this separate from overwriting so we don't overwrite hashes for other CROs (yet).
            int updatedCTR = 0;

            for (int i = 0; i < hashData.Length; i++)
            {
                // Check to see if the hash is currently in the table already.
                int index = IndexOfBytes(CRR, hashData[i], 0, CRR.Length);
                if (index < 0)
                {
                    // CRO was updated.
                    string file = CROFiles[Array.IndexOf(hashCopy, hashes[i])];
                    updateTB(TB_Progress, $"{Path.GetFileName(file)} hash has been updated.");
                    updatedCTR++;
                }
            }
            // Store Hashes in CRR
            for (int i = 0; i < hashData.Length; i++)
            {
                Array.Copy(hashData[i], 0, CRR, hashTableOffset + (0x20 * i), 0x20);
            }

            updateTB(TB_Progress,
                     updatedCTR > 0
                    ? $"{updatedCTR} hashes have been updated."
                    : "CRR is fine. No modifications are necessary.");

            // Save File
            if (saveCRR && updatedCTR > 0)
            {
                File.WriteAllBytes(PATH_CRR, CRR);
                updateTB(TB_Progress, "Wrote CRR.");
            }
            else
            {
                updateTB(TB_Progress, "CRR has not been updated.");
            }
            return(true);
        }
Example #3
0
        private void MakeRomFSData(RomfsFile[] RomFiles, MemoryStream metadata)
        {
            TempFile = Path.GetRandomFileName();
            TB_Progress.Invoke((Action)(() => UpdateTB_Progress("Computing IVFC Header Data...")));
            IVFCInfo ivfc = new IVFCInfo();

            ivfc.Levels = new IVFCLevel[3];
            for (int i = 0; i < ivfc.Levels.Length; i++)
            {
                ivfc.Levels[i]           = new IVFCLevel();
                ivfc.Levels[i].BlockSize = 0x1000;
            }
            ivfc.Levels[2].DataLength = RomfsFile.GetDataBlockLength(RomFiles, (ulong)metadata.Length);
            ivfc.Levels[1].DataLength = (Align(ivfc.Levels[2].DataLength, ivfc.Levels[2].BlockSize) / ivfc.Levels[2].BlockSize) * 0x20; //0x20 per SHA256 hash
            ivfc.Levels[0].DataLength = (Align(ivfc.Levels[1].DataLength, ivfc.Levels[1].BlockSize) / ivfc.Levels[1].BlockSize) * 0x20; //0x20 per SHA256 hash
            ulong MasterHashLen = (Align(ivfc.Levels[0].DataLength, ivfc.Levels[0].BlockSize) / ivfc.Levels[0].BlockSize) * 0x20;
            ulong lofs          = 0;

            for (int i = 0; i < ivfc.Levels.Length; i++)
            {
                ivfc.Levels[i].HashOffset = lofs;
                lofs += Align(ivfc.Levels[i].DataLength, ivfc.Levels[i].BlockSize);
            }
            uint IVFC_MAGIC      = 0x43465649; //IVFC
            uint RESERVED        = 0x0;
            uint HeaderLen       = 0x5C;
            uint MEDIA_UNIT_SIZE = 0x200;

            byte[]     SuperBlockHash = new byte[0x20];
            FileStream OutFileStream  = new FileStream(TempFile, FileMode.Create, FileAccess.ReadWrite);

            try
            {
                OutFileStream.Seek(0, SeekOrigin.Begin);
                OutFileStream.Write(BitConverter.GetBytes(IVFC_MAGIC), 0, 0x4);
                OutFileStream.Write(BitConverter.GetBytes(0x10000), 0, 0x4);
                OutFileStream.Write(BitConverter.GetBytes(MasterHashLen), 0, 0x4);
                for (int i = 0; i < ivfc.Levels.Length; i++)
                {
                    OutFileStream.Write(BitConverter.GetBytes(ivfc.Levels[i].HashOffset), 0, 0x8);
                    OutFileStream.Write(BitConverter.GetBytes(ivfc.Levels[i].DataLength), 0, 0x8);
                    OutFileStream.Write(BitConverter.GetBytes((int)(Math.Log(ivfc.Levels[i].BlockSize, 2))), 0, 0x4);
                    OutFileStream.Write(BitConverter.GetBytes(RESERVED), 0, 0x4);
                }
                OutFileStream.Write(BitConverter.GetBytes(HeaderLen), 0, 0x4);
                //IVFC Header is Written.
                OutFileStream.Seek((long)Align(MasterHashLen + 0x60, ivfc.Levels[0].BlockSize), SeekOrigin.Begin);
                byte[] metadataArray = metadata.ToArray();
                OutFileStream.Write(metadataArray, 0, metadataArray.Length);
                long baseOfs = OutFileStream.Position;
                TB_Progress.Invoke((Action)(() => UpdateTB_Progress("Writing Level 2 Data...")));
                PB_Show.Invoke((Action)(() =>
                {
                    PB_Show.Minimum = 0;
                    PB_Show.Maximum = RomFiles.Length;
                    PB_Show.Value = 0;
                    PB_Show.Step = 1;
                }));
                for (int i = 0; i < RomFiles.Length; i++)
                {
                    OutFileStream.Seek((long)(baseOfs + (long)RomFiles[i].Offset), SeekOrigin.Begin);
                    using (FileStream inStream = new FileStream(RomFiles[i].FullName, FileMode.Open, FileAccess.Read))
                    {
                        while (inStream.Position < inStream.Length)
                        {
                            byte[] buffer = new byte[inStream.Length - inStream.Position > 0x100000 ? 0x100000 : inStream.Length - inStream.Position];
                            inStream.Read(buffer, 0, buffer.Length);
                            OutFileStream.Write(buffer, 0, buffer.Length);
                        }
                    }
                    PB_Show.Invoke((Action)(() => PB_Show.PerformStep()));
                }
                long          hashBaseOfs = (long)Align((ulong)OutFileStream.Position, ivfc.Levels[2].BlockSize);
                long          hOfs        = (long)Align(MasterHashLen, ivfc.Levels[0].BlockSize);
                long          cOfs        = hashBaseOfs + (long)ivfc.Levels[1].HashOffset;
                SHA256Managed sha         = new SHA256Managed();
                for (int i = ivfc.Levels.Length - 1; i >= 0; i--)
                {
                    TB_Progress.Invoke((Action)(() => UpdateTB_Progress("Computing Level " + i + " Hashes...")));
                    byte[] buffer = new byte[(int)ivfc.Levels[i].BlockSize];
                    PB_Show.Invoke((Action)(() =>
                    {
                        PB_Show.Minimum = 0;
                        PB_Show.Maximum = (int)(ivfc.Levels[i].DataLength / ivfc.Levels[i].BlockSize);
                        PB_Show.Value = 0;
                        PB_Show.Step = 1;
                    }));
                    for (long ofs = 0; ofs < (long)ivfc.Levels[i].DataLength; ofs += ivfc.Levels[i].BlockSize)
                    {
                        OutFileStream.Seek(hOfs, SeekOrigin.Begin);
                        OutFileStream.Read(buffer, 0, (int)ivfc.Levels[i].BlockSize);
                        hOfs = OutFileStream.Position;
                        byte[] hash = sha.ComputeHash(buffer);
                        OutFileStream.Seek(cOfs, SeekOrigin.Begin);
                        OutFileStream.Write(hash, 0, hash.Length);
                        cOfs = OutFileStream.Position;
                        PB_Show.Invoke((Action)(() => PB_Show.PerformStep()));
                    }
                    if (i == 2)
                    {
                        long len = OutFileStream.Position;
                        if (len % 0x1000 != 0)
                        {
                            len = (long)Align((ulong)len, 0x1000);
                            byte[] buf = new byte[len - OutFileStream.Position];
                            OutFileStream.Write(buf, 0, buf.Length);
                        }
                    }
                    if (i > 0)
                    {
                        hOfs = hashBaseOfs + (long)ivfc.Levels[i - 1].HashOffset;
                        if (i > 1)
                        {
                            cOfs = hashBaseOfs + (long)ivfc.Levels[i - 2].HashOffset;
                        }
                        else
                        {
                            cOfs = (long)Align(HeaderLen, PADDING_ALIGN);
                        }
                    }
                }
                OutFileStream.Seek(0, SeekOrigin.Begin);
                uint   SuperBlockLen = (uint)Align(MasterHashLen + 0x60, MEDIA_UNIT_SIZE);
                byte[] MasterHashes  = new byte[SuperBlockLen];
                OutFileStream.Read(MasterHashes, 0, (int)SuperBlockLen);
                SuperBlockHash = sha.ComputeHash(MasterHashes);
            }
            finally
            {
                if (OutFileStream != null)
                {
                    OutFileStream.Dispose();
                }
            }
            TB_Progress.Invoke((Action)(() => UpdateTB_Progress("RomFS Super Block Hash: " + ByteArrayToString(SuperBlockHash))));
            TB_Progress.Invoke((Action)(() => UpdateTB_Progress("Prompting to Save...")));
            SaveFileDialog sfd = new SaveFileDialog();

            Invoke((Action)(() =>
            {
                if (sfd.ShowDialog() == DialogResult.OK)
                {
                    TB_Progress.Invoke((Action)(() => UpdateTB_Progress("Writing Binary to " + sfd.FileName + "...")));
                    Thread thread = new Thread(() => WriteBinary(TempFile, sfd.FileName));
                    thread.IsBackground = true;
                    thread.Start();
                }
            }));
        }