diff --git a/Plugins/SDAT/SDAT/SWAR.cs b/Plugins/SDAT/SDAT/SWAR.cs index 24ef6bd..640f7d9 100644 --- a/Plugins/SDAT/SDAT/SWAR.cs +++ b/Plugins/SDAT/SDAT/SWAR.cs @@ -130,7 +130,7 @@ namespace SDAT for (int i = 0; i < sounds.Length; i++) { bw.Write(currOffset); - currOffset += (uint)sounds[i].data.data.Length + 0x0C; + currOffset += (uint)sounds[i].data.data.Length + 0x0A; } // Write data diff --git a/Tinke/Dialog/SaveOptions.Designer.cs b/Tinke/Dialog/SaveOptions.Designer.cs index 83a2a4c..d38bfe0 100644 --- a/Tinke/Dialog/SaveOptions.Designer.cs +++ b/Tinke/Dialog/SaveOptions.Designer.cs @@ -32,6 +32,8 @@ this.checkBox2 = new System.Windows.Forms.CheckBox(); this.btn_OK = new System.Windows.Forms.Button(); this.btn_Cancel = new System.Windows.Forms.Button(); + this.checkBox3 = new System.Windows.Forms.CheckBox(); + this.checkBox4 = new System.Windows.Forms.CheckBox(); this.SuspendLayout(); // // checkBox1 @@ -39,7 +41,7 @@ this.checkBox1.AutoSize = true; this.checkBox1.Location = new System.Drawing.Point(12, 12); this.checkBox1.Name = "checkBox1"; - this.checkBox1.Size = new System.Drawing.Size(42, 16); + this.checkBox1.Size = new System.Drawing.Size(53, 19); this.checkBox1.TabIndex = 0; this.checkBox1.Text = "S1E"; this.checkBox1.UseVisualStyleBackColor = true; @@ -47,9 +49,9 @@ // checkBox2 // this.checkBox2.AutoSize = true; - this.checkBox2.Location = new System.Drawing.Point(12, 34); + this.checkBox2.Location = new System.Drawing.Point(12, 37); this.checkBox2.Name = "checkBox2"; - this.checkBox2.Size = new System.Drawing.Size(42, 16); + this.checkBox2.Size = new System.Drawing.Size(53, 19); this.checkBox2.TabIndex = 2; this.checkBox2.Text = "S1F"; this.checkBox2.UseVisualStyleBackColor = true; @@ -58,7 +60,7 @@ // this.btn_OK.DialogResult = System.Windows.Forms.DialogResult.OK; this.btn_OK.Image = global::Tinke.Properties.Resources.accept; - this.btn_OK.Location = new System.Drawing.Point(12, 56); + this.btn_OK.Location = new System.Drawing.Point(12, 112); this.btn_OK.Name = "btn_OK"; this.btn_OK.Size = new System.Drawing.Size(90, 30); this.btn_OK.TabIndex = 3; @@ -71,7 +73,7 @@ // this.btn_Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btn_Cancel.Image = global::Tinke.Properties.Resources.cancel; - this.btn_Cancel.Location = new System.Drawing.Point(137, 56); + this.btn_Cancel.Location = new System.Drawing.Point(137, 112); this.btn_Cancel.Name = "btn_Cancel"; this.btn_Cancel.Size = new System.Drawing.Size(90, 30); this.btn_Cancel.TabIndex = 4; @@ -80,10 +82,34 @@ this.btn_Cancel.UseVisualStyleBackColor = true; this.btn_Cancel.Click += new System.EventHandler(this.btn_Cancel_Click); // + // checkBox3 + // + this.checkBox3.AutoSize = true; + this.checkBox3.Location = new System.Drawing.Point(12, 62); + this.checkBox3.Name = "checkBox3"; + this.checkBox3.Size = new System.Drawing.Size(53, 19); + this.checkBox3.TabIndex = 5; + this.checkBox3.Text = "S20"; + this.checkBox3.UseVisualStyleBackColor = true; + this.checkBox3.CheckedChanged += new System.EventHandler(this.checkBox3_CheckedChanged); + // + // checkBox4 + // + this.checkBox4.AutoSize = true; + this.checkBox4.Enabled = false; + this.checkBox4.Location = new System.Drawing.Point(12, 87); + this.checkBox4.Name = "checkBox4"; + this.checkBox4.Size = new System.Drawing.Size(53, 19); + this.checkBox4.TabIndex = 6; + this.checkBox4.Text = "S21"; + this.checkBox4.UseVisualStyleBackColor = true; + // // SaveOptions // this.BackColor = System.Drawing.SystemColors.GradientInactiveCaption; - this.ClientSize = new System.Drawing.Size(239, 98); + this.ClientSize = new System.Drawing.Size(239, 154); + this.Controls.Add(this.checkBox4); + this.Controls.Add(this.checkBox3); this.Controls.Add(this.btn_Cancel); this.Controls.Add(this.btn_OK); this.Controls.Add(this.checkBox2); @@ -107,5 +133,7 @@ private System.Windows.Forms.CheckBox checkBox2; private System.Windows.Forms.Button btn_OK; private System.Windows.Forms.Button btn_Cancel; + private System.Windows.Forms.CheckBox checkBox3; + private System.Windows.Forms.CheckBox checkBox4; } } diff --git a/Tinke/Dialog/SaveOptions.cs b/Tinke/Dialog/SaveOptions.cs index c44c4b5..d46ca67 100644 --- a/Tinke/Dialog/SaveOptions.cs +++ b/Tinke/Dialog/SaveOptions.cs @@ -22,6 +22,8 @@ namespace Tinke.Dialog btn_Cancel.Text = xml.Element("S1C").Value; checkBox1.Text = xml.Element("S1E").Value; checkBox2.Text = xml.Element("S1F").Value; + checkBox3.Text = xml.Element("S20").Value; + checkBox4.Text = xml.Element("S21").Value; } catch { throw new NotImplementedException("There was an error reading the language file"); } } @@ -36,6 +38,16 @@ namespace Tinke.Dialog get { return checkBox2.Checked; } } + public bool IsReCompress + { + get { return checkBox3.Checked; } + } + + public bool IsBetterCompress + { + get { return checkBox4.Checked; } + } + private void btn_OK_Click(object sender, EventArgs e) { this.Close(); @@ -45,5 +57,17 @@ namespace Tinke.Dialog { this.Close(); } + + private void checkBox3_CheckedChanged(object sender, EventArgs e) + { + if (checkBox3.Checked) + { + checkBox4.Enabled = true; + } else + { + checkBox4.Checked = false; + checkBox4.Enabled= false; + } + } } } diff --git a/Tinke/Nitro/TWL.cs b/Tinke/Nitro/TWL.cs index 2dcd58b..75ce49b 100644 --- a/Tinke/Nitro/TWL.cs +++ b/Tinke/Nitro/TWL.cs @@ -1,83 +1,83 @@ -// ---------------------------------------------------------------------- -// - -// Copyright (C) 2017 -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// - -// MetLob -// metlob@mail333.com -// 13/10/2017 18:53:14 -// ----------------------------------------------------------------------- -using System; -using System.Collections.Generic; -using System.Text; - -namespace Tinke.Nitro -{ - using System.IO; - using System.Security.Cryptography; - - using DSDecmp.Formats; - - using Ekona; - - using Tinke.Tools; - using Tinke.Tools.Cryptography; - - class TWL - { - private static byte[] modcryptCmnKey = - { - 0x79, 0x3E, 0x4F, 0x1A, 0x5F, 0x0F, 0x68, 0x2A, 0x58, 0x02, 0x59, 0x29, 0x4E, - 0xFB, 0xFE, 0xFF - }; - - internal static byte[] hmac_sha1_key = - { - 0x21,0x06,0xC0,0xDE,0xBA,0x98,0xCE,0x3F,0xA6,0x92,0xE3,0x9D,0x46,0xF2,0xED,0x01, - 0x76,0xE3,0xCC,0x08,0x56,0x23,0x63,0xFA,0xCA,0xD4,0xEC,0xDF,0x9A,0x62,0x78,0x34, - 0x8F,0x6D,0x63,0x3C,0xFE,0x22,0xCA,0x92,0x20,0x88,0x97,0x23,0xD2,0xCF,0xAE,0xC2, - 0x32,0x67,0x8D,0xFE,0xCA,0x83,0x64,0x98,0xAC,0xFD,0x3E,0x37,0x87,0x46,0x58,0x24, - }; - - internal static byte[] rsaPublicKey = - { - 0x95, 0x6F, 0x79, 0x0D, 0xF0, 0x8B, 0xB8, 0x5A, 0x76, 0xAA, 0xEF, 0xA2, 0x7F, 0xE8, 0x74, 0x75, - 0x8B, 0xED, 0x9E, 0xDF, 0x9E, 0x9A, 0x67, 0x0C, 0xD8, 0x18, 0xBE, 0xB9, 0xB2, 0x88, 0x52, 0x03, - 0xB3, 0xFA, 0x11, 0xAE, 0xAA, 0x18, 0x65, 0x13, 0xB5, 0xD6, 0xBB, 0x85, 0xA3, 0x84, 0xD0, 0xD0, - 0xEF, 0xB3, 0x66, 0xCB, 0xC6, 0x05, 0x1A, 0xAA, 0x86, 0x82, 0x7A, 0xB7, 0x43, 0x11, 0xF5, 0x9C, - 0x9B, 0xFC, 0x6C, 0x70, 0x79, 0xD5, 0xF1, 0x7B, 0xD0, 0x81, 0x9F, 0x52, 0x20, 0x56, 0x73, 0x8C, - 0x72, 0x1F, 0x40, 0xCF, 0x23, 0x61, 0x93, 0x25, 0x90, 0xA3, 0xC5, 0xDC, 0x94, 0xCF, 0xD1, 0x7A, - 0x8C, 0xBC, 0x95, 0x4A, 0x91, 0x8A, 0xA8, 0x58, 0xF4, 0xD8, 0x04, 0xBA, 0xF7, 0xD3, 0xC1, 0xC4, - 0xD7, 0xB8, 0xF0, 0x77, 0x01, 0x2F, 0xA1, 0x70, 0x26, 0x0B, 0x2C, 0x04, 0x90, 0x56, 0xF3, 0xA5 - }; - - internal static byte[] rsaSignatureMask = - { - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, - 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC - }; - +// ---------------------------------------------------------------------- +// + +// Copyright (C) 2017 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// + +// MetLob +// metlob@mail333.com +// 13/10/2017 18:53:14 +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tinke.Nitro +{ + using System.IO; + using System.Security.Cryptography; + + using DSDecmp.Formats; + + using Ekona; + + using Tinke.Tools; + using Tinke.Tools.Cryptography; + + class TWL + { + private static byte[] modcryptCmnKey = + { + 0x79, 0x3E, 0x4F, 0x1A, 0x5F, 0x0F, 0x68, 0x2A, 0x58, 0x02, 0x59, 0x29, 0x4E, + 0xFB, 0xFE, 0xFF + }; + + internal static byte[] hmac_sha1_key = + { + 0x21,0x06,0xC0,0xDE,0xBA,0x98,0xCE,0x3F,0xA6,0x92,0xE3,0x9D,0x46,0xF2,0xED,0x01, + 0x76,0xE3,0xCC,0x08,0x56,0x23,0x63,0xFA,0xCA,0xD4,0xEC,0xDF,0x9A,0x62,0x78,0x34, + 0x8F,0x6D,0x63,0x3C,0xFE,0x22,0xCA,0x92,0x20,0x88,0x97,0x23,0xD2,0xCF,0xAE,0xC2, + 0x32,0x67,0x8D,0xFE,0xCA,0x83,0x64,0x98,0xAC,0xFD,0x3E,0x37,0x87,0x46,0x58,0x24, + }; + + internal static byte[] rsaPublicKey = + { + 0x95, 0x6F, 0x79, 0x0D, 0xF0, 0x8B, 0xB8, 0x5A, 0x76, 0xAA, 0xEF, 0xA2, 0x7F, 0xE8, 0x74, 0x75, + 0x8B, 0xED, 0x9E, 0xDF, 0x9E, 0x9A, 0x67, 0x0C, 0xD8, 0x18, 0xBE, 0xB9, 0xB2, 0x88, 0x52, 0x03, + 0xB3, 0xFA, 0x11, 0xAE, 0xAA, 0x18, 0x65, 0x13, 0xB5, 0xD6, 0xBB, 0x85, 0xA3, 0x84, 0xD0, 0xD0, + 0xEF, 0xB3, 0x66, 0xCB, 0xC6, 0x05, 0x1A, 0xAA, 0x86, 0x82, 0x7A, 0xB7, 0x43, 0x11, 0xF5, 0x9C, + 0x9B, 0xFC, 0x6C, 0x70, 0x79, 0xD5, 0xF1, 0x7B, 0xD0, 0x81, 0x9F, 0x52, 0x20, 0x56, 0x73, 0x8C, + 0x72, 0x1F, 0x40, 0xCF, 0x23, 0x61, 0x93, 0x25, 0x90, 0xA3, 0xC5, 0xDC, 0x94, 0xCF, 0xD1, 0x7A, + 0x8C, 0xBC, 0x95, 0x4A, 0x91, 0x8A, 0xA8, 0x58, 0xF4, 0xD8, 0x04, 0xBA, 0xF7, 0xD3, 0xC1, 0xC4, + 0xD7, 0xB8, 0xF0, 0x77, 0x01, 0x2F, 0xA1, 0x70, 0x26, 0x0B, 0x2C, 0x04, 0x90, 0x56, 0xF3, 0xA5 + }; + + internal static byte[] rsaSignatureMask = + { + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC + }; + internal static byte[] rsaFontKey = { 0x9F, 0x80, 0xBC, 0x5F, 0xB6, 0xB6, 0x1D, 0x2A, 0x46, 0x02, 0x52, 0x64, 0xB2, 0xA3, 0x86, 0xCE, @@ -88,392 +88,392 @@ namespace Tinke.Nitro 0x4E, 0x82, 0xF7, 0xB3, 0xE2, 0x9C, 0xE4, 0x72, 0xE3, 0xDC, 0x60, 0xAF, 0xCC, 0x18, 0xE2, 0xD4, 0xEF, 0xD2, 0x76, 0x47, 0x31, 0xE6, 0x14, 0x0E, 0x1D, 0x26, 0xB5, 0x85, 0x97, 0xBC, 0xC6, 0xB6, 0xD8, 0xE7, 0x69, 0x2D, 0x2C, 0x26, 0xFB, 0x5F, 0x70, 0x9E, 0x19, 0x9C, 0x6B, 0x02, 0x6D, 0x97 - }; - - private uint firstDSiHashOffset; - private uint dsiHashSize; - bool twlEncrypted; - - public byte[][] Overlays9Sha1Hmac { get; private set; } - public byte[][] Header2Data { get; private set; } - public byte[] DSi9Data { get; private set; } - public byte[] DSi7Data { get; private set; } - public byte[] Hashtable1Data { get; private set; } - public byte[] Hashtable2Data { get; private set; } - - public TWL(string file, Estructuras.ROMHeader hdr, Estructuras.sFAT[] fat) - { - sFile[] overlays = Overlay.ReadBasicOverlays(file, hdr.ARM9overlayOffset, hdr.ARM9overlaySize, true, fat); - this.firstDSiHashOffset = hdr.digest_ntr_size / hdr.digest_sector_size * 0x14; - this.dsiHashSize = hdr.digest_twl_size / hdr.digest_sector_size * 0x14; - - // Read data - BinaryReader br = new BinaryReader(File.OpenRead(file)); - br.BaseStream.Position = hdr.sector_hashtable_start; - this.Hashtable1Data = br.ReadBytes((int)hdr.sector_hashtable_size); - br.BaseStream.Position = hdr.block_hashtable_start; - this.Hashtable2Data = br.ReadBytes((int)hdr.block_hashtable_size); - br.BaseStream.Position = hdr.dsi9_rom_offset; - this.DSi9Data = br.ReadBytes(Math.Max((int)hdr.modcrypt1_size, (int)hdr.dsi9_size)); - br.BaseStream.Position = hdr.dsi7_rom_offset; - this.DSi7Data = br.ReadBytes(Math.Max((int)hdr.modcrypt2_size, (int)hdr.dsi7_size)); - if (!hdr.trimmedRom) - { - //br.BaseStream.Position = hdr.digest_twl_start - 0x3000; - //this.Header2Data = br.ReadBytes(0x3000); + }; + + private uint firstDSiHashOffset; + private uint dsiHashSize; + bool twlEncrypted; + + public byte[][] Overlays9Sha1Hmac { get; private set; } + public byte[][] Header2Data { get; private set; } + public byte[] DSi9Data { get; private set; } + public byte[] DSi7Data { get; private set; } + public byte[] Hashtable1Data { get; private set; } + public byte[] Hashtable2Data { get; private set; } + + public TWL(string file, Estructuras.ROMHeader hdr, Estructuras.sFAT[] fat) + { + sFile[] overlays = Overlay.ReadBasicOverlays(file, hdr.ARM9overlayOffset, hdr.ARM9overlaySize, true, fat); + this.firstDSiHashOffset = hdr.digest_ntr_size / hdr.digest_sector_size * 0x14; + this.dsiHashSize = hdr.digest_twl_size / hdr.digest_sector_size * 0x14; + + // Read data + BinaryReader br = new BinaryReader(File.OpenRead(file)); + br.BaseStream.Position = hdr.sector_hashtable_start; + this.Hashtable1Data = br.ReadBytes((int)hdr.sector_hashtable_size); + br.BaseStream.Position = hdr.block_hashtable_start; + this.Hashtable2Data = br.ReadBytes((int)hdr.block_hashtable_size); + br.BaseStream.Position = hdr.dsi9_rom_offset; + this.DSi9Data = br.ReadBytes(Math.Max((int)hdr.modcrypt1_size, (int)hdr.dsi9_size)); + br.BaseStream.Position = hdr.dsi7_rom_offset; + this.DSi7Data = br.ReadBytes(Math.Max((int)hdr.modcrypt2_size, (int)hdr.dsi7_size)); + if (!hdr.trimmedRom) + { + //br.BaseStream.Position = hdr.digest_twl_start - 0x3000; + //this.Header2Data = br.ReadBytes(0x3000); this.Header2Data = new byte[3][]; for (int i = 0; i < 3; i++) - { - br.BaseStream.Position = hdr.digest_ntr_start + 0x4000; + { + br.BaseStream.Position = hdr.digest_ntr_start + 0x4000; this.Header2Data[i] = br.ReadBytes(0x1000); - } - } - - // Calc SHA1-HMAC of overlays9 - HMACSHA1 hmac = new HMACSHA1(TWL.hmac_sha1_key); - this.Overlays9Sha1Hmac = new byte[overlays.Length][]; - for (int i = 0; i < overlays.Length; i++) - { - br.BaseStream.Position = overlays[i].offset; - byte[] ovlData = br.ReadBytes((int)overlays[i].size); - this.Overlays9Sha1Hmac[i] = hmac.ComputeHash(ovlData, 0, ovlData.Length); - } - - // Check for encryption modcrypt section - this.twlEncrypted = false; // (hdr.twlInternalFlags & 2) > 0; - if (hdr.modcrypt1_start >= hdr.digest_twl_start && hdr.modcrypt1_start < 0xFFFFFFFF) - { - uint modcryptHashedSectorIndex = (hdr.modcrypt1_start - hdr.digest_twl_start) / hdr.digest_sector_size; - uint modcryptHashedSectorOff = modcryptHashedSectorIndex * hdr.digest_sector_size; - uint hashOff = modcryptHashedSectorIndex * 0x14; - - br.BaseStream.Position = hdr.digest_twl_start + modcryptHashedSectorOff; - byte[] firstModcryptBlock = br.ReadBytes((int)hdr.digest_sector_size); - byte[] hash = hmac.ComputeHash(firstModcryptBlock, 0, (int)hdr.digest_sector_size); - for (int i = 0; i < 20 && !twlEncrypted; i++) twlEncrypted = hash[i] != Hashtable1Data[this.firstDSiHashOffset + hashOff + i]; - } - br.Close(); - - // Decrypt modcrypt sections - if (this.twlEncrypted) - { - byte[] key = AES128KeyGenerate(hdr); - byte[] counter = new byte[16]; - if (hdr.modcrypt1_size > 0 && hdr.modcrypt1_size < 0xFFFFFFFF) - { - Array.Copy(hdr.hmac_arm9, 0, counter, 0, 16); - uint offset = hdr.modcrypt1_start - hdr.dsi9_rom_offset; - byte[] decrypted = AES128CTRCrypt(key, counter, this.DSi9Data, offset, hdr.modcrypt1_size); - if (offset == 0 && decrypted.Length == this.DSi9Data.Length) this.DSi9Data = decrypted; - else Array.Copy(decrypted, 0, this.DSi9Data, offset, decrypted.Length); - } - - if (hdr.modcrypt2_size > 0 && hdr.modcrypt2_size < 0xFFFFFFFF) - { - Array.Copy(hdr.hmac_arm7, 0, counter, 0, 16); - uint offset = hdr.modcrypt2_start - hdr.dsi7_rom_offset; - byte[] decrypted = AES128CTRCrypt(key, counter, this.DSi7Data, offset, hdr.modcrypt2_size); - if (offset == 0 && decrypted.Length == this.DSi7Data.Length) this.DSi7Data = decrypted; - else Array.Copy(decrypted, 0, this.DSi7Data, offset, decrypted.Length); - } - } - - hmac.Clear(); - hmac.Dispose(); - this.twlEncrypted = (hdr.twlInternalFlags & 2) > 0; - } - - public void UpdateOverlays9Sha1Hmac(ref sFile arm9, Estructuras.ROMHeader hdr, List ov9, HMACSHA1 hmac = null) - { - if (hmac == null) hmac = new HMACSHA1(hmac_sha1_key); - byte[][] hashes = new byte[ov9.Count][]; - bool changed = false; - for (int i = 0; i < ov9.Count; i++) - { - Stream str = File.OpenRead(ov9[i].path); - byte[] buffer = new byte[ov9[i].size]; - str.Position = ov9[i].offset; - str.Read(buffer, 0, buffer.Length); - str.Close(); - hashes[i] = hmac.ComputeHash(buffer); - for (int j = 0; j < hashes[i].Length && !changed; j++) changed |= hashes[i][j] != this.Overlays9Sha1Hmac[i][j]; - } - - if (changed) - { - // Read arm9 - BinaryReader br = new BinaryReader(File.OpenRead(arm9.path)); - br.BaseStream.Position = arm9.offset; - byte[] arm9Data = br.ReadBytes((int)arm9.size); - br.Close(); - - // Decompress arm9 - hdr.ARM9size = arm9.size; - uint initptr = BitConverter.ToUInt32(hdr.reserved2, 0) & 0x3FFF; - uint hdrptr = BitConverter.ToUInt32(arm9Data, (int)initptr + 0x14) - hdr.ARM9ramAddress; - bool cmparm9 = ARM9BLZ.Decompress(arm9Data, hdr, out arm9Data); - - // Get hmac offset - uint offset = 0; - uint end = BitConverter.ToUInt32(arm9Data, (int)initptr + 8) - hdr.ARM9ramAddress; - for (long i = end - 0x14 * ov9.Count; i >= 0 && offset == 0; i--) - { - bool cond = arm9Data[i] == this.Overlays9Sha1Hmac[0][0]; - for (int j = 1; j < 20 && cond; j++) cond = arm9Data[i + j] == this.Overlays9Sha1Hmac[0][j]; - if (cond) offset = (uint)i; - } - - // Write new hash - if (offset > 0) - { - for (int i = 0; i < ov9.Count; i++) Array.Copy(hashes[i], 0, arm9Data, offset + i * 0x14, 20); - if (!cmparm9) arm9Data = ARM9BLZ.Compress(arm9Data, hdr, arm9.size - hdrptr); - - string arm9Binary = Path.GetTempFileName(); - File.WriteAllBytes(arm9Binary, arm9Data); - arm9.path = arm9Binary; - arm9.offset = 0; - arm9.size = (uint)arm9Data.Length; - } - else Console.WriteLine("Overlays9 has been modified but can't update hashes in ARM9.bin!"); - } - } - - public void ImportArm9iData(string filePath, uint offset, uint size) - { - uint sizePad = size; - if (size % 0x10 != 0) sizePad += 0x10 - size % 0x10; - this.DSi9Data = new byte[sizePad]; - for (long i = size; i < sizePad; i++) this.DSi9Data[i] = 0xFF; - - Stream str = File.OpenRead(filePath); - str.Position = offset; - str.Read(this.DSi9Data, 0, (int)size); - str.Close(); - } - - public void ImportArm7iData(string filePath, uint offset, uint size) - { - uint sizePad = size; - if (size % 0x10 != 0) sizePad += 0x10 - size % 0x10; - this.DSi7Data = new byte[sizePad]; - for (long i = size; i < sizePad; i++) this.DSi7Data[i] = 0xFF; - - Stream str = File.OpenRead(filePath); - str.Position = offset; - str.Read(this.DSi7Data, 0, (int)size); - str.Close(); - } - - public void Write(ref BinaryWriter bw, Estructuras.ROMHeader hdr, out byte[] digest_master_hash) - { - // Write DSi ARM sections and padding - while (bw.BaseStream.Position < hdr.sector_hashtable_start) bw.Write((byte)0xFF); - bw.BaseStream.Position = hdr.sector_hashtable_start + hdr.sector_hashtable_size; - while (bw.BaseStream.Position < hdr.block_hashtable_start) bw.Write((byte)0xFF); - bw.BaseStream.Position = hdr.block_hashtable_start + hdr.block_hashtable_size; - while (bw.BaseStream.Position < hdr.dsi9_rom_offset) bw.Write((byte)0xFF); - if (this.Header2Data != null && !hdr.trimmedRom) - //if (this.Header2Data != null) - { - bw.BaseStream.Position = hdr.digest_twl_start - 0x3000; - for (int j = 0; j < 3; j++) bw.Write(this.Header2Data[j]); - } - - bw.Write(this.DSi9Data, 0, this.DSi9Data.Length); - while (bw.BaseStream.Position < hdr.dsi7_rom_offset) bw.Write((byte)0xFF); - bw.Write(this.DSi7Data, 0, this.DSi7Data.Length); - while (bw.BaseStream.Position < hdr.total_rom_size) bw.Write((byte)0xFF); - long pos = bw.BaseStream.Position; - - // Compute NTR Secure Area Hashtable - int i = 0; - HMACSHA1 hmac = new HMACSHA1(TWL.hmac_sha1_key); - BinaryReader br = new BinaryReader(bw.BaseStream); - br.BaseStream.Position = hdr.digest_ntr_start; - byte[] saData = br.ReadBytes(0x4000); - uint gameCode = BitConverter.ToUInt32(Encoding.ASCII.GetBytes(hdr.gameCode), 0); - SAEncryptor.EncryptSecureArea(gameCode, saData); - while (i < 0x4000 / hdr.digest_sector_size) - { - byte[] hash = hmac.ComputeHash(saData, (int)(i * hdr.digest_sector_size), (int)hdr.digest_sector_size); - bw.BaseStream.Position = hdr.sector_hashtable_start + i * 0x14; - bw.Write(hash); - i++; - } - - // Compute NTR Hashtable - br.BaseStream.Position = hdr.digest_ntr_start + 0x4000; - while (br.BaseStream.Position < hdr.digest_ntr_start + hdr.digest_ntr_size) - { - byte[] hash = hmac.ComputeHash(br.ReadBytes((int)hdr.digest_sector_size)); - long tmp = br.BaseStream.Position; - bw.BaseStream.Position = hdr.sector_hashtable_start + i * 0x14; - bw.Write(hash); - br.BaseStream.Position = tmp; - i++; - } - - // Compute TWL Hashtable - br.BaseStream.Position = hdr.digest_twl_start; - while (br.BaseStream.Position < hdr.digest_twl_start + hdr.digest_twl_size) - { - byte[] hash = hmac.ComputeHash(br.ReadBytes((int)hdr.digest_sector_size)); - long tmp = br.BaseStream.Position; - bw.BaseStream.Position = hdr.sector_hashtable_start + i * 0x14; - bw.Write(hash); - br.BaseStream.Position = tmp; - i++; - } - - // Compute Secondary Hashtable - i = 0; - br.BaseStream.Position = hdr.sector_hashtable_start; - while (br.BaseStream.Position < hdr.sector_hashtable_start + hdr.sector_hashtable_size) - { - byte[] hash = hmac.ComputeHash(br.ReadBytes((int)hdr.digest_block_sectorcount * 0x14)); - long tmp = br.BaseStream.Position; - bw.BaseStream.Position = hdr.block_hashtable_start + i * 0x14; - bw.Write(hash); - br.BaseStream.Position = tmp; - i++; - } - - // Compute Master Hashtable - br.BaseStream.Position = hdr.block_hashtable_start; - digest_master_hash = hmac.ComputeHash(br.ReadBytes((int)hdr.block_hashtable_size)); - - // Encrypt DSi sections - if (this.twlEncrypted) - { - byte[] key = AES128KeyGenerate(hdr); - byte[] counter9 = new byte[16]; - byte[] counter7 = new byte[16]; - Array.Copy(hdr.hmac_arm9, 0, counter9, 0, 16); - Array.Copy(hdr.hmac_arm7, 0, counter7, 0, 16); - bw.BaseStream.Position = hdr.dsi9_rom_offset; - if (hdr.modcrypt1_size > 0) bw.Write(AES128CTRCrypt(key, counter9, this.DSi9Data, 0, hdr.modcrypt1_size)); - bw.BaseStream.Position = hdr.dsi7_rom_offset; - if (hdr.modcrypt2_size > 0) bw.Write(AES128CTRCrypt(key, counter7, this.DSi7Data, 0, hdr.modcrypt2_size)); - } - - bw.BaseStream.Position = pos; - } - - public static void UpdateHeaderSignatures( - ref BinaryWriter bw, - ref Estructuras.ROMHeader header, - string header_file, - bool keep_original) - { - long pos = bw.BaseStream.Position; - - // Update digest master hash - bw.BaseStream.Position = 0x328; - bw.Write(header.hmac_digest_master); - - // Read signed header data - BinaryReader br = new BinaryReader(File.OpenRead(header_file)); - byte[] hdrSignedData = br.ReadBytes(0xE00); - Array.Copy(header.hmac_digest_master, 0, hdrSignedData, 0x328, 0x14); - br.Close(); - - // Verify RSA Signature - RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024); - RSAParameters rsaKey = new RSAParameters(); - rsaKey.Exponent = new byte[] { 1, 0, 1 }; - rsaKey.Modulus = (byte[])TWL.rsaPublicKey.Clone(); - rsaKey.D = null; // In future: here set Private key - rsa.ImportParameters(rsaKey); - bool verify = rsa.VerifyData(hdrSignedData, new SHA1CryptoServiceProvider(), header.rsa_signature); - if (!verify) - { - // RSA encrypt signature - if (rsaKey.D != null) - { - header.rsa_signature = rsa.SignData(hdrSignedData, new SHA1CryptoServiceProvider()); - } - else - { - // Calc SHA1 hash - SHA1 sha1 = new SHA1CryptoServiceProvider(); - byte[] hash = sha1.ComputeHash(hdrSignedData); - //Array.Reverse(hash); - sha1.Clear(); - sha1.Dispose(); - + } + } + + // Calc SHA1-HMAC of overlays9 + HMACSHA1 hmac = new HMACSHA1(TWL.hmac_sha1_key); + this.Overlays9Sha1Hmac = new byte[overlays.Length][]; + for (int i = 0; i < overlays.Length; i++) + { + br.BaseStream.Position = overlays[i].offset; + byte[] ovlData = br.ReadBytes((int)overlays[i].size); + this.Overlays9Sha1Hmac[i] = hmac.ComputeHash(ovlData, 0, ovlData.Length); + } + + // Check for encryption modcrypt section + this.twlEncrypted = false; // (hdr.twlInternalFlags & 2) > 0; + if (hdr.modcrypt1_start >= hdr.digest_twl_start && hdr.modcrypt1_start < 0xFFFFFFFF) + { + uint modcryptHashedSectorIndex = (hdr.modcrypt1_start - hdr.digest_twl_start) / hdr.digest_sector_size; + uint modcryptHashedSectorOff = modcryptHashedSectorIndex * hdr.digest_sector_size; + uint hashOff = modcryptHashedSectorIndex * 0x14; + + br.BaseStream.Position = hdr.digest_twl_start + modcryptHashedSectorOff; + byte[] firstModcryptBlock = br.ReadBytes((int)hdr.digest_sector_size); + byte[] hash = hmac.ComputeHash(firstModcryptBlock, 0, (int)hdr.digest_sector_size); + for (int i = 0; i < 20 && !twlEncrypted; i++) twlEncrypted = hash[i] != Hashtable1Data[this.firstDSiHashOffset + hashOff + i]; + } + br.Close(); + + // Decrypt modcrypt sections + if (this.twlEncrypted) + { + byte[] key = AES128KeyGenerate(hdr); + byte[] counter = new byte[16]; + if (hdr.modcrypt1_size > 0 && hdr.modcrypt1_size < 0xFFFFFFFF) + { + Array.Copy(hdr.hmac_arm9, 0, counter, 0, 16); + uint offset = hdr.modcrypt1_start - hdr.dsi9_rom_offset; + byte[] decrypted = AES128CTRCrypt(key, counter, this.DSi9Data, offset, hdr.modcrypt1_size); + if (offset == 0 && decrypted.Length == this.DSi9Data.Length) this.DSi9Data = decrypted; + else Array.Copy(decrypted, 0, this.DSi9Data, offset, decrypted.Length); + } + + if (hdr.modcrypt2_size > 0 && hdr.modcrypt2_size < 0xFFFFFFFF) + { + Array.Copy(hdr.hmac_arm7, 0, counter, 0, 16); + uint offset = hdr.modcrypt2_start - hdr.dsi7_rom_offset; + byte[] decrypted = AES128CTRCrypt(key, counter, this.DSi7Data, offset, hdr.modcrypt2_size); + if (offset == 0 && decrypted.Length == this.DSi7Data.Length) this.DSi7Data = decrypted; + else Array.Copy(decrypted, 0, this.DSi7Data, offset, decrypted.Length); + } + } + + hmac.Clear(); + hmac.Dispose(); + this.twlEncrypted = (hdr.twlInternalFlags & 2) > 0; + } + + public void UpdateOverlays9Sha1Hmac(ref sFile arm9, Estructuras.ROMHeader hdr, List ov9, HMACSHA1 hmac = null) + { + if (hmac == null) hmac = new HMACSHA1(hmac_sha1_key); + byte[][] hashes = new byte[ov9.Count][]; + bool changed = false; + for (int i = 0; i < ov9.Count; i++) + { + Stream str = File.OpenRead(ov9[i].path); + byte[] buffer = new byte[ov9[i].size]; + str.Position = ov9[i].offset; + str.Read(buffer, 0, buffer.Length); + str.Close(); + hashes[i] = hmac.ComputeHash(buffer); + for (int j = 0; j < hashes[i].Length && !changed; j++) changed |= hashes[i][j] != this.Overlays9Sha1Hmac[i][j]; + } + + if (changed) + { + // Read arm9 + BinaryReader br = new BinaryReader(File.OpenRead(arm9.path)); + br.BaseStream.Position = arm9.offset; + byte[] arm9Data = br.ReadBytes((int)arm9.size); + br.Close(); + + // Decompress arm9 + hdr.ARM9size = arm9.size; + uint initptr = BitConverter.ToUInt32(hdr.reserved2, 0) & 0x3FFF; + uint hdrptr = BitConverter.ToUInt32(arm9Data, (int)initptr + 0x14) - hdr.ARM9ramAddress; + uint cmparm9 = ARM9BLZ.Decompress(arm9Data, hdr, out arm9Data); + + // Get hmac offset + uint offset = 0; + uint end = BitConverter.ToUInt32(arm9Data, (int)initptr + 8) - hdr.ARM9ramAddress; + for (long i = end - 0x14 * ov9.Count; i >= 0 && offset == 0; i--) + { + bool cond = arm9Data[i] == this.Overlays9Sha1Hmac[0][0]; + for (int j = 1; j < 20 && cond; j++) cond = arm9Data[i + j] == this.Overlays9Sha1Hmac[0][j]; + if (cond) offset = (uint)i; + } + + // Write new hash + if (offset > 0) + { + for (int i = 0; i < ov9.Count; i++) Array.Copy(hashes[i], 0, arm9Data, offset + i * 0x14, 20); + if (cmparm9 == 0) arm9Data = ARM9BLZ.Compress(arm9Data, hdr, arm9.size - hdrptr); + + string arm9Binary = Path.GetTempFileName(); + File.WriteAllBytes(arm9Binary, arm9Data); + arm9.path = arm9Binary; + arm9.offset = 0; + arm9.size = (uint)arm9Data.Length; + } + else Console.WriteLine("Overlays9 has been modified but can't update hashes in ARM9.bin!"); + } + } + + public void ImportArm9iData(string filePath, uint offset, uint size) + { + uint sizePad = size; + if (size % 0x10 != 0) sizePad += 0x10 - size % 0x10; + this.DSi9Data = new byte[sizePad]; + for (long i = size; i < sizePad; i++) this.DSi9Data[i] = 0xFF; + + Stream str = File.OpenRead(filePath); + str.Position = offset; + str.Read(this.DSi9Data, 0, (int)size); + str.Close(); + } + + public void ImportArm7iData(string filePath, uint offset, uint size) + { + uint sizePad = size; + if (size % 0x10 != 0) sizePad += 0x10 - size % 0x10; + this.DSi7Data = new byte[sizePad]; + for (long i = size; i < sizePad; i++) this.DSi7Data[i] = 0xFF; + + Stream str = File.OpenRead(filePath); + str.Position = offset; + str.Read(this.DSi7Data, 0, (int)size); + str.Close(); + } + + public void Write(ref BinaryWriter bw, Estructuras.ROMHeader hdr, out byte[] digest_master_hash) + { + // Write DSi ARM sections and padding + while (bw.BaseStream.Position < hdr.sector_hashtable_start) bw.Write((byte)0xFF); + bw.BaseStream.Position = hdr.sector_hashtable_start + hdr.sector_hashtable_size; + while (bw.BaseStream.Position < hdr.block_hashtable_start) bw.Write((byte)0xFF); + bw.BaseStream.Position = hdr.block_hashtable_start + hdr.block_hashtable_size; + while (bw.BaseStream.Position < hdr.dsi9_rom_offset) bw.Write((byte)0xFF); + if (this.Header2Data != null && !hdr.trimmedRom) + //if (this.Header2Data != null) + { + bw.BaseStream.Position = hdr.digest_twl_start - 0x3000; + for (int j = 0; j < 3; j++) bw.Write(this.Header2Data[j]); + } + + bw.Write(this.DSi9Data, 0, this.DSi9Data.Length); + while (bw.BaseStream.Position < hdr.dsi7_rom_offset) bw.Write((byte)0xFF); + bw.Write(this.DSi7Data, 0, this.DSi7Data.Length); + while (bw.BaseStream.Position < hdr.total_rom_size) bw.Write((byte)0xFF); + long pos = bw.BaseStream.Position; + + // Compute NTR Secure Area Hashtable + int i = 0; + HMACSHA1 hmac = new HMACSHA1(TWL.hmac_sha1_key); + BinaryReader br = new BinaryReader(bw.BaseStream); + br.BaseStream.Position = hdr.digest_ntr_start; + byte[] saData = br.ReadBytes(0x4000); + uint gameCode = BitConverter.ToUInt32(Encoding.ASCII.GetBytes(hdr.gameCode), 0); + SAEncryptor.EncryptSecureArea(gameCode, saData); + while (i < 0x4000 / hdr.digest_sector_size) + { + byte[] hash = hmac.ComputeHash(saData, (int)(i * hdr.digest_sector_size), (int)hdr.digest_sector_size); + bw.BaseStream.Position = hdr.sector_hashtable_start + i * 0x14; + bw.Write(hash); + i++; + } + + // Compute NTR Hashtable + br.BaseStream.Position = hdr.digest_ntr_start + 0x4000; + while (br.BaseStream.Position < hdr.digest_ntr_start + hdr.digest_ntr_size) + { + byte[] hash = hmac.ComputeHash(br.ReadBytes((int)hdr.digest_sector_size)); + long tmp = br.BaseStream.Position; + bw.BaseStream.Position = hdr.sector_hashtable_start + i * 0x14; + bw.Write(hash); + br.BaseStream.Position = tmp; + i++; + } + + // Compute TWL Hashtable + br.BaseStream.Position = hdr.digest_twl_start; + while (br.BaseStream.Position < hdr.digest_twl_start + hdr.digest_twl_size) + { + byte[] hash = hmac.ComputeHash(br.ReadBytes((int)hdr.digest_sector_size)); + long tmp = br.BaseStream.Position; + bw.BaseStream.Position = hdr.sector_hashtable_start + i * 0x14; + bw.Write(hash); + br.BaseStream.Position = tmp; + i++; + } + + // Compute Secondary Hashtable + i = 0; + br.BaseStream.Position = hdr.sector_hashtable_start; + while (br.BaseStream.Position < hdr.sector_hashtable_start + hdr.sector_hashtable_size) + { + byte[] hash = hmac.ComputeHash(br.ReadBytes((int)hdr.digest_block_sectorcount * 0x14)); + long tmp = br.BaseStream.Position; + bw.BaseStream.Position = hdr.block_hashtable_start + i * 0x14; + bw.Write(hash); + br.BaseStream.Position = tmp; + i++; + } + + // Compute Master Hashtable + br.BaseStream.Position = hdr.block_hashtable_start; + digest_master_hash = hmac.ComputeHash(br.ReadBytes((int)hdr.block_hashtable_size)); + + // Encrypt DSi sections + if (this.twlEncrypted) + { + byte[] key = AES128KeyGenerate(hdr); + byte[] counter9 = new byte[16]; + byte[] counter7 = new byte[16]; + Array.Copy(hdr.hmac_arm9, 0, counter9, 0, 16); + Array.Copy(hdr.hmac_arm7, 0, counter7, 0, 16); + bw.BaseStream.Position = hdr.dsi9_rom_offset; + if (hdr.modcrypt1_size > 0) bw.Write(AES128CTRCrypt(key, counter9, this.DSi9Data, 0, hdr.modcrypt1_size)); + bw.BaseStream.Position = hdr.dsi7_rom_offset; + if (hdr.modcrypt2_size > 0) bw.Write(AES128CTRCrypt(key, counter7, this.DSi7Data, 0, hdr.modcrypt2_size)); + } + + bw.BaseStream.Position = pos; + } + + public static void UpdateHeaderSignatures( + ref BinaryWriter bw, + ref Estructuras.ROMHeader header, + string header_file, + bool keep_original) + { + long pos = bw.BaseStream.Position; + + // Update digest master hash + bw.BaseStream.Position = 0x328; + bw.Write(header.hmac_digest_master); + + // Read signed header data + BinaryReader br = new BinaryReader(File.OpenRead(header_file)); + byte[] hdrSignedData = br.ReadBytes(0xE00); + Array.Copy(header.hmac_digest_master, 0, hdrSignedData, 0x328, 0x14); + br.Close(); + + // Verify RSA Signature + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024); + RSAParameters rsaKey = new RSAParameters(); + rsaKey.Exponent = new byte[] { 1, 0, 1 }; + rsaKey.Modulus = (byte[])TWL.rsaPublicKey.Clone(); + rsaKey.D = null; // In future: here set Private key + rsa.ImportParameters(rsaKey); + bool verify = rsa.VerifyData(hdrSignedData, new SHA1CryptoServiceProvider(), header.rsa_signature); + if (!verify) + { + // RSA encrypt signature + if (rsaKey.D != null) + { + header.rsa_signature = rsa.SignData(hdrSignedData, new SHA1CryptoServiceProvider()); + } + else + { + // Calc SHA1 hash + SHA1 sha1 = new SHA1CryptoServiceProvider(); + byte[] hash = sha1.ComputeHash(hdrSignedData); + //Array.Reverse(hash); + sha1.Clear(); + sha1.Dispose(); + if (!keep_original) { // Set unencrypted signature for no$gba compatible header.rsa_signature = (byte[])TWL.rsaSignatureMask.Clone(); Array.Copy(hash, 0, header.rsa_signature, 0x80 - 0x14, 0x14); - } - } - - // Write signature - bw.BaseStream.Position = 0xF80; - bw.Write(header.rsa_signature, 0, 0x80); - } - - bw.BaseStream.Position = pos; - } - - private static byte[] AES128CTRCrypt(byte[] key, byte[] counter, byte[] data, uint offset, uint size) - { - AES128CounterMode aes128 = new AES128CounterMode(counter); - ICryptoTransform ict = aes128.CreateEncryptor(key, null); - return ict.TransformFinalBlock(data, (int)offset, (int)size); - } - - private static byte[] AES128KeyGenerate(Estructuras.ROMHeader hdr) - { - bool debug = ((hdr.twlInternalFlags & 4) > 0) || ((hdr.appflags[3] & 0x80) > 0); - if (debug) - { - byte[] key = new byte[16]; - Array.Copy(Encoding.ASCII.GetBytes(hdr.gameTitle), 0, key, 0, 12); - Array.Copy(Encoding.ASCII.GetBytes(hdr.gameCode), 0, key, 12, 4); - return key; - } - else - { - byte[] keyX = new byte[16]; - byte[] keyY = new byte[16]; - Array.Copy(Encoding.ASCII.GetBytes("Nintendo"), 0, keyX, 0, 8); - Array.Copy(Encoding.ASCII.GetBytes(hdr.gameCode), 0, keyX, 8, 4); - for (int j = 0; j < 4; j++) keyX[12 + j] = (byte)hdr.gameCode[3 - j]; - //Array.Copy(BitConverter.GetBytes(hdr.tid_low), 0, keyX, 12, 4); - Array.Copy(hdr.hmac_arm9i, 0, keyY, 0, 16); - return AES128KeyGenerate(keyX, keyY); - } - } - - private static byte[] AES128KeyGenerate(byte[] keyX, byte[] keyY) - { - // Key = ((Key_X XOR Key_Y) + FFFEFB4E295902582A680F5F1A4F3E79h) ROL 42 - byte[] key = new byte[16]; - for (int i = 0; i < 16; i++) key[i] = (byte)(keyX[i] ^ keyY[i]); - - UInt64[] tmp = new ulong[2]; - UInt64[] xyKey = new[] { BitConverter.ToUInt64(key, 0), BitConverter.ToUInt64(key, 8) }; - UInt64[] cKey = new[] { BitConverter.ToUInt64(modcryptCmnKey, 0), BitConverter.ToUInt64(modcryptCmnKey, 8) }; - tmp[0] = (cKey[0] >> 1) + (xyKey[0] >> 1) + (cKey[0] & xyKey[0] & 1); - tmp[0] = tmp[0] >> 63; - cKey[0] = cKey[0] + xyKey[0]; - cKey[1] = cKey[1] + xyKey[1] + tmp[0]; - - int shift = 42; - tmp[0] = cKey[0] << shift; - tmp[1] = cKey[1] << shift; - tmp[0] |= (cKey[1] >> (64 - shift)); - tmp[1] |= (cKey[0] >> (64 - shift)); - cKey[0] = tmp[0]; - cKey[1] = tmp[1]; - - Array.Copy(BitConverter.GetBytes(cKey[0]), 0, key, 0, 8); - Array.Copy(BitConverter.GetBytes(cKey[1]), 0, key, 8, 8); - - return key; - } - } -} + } + } + + // Write signature + bw.BaseStream.Position = 0xF80; + bw.Write(header.rsa_signature, 0, 0x80); + } + + bw.BaseStream.Position = pos; + } + + private static byte[] AES128CTRCrypt(byte[] key, byte[] counter, byte[] data, uint offset, uint size) + { + AES128CounterMode aes128 = new AES128CounterMode(counter); + ICryptoTransform ict = aes128.CreateEncryptor(key, null); + return ict.TransformFinalBlock(data, (int)offset, (int)size); + } + + private static byte[] AES128KeyGenerate(Estructuras.ROMHeader hdr) + { + bool debug = ((hdr.twlInternalFlags & 4) > 0) || ((hdr.appflags[3] & 0x80) > 0); + if (debug) + { + byte[] key = new byte[16]; + Array.Copy(Encoding.ASCII.GetBytes(hdr.gameTitle), 0, key, 0, 12); + Array.Copy(Encoding.ASCII.GetBytes(hdr.gameCode), 0, key, 12, 4); + return key; + } + else + { + byte[] keyX = new byte[16]; + byte[] keyY = new byte[16]; + Array.Copy(Encoding.ASCII.GetBytes("Nintendo"), 0, keyX, 0, 8); + Array.Copy(Encoding.ASCII.GetBytes(hdr.gameCode), 0, keyX, 8, 4); + for (int j = 0; j < 4; j++) keyX[12 + j] = (byte)hdr.gameCode[3 - j]; + //Array.Copy(BitConverter.GetBytes(hdr.tid_low), 0, keyX, 12, 4); + Array.Copy(hdr.hmac_arm9i, 0, keyY, 0, 16); + return AES128KeyGenerate(keyX, keyY); + } + } + + private static byte[] AES128KeyGenerate(byte[] keyX, byte[] keyY) + { + // Key = ((Key_X XOR Key_Y) + FFFEFB4E295902582A680F5F1A4F3E79h) ROL 42 + byte[] key = new byte[16]; + for (int i = 0; i < 16; i++) key[i] = (byte)(keyX[i] ^ keyY[i]); + + UInt64[] tmp = new ulong[2]; + UInt64[] xyKey = new[] { BitConverter.ToUInt64(key, 0), BitConverter.ToUInt64(key, 8) }; + UInt64[] cKey = new[] { BitConverter.ToUInt64(modcryptCmnKey, 0), BitConverter.ToUInt64(modcryptCmnKey, 8) }; + tmp[0] = (cKey[0] >> 1) + (xyKey[0] >> 1) + (cKey[0] & xyKey[0] & 1); + tmp[0] = tmp[0] >> 63; + cKey[0] = cKey[0] + xyKey[0]; + cKey[1] = cKey[1] + xyKey[1] + tmp[0]; + + int shift = 42; + tmp[0] = cKey[0] << shift; + tmp[1] = cKey[1] << shift; + tmp[0] |= (cKey[1] >> (64 - shift)); + tmp[1] |= (cKey[0] >> (64 - shift)); + cKey[0] = tmp[0]; + cKey[1] = tmp[1]; + + Array.Copy(BitConverter.GetBytes(cKey[0]), 0, key, 0, 8); + Array.Copy(BitConverter.GetBytes(cKey[1]), 0, key, 8, 8); + + return key; + } + } +} diff --git a/Tinke/Program.cs b/Tinke/Program.cs index 27ddd51..59e2963 100644 --- a/Tinke/Program.cs +++ b/Tinke/Program.cs @@ -18,16 +18,20 @@ * */ using System; -//using System.Collections.Generic; -//using System.Linq; using System.Windows.Forms; -//using System.Reflection; using System.IO; +using System.Runtime.InteropServices; namespace Tinke { static class Program { + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool AttachConsole(int dwProcessId); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool FreeConsole(); + /// /// Punto de entrada principal para la aplicación. /// @@ -35,7 +39,7 @@ namespace Tinke static void Main(string[] args) { #region Comprobación de archivos necesarios - string[] archivos = new string[] { "Ekona.dll", "DSDecmp.dll" }; + string[] archivos = new string[] { "Ekona.dll", "DSDecmp.dll" , "Be.Windows.Forms.HexBox.dll" }; string faltan = ""; for (int i = 0; i < archivos.Length; i++) { @@ -55,5 +59,4 @@ namespace Tinke Application.Run(new Sistema()); } } - } diff --git a/Tinke/Sistema.cs b/Tinke/Sistema.cs index 2cc4f5d..0c06db4 100644 --- a/Tinke/Sistema.cs +++ b/Tinke/Sistema.cs @@ -62,12 +62,31 @@ namespace Tinke // The IE control of the Debug windows doesn't work in Mono isMono = (Type.GetType("Mono.Runtime") != null); + if (Environment.GetCommandLineArgs().Length == 2 && (Environment.GetCommandLineArgs()[1] == "-h" || Environment.GetCommandLineArgs()[1] == "--help")) + { + Program.AttachConsole(-1); + Console.WriteLine("\n" + this.Text); + Console.WriteLine("Usage: Tinke.exe rom_name [option]"); + Console.WriteLine("options:"); + Console.WriteLine("-x: Extract all files from nds rom"); + Console.WriteLine("-r: Replace all nitrofs files by dir, need -o to set an output rom path(-o Only allowed after -r)"); + Console.WriteLine("-h or --help: Show this message, must be the first param..."); + Program.FreeConsole(); + SendKeys.SendWait("{ENTER}"); + } + sb = new StringBuilder(); TextWriter tw = new StringWriter(sb); tw.NewLine = "
"; - if (!isMono) + if (!isMono && !(Environment.GetCommandLineArgs().Length >= 3 && (Environment.GetCommandLineArgs()[2] == "-x" || Environment.GetCommandLineArgs()[2] == "-r"))) Console.SetOut(tw); + if (Environment.GetCommandLineArgs().Length >= 3 && (Environment.GetCommandLineArgs()[2] == "-x" || Environment.GetCommandLineArgs()[2] == "-r")) + { + Program.AttachConsole(-1); + Console.WriteLine("\n" + this.Text); + } + #region Language if (!File.Exists(Application.StartupPath + Path.DirectorySeparatorChar + "Tinke.xml")) { @@ -144,11 +163,47 @@ namespace Tinke filesToRead[0] = o.SelectedPath; o.Dispose(); } + else if (Environment.GetCommandLineArgs()[1] == "-h" || Environment.GetCommandLineArgs()[1] == "--help") + { + Application.Exit(); + return; + } else filesToRead[0] = Environment.GetCommandLineArgs()[1]; } else if (Environment.GetCommandLineArgs().Length >= 3) { + if (Environment.GetCommandLineArgs()[2] == "-x") + { + filesToRead[0] = Environment.GetCommandLineArgs()[1]; + ReadGame(filesToRead[0]); + sFolder folderSelect = accion.Root; + + if (Environment.GetCommandLineArgs().Length > 3 && Environment.GetCommandLineArgs()[3] is string) + { + Directory.CreateDirectory(Environment.GetCommandLineArgs()[3] + Path.DirectorySeparatorChar + folderSelect.name); + RecursivoExtractFolder(folderSelect, Environment.GetCommandLineArgs()[3] + Path.DirectorySeparatorChar + folderSelect.name); + Console.WriteLine("Extract all files to " + Environment.GetCommandLineArgs()[3] + Path.DirectorySeparatorChar + folderSelect.name); + } else + Console.WriteLine("Param error..."); + Program.FreeConsole(); + SendKeys.SendWait("{ENTER}"); + Application.Exit(); + } else if (Environment.GetCommandLineArgs()[2] == "-r" && Environment.GetCommandLineArgs().Length > 5 && Environment.GetCommandLineArgs()[4] == "-o") + { + filesToRead[0] = Environment.GetCommandLineArgs()[1]; + ReadGame(filesToRead[0]); + if (Environment.GetCommandLineArgs()[3] is string) + { + ChangeByDir(Environment.GetCommandLineArgs()[3]); + } + // parse saving args + for(int i = 5; i < Environment.GetCommandLineArgs().Length; i++) + { + + } + return; + } filesToRead = new String[Environment.GetCommandLineArgs().Length - 1]; Array.Copy(Environment.GetCommandLineArgs(), 1, filesToRead, 0, filesToRead.Length); } @@ -1444,6 +1499,8 @@ namespace Tinke * Files... */ bool keep_original = false; + bool a9_recomp = false; + bool a9_bestcomp = false; Nitro.Estructuras.ROMHeader header = romInfo.Cabecera; Dialog.SaveOptions dialog = new Dialog.SaveOptions(); @@ -1453,6 +1510,10 @@ namespace Tinke keep_original = true; if (dialog.IsSafeTrim) header.trimmedRom = true; + if (dialog.IsReCompress) + a9_recomp = true; + if (dialog.IsBetterCompress) + a9_bestcomp = true; Thread create = new Thread(ThreadEspera) { @@ -1533,16 +1594,19 @@ namespace Tinke header.secureCRC16 = SecureArea.CalcCRC(this.secureArea.EncryptedData, gameCode); } - bool cmparm9 = true; + uint cmparm9 = 0; if (!ov9Sha1Hmac_updated) { uint initptr = BitConverter.ToUInt32(header.reserved2, 0) & 0x3FFF; uint hdrptr = BitConverter.ToUInt32(arm9Data, (int)initptr + 0x14) - header.ARM9ramAddress; byte[] arm9Data_dec; cmparm9 = ARM9BLZ.Decompress(arm9Data, header, out arm9Data_dec); - if (!cmparm9) + if (cmparm9 == 0 && a9_recomp) { - arm9Data = ARM9BLZ.Compress(arm9Data_dec, header, 0); + arm9Data = ARM9BLZ.Compress(arm9Data, header, 0, a9_bestcomp); + } else if (cmparm9 == 1 && a9_recomp) + { + arm9Data = ARM9BLZ.Compress(arm9Data_dec, header, 0, a9_bestcomp); } } @@ -1551,7 +1615,7 @@ namespace Tinke bw.Flush(); br.Close(); - if (!ov9Sha1Hmac_updated && !cmparm9) + if (!ov9Sha1Hmac_updated && a9_recomp) { arm9.path = arm9Binary; arm9.offset = 0; @@ -1627,7 +1691,6 @@ namespace Tinke Console.WriteLine(Tools.Helper.GetTranslation("Messages", "S09"), new FileInfo(arm9Binary).Length); - // Escribismo el ARM7 Binary string arm7Binary = Path.GetTempFileName(); string overlays7 = Path.GetTempFileName(); @@ -1690,7 +1753,6 @@ namespace Tinke bw.Close(); Console.WriteLine(Tools.Helper.GetTranslation("Messages", "S09"), new FileInfo(arm7Binary).Length); - // Escribimos el FNT (File Name Table) string fileFNT = Path.GetTempFileName(); Console.Write("\tFile Name Table (FNT)..."); @@ -1723,7 +1785,7 @@ namespace Tinke // Escribimos el banner string banner = Path.GetTempFileName(); header.banner_size = Nitro.NDS.EscribirBanner(banner, romInfo.Banner); - + // Escribimos el FAT (File Allocation Table) string fileFAT = Path.GetTempFileName(); header.FAToffset = currPos; @@ -1865,15 +1927,8 @@ namespace Tinke o.DefaultExt = ".nds"; o.Filter = "Nintendo DS ROM (*.nds)|*.nds"; o.OverwritePrompt = true; - Open_Dialog: if (o.ShowDialog() == System.Windows.Forms.DialogResult.OK) { - if (o.FileName == accion.ROMFile) - { - MessageBox.Show(Tools.Helper.GetTranslation("Sistema", "S44")); - goto Open_Dialog; - } - Thread saverom = new Thread(ThreadEspera) { IsBackground = true @@ -1921,7 +1976,7 @@ namespace Tinke } sb.Length = 0; } - + // Borramos archivos ya innecesarios File.Delete(header_file); File.Delete(arm9Binary); @@ -1932,10 +1987,6 @@ namespace Tinke File.Delete(fileFAT); File.Delete(banner); File.Delete(files); - - //if (!isMono) - //debug.Add_Text(sb.ToString()); - //sb.Length = 0; } private void btnImport_Click(object sender, EventArgs e) { @@ -2249,11 +2300,7 @@ namespace Tinke if (!isMono) { - try - { - espera.Close(); - } - catch { }; + CloseEspera(wait); debug.Add_Text(sb.ToString()); } sb.Length = 0; @@ -2502,30 +2549,10 @@ namespace Tinke btnDesplazar.Text = ">>>>>"; } } - private void btnImport1_Click(object sender, EventArgs e) + private void ChangeByDir(string files_path) { - Thread matching = new Thread(ThreadEspera) - { - IsBackground = true - }; - if (!isMono) - matching.Start("S08"); - - FolderBrowserDialog FBD = new FolderBrowserDialog - { - Description = Tools.Helper.GetTranslation("Sistema", "S47"), - ShowNewFolderButton = false - }; - if (FBD.ShowDialog() != DialogResult.OK) - { - if (!isMono) - CloseEspera(matching); - return; - } - - Console.WriteLine(FBD.SelectedPath); List files = new List(); - files = GetAllSubFiles(FBD.SelectedPath, files); + files = GetAllSubFiles(files_path, files); foreach (string currFile in files) { string nstr; @@ -2569,12 +2596,32 @@ namespace Tinke accion.Change_File(fileToBeChanged.id, currFile); Console.WriteLine(currFile); } + } + private void btnImport1_Click(object sender, EventArgs e) + { + Thread matching = new Thread(ThreadEspera) + { + IsBackground = true + }; if (!isMono) - try - { - espera.Close(); - } - catch { }; + matching.Start("S08"); + + FolderBrowserDialog FBD = new FolderBrowserDialog + { + Description = Tools.Helper.GetTranslation("Sistema", "S47"), + ShowNewFolderButton = false + }; + if (FBD.ShowDialog() != DialogResult.OK) + { + if (!isMono) + CloseEspera(matching); + return; + } + + Console.WriteLine(FBD.SelectedPath); + ChangeByDir(FBD.SelectedPath); + if (!isMono) + CloseEspera(matching); } public static List GetAllSubFiles(string directoryPath, List files) { diff --git a/Tinke/Tools/ARM9BLZ.cs b/Tinke/Tools/ARM9BLZ.cs index c8b7f00..6fb2eed 100644 --- a/Tinke/Tools/ARM9BLZ.cs +++ b/Tinke/Tools/ARM9BLZ.cs @@ -1,89 +1,91 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Tinke.Tools -{ - using System.IO; - - using DSDecmp.Formats; - - using Nitro; - - class ARM9BLZ - { - /// - /// Decompress ARM9.bin - /// - /// Compressed ARM9.bin data - /// ROM header - /// Decompressed data - /// True if the decompression was successful. - public static bool Decompress(byte[] arm9Data, Estructuras.ROMHeader hdr, out byte[] decompressed) - { - decompressed = arm9Data; - uint nitrocode_length = 0; - if (arm9Data[arm9Data.Length - 0xC] == 0x21 && arm9Data[arm9Data.Length - 0xB] == 0x06 +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tinke.Tools +{ + using System.IO; + + using DSDecmp.Formats; + + using Nitro; + + class ARM9BLZ + { + /// + /// Decompress ARM9.bin + /// + /// Compressed ARM9.bin data + /// ROM header + /// Decompressed data + /// 0 = uncompressed; 1 = compressed + public static uint Decompress(byte[] arm9Data, Estructuras.ROMHeader hdr, out byte[] decompressed) + { + decompressed = arm9Data; + uint nitrocode_length = 0; + if (arm9Data[arm9Data.Length - 0xC] == 0x21 && arm9Data[arm9Data.Length - 0xB] == 0x06 && arm9Data[arm9Data.Length - 0xA] == 0xC0 && arm9Data[arm9Data.Length - 0x9] == 0xDE) { nitrocode_length = 0x0C; //Nitrocode found. - } - uint initptr = BitConverter.ToUInt32(hdr.reserved2, 0) & 0x3FFF; - uint hdrptr = BitConverter.ToUInt32(arm9Data, (int)initptr + 0x14); + } + uint initptr = BitConverter.ToUInt32(hdr.reserved2, 0) & 0x3FFF; + uint hdrptr = BitConverter.ToUInt32(arm9Data, (int)initptr + 0x14); if (initptr == 0) { hdrptr = hdr.ARM9ramAddress + hdr.ARM9size; - } - uint postSize = (uint)arm9Data.Length - (hdrptr - hdr.ARM9ramAddress); - bool cmparm9 = hdrptr > hdr.ARM9ramAddress && hdrptr + nitrocode_length >= hdr.ARM9ramAddress + arm9Data.Length; - if (cmparm9) - { - Stream input = new MemoryStream(arm9Data); - MemoryStream output = new MemoryStream(); - - LZOvl blz = new LZOvl(); - blz.Decompress(input, hdrptr - hdr.ARM9ramAddress, output); - output.Write(arm9Data, arm9Data.Length - (int)postSize, (int)postSize); - input.Close(); - decompressed = output.ToArray(); - cmparm9 = false; - - input.Close(); - output.Close(); - } - - return cmparm9; - } - - /// - /// Compress ARM9.bin - /// - /// Uncompressed ARM9.bin data - /// ROM header - /// Data size from the end what will be ignored. - /// Compressed data with uncompressed Secure Area (first 0x4000 bytes). - public static byte[] Compress(byte[] arm9Data, Estructuras.ROMHeader hdr, uint postSize = 0) - { - Stream input = new MemoryStream(arm9Data); - input.Position = 0x4000; - MemoryStream output = new MemoryStream(); - output.Write(arm9Data, 0, 0x4000); - LZOvl blz = new LZOvl(); - blz.Compress(input, input.Length - 0x4000, output); - input.Close(); - output.Write(arm9Data, arm9Data.Length - (int)postSize, (int)postSize); - byte[] result = output.ToArray(); - output.Close(); - - // Update size - uint initptr = BitConverter.ToUInt32(hdr.reserved2, 0) & 0x3FFF; - if (initptr > 0) - { - uint hdrptr = (uint)result.Length - postSize + hdr.ARM9ramAddress; - Array.Copy(BitConverter.GetBytes(hdrptr), 0, result, initptr + 0x14, 4); - } - - return result; - } - } -} + } + uint postSize = (uint)arm9Data.Length - (hdrptr - hdr.ARM9ramAddress); + bool cmparm9 = hdrptr > hdr.ARM9ramAddress && hdrptr + nitrocode_length >= hdr.ARM9ramAddress + arm9Data.Length; + if (cmparm9) + { + Stream input = new MemoryStream(arm9Data); + MemoryStream output = new MemoryStream(); + + LZOvl blz = new LZOvl(); + blz.Decompress(input, hdrptr - hdr.ARM9ramAddress, output); + output.Write(arm9Data, arm9Data.Length - (int)postSize, (int)postSize); + input.Close(); + decompressed = output.ToArray(); + + input.Close(); + output.Close(); + return 1; + } + + return 0; + } + + /// + /// Compress ARM9.bin + /// + /// Uncompressed ARM9.bin data + /// ROM header + /// Data size from the end what will be ignored. + /// 0 = BLZ; 1 = BLZ-Cue + /// Compressed data with uncompressed Secure Area (first 0x4000 bytes). + public static byte[] Compress(byte[] arm9Data, Estructuras.ROMHeader hdr, uint postSize = 0, bool method = false) + { + Stream input = new MemoryStream(arm9Data); + input.Position = 0x4000; + MemoryStream output = new MemoryStream(); + output.Write(arm9Data, 0, 0x4000); + LZOvl blz = new LZOvl(); + LZOvl.LookAhead = method; + blz.Compress(input, input.Length - 0x4000, output); + input.Close(); + output.Write(arm9Data, arm9Data.Length - (int)postSize, (int)postSize); + byte[] result = output.ToArray(); + output.Close(); + + // Update size + uint initptr = BitConverter.ToUInt32(hdr.reserved2, 0) & 0x3FFF; + if (initptr > 0) + { + uint hdrptr = (uint)result.Length - postSize + hdr.ARM9ramAddress; + Array.Copy(BitConverter.GetBytes(hdrptr), 0, result, initptr + 0x14, 4); + } + + return result; + } + } +} diff --git a/Tinke/langs/en-us.xml b/Tinke/langs/en-us.xml index 72c33c0..2fccd25 100644 --- a/Tinke/langs/en-us.xml +++ b/Tinke/langs/en-us.xml @@ -425,6 +425,8 @@ Cancel Safe Trim Keep Original RSA SHA1 Signature + Recompress ARM9 binary (BLZ) + Better compress method (BLZ-Cue) File diff --git a/Tinke/langs/es-es.xml b/Tinke/langs/es-es.xml index e7c895e..8e88300 100644 --- a/Tinke/langs/es-es.xml +++ b/Tinke/langs/es-es.xml @@ -429,6 +429,8 @@ Cancelar Safe Trim Keep Original RSA SHA1 Signature + Recompress ARM9 binary (BLZ) + Better compress method (BLZ-Cue) Archivo diff --git a/Tinke/langs/fr-fr.xml b/Tinke/langs/fr-fr.xml index 260cd72..c449685 100644 --- a/Tinke/langs/fr-fr.xml +++ b/Tinke/langs/fr-fr.xml @@ -425,6 +425,8 @@ Annuler Safe Trim Keep Original RSA SHA1 Signature + Recompress ARM9 binary (BLZ) + Better compress method (BLZ-Cue) Archive diff --git a/Tinke/langs/it-it.xml b/Tinke/langs/it-it.xml index 8ebeb57..b591a43 100644 --- a/Tinke/langs/it-it.xml +++ b/Tinke/langs/it-it.xml @@ -424,6 +424,8 @@ Cancella Safe Trim Keep Original RSA SHA1 Signature + Recompress ARM9 binary (BLZ) + Better compress method (BLZ-Cue) File diff --git a/Tinke/langs/zh-hans.xml b/Tinke/langs/zh-hans.xml index 134dc29..0e79d24 100644 --- a/Tinke/langs/zh-hans.xml +++ b/Tinke/langs/zh-hans.xml @@ -422,6 +422,8 @@ 取消 安全裁剪 保持原始的 RSA SHA1 签名 + 重压缩 ARM9 文件 (BLZ 算法) + 更好的压缩率算法 (BLZ-Cue) 文件 diff --git a/changelog.txt b/changelog.txt index 208ee37..ae720ff 100644 --- a/changelog.txt +++ b/changelog.txt @@ -13,10 +13,12 @@ TinkeDSi 0.9.5 (Made by R-YaTian) * DSDecmp: Add and use CUE's BLZ_Encoder, clean old method * Add saveoptions window before saving rom (Allow keep original RSA signature, safe trim the rom) * Allow opening .SRL .IDS .DSI .APP files -* WIP: Improve ARM9BLZ compression logic +* Improve ARM9BLZ compression logic * Add McDonalds Maker Code to Estructuras.makerCode * Image: Set gimp_error to default false, hope this will fix palette exporting for anything that's not GIMP * 3DModels: Update to OpenTK 3.3.3, fix bug on fullscreen btn +* Improved SF Feather Plugin (By @mn1712trungson) +* Core: Improve Nitrocode check when saving rom TODO: full i18n support (include plugins) TinkeDSi 0.9.4 diff --git a/compile.bat b/compile.bat index d79516b..8bf07a5 100644 --- a/compile.bat +++ b/compile.bat @@ -41,7 +41,7 @@ REM Get compiler SET netver=v4.5 SET msbuild_path=%windir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe SET msbuild=%msbuild_path% /p:Configuration=%conf% /p:TargetFrameworkVersion=%netver% -SET msbuild_plugin=%msbuild% /p:OutputPath="%build_dir%\Plugins\\" +SET msbuild_plugin=%msbuild% /p:OutputPath="%build_dir%\Plugins\\" /m REM Compile program in standard directory, to allow plugins find Ekona ECHO Compiling base library @@ -49,7 +49,7 @@ ECHO Compiling base library REM Compiling program echo Compiling Tinke -%msbuild% /p:Platform=%plat% /p:OutputPath="%build_dir%\\" Tinke.sln > error.log || (TYPE error.log & EXIT /B 1) +%msbuild% /p:Platform=%plat% /p:OutputPath="%build_dir%\\" /m Tinke.sln > error.log || (TYPE error.log & EXIT /B 1) REM Compiling format plugins call :compile_plugin "Plugins\Pack\Pack.sln"