private void btnBuildHFS0_Click(object sender, EventArgs e) { clearReadData(); if (!prepareInOutDialogs()) { try { HFS0Manager.BuildHFS0(inDirDialog.SelectedPath, outFileDialog.FileName); MessageBox.Show("Sucessfully build the file!"); System.Diagnostics.Process.Start("explorer.exe", "/select, \"" + outFileDialog.FileName + "\""); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } } else { MessageBox.Show("Error when setting the paths!"); } }
private void btnAutoXCI_Click(object sender, EventArgs e) { clearReadData(); if (!prepareInOutDialogs(Environment.CurrentDirectory, "XCI-File|*.xci")) { try { string inPath = Path.Combine(inDirDialog.SelectedPath); string outPath = Path.Combine(outFileDialog.FileName); string tmpPath = Path.Combine(inPath, "root_tmp"); Directory.CreateDirectory(tmpPath); HFS0Manager.BuildHFS0(Path.Combine(inPath, "secure"), Path.Combine(tmpPath, "secure")); HFS0Manager.BuildHFS0(Path.Combine(inPath, "normal"), Path.Combine(tmpPath, "normal")); HFS0Manager.BuildHFS0(Path.Combine(inPath, "update"), Path.Combine(tmpPath, "update")); if (Directory.Exists(Path.Combine(inPath, "logo"))) { HFS0Manager.BuildHFS0(Path.Combine(inPath, "logo"), Path.Combine(tmpPath, "logo")); } HFS0Manager.BuildHFS0(tmpPath, Path.Combine(inPath, "root.hfs0")); XCIManager.BuildXCI(inPath, outPath); File.Delete(Path.Combine(inPath, "root.hfs0")); Directory.Delete(tmpPath, true); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } } else { MessageBox.Show("Error when setting the paths!"); } }
internal static bool BuildXCI(string inDir, string outFile) { // root.hfs0 contains secure/update/normal which are hfs0 on their owno string rootPath = Path.Combine(inDir, "root.hfs0"); // gameData.ini contains vital data to build the XCI string iniPath = Path.Combine(inDir, "game_info.ini"); if (!File.Exists(rootPath)) { Console.WriteLine("[ERR] {0} does not exist.", rootPath); return(false); } xci_header header = new xci_header(); gamecard_info gcInfo = new gamecard_info(); // Static stuff header.Magic = 0x44414548; // HEAD < -- XCI Header header.BackupAreaAddress = 0xFFFFFFFF; // This is probably reserved for future use header.HeaderVersion = (byte)0x0; // This is probably reserved for future use header.Flag = 0; // This is probably reserved for future use header.SecureModeFlag = 1; // Secure mode enabled header.TitleKeyFlag = 2; header.KeyFlag = 0; // Fake RSA signature byte[] fakeSignature = new byte[XCI_SIGNATURE_SIZE]; mainForm.Rand.NextBytes(fakeSignature); header.Signature = fakeSignature; // Ini loaded stuff if (File.Exists(iniPath)) { IniFile iniFile = new IniFile(iniPath); // Header header.KEK = byte.Parse(iniFile.Read("KEKIndex", "XCI_Header")); header.GamecardIV = iniFile.ReadBytes("GamecardIV", "XCI_Header"); header.InitialDataHash = iniFile.ReadBytes("InitialDataHash", "XCI_Header"); header.PackageID = UInt64.Parse(iniFile.Read("PackageID", "XCI_Header")); // Gamecard Info gcInfo.Version = UInt64.Parse(iniFile.Read("Version", "GameCard_Info")); gcInfo.AccessControlFlags = UInt32.Parse(iniFile.Read("AccessControlFlags", "GameCard_Info")); gcInfo.ReadWaitTime = UInt32.Parse(iniFile.Read("ReadWaitTime", "GameCard_Info")); gcInfo.ReadWaitTime2 = UInt32.Parse(iniFile.Read("ReadWaitTime2", "GameCard_Info")); gcInfo.WriteWriteTime = UInt32.Parse(iniFile.Read("WriteWriteTime", "GameCard_Info")); gcInfo.WriteWriteTime2 = UInt32.Parse(iniFile.Read("WriteWriteTime2", "GameCard_Info")); gcInfo.FirmwareMode = UInt32.Parse(iniFile.Read("FirmwareMode", "GameCard_Info")); gcInfo.CUPVersion = UInt32.Parse(iniFile.Read("CUPVersion", "GameCard_Info")); gcInfo.CUPID = UInt64.Parse(iniFile.Read("CUPID", "GameCard_Info")); } else { Console.WriteLine("[WARN] {0} does not exist. Data will be randomized (and the XCI could not work)", iniPath); // Header header.KEK = 0; mainForm.Rand.NextBytes(header.GamecardIV); header.PackageID = Utils.LongRandom(0, 100000000000000000, mainForm.Rand); // Gamecard Info - Taken from Cave Story (and pretty much universal) gcInfo.Version = 1; gcInfo.AccessControlFlags = 10551313; gcInfo.ReadWaitTime = 5000; gcInfo.ReadWaitTime2 = 0; gcInfo.WriteWriteTime = 0; gcInfo.WriteWriteTime2 = 0; gcInfo.FirmwareMode = 790784; gcInfo.CUPVersion = 450; gcInfo.CUPID = 72057594037930006; } // Read root.hfs0 raw (for header size and hash) byte[] rootHeader = HFS0Manager.GetHFS0Header(rootPath); header.HFS0HeaderSize = Convert.ToUInt32(rootHeader.Length); // hfs0 should be 0x200 aligned in order to properly work. // TODO should it? if (header.HFS0HeaderSize % 0x200 != 0) { Console.WriteLine("[WARN] root.hfs0 is not 0x200 aligned."); } // Calculating SHA256 of root.hfs0 header header.HFS0HeaderHash = mainForm.SHA256.ComputeHash(rootHeader); // Read root.hfs0 (for partition details) HFS0Manager.hfs0_header rootHeaderManaged = new HFS0Manager.hfs0_header(); List <HFS0Manager.hfs0_file_entry> rootFileEntries = new List <HFS0Manager.hfs0_file_entry>(); List <string> rootStringTable = new List <string>(); HFS0Manager.GetHFS0Managed(rootPath, ref rootHeaderManaged, ref rootFileEntries, ref rootStringTable); int partitionIndex = 0; foreach (var fileName in rootStringTable) { if (fileName == "secure") { UInt32 secureOffset = Convert.ToUInt32(HFS0_START + header.HFS0HeaderSize + rootFileEntries[partitionIndex].Offset); if (secureOffset % 0x200 != 0) { Console.WriteLine("[WARN] secure.hfs0 is not 0x200 aligned."); } // This is fine since we force partition order header.SecureOffset = header.NormalAreaEndAddress = (UInt32)(secureOffset / 0x200); } partitionIndex++; } header.HFS0Offset = HFS0_START; UInt32 CardSize = Convert.ToUInt32(HFS0_START + (ulong)(new FileInfo(rootPath).Length)); if (CardSize % 0x200 != 0) { Console.WriteLine("[WARN] card size is not 0x200 aligned."); } header.CardSize = CardSize / 0x200 - 1; // Excludes signature if (header.CardSize * 0x200l > 16l * 1024l * 1024l * 1024l) { header.CartType = CartridgeType.CARTSIZE_32GB; } else if (header.CardSize * 0x200l > 8l * 1024l * 1024l * 1024l) { header.CartType = CartridgeType.CARTSIZE_16GB; } else if (header.CardSize * 0x200l > 4l * 1024l * 1024l * 1024l) { header.CartType = CartridgeType.CARTSIZE_8GB; } else if (header.CardSize * 0x200l > 2l * 1024l * 1024l * 1024l) { header.CartType = CartridgeType.CARTSIZE_4GB; } else { header.CartType = CartridgeType.CARTSIZE_2GB; } // Write encrypted gamecardinfo header byte[] rawGameCardInfo = Utils.StructureToByteArray(gcInfo); // REVERSE THA IV byte[] iv_flipped = new byte[XCIManager.XCI_IV_SIZE]; Array.Copy(header.GamecardIV, iv_flipped, XCIManager.XCI_IV_SIZE); Array.Reverse(iv_flipped); // GameCardInfo Encrypt var encrypt = mainForm.AES128CBC.CreateEncryptor(XCIManager.XCI_GAMECARDINFO_KEY, iv_flipped); var gcInfoStream = new MemoryStream(rawGameCardInfo); var gcCryptoStream = new CryptoStream(gcInfoStream, encrypt, CryptoStreamMode.Read); // Create the struct byte[] rawEncryptedGameCardInfo = new byte[XCI_GAMECARD_INFO_LENGTH]; gcCryptoStream.Read(rawEncryptedGameCardInfo, 0, XCI_GAMECARD_INFO_LENGTH); // Clean stuff up gcInfoStream.Close(); gcCryptoStream.Close(); encrypt.Dispose(); header.GamecardInfo = rawEncryptedGameCardInfo; FileStream fs; BinaryWriter bw; // Opening output file try { fs = new FileStream(outFile, FileMode.Create, FileAccess.Write); bw = new BinaryWriter(fs); } catch (Exception ex) { Console.WriteLine("[ERR] Cannot create {0}.\n{1}", outFile, ex.Message); return(false); } // Writing header bw.Write(Utils.StructureToByteArray(header)); // Writing padding int toWrite00 = 0x6E00; for (int i = 0; i < toWrite00; i++) { bw.Write((byte)0x0); } int toWriteFF = 0x8000; for (int i = 0; i < toWriteFF; i++) { bw.Write((byte)0xFF); } // Writing data FileStream stream = new FileStream(rootPath, FileMode.Open, FileAccess.Read); byte[] buffer = new Byte[1024 * 5]; int count = 0; while ((count = stream.Read(buffer, 0, buffer.Length)) > 0) { bw.Write(buffer, 0, count); } stream.Close(); return(true); }