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 + "."); })); }
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); }
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(); } })); }