diff --git a/NUS Downloader/Form1.Designer.cs b/NUS Downloader/Form1.Designer.cs index aae886f..f370bd9 100644 --- a/NUS Downloader/Form1.Designer.cs +++ b/NUS Downloader/Form1.Designer.cs @@ -116,6 +116,8 @@ this.europePALToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.japanNTSCJToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.koreaToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.saveaswadbox = new System.Windows.Forms.CheckBox(); + this.deletecontentsbox = new System.Windows.Forms.CheckBox(); this.databaseStrip.SuspendLayout(); this.tmdgpbox.SuspendLayout(); this.ticketgpbox.SuspendLayout(); @@ -169,13 +171,14 @@ // packbox // this.packbox.AutoSize = true; - this.packbox.Location = new System.Drawing.Point(12, 422); + this.packbox.Location = new System.Drawing.Point(12, 416); this.packbox.Name = "packbox"; this.packbox.Size = new System.Drawing.Size(92, 17); this.packbox.TabIndex = 6; this.packbox.Text = "Pack -> WAD"; this.packbox.UseVisualStyleBackColor = true; this.packbox.CheckedChanged += new System.EventHandler(this.packbox_CheckedChanged); + this.packbox.EnabledChanged += new System.EventHandler(this.packbox_EnabledChanged); // // dlprogress // @@ -191,11 +194,11 @@ this.localuse.Checked = true; this.localuse.CheckState = System.Windows.Forms.CheckState.Checked; this.localuse.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.localuse.Location = new System.Drawing.Point(12, 468); + this.localuse.Location = new System.Drawing.Point(104, 463); this.localuse.Name = "localuse"; - this.localuse.Size = new System.Drawing.Size(167, 17); + this.localuse.Size = new System.Drawing.Size(76, 17); this.localuse.TabIndex = 8; - this.localuse.Text = "Use/Keep Present Local Files"; + this.localuse.Text = "Local Files"; this.localuse.UseVisualStyleBackColor = true; // // NUSDownloader @@ -249,7 +252,7 @@ this.wadnamebox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.wadnamebox.Enabled = false; this.wadnamebox.Font = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.wadnamebox.Location = new System.Drawing.Point(102, 421); + this.wadnamebox.Location = new System.Drawing.Point(102, 416); this.wadnamebox.MaxLength = 99999; this.wadnamebox.Name = "wadnamebox"; this.wadnamebox.Size = new System.Drawing.Size(160, 18); @@ -258,21 +261,21 @@ // ignoreticket // this.ignoreticket.AutoSize = true; - this.ignoreticket.Location = new System.Drawing.Point(12, 445); + this.ignoreticket.Location = new System.Drawing.Point(104, 440); this.ignoreticket.Name = "ignoreticket"; - this.ignoreticket.Size = new System.Drawing.Size(135, 17); + this.ignoreticket.Size = new System.Drawing.Size(89, 17); this.ignoreticket.TabIndex = 18; - this.ignoreticket.Text = "Ignore Ticket if Missing"; + this.ignoreticket.Text = "Ignore Ticket"; this.ignoreticket.UseVisualStyleBackColor = true; // // decryptbox // this.decryptbox.AutoSize = true; - this.decryptbox.Location = new System.Drawing.Point(154, 445); + this.decryptbox.Location = new System.Drawing.Point(199, 440); this.decryptbox.Name = "decryptbox"; - this.decryptbox.Size = new System.Drawing.Size(108, 17); + this.decryptbox.Size = new System.Drawing.Size(63, 17); this.decryptbox.TabIndex = 19; - this.decryptbox.Text = "Decrypt Contents"; + this.decryptbox.Text = "Decrypt"; this.decryptbox.UseVisualStyleBackColor = true; // // databaseButton @@ -431,7 +434,7 @@ // truchabox // this.truchabox.AutoSize = true; - this.truchabox.Location = new System.Drawing.Point(184, 468); + this.truchabox.Location = new System.Drawing.Point(199, 463); this.truchabox.Name = "truchabox"; this.truchabox.Size = new System.Drawing.Size(60, 17); this.truchabox.TabIndex = 21; @@ -870,7 +873,7 @@ this.radioButton2.ImageAlign = System.Drawing.ContentAlignment.TopCenter; this.radioButton2.Location = new System.Drawing.Point(78, 385); this.radioButton2.Name = "radioButton2"; - this.radioButton2.Size = new System.Drawing.Size(74, 31); + this.radioButton2.Size = new System.Drawing.Size(74, 30); this.radioButton2.TabIndex = 13; this.radioButton2.UseVisualStyleBackColor = true; this.radioButton2.CheckedChanged += new System.EventHandler(this.radioButton2_CheckedChanged); @@ -944,40 +947,64 @@ this.koreaToolStripMenuItem.Size = new System.Drawing.Size(154, 22); this.koreaToolStripMenuItem.Text = "Korea"; // + // saveaswadbox + // + this.saveaswadbox.AutoSize = true; + this.saveaswadbox.Font = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.saveaswadbox.Location = new System.Drawing.Point(22, 437); + this.saveaswadbox.Name = "saveaswadbox"; + this.saveaswadbox.Size = new System.Drawing.Size(58, 16); + this.saveaswadbox.TabIndex = 43; + this.saveaswadbox.Text = "SaveAs"; + this.saveaswadbox.UseVisualStyleBackColor = true; + // + // deletecontentsbox + // + this.deletecontentsbox.AutoSize = true; + this.deletecontentsbox.Font = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.deletecontentsbox.Location = new System.Drawing.Point(22, 454); + this.deletecontentsbox.Name = "deletecontentsbox"; + this.deletecontentsbox.Size = new System.Drawing.Size(62, 28); + this.deletecontentsbox.TabIndex = 44; + this.deletecontentsbox.Text = "Delete\r\nContents"; + this.deletecontentsbox.UseVisualStyleBackColor = true; + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(539, 492); + this.Controls.Add(this.deletecontentsbox); this.Controls.Add(this.button3); this.Controls.Add(this.shamelessvariablelabel); this.Controls.Add(this.button1); this.Controls.Add(this.button17); this.Controls.Add(this.ticketgpbox); this.Controls.Add(this.tmdgpbox); - this.Controls.Add(this.truchabox); + this.Controls.Add(this.saveaswadbox); this.Controls.Add(this.databaseButton); this.Controls.Add(this.button5); this.Controls.Add(this.contentModBox); this.Controls.Add(this.button4); - this.Controls.Add(this.decryptbox); - this.Controls.Add(this.ignoreticket); this.Controls.Add(this.wadnamebox); this.Controls.Add(this.button7); + this.Controls.Add(this.truchabox); this.Controls.Add(this.label2); this.Controls.Add(this.titleversion); this.Controls.Add(this.button2); + this.Controls.Add(this.decryptbox); this.Controls.Add(this.label1); this.Controls.Add(this.radioButton1); this.Controls.Add(this.radioButton2); - this.Controls.Add(this.localuse); this.Controls.Add(this.dlprogress); this.Controls.Add(this.packbox); this.Controls.Add(this.statusbox); + this.Controls.Add(this.ignoreticket); this.Controls.Add(this.downloadstartbtn); this.Controls.Add(this.titleidbox); this.Controls.Add(this.Extrasbtn); this.Controls.Add(this.button6); + this.Controls.Add(this.localuse); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximizeBox = false; @@ -1086,6 +1113,8 @@ private System.Windows.Forms.ToolStripMenuItem europePALToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem japanNTSCJToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem koreaToolStripMenuItem; + private System.Windows.Forms.CheckBox saveaswadbox; + private System.Windows.Forms.CheckBox deletecontentsbox; } } diff --git a/NUS Downloader/Form1.cs b/NUS Downloader/Form1.cs index 401ba7a..6974475 100644 --- a/NUS Downloader/Form1.cs +++ b/NUS Downloader/Form1.cs @@ -22,7 +22,6 @@ namespace NUS_Downloader WebClient generalWC = new WebClient(); static RijndaelManaged rijndaelCipher; static bool dsidecrypt = false; - const string certs_MD5 = "7677AD47BAA5D6E3E313E72661FBDC16"; // Images do not compare unless globalized... Image green = Properties.Resources.bullet_green; @@ -42,6 +41,8 @@ namespace NUS_Downloader byte[] cert_total_sha1 = new byte[20] {0xAC, 0xE0, 0xF1, 0x5D, 0x2A, 0x85, 0x1C, 0x38, 0x3F, 0xE4, 0x65, 0x7A, 0xFC, 0x38, 0x40, 0xD6, 0xFF, 0xE3, 0x0A, 0xD0}; + string WAD_Saveas_Filename; + /* public struct WADHeader { public int HeaderSize; @@ -52,7 +53,7 @@ namespace NUS_Downloader public int TMDSize; public int DataSize; public int FooterSize; - }; + };*/ public struct TitleContent { @@ -171,6 +172,10 @@ namespace NUS_Downloader this.Size = this.MinimumSize; } + /// + /// Checks certain file existances, etc. + /// + /// private bool BootChecks() { // Success? @@ -265,6 +270,11 @@ namespace NUS_Downloader return result; } + /// + /// Gets the database version. + /// + /// The database file. + /// private string GetDatabaseVersion(string file) { // Read version of Database.xml @@ -284,6 +294,9 @@ namespace NUS_Downloader extrasStrip.Show(Extrasbtn, 2, 2); } + /// + /// Loads the title info from TMD. + /// private void LoadTitleFromTMD() { // Show dialog for opening TMD file... @@ -350,6 +363,11 @@ namespace NUS_Downloader } } + /// + /// Returns needed IOS from TMD. + /// + /// The TMD. + /// private string IOSNeededFromTMD(byte[] tmd) { string sysversion = ""; @@ -361,6 +379,11 @@ namespace NUS_Downloader return sysversion; } + /// + /// Returns content count of TMD + /// + /// The TMD. + /// int Count of Contents private int ContentCount(byte[] tmd) { // nbr_cont (0xDE) len=0x02 @@ -369,6 +392,11 @@ namespace NUS_Downloader return nbr_cont; } + /// + /// Gets a TMD Boot Index + /// + /// The TMD. + /// int BootIndex private int GetBootIndex(byte[] tmd) { // nbr_cont (0xE0) len=0x02 @@ -377,6 +405,12 @@ namespace NUS_Downloader return bootidx; } + /// + /// Sets the Boot index of a TMD. + /// + /// The TMD. + /// Index to set it too + /// Edited TMD private byte[] SetBootIndex(byte[] tmd, int bootindex) { // nbr_cont (0xE0) len=0x02 @@ -386,7 +420,11 @@ namespace NUS_Downloader return tmd; } - private void WriteStatus(string Update) + /// + /// Writes the status to the statusbox. + /// + /// The update. + public void WriteStatus(string Update) { // Small function for writing text to the statusbox... if (statusbox.Text == "") @@ -450,6 +488,11 @@ namespace NUS_Downloader return ret; } + /// + /// Makes a hex string the correct length. + /// + /// The hex. + /// private string MakeProperLength(string hex) { // If hex is like, 'A', makes it '0A', etc. @@ -459,6 +502,11 @@ namespace NUS_Downloader return hex; } + /// + /// Converts to hex. + /// + /// The string. + /// hex string private string ConvertToHex(string decval) { // Convert text string to unsigned integer @@ -466,6 +514,10 @@ namespace NUS_Downloader return String.Format("{0:x2}", uiDecimal); } + /// + /// Reads the type of the Title ID. + /// + /// The TitleID. private void ReadIDType(string ttlid) { /* Wiibrew TitleID Info... @@ -488,39 +540,28 @@ namespace NUS_Downloader */ if (ttlid.Substring(0, 8) == "00000001") - { WriteStatus("ID Type: System Title. BE CAREFUL!"); - } else if ((ttlid.Substring(0, 8) == "00010000") || (ttlid.Substring(0, 8) == "00010004")) - { WriteStatus("ID Type: Disc-Based Game. Unlikely NUS Content!"); - } else if (ttlid.Substring(0, 8) == "00010001") - { WriteStatus("ID Type: Downloaded Channel. Possible NUS Content."); - } else if (ttlid.Substring(0, 8) == "00010002") - { WriteStatus("ID Type: System Channel. BE CAREFUL!"); - } else if (ttlid.Substring(0, 8) == "00010004") - { WriteStatus("ID Type: Game Channel. Unlikely NUS Content!"); - } else if (ttlid.Substring(0, 8) == "00010005") - { WriteStatus("ID Type: Downloaded Game Content. Unlikely NUS Content!"); - } else if (ttlid.Substring(0, 8) == "00010008") - { WriteStatus("ID Type: 'Hidden' Channel. Unlikely NUS Content!"); - } else - { WriteStatus("ID Type: Unknown. Unlikely NUS Content!"); - } } + /// + /// Trims the leading zeros of a string. + /// + /// The string with leading zeros. + /// no-0-string private string TrimLeadingZeros(string num) { int startindex = 0; @@ -535,6 +576,12 @@ namespace NUS_Downloader return num.Substring(startindex, (num.Length - startindex)); } + /// + /// Gets the content names in a TMD. + /// + /// The TMD. + /// The TMD contentcount. + /// Array of Content names private string[] GetContentNames(byte[] tmdfile, int length) { string[] contentnames = new string[length]; @@ -552,6 +599,12 @@ namespace NUS_Downloader return contentnames; } + /// + /// Gets the content sizes in a TMD. + /// + /// The TMD. + /// The TMD contentcount. + /// private string[] GetContentSizes(byte[] tmdfile, int length) { string[] contentsizes = new string[length]; @@ -583,6 +636,12 @@ namespace NUS_Downloader return contentsizes; } + /// + /// Gets the content hashes. + /// + /// The tmd. + /// The content_count. + /// private byte[] GetContentHashes(byte[] tmdfile, int length) { byte[] contenthashes = new byte[length*20]; @@ -599,7 +658,12 @@ namespace NUS_Downloader return contenthashes; } - // Returns array of shared/normal values for a tmd... + /// + /// Gets the content types. + /// + /// The tmd. + /// The content_count. + /// private int[] GetContentTypes(byte[] tmdfile, int length) { int[] contenttypes = new int[length]; @@ -617,6 +681,12 @@ namespace NUS_Downloader return contenttypes; } + /// + /// Gets the content indices. + /// + /// The tmd. + /// The contentcount. + /// private byte[] GetContentIndices(byte[] tmdfile, int length) { byte[] contentindices = new byte[length]; @@ -652,6 +722,20 @@ namespace NUS_Downloader } } + // Handle SaveAs here so it shows up properly... + if (saveaswadbox.Checked) + { + SaveFileDialog wad_saveas = new SaveFileDialog(); + wad_saveas.Title = "Save WAD File..."; + wad_saveas.Filter = "WAD Files|*.wad|All Files|*.*"; + wad_saveas.AddExtension = true; + DialogResult dres = wad_saveas.ShowDialog(); + if (dres != DialogResult.Cancel) + WAD_Saveas_Filename = wad_saveas.FileName; + } + else + WAD_Saveas_Filename = ""; + // Running Downloads in background so no form freezing NUSDownloader.RunWorkerAsync(); } @@ -1006,12 +1090,12 @@ namespace NUS_Downloader System.Threading.Thread.Sleep(1000); } - // Re-Gather information... + /* Re-Gather information... byte[] tmdrefresh = FileLocationToByteArray(titledirectory + tmdfull); tmdcontents = GetContentNames(tmd, ContentCount(tmdrefresh)); tmdsizes = GetContentSizes(tmd, ContentCount(tmdrefresh)); tmdhashes = GetContentHashes(tmd, ContentCount(tmdrefresh)); - tmdindices = GetContentIndices(tmd, ContentCount(tmdrefresh)); + tmdindices = GetContentIndices(tmd, ContentCount(tmdrefresh)); */ /* WriteStatus("Trucha Signing TMD..."); @@ -1043,7 +1127,7 @@ namespace NUS_Downloader if ((packbox.Checked == true) && (wiimode == true)) { - PackWAD(titleid, tmdfull, tmdcontents.Length, tmdcontents, tmdsizes, titledirectory); + PackWAD(titleid, tmdfull, titledirectory); } SetEnableforDownload(true); @@ -1052,6 +1136,9 @@ namespace NUS_Downloader } + /// + /// Creates the title directory. + /// private void CreateTitleDirectory() { // Creates the directory for the downloaded title... @@ -1080,6 +1167,9 @@ namespace NUS_Downloader } } + /// + /// Deletes the title directory. + /// private void DeleteTitleDirectory() { string currentdir = Application.StartupPath; @@ -1099,6 +1189,14 @@ namespace NUS_Downloader //Directory.CreateDirectory(currentdir + titleidbox.Text); } + /// + /// Downloads the NUS file. + /// + /// The titleid. + /// The filename. + /// The placementdir. + /// The sizeinbytes. + /// if set to true [iswiititle]. private void DownloadNUSFile(string titleid, string filename, string placementdir, int sizeinbytes, bool iswiititle) { // Create NUS URL... @@ -1118,7 +1216,18 @@ namespace NUS_Downloader generalWC.DownloadFile(nusfileurl, placementdir + filename); } - public void PackWAD(string titleid, string tmdfilename, int contentcount, string[] contentnames, string[] contentsizes, string totaldirectory) + void StatusChange(string status) + { + WriteStatus(status); + } + + /// + /// Packs the WAD. + /// + /// The titleid. + /// The tmdfilename. + /// The working directory. + public void PackWAD(string titleid, string tmdfilename, string totaldirectory) { WriteStatus("Beginning WAD Pack..."); // Directory stuff @@ -1126,6 +1235,9 @@ namespace NUS_Downloader if (!(currentdir.EndsWith(@"\")) || !(currentdir.EndsWith(@"/"))) currentdir += @"\"; + WADPacker packer = new WADPacker(); + packer.StatusChanged += WriteStatus; + // Create cert file holder //byte[] certsbuf = FileLocationToByteArray(currentdir + @"\cert.sys"); byte[] certsbuf = new byte[0xA00]; @@ -1135,34 +1247,63 @@ namespace NUS_Downloader return; } for (int c = 0; c < cert_CA.Length; c++) - { certsbuf[c] = cert_CA[c]; - } for (int c = 0; c < cert_CACP.Length; c++) - { certsbuf[c + 0x400] = cert_CACP[c]; - } for (int c = 0; c < cert_CAXS.Length; c++) - { certsbuf[c + 0x700] = cert_CAXS[c]; - } if (!(TotalCertValid(certsbuf))) { WriteStatus("Error: Cert array did not hash properly!"); return; } - + packer.Certs = certsbuf; + // Create ticket file holder - byte[] cetkbuf = FileLocationToByteArray(totaldirectory + @"\cetk"); + //byte[] cetkbuf = FileLocationToByteArray(totaldirectory + @"\cetk"); + packer.Ticket = FileLocationToByteArray(totaldirectory + @"\cetk"); // Create tmd file holder - byte[] tmdbuf = FileLocationToByteArray(totaldirectory + @"\" + tmdfilename); + //byte[] tmdbuf = FileLocationToByteArray(totaldirectory + @"\" + tmdfilename); + packer.TMD = FileLocationToByteArray(totaldirectory + @"\" + tmdfilename); + + // Get the TMD variables in here instead... + int contentcount = ContentCount(packer.TMD); + //packer.TMDContentCount = ContentCount(packer.TMD); + string[] contentnames = GetContentNames(packer.TMD, contentcount); + //string[] contentsizes = + packer.tmdnames = GetContentNames(packer.TMD, contentcount); + packer.tmdsizes = GetContentSizes(packer.TMD, contentcount); if (wadnamebox.Text.Contains("[v]") == true) wadnamebox.Text = wadnamebox.Text.Replace("[v]", "v" + titleversion.Text); - + + // SaveAs Dialog + string wad_filename = totaldirectory + @"\" + RemoveIllegalCharacters(wadnamebox.Text); + + if (!(String.IsNullOrEmpty(WAD_Saveas_Filename))) + { + packer.FileName = System.IO.Path.GetFileName(WAD_Saveas_Filename); + packer.Directory = WAD_Saveas_Filename.Replace(packer.FileName, ""); + } + else + { + packer.Directory = totaldirectory; + packer.FileName = System.IO.Path.GetFileName(wad_filename); + } + + // Gather contents... + byte[][] contents_array = new byte[contentcount][]; + for (int a = 0; a < contentcount; a++) + { + contents_array[a] = FileLocationToByteArray(totaldirectory + contentnames[a]); + } + packer.Contents = contents_array; + + packer.PackWAD(); + /* // Create wad file - FileStream wadfs = new FileStream(totaldirectory + @"\" + RemoveIllegalCharacters(wadnamebox.Text), FileMode.Create); + FileStream wadfs = new FileStream(wad_filename, FileMode.Create); // Add wad stuffs WADHeader wad = new WADHeader(); @@ -1178,7 +1319,6 @@ namespace NUS_Downloader // Need 64 byte boundary... wadfs.Seek(2624, SeekOrigin.Begin); - // Cert is 2560 // Write ticket at this point... wad.TicketSize = 0x2A4; wadfs.Write(cetkbuf, 0, wad.TicketSize); @@ -1245,13 +1385,38 @@ namespace NUS_Downloader byte[] datasize = InttoByteArray(wad.DataSize, 4); wadfs.Write(datasize, 0, 4); - // Finished. - WriteStatus("WAD Created: " + wadnamebox.Text); - // Close filesystem... wadfs.Close(); + + // Finished. + WriteStatus("WAD Created: " + wadnamebox.Text); + */ + // Delete contents now... + if (deletecontentsbox.Checked) + { + WriteStatus("Deleting contents..."); + File.Delete(totaldirectory + @"\" + tmdfilename); + File.Delete(totaldirectory + @"\cetk"); + for (int a = 0; a < contentnames.Length; a++) + { + File.Delete(totaldirectory + @"\" + contentnames[a]); + } + WriteStatus(" - Contents have been deleted."); + string[] leftovers = Directory.GetFiles(totaldirectory); + if (leftovers.Length <= 0) + { + WriteStatus(" - Title directory was empty; Deleted."); + Directory.Delete(totaldirectory); + } + WriteStatus("All deletion completed."); + } } + /// + /// Returns next 0x40 padded length. + /// + /// The currentlength. + /// private long ByteBoundary(int currentlength) { // Gets the next 0x40 offset. @@ -1270,6 +1435,12 @@ namespace NUS_Downloader return (long)thelength; } + /// + /// Int -> Byte[] (OLD) + /// + /// The int. + /// The array length. + /// private byte[] InttoByteArray(int inte, int arraysize) { // Take integer and make into byte array @@ -1299,6 +1470,9 @@ namespace NUS_Downloader wadnamebox.Enabled = false; wadnamebox.Text = ""; + + // Cannot doit + truchabox.Enabled = false; } } @@ -1310,6 +1484,7 @@ namespace NUS_Downloader // packbox.Checked = true; packbox.Enabled = true; decryptbox.Enabled = true; + truchabox.Enabled = true; } } @@ -1357,104 +1532,6 @@ namespace NUS_Downloader WriteStatus(" * Famfamfam for the Silk Icon Set."); } - private void getcerts_Click(object sender, EventArgs e) - { - // Get a certs.sys from NUS... - /* - // Directory stuff - string currentdir = Application.StartupPath; - if (currentdir.EndsWith(Convert.ToString(Path.DirectorySeparatorChar)) == false) - currentdir += Path.DirectorySeparatorChar; - - // Create certs file - FileStream certsfs = new FileStream(currentdir + @"\cert.sys", FileMode.Create); - - // Getting it from SystemMenu 3.2 - DownloadNUSFile("0000000100000002", "tmd.289", currentdir + @"\", 0, true); - DownloadNUSFile("0000000100000002", "cetk", currentdir + @"\", 0, true); - - // Create ticket file holder - byte[] cetkbuf = FileLocationToByteArray(currentdir + "cetk"); - - // Create tmd file holder - byte[] tmdbuf = FileLocationToByteArray(currentdir + "tmd.289"); - - // Write CA cert... - certsfs.Seek(0, SeekOrigin.Begin); - certsfs.Write(tmdbuf, 0x628, 0x400); - WriteStatus("Added CA Cert!"); - - // Write CACP cert... - certsfs.Seek(0x400, SeekOrigin.Begin); - certsfs.Write(tmdbuf, 0x328, 0x300); - WriteStatus("Added CACP Cert!"); - - // Write CAXS cert... - certsfs.Seek(0x700, SeekOrigin.Begin); - certsfs.Write(cetkbuf, 0x2A4, 0x300); - WriteStatus("Added CAXS Cert!"); - certsfs.Close(); - - // Hash check the cert.sys... - if (verifyMd5Hash(currentdir + @"\cert.sys", certs_MD5) == true) - { - WriteStatus("Certs File Successfully Created!"); - } - else - { - WriteStatus("Error in Creating Certs File!"); - WriteStatus("Please report this error if you are sure it is not your internet connection"); - } - - // Re-enable controls... - foreach (Control ctrl in this.Controls) - { - ctrl.Enabled = true; - } - getcerts.Visible = false; - wadnamebox.Enabled = false; - - // Cleanup... - File.Delete(currentdir + "cetk"); - File.Delete(currentdir + "tmd.289"); - */ - } - /* - static string getMd5Hash(string input) - { - System.Text.StringBuilder sb = new System.Text.StringBuilder(); - FileStream fs = new FileStream(input, FileMode.Open); - MD5 md5 = new MD5CryptoServiceProvider(); - byte[] hash = md5.ComputeHash(fs); - fs.Close(); - fs.Dispose(); - foreach (byte hex in hash) - { - //Returns hash in lower case. - sb.Append(hex.ToString("x2")); - } - return sb.ToString(); - } - - // Verify a hash against a string. - static bool verifyMd5Hash(string input, string hash) - { - // Hash the input. - string hashOfInput = getMd5Hash(input); - - // Create a StringComparer an comare the hashes. - StringComparer comparer = StringComparer.OrdinalIgnoreCase; - - if (0 == comparer.Compare(hashOfInput, hash)) - { - return true; - } - else - { - return false; - } - } - */ private void packbox_CheckedChanged(object sender, EventArgs e) { if (packbox.Checked == true) @@ -1468,6 +1545,7 @@ namespace NUS_Downloader wadnamebox.Enabled = false; wadnamebox.Text = ""; } + } private void titleidbox_TextChanged(object sender, EventArgs e) @@ -1480,6 +1558,11 @@ namespace NUS_Downloader UpdatePackedName(); } + /// + /// Inits the crypto stuffz. + /// + /// The iv. + /// The key. public void initCrypt(byte[] iv, byte[] key) { rijndaelCipher = new RijndaelManaged(); @@ -1491,6 +1574,11 @@ namespace NUS_Downloader rijndaelCipher.IV = iv; } + /// + /// Encrypts the specified plain bytes. + /// + /// The plain bytes. + /// public byte[] Encrypt(byte[] plainBytes) { ICryptoTransform transform = rijndaelCipher.CreateEncryptor(); @@ -1503,6 +1591,11 @@ namespace NUS_Downloader } } + /// + /// Decrypts the specified encrypted data. + /// + /// The encrypted data. + /// public byte[] Decrypt(byte[] encryptedData) { ICryptoTransform transform = rijndaelCipher.CreateDecryptor(); @@ -1515,6 +1608,11 @@ namespace NUS_Downloader } } + /// + /// Reads the stream. + /// + /// The stream. + /// public byte[] ReadFully(Stream stream) { byte[] buffer = new byte[32768]; @@ -1530,6 +1628,12 @@ namespace NUS_Downloader } } + /// + /// Displays the bytes. + /// + /// The bytes. + /// What separates the bytes + /// public string DisplayBytes(byte[] bytes, string spacer) { string output = ""; @@ -1540,6 +1644,11 @@ namespace NUS_Downloader return output; } + /// + /// Computes the SHA-1 Hash. + /// + /// A byte[]. + /// static public byte[] ComputeSHA(byte[] data) { SHA1 sha = new SHA1CryptoServiceProvider(); @@ -1547,6 +1656,11 @@ namespace NUS_Downloader return sha.ComputeHash(data); } + /// + /// Loads the common key from disc. + /// + /// The keyfile. + /// public byte[] LoadCommonKey(string keyfile) { // Directory stuff @@ -1569,6 +1683,9 @@ namespace NUS_Downloader databaseStrip.Show(databaseButton, 2, 2); } + /// + /// Clears the database strip. + /// private void ClearDatabaseStrip() { SystemMenuList.DropDownItems.Clear(); @@ -1589,6 +1706,9 @@ namespace NUS_Downloader VCArcadeMenuList.DropDownItems.Clear(); } + /// + /// Fills the database strip. + /// private void FillDatabaseStrip() { XmlDocument xDoc = new XmlDocument(); @@ -1685,6 +1805,12 @@ namespace NUS_Downloader } } + /// + /// Adds the tool strip item to strip. + /// + /// The type. + /// The additionitem. + /// The attributes. void AddToolStripItemToStrip(int type, ToolStripMenuItem additionitem, XmlAttributeCollection attributes) { // Deal with VC list depth... @@ -1801,6 +1927,10 @@ namespace NUS_Downloader } } + /// + /// Mods WAD names to be official. + /// + /// The titlename. public void OfficialWADNaming(string titlename) { if (titlename.Contains("IOS")) @@ -1908,21 +2038,12 @@ namespace NUS_Downloader } } - void HandleMismatch(int contentsize, int actualsize) - { - if (contentsize != actualsize) - { - if ((contentsize - actualsize) > 16) - { - statusbox.Text += " (BAD Mismatch) (Dif: " + (contentsize - actualsize); - } - else - { - statusbox.Text += " (Safe Mismatch)"; - } - } - } - + /// + /// Gathers the region based on index + /// + /// The index. + /// XmlDocument with database inside + /// Region desc string RegionFromIndex(int index, XmlDocument databasexml) { /* Typical Region XML @@ -1960,6 +2081,9 @@ namespace NUS_Downloader return "XX (Error)"; } + /// + /// Loads the region codes. + /// private void LoadRegionCodes() { XmlDocument xDoc = new XmlDocument(); @@ -1981,6 +2105,11 @@ namespace NUS_Downloader titleidbox.Text = titleidbox.Text.Substring(0, 14) + e.ClickedItem.Text.Substring(0, 2); } + /// + /// Removes the illegal characters. + /// + /// removes the illegal chars + /// legal string private string RemoveIllegalCharacters(string databasestr) { // Database strings must contain filename-legal characters. @@ -1992,6 +2121,11 @@ namespace NUS_Downloader return databasestr; } + /// + /// Zeroes the signature in TMD/TIK. + /// + /// TMD/TIK + /// Zeroed TMD/TIK private byte[] ZeroSignature(byte[] tmdortik) { // Write all 0x00 to signature... @@ -2005,6 +2139,11 @@ namespace NUS_Downloader return tmdortik; } + /// + /// Trucha Signs a TMD/TIK + /// + /// The tmdortik. + /// Fake-signed byte[] private byte[] TruchaSign(byte[] tmdortik) { // Loop through 2 bytes worth of numbers until hash starts with 0x00... @@ -2036,6 +2175,12 @@ namespace NUS_Downloader return tmdortik; } + /// + /// Increments at an index. + /// + /// The array. + /// The index. + /// static public byte[] incrementAtIndex(byte[] array, int index) { if (array[index] == byte.MaxValue) @@ -2231,13 +2376,6 @@ namespace NUS_Downloader testtik.Close(); } - // C# to convert a string to a byte array. - public static byte[] StrToByteArray(string str) - { - System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding(); - return encoding.GetBytes(str); - } - private void button7_Click(object sender, EventArgs e) { // Proceed with process (BG worker waits for form to resize) @@ -2251,6 +2389,10 @@ namespace NUS_Downloader statusbox.Text = ""; } + /// + /// Makes everything disabled/enabled. + /// + /// if set to true [enabled]. private void SetEnableforDownload(bool enabled) { // Disable things the user should not mess with during download... @@ -2266,6 +2408,10 @@ namespace NUS_Downloader decryptbox.Enabled = enabled; } + /// + /// Makes tooltips disappear in the database, as many contain danger tag info. + /// + /// if set to true [enabled]. private void ShowInnerToolTips(bool enabled) { // Force tooltips to GTFO in sub menus... @@ -2284,6 +2430,12 @@ namespace NUS_Downloader } } + /// + /// Selects the database item image. + /// + /// if set to true [ticket]. + /// if set to true [danger]. + /// Correct Image private System.Drawing.Image SelectItemImage(bool ticket, bool danger) { // All is good, go green... @@ -2305,6 +2457,11 @@ namespace NUS_Downloader return null; } + /// + /// Loads a file into a byte[] + /// + /// The filename. + /// byte[] of file contents private byte[] FileLocationToByteArray(string filename) { FileStream fs = File.OpenRead(filename); @@ -2313,6 +2470,9 @@ namespace NUS_Downloader return filebytearray; } + /// + /// Updates the name of the packed WAD in the textbox. + /// private void UpdatePackedName() { // Change WAD name if applicable @@ -2343,7 +2503,12 @@ namespace NUS_Downloader } - // This is WIP code/theory... + /// + /// Generates a ticket from TitleKey/ID + /// + /// The enc title key. + /// The title ID. + /// New Ticket private byte[] GenerateTicket(byte[] EncTitleKey, byte[] TitleID) { byte[] Ticket = new byte[0x2A4]; @@ -2403,6 +2568,10 @@ namespace NUS_Downloader FillContentInfo(tmd); } + /// + /// Fills the content editor with info from TMD + /// + /// The TMD. private void FillContentInfo(byte[] tmd) { // Clear anything existing... @@ -2603,6 +2772,11 @@ namespace NUS_Downloader } } + /// + /// Checks for a hex string. + /// + /// The test string + /// Whether string is hex or not. public bool OnlyHexInString(string test) { return System.Text.RegularExpressions.Regex.IsMatch(test, @"\A\b[0-9a-fA-F]+\b\Z"); @@ -2640,6 +2814,9 @@ namespace NUS_Downloader UpdateTMDContents(); } + /// + /// Updates the TMD contents. + /// private void UpdateTMDContents() { // Write changes to TMD of contents... @@ -2903,21 +3080,12 @@ namespace NUS_Downloader testtmd.Close(); } - /* Pad Byte[] to specific alignment... - private byte[] AlignByteArray(byte[] content, int alignto) - { - long thelength = content.Length - 1; - long remainder = thelength % alignto; - - while (remainder != 0) - { - thelength += 1; - remainder = thelength % alignto; - } - Array.Resize(ref content, (int)thelength); - return content; - } */ - + /// + /// Pads to multiple of.... + /// + /// The binary. + /// The pad amount. + /// Padded byte[] private byte[] PadToMultipleOf(byte[] src, int pad) { int len = (src.Length + pad - 1) / pad * pad; @@ -2971,6 +3139,12 @@ namespace NUS_Downloader } } + /// + /// Determines whether OS is win7. + /// + /// + /// true if OS = win7; otherwise, false. + /// private bool IsWin7() { return (Environment.OSVersion.VersionString.Contains("6.1") == true); @@ -3177,6 +3351,12 @@ namespace NUS_Downloader } } + /// + /// Does byte[] contain byte[]? + /// + /// The large byte[]. + /// Small byte[] which may be in large one. + /// messed up int[] with offsets. private int[] ByteArrayContainsByteArray(byte[] bigboy, byte[] littleman) { // bigboy.Contains(littleman); @@ -3200,6 +3380,13 @@ namespace NUS_Downloader return offset; } + /// + /// Patches the binary. + /// + /// The content. + /// The offset. + /// The newvalues. + /// private byte[] PatchBinary(byte[] content, int offset, byte[] newvalues) { for (int a = 0; a < newvalues.Length; a++) @@ -3210,6 +3397,9 @@ namespace NUS_Downloader return content; } + /// + /// Recalculates the indices. + /// private void RecalculateIndices() { for (int a = 0; a < contentsEdit.Items.Count; a++) @@ -3226,6 +3416,10 @@ namespace NUS_Downloader } } + /// + /// Retrieves the new database via WiiBrew. + /// + /// Database as a String private string RetrieveNewDatabase() { // Retrieve Wiibrew database page source code @@ -3288,6 +3482,11 @@ namespace NUS_Downloader LoadTitleFromTMD(); } + /// + /// Sends the SOAP request to NUS. + /// + /// The Request + /// public string SendSOAPRequest(string soap_xml) { System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create("http://nus.shop.wii.com:80/nus/services/NetUpdateSOAP"); @@ -3391,9 +3590,12 @@ namespace NUS_Downloader } } + /// + /// Scans for certs in TMD/TIK. + /// + /// The tmdortik. private void ScanForCerts(byte[] tmdortik) { - // For some reason a few 00s are cut off, so pad it up to be safe. tmdortik = PadToMultipleOf(tmdortik, 16); @@ -3432,7 +3634,7 @@ namespace NUS_Downloader } // Search for cert_CA - if ((!(tmdortik.Length < 0x400)) && ((Convert.ToBase64String(cert_CA) != Convert.ToBase64String(cert_CA_sha1)))) + if ((!(tmdortik.Length < 0x400)) && ((Convert.ToBase64String(ComputeSHA(cert_CA)) != Convert.ToBase64String(cert_CA_sha1)))) { for (int a = 0; a < (tmdortik.Length - 0x400); a++) { @@ -3451,6 +3653,10 @@ namespace NUS_Downloader } } + /// + /// Checks whether the certs are obtained. + /// + /// private bool CertsValid() { if (Convert.ToBase64String(ComputeSHA(cert_CA)) != Convert.ToBase64String(cert_CA_sha1)) @@ -3462,6 +3668,11 @@ namespace NUS_Downloader return true; } + /// + /// Checks the whole cert file for validity. + /// + /// The cert_sys. + /// Valid Cert state. private bool TotalCertValid(byte[] cert_sys) { if (Convert.ToBase64String(ComputeSHA(cert_sys)) != Convert.ToBase64String(cert_total_sha1)) @@ -3469,6 +3680,11 @@ namespace NUS_Downloader return true; } + /// + /// Looks for a title's name by TitleID in Database. + /// + /// The titleid. + /// Existing name; else null private string NameFromDatabase(string titleid) { XmlDocument xDoc = new XmlDocument(); @@ -3514,6 +3730,7 @@ namespace NUS_Downloader { case "name": return ChildrenOfTheNode[z].InnerText; + default: break; } } @@ -3522,5 +3739,11 @@ namespace NUS_Downloader } return null; } + + private void packbox_EnabledChanged(object sender, EventArgs e) + { + saveaswadbox.Enabled = packbox.Enabled; + deletecontentsbox.Enabled = packbox.Enabled; + } } } diff --git a/NUS Downloader/NUS Downloader.csproj b/NUS Downloader/NUS Downloader.csproj index dbbdd8e..e603db5 100644 --- a/NUS Downloader/NUS Downloader.csproj +++ b/NUS Downloader/NUS Downloader.csproj @@ -95,6 +95,7 @@ Settings.settings True + diff --git a/NUS Downloader/WADPacker.cs b/NUS Downloader/WADPacker.cs new file mode 100644 index 0000000..7a25aad --- /dev/null +++ b/NUS Downloader/WADPacker.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace NUS_Downloader +{ + /// + /// Class for handling WAD Packaging. + /// + class WADPacker + { + // WAD Component Variables + private byte[] Certsys; + public byte[] Certs { get { return Certsys;} set { Certsys = value; CertChainSize = Certsys.Length; } } + private byte[] tmd; + public byte[] TMD { get { return tmd; } + set { + tmd = value; + TMDContentCount = ContentCount(TMD); + TMDSize = 484 + (TMDContentCount * 36); + } } + public byte[] Ticket; //{ get { return Ticket; } set { Ticket = value; } } + private int TMDContentCount; //{ get { return TMDContentCount; } set { TMDContentCount = value; } } + + // WAD Contents + private byte[][] TMDContents; + public byte[][] Contents { get { return TMDContents; } + set { + TMDContents = value; + for (int a = 0; a < TMDContents.Length; a++) + { + DataSize += TMDContents[a].Length; + } + } } + + // WAD Saving Variables + public string Directory; //{ get { return Directory; } set { Directory = value; } } + public string FileName; //{ get { return FileName; } set { FileName = value; } } + + // TMD Informations + public string[] tmdnames; //{ get { return tmdnames; } set { tmdnames = value; } } + public string[] tmdsizes; //{ get { return tmdsizes; } set { tmdsizes = value; } } + + // WAD Header Variables + private const int HeaderSize = 0x20; + private int CertChainSize; //{ get { return CertChainSize; } set { CertChainSize = value; } } + private const int TicketSize = 0x2A4; + private int TMDSize; //{ get { return TMDSize; } set { TMDSize = value; } } + private int DataSize; //{ get { return DataSize; } set { DataSize = value; } } + private byte[] WADMagic = new byte[8] { 0x00, 0x00, 0x00, 0x20, 0x49, 0x73, 0x00, 0x00 }; + private byte[] RESERVED_CONST = new byte[4] { 0x00, 0x00, 0x00, 0x00 }; + private byte[] TIKSIZE_CONST = new byte[4] { 0x00, 0x00, 0x02, 0xA4 }; + + // Report Status back in EventHandler + public delegate void StatusChangedEventHandler(string status); + public event StatusChangedEventHandler StatusChanged; + + + /// + /// Pads byte[]. + /// + /// The byte[] or binary to be padded. + /// How much to pad by. + /// Padded byte[] + private long PadToMultipleOf(long src, int pad) + { + long len = (src + pad - 1) / pad * pad; + return len; + } + + /// + /// Converts an integer into its equivilant byte array. + /// + /// The integer + /// Length you desire the byte[] to be. + /// + private byte[] ConvertInttoByteArray(int theInt, int arrayLen) + { + byte[] resultArray = new byte[arrayLen]; + for (int i = arrayLen - 1; i >= 0; i--) + { + resultArray[i] = (byte)((theInt >> (8 * i)) & 0xFF); + } + Array.Reverse(resultArray); + + // Fix duplication, rewrite extra to 0x00; + if (arrayLen > 4) + { + for (int i = 0; i < (arrayLen - 4); i++) + resultArray[i] = 0x00; + } + return resultArray; + } + + /// + /// Handles the size mismatch. + /// + /// The contentsize. + /// The actualsize. + void HandleMismatch(int contentsize, int actualsize) + { + if (contentsize != actualsize) + if ((contentsize - actualsize) > 16) + StatusChanged(String.Format(" (BAD Mismatch) (Dif: {0}", (contentsize - actualsize))); + //else + //statusbox.Text += " (Safe Mismatch)"; + } + + /// + /// Returns content count of TMD + /// + /// The TMD. + /// int Count of Contents + private int ContentCount(byte[] tmd) + { + return (tmd[0x1DE] * 256) + tmd[0x1DF]; + } + + /// + /// Packs the WAD file, saves it to specified location. + /// + public void PackWAD() + { + //StatusChanged("Beginning WAD Pack..."); + + if ((String.IsNullOrEmpty(Directory)) || (String.IsNullOrEmpty(FileName))) + { + StatusChanged("ERROR: No Directory/FileName provided!"); + return; + } + + FileStream wadfs = new FileStream((Directory + FileName), FileMode.Create); + + // Seek the beginning of the WAD... + wadfs.Seek(0, SeekOrigin.Begin); + + // Write initial part of header (WADType) + wadfs.Write(WADMagic, 0, WADMagic.Length); + + // Write CertChainLength + wadfs.Seek(0x08, SeekOrigin.Begin); + byte[] chainsize = ConvertInttoByteArray(CertChainSize, 4); + wadfs.Write(chainsize, 0, chainsize.Length); + + // Write res + wadfs.Seek(0x0C, SeekOrigin.Begin); + wadfs.Write(RESERVED_CONST, 0, RESERVED_CONST.Length); + + // Write ticketsize + wadfs.Seek(0x10, SeekOrigin.Begin); + wadfs.Write(TIKSIZE_CONST, 0, TIKSIZE_CONST.Length); + + // Write tmdsize + wadfs.Seek(0x14, SeekOrigin.Begin); + byte[] tmdsize = ConvertInttoByteArray(TMDSize, 4); + wadfs.Write(tmdsize, 0, tmdsize.Length); + + // Write data size + wadfs.Seek(0x18, SeekOrigin.Begin); + wadfs.Write(ConvertInttoByteArray(DataSize, 4), 0, 4); + StatusChanged(" - WAD Header wrote (0x00)"); + + // Write cert[] to 0x40. + wadfs.Seek(0x40, SeekOrigin.Begin); + wadfs.Write(Certs, 0, Certs.Length); + StatusChanged(String.Format(" - Certs wrote (0x{0})", Convert.ToString(64, 16))); + + // Pad to next 64 byte boundary. + wadfs.Seek(2624, SeekOrigin.Begin); + + // Write ticket at this point... + wadfs.Write(Ticket, 0, TicketSize); + StatusChanged(String.Format(" - Ticket wrote (0x{0})", Convert.ToString((wadfs.Length - 0x2A4), 16))); + + // Pad to next 64 byte boundary. + wadfs.Seek(PadToMultipleOf(wadfs.Length, 64), SeekOrigin.Begin); + + // Write TMD at this point... + wadfs.Write(TMD, 0, TMDSize); + StatusChanged(String.Format(" - TMD wrote (0x{0})", Convert.ToString((wadfs.Length - TMDSize), 16))); + + // Add the individual contents + for (int a = 0; a < TMDContentCount; a++) + { + // Pad to next 64 byte boundary... + wadfs.Seek(PadToMultipleOf(wadfs.Length, 64), SeekOrigin.Begin); + + wadfs.Write(Contents[a], 0, Contents[a].Length); + + StatusChanged(String.Format(" - {0} wrote (0x{1})", tmdnames[a], Convert.ToString((wadfs.Length - Contents[a].Length), 16))); + HandleMismatch(int.Parse(tmdsizes[a], System.Globalization.NumberStyles.HexNumber), Contents[a].Length); + } + + // Close filesystem... + wadfs.Close(); + + // Finished. + StatusChanged("WAD Created: " + FileName); + } + } +}