Add an option to "Recompress ARM9 binary", improve arm9 blz

Revert #5b6afa1
Update changelog, compile batch and translations
[WIP] Basic command line support
This commit is contained in:
R-YaTian 2024-02-06 18:03:39 +08:00
parent 7ac89ea4dc
commit a39ebedf66
14 changed files with 727 additions and 611 deletions

View File

@ -130,7 +130,7 @@ namespace SDAT
for (int i = 0; i < sounds.Length; i++) for (int i = 0; i < sounds.Length; i++)
{ {
bw.Write(currOffset); bw.Write(currOffset);
currOffset += (uint)sounds[i].data.data.Length + 0x0C; currOffset += (uint)sounds[i].data.data.Length + 0x0A;
} }
// Write data // Write data

View File

@ -32,6 +32,8 @@
this.checkBox2 = new System.Windows.Forms.CheckBox(); this.checkBox2 = new System.Windows.Forms.CheckBox();
this.btn_OK = new System.Windows.Forms.Button(); this.btn_OK = new System.Windows.Forms.Button();
this.btn_Cancel = 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(); this.SuspendLayout();
// //
// checkBox1 // checkBox1
@ -39,7 +41,7 @@
this.checkBox1.AutoSize = true; this.checkBox1.AutoSize = true;
this.checkBox1.Location = new System.Drawing.Point(12, 12); this.checkBox1.Location = new System.Drawing.Point(12, 12);
this.checkBox1.Name = "checkBox1"; 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.TabIndex = 0;
this.checkBox1.Text = "S1E"; this.checkBox1.Text = "S1E";
this.checkBox1.UseVisualStyleBackColor = true; this.checkBox1.UseVisualStyleBackColor = true;
@ -47,9 +49,9 @@
// checkBox2 // checkBox2
// //
this.checkBox2.AutoSize = true; 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.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.TabIndex = 2;
this.checkBox2.Text = "S1F"; this.checkBox2.Text = "S1F";
this.checkBox2.UseVisualStyleBackColor = true; this.checkBox2.UseVisualStyleBackColor = true;
@ -58,7 +60,7 @@
// //
this.btn_OK.DialogResult = System.Windows.Forms.DialogResult.OK; this.btn_OK.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btn_OK.Image = global::Tinke.Properties.Resources.accept; 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.Name = "btn_OK";
this.btn_OK.Size = new System.Drawing.Size(90, 30); this.btn_OK.Size = new System.Drawing.Size(90, 30);
this.btn_OK.TabIndex = 3; this.btn_OK.TabIndex = 3;
@ -71,7 +73,7 @@
// //
this.btn_Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btn_Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btn_Cancel.Image = global::Tinke.Properties.Resources.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.Name = "btn_Cancel";
this.btn_Cancel.Size = new System.Drawing.Size(90, 30); this.btn_Cancel.Size = new System.Drawing.Size(90, 30);
this.btn_Cancel.TabIndex = 4; this.btn_Cancel.TabIndex = 4;
@ -80,10 +82,34 @@
this.btn_Cancel.UseVisualStyleBackColor = true; this.btn_Cancel.UseVisualStyleBackColor = true;
this.btn_Cancel.Click += new System.EventHandler(this.btn_Cancel_Click); 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 // SaveOptions
// //
this.BackColor = System.Drawing.SystemColors.GradientInactiveCaption; 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_Cancel);
this.Controls.Add(this.btn_OK); this.Controls.Add(this.btn_OK);
this.Controls.Add(this.checkBox2); this.Controls.Add(this.checkBox2);
@ -107,5 +133,7 @@
private System.Windows.Forms.CheckBox checkBox2; private System.Windows.Forms.CheckBox checkBox2;
private System.Windows.Forms.Button btn_OK; private System.Windows.Forms.Button btn_OK;
private System.Windows.Forms.Button btn_Cancel; private System.Windows.Forms.Button btn_Cancel;
private System.Windows.Forms.CheckBox checkBox3;
private System.Windows.Forms.CheckBox checkBox4;
} }
} }

View File

@ -22,6 +22,8 @@ namespace Tinke.Dialog
btn_Cancel.Text = xml.Element("S1C").Value; btn_Cancel.Text = xml.Element("S1C").Value;
checkBox1.Text = xml.Element("S1E").Value; checkBox1.Text = xml.Element("S1E").Value;
checkBox2.Text = xml.Element("S1F").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"); } catch { throw new NotImplementedException("There was an error reading the language file"); }
} }
@ -36,6 +38,16 @@ namespace Tinke.Dialog
get { return checkBox2.Checked; } 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) private void btn_OK_Click(object sender, EventArgs e)
{ {
this.Close(); this.Close();
@ -45,5 +57,17 @@ namespace Tinke.Dialog
{ {
this.Close(); this.Close();
} }
private void checkBox3_CheckedChanged(object sender, EventArgs e)
{
if (checkBox3.Checked)
{
checkBox4.Enabled = true;
} else
{
checkBox4.Checked = false;
checkBox4.Enabled= false;
}
}
} }
} }

View File

@ -1,83 +1,83 @@
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// <copyright file="TWL.cs" company="none"> // <copyright file="TWL.cs" company="none">
// Copyright (C) 2017 // Copyright (C) 2017
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
// </copyright> // </copyright>
// <author>MetLob</author> // <author>MetLob</author>
// <email>metlob@mail333.com</email> // <email>metlob@mail333.com</email>
// <date>13/10/2017 18:53:14</date> // <date>13/10/2017 18:53:14</date>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
namespace Tinke.Nitro namespace Tinke.Nitro
{ {
using System.IO; using System.IO;
using System.Security.Cryptography; using System.Security.Cryptography;
using DSDecmp.Formats; using DSDecmp.Formats;
using Ekona; using Ekona;
using Tinke.Tools; using Tinke.Tools;
using Tinke.Tools.Cryptography; using Tinke.Tools.Cryptography;
class TWL class TWL
{ {
private static byte[] modcryptCmnKey = private static byte[] modcryptCmnKey =
{ {
0x79, 0x3E, 0x4F, 0x1A, 0x5F, 0x0F, 0x68, 0x2A, 0x58, 0x02, 0x59, 0x29, 0x4E, 0x79, 0x3E, 0x4F, 0x1A, 0x5F, 0x0F, 0x68, 0x2A, 0x58, 0x02, 0x59, 0x29, 0x4E,
0xFB, 0xFE, 0xFF 0xFB, 0xFE, 0xFF
}; };
internal static byte[] hmac_sha1_key = internal static byte[] hmac_sha1_key =
{ {
0x21,0x06,0xC0,0xDE,0xBA,0x98,0xCE,0x3F,0xA6,0x92,0xE3,0x9D,0x46,0xF2,0xED,0x01, 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, 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, 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, 0x32,0x67,0x8D,0xFE,0xCA,0x83,0x64,0x98,0xAC,0xFD,0x3E,0x37,0x87,0x46,0x58,0x24,
}; };
internal static byte[] rsaPublicKey = internal static byte[] rsaPublicKey =
{ {
0x95, 0x6F, 0x79, 0x0D, 0xF0, 0x8B, 0xB8, 0x5A, 0x76, 0xAA, 0xEF, 0xA2, 0x7F, 0xE8, 0x74, 0x75, 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, 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, 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, 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, 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, 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, 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 0xD7, 0xB8, 0xF0, 0x77, 0x01, 0x2F, 0xA1, 0x70, 0x26, 0x0B, 0x2C, 0x04, 0x90, 0x56, 0xF3, 0xA5
}; };
internal static byte[] rsaSignatureMask = internal static byte[] rsaSignatureMask =
{ {
0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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, 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, 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 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC
}; };
internal static byte[] rsaFontKey = internal static byte[] rsaFontKey =
{ {
0x9F, 0x80, 0xBC, 0x5F, 0xB6, 0xB6, 0x1D, 0x2A, 0x46, 0x02, 0x52, 0x64, 0xB2, 0xA3, 0x86, 0xCE, 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, 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, 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 0xD8, 0xE7, 0x69, 0x2D, 0x2C, 0x26, 0xFB, 0x5F, 0x70, 0x9E, 0x19, 0x9C, 0x6B, 0x02, 0x6D, 0x97
}; };
private uint firstDSiHashOffset; private uint firstDSiHashOffset;
private uint dsiHashSize; private uint dsiHashSize;
bool twlEncrypted; bool twlEncrypted;
public byte[][] Overlays9Sha1Hmac { get; private set; } public byte[][] Overlays9Sha1Hmac { get; private set; }
public byte[][] Header2Data { get; private set; } public byte[][] Header2Data { get; private set; }
public byte[] DSi9Data { get; private set; } public byte[] DSi9Data { get; private set; }
public byte[] DSi7Data { get; private set; } public byte[] DSi7Data { get; private set; }
public byte[] Hashtable1Data { get; private set; } public byte[] Hashtable1Data { get; private set; }
public byte[] Hashtable2Data { get; private set; } public byte[] Hashtable2Data { get; private set; }
public TWL(string file, Estructuras.ROMHeader hdr, Estructuras.sFAT[] fat) public TWL(string file, Estructuras.ROMHeader hdr, Estructuras.sFAT[] fat)
{ {
sFile[] overlays = Overlay.ReadBasicOverlays(file, hdr.ARM9overlayOffset, hdr.ARM9overlaySize, true, fat); sFile[] overlays = Overlay.ReadBasicOverlays(file, hdr.ARM9overlayOffset, hdr.ARM9overlaySize, true, fat);
this.firstDSiHashOffset = hdr.digest_ntr_size / hdr.digest_sector_size * 0x14; this.firstDSiHashOffset = hdr.digest_ntr_size / hdr.digest_sector_size * 0x14;
this.dsiHashSize = hdr.digest_twl_size / hdr.digest_sector_size * 0x14; this.dsiHashSize = hdr.digest_twl_size / hdr.digest_sector_size * 0x14;
// Read data // Read data
BinaryReader br = new BinaryReader(File.OpenRead(file)); BinaryReader br = new BinaryReader(File.OpenRead(file));
br.BaseStream.Position = hdr.sector_hashtable_start; br.BaseStream.Position = hdr.sector_hashtable_start;
this.Hashtable1Data = br.ReadBytes((int)hdr.sector_hashtable_size); this.Hashtable1Data = br.ReadBytes((int)hdr.sector_hashtable_size);
br.BaseStream.Position = hdr.block_hashtable_start; br.BaseStream.Position = hdr.block_hashtable_start;
this.Hashtable2Data = br.ReadBytes((int)hdr.block_hashtable_size); this.Hashtable2Data = br.ReadBytes((int)hdr.block_hashtable_size);
br.BaseStream.Position = hdr.dsi9_rom_offset; br.BaseStream.Position = hdr.dsi9_rom_offset;
this.DSi9Data = br.ReadBytes(Math.Max((int)hdr.modcrypt1_size, (int)hdr.dsi9_size)); this.DSi9Data = br.ReadBytes(Math.Max((int)hdr.modcrypt1_size, (int)hdr.dsi9_size));
br.BaseStream.Position = hdr.dsi7_rom_offset; br.BaseStream.Position = hdr.dsi7_rom_offset;
this.DSi7Data = br.ReadBytes(Math.Max((int)hdr.modcrypt2_size, (int)hdr.dsi7_size)); this.DSi7Data = br.ReadBytes(Math.Max((int)hdr.modcrypt2_size, (int)hdr.dsi7_size));
if (!hdr.trimmedRom) if (!hdr.trimmedRom)
{ {
//br.BaseStream.Position = hdr.digest_twl_start - 0x3000; //br.BaseStream.Position = hdr.digest_twl_start - 0x3000;
//this.Header2Data = br.ReadBytes(0x3000); //this.Header2Data = br.ReadBytes(0x3000);
this.Header2Data = new byte[3][]; this.Header2Data = new byte[3][];
for (int i = 0; i < 3; i++) 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); this.Header2Data[i] = br.ReadBytes(0x1000);
} }
} }
// Calc SHA1-HMAC of overlays9 // Calc SHA1-HMAC of overlays9
HMACSHA1 hmac = new HMACSHA1(TWL.hmac_sha1_key); HMACSHA1 hmac = new HMACSHA1(TWL.hmac_sha1_key);
this.Overlays9Sha1Hmac = new byte[overlays.Length][]; this.Overlays9Sha1Hmac = new byte[overlays.Length][];
for (int i = 0; i < overlays.Length; i++) for (int i = 0; i < overlays.Length; i++)
{ {
br.BaseStream.Position = overlays[i].offset; br.BaseStream.Position = overlays[i].offset;
byte[] ovlData = br.ReadBytes((int)overlays[i].size); byte[] ovlData = br.ReadBytes((int)overlays[i].size);
this.Overlays9Sha1Hmac[i] = hmac.ComputeHash(ovlData, 0, ovlData.Length); this.Overlays9Sha1Hmac[i] = hmac.ComputeHash(ovlData, 0, ovlData.Length);
} }
// Check for encryption modcrypt section // Check for encryption modcrypt section
this.twlEncrypted = false; // (hdr.twlInternalFlags & 2) > 0; this.twlEncrypted = false; // (hdr.twlInternalFlags & 2) > 0;
if (hdr.modcrypt1_start >= hdr.digest_twl_start && hdr.modcrypt1_start < 0xFFFFFFFF) 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 modcryptHashedSectorIndex = (hdr.modcrypt1_start - hdr.digest_twl_start) / hdr.digest_sector_size;
uint modcryptHashedSectorOff = modcryptHashedSectorIndex * hdr.digest_sector_size; uint modcryptHashedSectorOff = modcryptHashedSectorIndex * hdr.digest_sector_size;
uint hashOff = modcryptHashedSectorIndex * 0x14; uint hashOff = modcryptHashedSectorIndex * 0x14;
br.BaseStream.Position = hdr.digest_twl_start + modcryptHashedSectorOff; br.BaseStream.Position = hdr.digest_twl_start + modcryptHashedSectorOff;
byte[] firstModcryptBlock = br.ReadBytes((int)hdr.digest_sector_size); byte[] firstModcryptBlock = br.ReadBytes((int)hdr.digest_sector_size);
byte[] hash = hmac.ComputeHash(firstModcryptBlock, 0, (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]; for (int i = 0; i < 20 && !twlEncrypted; i++) twlEncrypted = hash[i] != Hashtable1Data[this.firstDSiHashOffset + hashOff + i];
} }
br.Close(); br.Close();
// Decrypt modcrypt sections // Decrypt modcrypt sections
if (this.twlEncrypted) if (this.twlEncrypted)
{ {
byte[] key = AES128KeyGenerate(hdr); byte[] key = AES128KeyGenerate(hdr);
byte[] counter = new byte[16]; byte[] counter = new byte[16];
if (hdr.modcrypt1_size > 0 && hdr.modcrypt1_size < 0xFFFFFFFF) if (hdr.modcrypt1_size > 0 && hdr.modcrypt1_size < 0xFFFFFFFF)
{ {
Array.Copy(hdr.hmac_arm9, 0, counter, 0, 16); Array.Copy(hdr.hmac_arm9, 0, counter, 0, 16);
uint offset = hdr.modcrypt1_start - hdr.dsi9_rom_offset; uint offset = hdr.modcrypt1_start - hdr.dsi9_rom_offset;
byte[] decrypted = AES128CTRCrypt(key, counter, this.DSi9Data, offset, hdr.modcrypt1_size); byte[] decrypted = AES128CTRCrypt(key, counter, this.DSi9Data, offset, hdr.modcrypt1_size);
if (offset == 0 && decrypted.Length == this.DSi9Data.Length) this.DSi9Data = decrypted; if (offset == 0 && decrypted.Length == this.DSi9Data.Length) this.DSi9Data = decrypted;
else Array.Copy(decrypted, 0, this.DSi9Data, offset, decrypted.Length); else Array.Copy(decrypted, 0, this.DSi9Data, offset, decrypted.Length);
} }
if (hdr.modcrypt2_size > 0 && hdr.modcrypt2_size < 0xFFFFFFFF) if (hdr.modcrypt2_size > 0 && hdr.modcrypt2_size < 0xFFFFFFFF)
{ {
Array.Copy(hdr.hmac_arm7, 0, counter, 0, 16); Array.Copy(hdr.hmac_arm7, 0, counter, 0, 16);
uint offset = hdr.modcrypt2_start - hdr.dsi7_rom_offset; uint offset = hdr.modcrypt2_start - hdr.dsi7_rom_offset;
byte[] decrypted = AES128CTRCrypt(key, counter, this.DSi7Data, offset, hdr.modcrypt2_size); byte[] decrypted = AES128CTRCrypt(key, counter, this.DSi7Data, offset, hdr.modcrypt2_size);
if (offset == 0 && decrypted.Length == this.DSi7Data.Length) this.DSi7Data = decrypted; if (offset == 0 && decrypted.Length == this.DSi7Data.Length) this.DSi7Data = decrypted;
else Array.Copy(decrypted, 0, this.DSi7Data, offset, decrypted.Length); else Array.Copy(decrypted, 0, this.DSi7Data, offset, decrypted.Length);
} }
} }
hmac.Clear(); hmac.Clear();
hmac.Dispose(); hmac.Dispose();
this.twlEncrypted = (hdr.twlInternalFlags & 2) > 0; this.twlEncrypted = (hdr.twlInternalFlags & 2) > 0;
} }
public void UpdateOverlays9Sha1Hmac(ref sFile arm9, Estructuras.ROMHeader hdr, List<sFile> ov9, HMACSHA1 hmac = null) public void UpdateOverlays9Sha1Hmac(ref sFile arm9, Estructuras.ROMHeader hdr, List<sFile> ov9, HMACSHA1 hmac = null)
{ {
if (hmac == null) hmac = new HMACSHA1(hmac_sha1_key); if (hmac == null) hmac = new HMACSHA1(hmac_sha1_key);
byte[][] hashes = new byte[ov9.Count][]; byte[][] hashes = new byte[ov9.Count][];
bool changed = false; bool changed = false;
for (int i = 0; i < ov9.Count; i++) for (int i = 0; i < ov9.Count; i++)
{ {
Stream str = File.OpenRead(ov9[i].path); Stream str = File.OpenRead(ov9[i].path);
byte[] buffer = new byte[ov9[i].size]; byte[] buffer = new byte[ov9[i].size];
str.Position = ov9[i].offset; str.Position = ov9[i].offset;
str.Read(buffer, 0, buffer.Length); str.Read(buffer, 0, buffer.Length);
str.Close(); str.Close();
hashes[i] = hmac.ComputeHash(buffer); hashes[i] = hmac.ComputeHash(buffer);
for (int j = 0; j < hashes[i].Length && !changed; j++) changed |= hashes[i][j] != this.Overlays9Sha1Hmac[i][j]; for (int j = 0; j < hashes[i].Length && !changed; j++) changed |= hashes[i][j] != this.Overlays9Sha1Hmac[i][j];
} }
if (changed) if (changed)
{ {
// Read arm9 // Read arm9
BinaryReader br = new BinaryReader(File.OpenRead(arm9.path)); BinaryReader br = new BinaryReader(File.OpenRead(arm9.path));
br.BaseStream.Position = arm9.offset; br.BaseStream.Position = arm9.offset;
byte[] arm9Data = br.ReadBytes((int)arm9.size); byte[] arm9Data = br.ReadBytes((int)arm9.size);
br.Close(); br.Close();
// Decompress arm9 // Decompress arm9
hdr.ARM9size = arm9.size; hdr.ARM9size = arm9.size;
uint initptr = BitConverter.ToUInt32(hdr.reserved2, 0) & 0x3FFF; uint initptr = BitConverter.ToUInt32(hdr.reserved2, 0) & 0x3FFF;
uint hdrptr = BitConverter.ToUInt32(arm9Data, (int)initptr + 0x14) - hdr.ARM9ramAddress; uint hdrptr = BitConverter.ToUInt32(arm9Data, (int)initptr + 0x14) - hdr.ARM9ramAddress;
bool cmparm9 = ARM9BLZ.Decompress(arm9Data, hdr, out arm9Data); uint cmparm9 = ARM9BLZ.Decompress(arm9Data, hdr, out arm9Data);
// Get hmac offset // Get hmac offset
uint offset = 0; uint offset = 0;
uint end = BitConverter.ToUInt32(arm9Data, (int)initptr + 8) - hdr.ARM9ramAddress; uint end = BitConverter.ToUInt32(arm9Data, (int)initptr + 8) - hdr.ARM9ramAddress;
for (long i = end - 0x14 * ov9.Count; i >= 0 && offset == 0; i--) for (long i = end - 0x14 * ov9.Count; i >= 0 && offset == 0; i--)
{ {
bool cond = arm9Data[i] == this.Overlays9Sha1Hmac[0][0]; bool cond = arm9Data[i] == this.Overlays9Sha1Hmac[0][0];
for (int j = 1; j < 20 && cond; j++) cond = arm9Data[i + j] == this.Overlays9Sha1Hmac[0][j]; for (int j = 1; j < 20 && cond; j++) cond = arm9Data[i + j] == this.Overlays9Sha1Hmac[0][j];
if (cond) offset = (uint)i; if (cond) offset = (uint)i;
} }
// Write new hash // Write new hash
if (offset > 0) if (offset > 0)
{ {
for (int i = 0; i < ov9.Count; i++) Array.Copy(hashes[i], 0, arm9Data, offset + i * 0x14, 20); 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); if (cmparm9 == 0) arm9Data = ARM9BLZ.Compress(arm9Data, hdr, arm9.size - hdrptr);
string arm9Binary = Path.GetTempFileName(); string arm9Binary = Path.GetTempFileName();
File.WriteAllBytes(arm9Binary, arm9Data); File.WriteAllBytes(arm9Binary, arm9Data);
arm9.path = arm9Binary; arm9.path = arm9Binary;
arm9.offset = 0; arm9.offset = 0;
arm9.size = (uint)arm9Data.Length; arm9.size = (uint)arm9Data.Length;
} }
else Console.WriteLine("Overlays9 has been modified but can't update hashes in ARM9.bin!"); else Console.WriteLine("Overlays9 has been modified but can't update hashes in ARM9.bin!");
} }
} }
public void ImportArm9iData(string filePath, uint offset, uint size) public void ImportArm9iData(string filePath, uint offset, uint size)
{ {
uint sizePad = size; uint sizePad = size;
if (size % 0x10 != 0) sizePad += 0x10 - size % 0x10; if (size % 0x10 != 0) sizePad += 0x10 - size % 0x10;
this.DSi9Data = new byte[sizePad]; this.DSi9Data = new byte[sizePad];
for (long i = size; i < sizePad; i++) this.DSi9Data[i] = 0xFF; for (long i = size; i < sizePad; i++) this.DSi9Data[i] = 0xFF;
Stream str = File.OpenRead(filePath); Stream str = File.OpenRead(filePath);
str.Position = offset; str.Position = offset;
str.Read(this.DSi9Data, 0, (int)size); str.Read(this.DSi9Data, 0, (int)size);
str.Close(); str.Close();
} }
public void ImportArm7iData(string filePath, uint offset, uint size) public void ImportArm7iData(string filePath, uint offset, uint size)
{ {
uint sizePad = size; uint sizePad = size;
if (size % 0x10 != 0) sizePad += 0x10 - size % 0x10; if (size % 0x10 != 0) sizePad += 0x10 - size % 0x10;
this.DSi7Data = new byte[sizePad]; this.DSi7Data = new byte[sizePad];
for (long i = size; i < sizePad; i++) this.DSi7Data[i] = 0xFF; for (long i = size; i < sizePad; i++) this.DSi7Data[i] = 0xFF;
Stream str = File.OpenRead(filePath); Stream str = File.OpenRead(filePath);
str.Position = offset; str.Position = offset;
str.Read(this.DSi7Data, 0, (int)size); str.Read(this.DSi7Data, 0, (int)size);
str.Close(); str.Close();
} }
public void Write(ref BinaryWriter bw, Estructuras.ROMHeader hdr, out byte[] digest_master_hash) public void Write(ref BinaryWriter bw, Estructuras.ROMHeader hdr, out byte[] digest_master_hash)
{ {
// Write DSi ARM sections and padding // Write DSi ARM sections and padding
while (bw.BaseStream.Position < hdr.sector_hashtable_start) bw.Write((byte)0xFF); while (bw.BaseStream.Position < hdr.sector_hashtable_start) bw.Write((byte)0xFF);
bw.BaseStream.Position = hdr.sector_hashtable_start + hdr.sector_hashtable_size; bw.BaseStream.Position = hdr.sector_hashtable_start + hdr.sector_hashtable_size;
while (bw.BaseStream.Position < hdr.block_hashtable_start) bw.Write((byte)0xFF); while (bw.BaseStream.Position < hdr.block_hashtable_start) bw.Write((byte)0xFF);
bw.BaseStream.Position = hdr.block_hashtable_start + hdr.block_hashtable_size; bw.BaseStream.Position = hdr.block_hashtable_start + hdr.block_hashtable_size;
while (bw.BaseStream.Position < hdr.dsi9_rom_offset) bw.Write((byte)0xFF); while (bw.BaseStream.Position < hdr.dsi9_rom_offset) bw.Write((byte)0xFF);
if (this.Header2Data != null && !hdr.trimmedRom) if (this.Header2Data != null && !hdr.trimmedRom)
//if (this.Header2Data != null) //if (this.Header2Data != null)
{ {
bw.BaseStream.Position = hdr.digest_twl_start - 0x3000; bw.BaseStream.Position = hdr.digest_twl_start - 0x3000;
for (int j = 0; j < 3; j++) bw.Write(this.Header2Data[j]); for (int j = 0; j < 3; j++) bw.Write(this.Header2Data[j]);
} }
bw.Write(this.DSi9Data, 0, this.DSi9Data.Length); bw.Write(this.DSi9Data, 0, this.DSi9Data.Length);
while (bw.BaseStream.Position < hdr.dsi7_rom_offset) bw.Write((byte)0xFF); while (bw.BaseStream.Position < hdr.dsi7_rom_offset) bw.Write((byte)0xFF);
bw.Write(this.DSi7Data, 0, this.DSi7Data.Length); bw.Write(this.DSi7Data, 0, this.DSi7Data.Length);
while (bw.BaseStream.Position < hdr.total_rom_size) bw.Write((byte)0xFF); while (bw.BaseStream.Position < hdr.total_rom_size) bw.Write((byte)0xFF);
long pos = bw.BaseStream.Position; long pos = bw.BaseStream.Position;
// Compute NTR Secure Area Hashtable // Compute NTR Secure Area Hashtable
int i = 0; int i = 0;
HMACSHA1 hmac = new HMACSHA1(TWL.hmac_sha1_key); HMACSHA1 hmac = new HMACSHA1(TWL.hmac_sha1_key);
BinaryReader br = new BinaryReader(bw.BaseStream); BinaryReader br = new BinaryReader(bw.BaseStream);
br.BaseStream.Position = hdr.digest_ntr_start; br.BaseStream.Position = hdr.digest_ntr_start;
byte[] saData = br.ReadBytes(0x4000); byte[] saData = br.ReadBytes(0x4000);
uint gameCode = BitConverter.ToUInt32(Encoding.ASCII.GetBytes(hdr.gameCode), 0); uint gameCode = BitConverter.ToUInt32(Encoding.ASCII.GetBytes(hdr.gameCode), 0);
SAEncryptor.EncryptSecureArea(gameCode, saData); SAEncryptor.EncryptSecureArea(gameCode, saData);
while (i < 0x4000 / hdr.digest_sector_size) while (i < 0x4000 / hdr.digest_sector_size)
{ {
byte[] hash = hmac.ComputeHash(saData, (int)(i * hdr.digest_sector_size), (int)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.BaseStream.Position = hdr.sector_hashtable_start + i * 0x14;
bw.Write(hash); bw.Write(hash);
i++; i++;
} }
// Compute NTR Hashtable // Compute NTR Hashtable
br.BaseStream.Position = hdr.digest_ntr_start + 0x4000; br.BaseStream.Position = hdr.digest_ntr_start + 0x4000;
while (br.BaseStream.Position < hdr.digest_ntr_start + hdr.digest_ntr_size) while (br.BaseStream.Position < hdr.digest_ntr_start + hdr.digest_ntr_size)
{ {
byte[] hash = hmac.ComputeHash(br.ReadBytes((int)hdr.digest_sector_size)); byte[] hash = hmac.ComputeHash(br.ReadBytes((int)hdr.digest_sector_size));
long tmp = br.BaseStream.Position; long tmp = br.BaseStream.Position;
bw.BaseStream.Position = hdr.sector_hashtable_start + i * 0x14; bw.BaseStream.Position = hdr.sector_hashtable_start + i * 0x14;
bw.Write(hash); bw.Write(hash);
br.BaseStream.Position = tmp; br.BaseStream.Position = tmp;
i++; i++;
} }
// Compute TWL Hashtable // Compute TWL Hashtable
br.BaseStream.Position = hdr.digest_twl_start; br.BaseStream.Position = hdr.digest_twl_start;
while (br.BaseStream.Position < hdr.digest_twl_start + hdr.digest_twl_size) while (br.BaseStream.Position < hdr.digest_twl_start + hdr.digest_twl_size)
{ {
byte[] hash = hmac.ComputeHash(br.ReadBytes((int)hdr.digest_sector_size)); byte[] hash = hmac.ComputeHash(br.ReadBytes((int)hdr.digest_sector_size));
long tmp = br.BaseStream.Position; long tmp = br.BaseStream.Position;
bw.BaseStream.Position = hdr.sector_hashtable_start + i * 0x14; bw.BaseStream.Position = hdr.sector_hashtable_start + i * 0x14;
bw.Write(hash); bw.Write(hash);
br.BaseStream.Position = tmp; br.BaseStream.Position = tmp;
i++; i++;
} }
// Compute Secondary Hashtable // Compute Secondary Hashtable
i = 0; i = 0;
br.BaseStream.Position = hdr.sector_hashtable_start; br.BaseStream.Position = hdr.sector_hashtable_start;
while (br.BaseStream.Position < hdr.sector_hashtable_start + hdr.sector_hashtable_size) while (br.BaseStream.Position < hdr.sector_hashtable_start + hdr.sector_hashtable_size)
{ {
byte[] hash = hmac.ComputeHash(br.ReadBytes((int)hdr.digest_block_sectorcount * 0x14)); byte[] hash = hmac.ComputeHash(br.ReadBytes((int)hdr.digest_block_sectorcount * 0x14));
long tmp = br.BaseStream.Position; long tmp = br.BaseStream.Position;
bw.BaseStream.Position = hdr.block_hashtable_start + i * 0x14; bw.BaseStream.Position = hdr.block_hashtable_start + i * 0x14;
bw.Write(hash); bw.Write(hash);
br.BaseStream.Position = tmp; br.BaseStream.Position = tmp;
i++; i++;
} }
// Compute Master Hashtable // Compute Master Hashtable
br.BaseStream.Position = hdr.block_hashtable_start; br.BaseStream.Position = hdr.block_hashtable_start;
digest_master_hash = hmac.ComputeHash(br.ReadBytes((int)hdr.block_hashtable_size)); digest_master_hash = hmac.ComputeHash(br.ReadBytes((int)hdr.block_hashtable_size));
// Encrypt DSi sections // Encrypt DSi sections
if (this.twlEncrypted) if (this.twlEncrypted)
{ {
byte[] key = AES128KeyGenerate(hdr); byte[] key = AES128KeyGenerate(hdr);
byte[] counter9 = new byte[16]; byte[] counter9 = new byte[16];
byte[] counter7 = new byte[16]; byte[] counter7 = new byte[16];
Array.Copy(hdr.hmac_arm9, 0, counter9, 0, 16); Array.Copy(hdr.hmac_arm9, 0, counter9, 0, 16);
Array.Copy(hdr.hmac_arm7, 0, counter7, 0, 16); Array.Copy(hdr.hmac_arm7, 0, counter7, 0, 16);
bw.BaseStream.Position = hdr.dsi9_rom_offset; bw.BaseStream.Position = hdr.dsi9_rom_offset;
if (hdr.modcrypt1_size > 0) bw.Write(AES128CTRCrypt(key, counter9, this.DSi9Data, 0, hdr.modcrypt1_size)); if (hdr.modcrypt1_size > 0) bw.Write(AES128CTRCrypt(key, counter9, this.DSi9Data, 0, hdr.modcrypt1_size));
bw.BaseStream.Position = hdr.dsi7_rom_offset; bw.BaseStream.Position = hdr.dsi7_rom_offset;
if (hdr.modcrypt2_size > 0) bw.Write(AES128CTRCrypt(key, counter7, this.DSi7Data, 0, hdr.modcrypt2_size)); if (hdr.modcrypt2_size > 0) bw.Write(AES128CTRCrypt(key, counter7, this.DSi7Data, 0, hdr.modcrypt2_size));
} }
bw.BaseStream.Position = pos; bw.BaseStream.Position = pos;
} }
public static void UpdateHeaderSignatures( public static void UpdateHeaderSignatures(
ref BinaryWriter bw, ref BinaryWriter bw,
ref Estructuras.ROMHeader header, ref Estructuras.ROMHeader header,
string header_file, string header_file,
bool keep_original) bool keep_original)
{ {
long pos = bw.BaseStream.Position; long pos = bw.BaseStream.Position;
// Update digest master hash // Update digest master hash
bw.BaseStream.Position = 0x328; bw.BaseStream.Position = 0x328;
bw.Write(header.hmac_digest_master); bw.Write(header.hmac_digest_master);
// Read signed header data // Read signed header data
BinaryReader br = new BinaryReader(File.OpenRead(header_file)); BinaryReader br = new BinaryReader(File.OpenRead(header_file));
byte[] hdrSignedData = br.ReadBytes(0xE00); byte[] hdrSignedData = br.ReadBytes(0xE00);
Array.Copy(header.hmac_digest_master, 0, hdrSignedData, 0x328, 0x14); Array.Copy(header.hmac_digest_master, 0, hdrSignedData, 0x328, 0x14);
br.Close(); br.Close();
// Verify RSA Signature // Verify RSA Signature
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024);
RSAParameters rsaKey = new RSAParameters(); RSAParameters rsaKey = new RSAParameters();
rsaKey.Exponent = new byte[] { 1, 0, 1 }; rsaKey.Exponent = new byte[] { 1, 0, 1 };
rsaKey.Modulus = (byte[])TWL.rsaPublicKey.Clone(); rsaKey.Modulus = (byte[])TWL.rsaPublicKey.Clone();
rsaKey.D = null; // In future: here set Private key rsaKey.D = null; // In future: here set Private key
rsa.ImportParameters(rsaKey); rsa.ImportParameters(rsaKey);
bool verify = rsa.VerifyData(hdrSignedData, new SHA1CryptoServiceProvider(), header.rsa_signature); bool verify = rsa.VerifyData(hdrSignedData, new SHA1CryptoServiceProvider(), header.rsa_signature);
if (!verify) if (!verify)
{ {
// RSA encrypt signature // RSA encrypt signature
if (rsaKey.D != null) if (rsaKey.D != null)
{ {
header.rsa_signature = rsa.SignData(hdrSignedData, new SHA1CryptoServiceProvider()); header.rsa_signature = rsa.SignData(hdrSignedData, new SHA1CryptoServiceProvider());
} }
else else
{ {
// Calc SHA1 hash // Calc SHA1 hash
SHA1 sha1 = new SHA1CryptoServiceProvider(); SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] hash = sha1.ComputeHash(hdrSignedData); byte[] hash = sha1.ComputeHash(hdrSignedData);
//Array.Reverse(hash); //Array.Reverse(hash);
sha1.Clear(); sha1.Clear();
sha1.Dispose(); sha1.Dispose();
if (!keep_original) if (!keep_original)
{ {
// Set unencrypted signature for no$gba compatible // Set unencrypted signature for no$gba compatible
header.rsa_signature = (byte[])TWL.rsaSignatureMask.Clone(); header.rsa_signature = (byte[])TWL.rsaSignatureMask.Clone();
Array.Copy(hash, 0, header.rsa_signature, 0x80 - 0x14, 0x14); Array.Copy(hash, 0, header.rsa_signature, 0x80 - 0x14, 0x14);
} }
} }
// Write signature // Write signature
bw.BaseStream.Position = 0xF80; bw.BaseStream.Position = 0xF80;
bw.Write(header.rsa_signature, 0, 0x80); bw.Write(header.rsa_signature, 0, 0x80);
} }
bw.BaseStream.Position = pos; bw.BaseStream.Position = pos;
} }
private static byte[] AES128CTRCrypt(byte[] key, byte[] counter, byte[] data, uint offset, uint size) private static byte[] AES128CTRCrypt(byte[] key, byte[] counter, byte[] data, uint offset, uint size)
{ {
AES128CounterMode aes128 = new AES128CounterMode(counter); AES128CounterMode aes128 = new AES128CounterMode(counter);
ICryptoTransform ict = aes128.CreateEncryptor(key, null); ICryptoTransform ict = aes128.CreateEncryptor(key, null);
return ict.TransformFinalBlock(data, (int)offset, (int)size); return ict.TransformFinalBlock(data, (int)offset, (int)size);
} }
private static byte[] AES128KeyGenerate(Estructuras.ROMHeader hdr) private static byte[] AES128KeyGenerate(Estructuras.ROMHeader hdr)
{ {
bool debug = ((hdr.twlInternalFlags & 4) > 0) || ((hdr.appflags[3] & 0x80) > 0); bool debug = ((hdr.twlInternalFlags & 4) > 0) || ((hdr.appflags[3] & 0x80) > 0);
if (debug) if (debug)
{ {
byte[] key = new byte[16]; byte[] key = new byte[16];
Array.Copy(Encoding.ASCII.GetBytes(hdr.gameTitle), 0, key, 0, 12); Array.Copy(Encoding.ASCII.GetBytes(hdr.gameTitle), 0, key, 0, 12);
Array.Copy(Encoding.ASCII.GetBytes(hdr.gameCode), 0, key, 12, 4); Array.Copy(Encoding.ASCII.GetBytes(hdr.gameCode), 0, key, 12, 4);
return key; return key;
} }
else else
{ {
byte[] keyX = new byte[16]; byte[] keyX = new byte[16];
byte[] keyY = new byte[16]; byte[] keyY = new byte[16];
Array.Copy(Encoding.ASCII.GetBytes("Nintendo"), 0, keyX, 0, 8); Array.Copy(Encoding.ASCII.GetBytes("Nintendo"), 0, keyX, 0, 8);
Array.Copy(Encoding.ASCII.GetBytes(hdr.gameCode), 0, keyX, 8, 4); 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]; 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(BitConverter.GetBytes(hdr.tid_low), 0, keyX, 12, 4);
Array.Copy(hdr.hmac_arm9i, 0, keyY, 0, 16); Array.Copy(hdr.hmac_arm9i, 0, keyY, 0, 16);
return AES128KeyGenerate(keyX, keyY); return AES128KeyGenerate(keyX, keyY);
} }
} }
private static byte[] AES128KeyGenerate(byte[] keyX, byte[] keyY) private static byte[] AES128KeyGenerate(byte[] keyX, byte[] keyY)
{ {
// Key = ((Key_X XOR Key_Y) + FFFEFB4E295902582A680F5F1A4F3E79h) ROL 42 // Key = ((Key_X XOR Key_Y) + FFFEFB4E295902582A680F5F1A4F3E79h) ROL 42
byte[] key = new byte[16]; byte[] key = new byte[16];
for (int i = 0; i < 16; i++) key[i] = (byte)(keyX[i] ^ keyY[i]); for (int i = 0; i < 16; i++) key[i] = (byte)(keyX[i] ^ keyY[i]);
UInt64[] tmp = new ulong[2]; UInt64[] tmp = new ulong[2];
UInt64[] xyKey = new[] { BitConverter.ToUInt64(key, 0), BitConverter.ToUInt64(key, 8) }; UInt64[] xyKey = new[] { BitConverter.ToUInt64(key, 0), BitConverter.ToUInt64(key, 8) };
UInt64[] cKey = new[] { BitConverter.ToUInt64(modcryptCmnKey, 0), BitConverter.ToUInt64(modcryptCmnKey, 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] = (cKey[0] >> 1) + (xyKey[0] >> 1) + (cKey[0] & xyKey[0] & 1);
tmp[0] = tmp[0] >> 63; tmp[0] = tmp[0] >> 63;
cKey[0] = cKey[0] + xyKey[0]; cKey[0] = cKey[0] + xyKey[0];
cKey[1] = cKey[1] + xyKey[1] + tmp[0]; cKey[1] = cKey[1] + xyKey[1] + tmp[0];
int shift = 42; int shift = 42;
tmp[0] = cKey[0] << shift; tmp[0] = cKey[0] << shift;
tmp[1] = cKey[1] << shift; tmp[1] = cKey[1] << shift;
tmp[0] |= (cKey[1] >> (64 - shift)); tmp[0] |= (cKey[1] >> (64 - shift));
tmp[1] |= (cKey[0] >> (64 - shift)); tmp[1] |= (cKey[0] >> (64 - shift));
cKey[0] = tmp[0]; cKey[0] = tmp[0];
cKey[1] = tmp[1]; cKey[1] = tmp[1];
Array.Copy(BitConverter.GetBytes(cKey[0]), 0, key, 0, 8); Array.Copy(BitConverter.GetBytes(cKey[0]), 0, key, 0, 8);
Array.Copy(BitConverter.GetBytes(cKey[1]), 0, key, 8, 8); Array.Copy(BitConverter.GetBytes(cKey[1]), 0, key, 8, 8);
return key; return key;
} }
} }
} }

View File

@ -18,16 +18,20 @@
* *
*/ */
using System; using System;
//using System.Collections.Generic;
//using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
//using System.Reflection;
using System.IO; using System.IO;
using System.Runtime.InteropServices;
namespace Tinke namespace Tinke
{ {
static class Program 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();
/// <summary> /// <summary>
/// Punto de entrada principal para la aplicación. /// Punto de entrada principal para la aplicación.
/// </summary> /// </summary>
@ -35,7 +39,7 @@ namespace Tinke
static void Main(string[] args) static void Main(string[] args)
{ {
#region Comprobación de archivos necesarios #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 = ""; string faltan = "";
for (int i = 0; i < archivos.Length; i++) for (int i = 0; i < archivos.Length; i++)
{ {
@ -55,5 +59,4 @@ namespace Tinke
Application.Run(new Sistema()); Application.Run(new Sistema());
} }
} }
} }

View File

@ -62,12 +62,31 @@ namespace Tinke
// The IE control of the Debug windows doesn't work in Mono // The IE control of the Debug windows doesn't work in Mono
isMono = (Type.GetType("Mono.Runtime") != null); 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(); sb = new StringBuilder();
TextWriter tw = new StringWriter(sb); TextWriter tw = new StringWriter(sb);
tw.NewLine = "<br>"; tw.NewLine = "<br>";
if (!isMono) if (!isMono && !(Environment.GetCommandLineArgs().Length >= 3 && (Environment.GetCommandLineArgs()[2] == "-x" || Environment.GetCommandLineArgs()[2] == "-r")))
Console.SetOut(tw); 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 #region Language
if (!File.Exists(Application.StartupPath + Path.DirectorySeparatorChar + "Tinke.xml")) if (!File.Exists(Application.StartupPath + Path.DirectorySeparatorChar + "Tinke.xml"))
{ {
@ -144,11 +163,47 @@ namespace Tinke
filesToRead[0] = o.SelectedPath; filesToRead[0] = o.SelectedPath;
o.Dispose(); o.Dispose();
} }
else if (Environment.GetCommandLineArgs()[1] == "-h" || Environment.GetCommandLineArgs()[1] == "--help")
{
Application.Exit();
return;
}
else else
filesToRead[0] = Environment.GetCommandLineArgs()[1]; filesToRead[0] = Environment.GetCommandLineArgs()[1];
} }
else if (Environment.GetCommandLineArgs().Length >= 3) 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]; filesToRead = new String[Environment.GetCommandLineArgs().Length - 1];
Array.Copy(Environment.GetCommandLineArgs(), 1, filesToRead, 0, filesToRead.Length); Array.Copy(Environment.GetCommandLineArgs(), 1, filesToRead, 0, filesToRead.Length);
} }
@ -1444,6 +1499,8 @@ namespace Tinke
* Files... * Files...
*/ */
bool keep_original = false; bool keep_original = false;
bool a9_recomp = false;
bool a9_bestcomp = false;
Nitro.Estructuras.ROMHeader header = romInfo.Cabecera; Nitro.Estructuras.ROMHeader header = romInfo.Cabecera;
Dialog.SaveOptions dialog = new Dialog.SaveOptions(); Dialog.SaveOptions dialog = new Dialog.SaveOptions();
@ -1453,6 +1510,10 @@ namespace Tinke
keep_original = true; keep_original = true;
if (dialog.IsSafeTrim) if (dialog.IsSafeTrim)
header.trimmedRom = true; header.trimmedRom = true;
if (dialog.IsReCompress)
a9_recomp = true;
if (dialog.IsBetterCompress)
a9_bestcomp = true;
Thread create = new Thread(ThreadEspera) Thread create = new Thread(ThreadEspera)
{ {
@ -1533,16 +1594,19 @@ namespace Tinke
header.secureCRC16 = SecureArea.CalcCRC(this.secureArea.EncryptedData, gameCode); header.secureCRC16 = SecureArea.CalcCRC(this.secureArea.EncryptedData, gameCode);
} }
bool cmparm9 = true; uint cmparm9 = 0;
if (!ov9Sha1Hmac_updated) if (!ov9Sha1Hmac_updated)
{ {
uint initptr = BitConverter.ToUInt32(header.reserved2, 0) & 0x3FFF; uint initptr = BitConverter.ToUInt32(header.reserved2, 0) & 0x3FFF;
uint hdrptr = BitConverter.ToUInt32(arm9Data, (int)initptr + 0x14) - header.ARM9ramAddress; uint hdrptr = BitConverter.ToUInt32(arm9Data, (int)initptr + 0x14) - header.ARM9ramAddress;
byte[] arm9Data_dec; byte[] arm9Data_dec;
cmparm9 = ARM9BLZ.Decompress(arm9Data, header, out 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(); bw.Flush();
br.Close(); br.Close();
if (!ov9Sha1Hmac_updated && !cmparm9) if (!ov9Sha1Hmac_updated && a9_recomp)
{ {
arm9.path = arm9Binary; arm9.path = arm9Binary;
arm9.offset = 0; arm9.offset = 0;
@ -1627,7 +1691,6 @@ namespace Tinke
Console.WriteLine(Tools.Helper.GetTranslation("Messages", "S09"), new FileInfo(arm9Binary).Length); Console.WriteLine(Tools.Helper.GetTranslation("Messages", "S09"), new FileInfo(arm9Binary).Length);
// Escribismo el ARM7 Binary // Escribismo el ARM7 Binary
string arm7Binary = Path.GetTempFileName(); string arm7Binary = Path.GetTempFileName();
string overlays7 = Path.GetTempFileName(); string overlays7 = Path.GetTempFileName();
@ -1690,7 +1753,6 @@ namespace Tinke
bw.Close(); bw.Close();
Console.WriteLine(Tools.Helper.GetTranslation("Messages", "S09"), new FileInfo(arm7Binary).Length); Console.WriteLine(Tools.Helper.GetTranslation("Messages", "S09"), new FileInfo(arm7Binary).Length);
// Escribimos el FNT (File Name Table) // Escribimos el FNT (File Name Table)
string fileFNT = Path.GetTempFileName(); string fileFNT = Path.GetTempFileName();
Console.Write("\tFile Name Table (FNT)..."); Console.Write("\tFile Name Table (FNT)...");
@ -1723,7 +1785,7 @@ namespace Tinke
// Escribimos el banner // Escribimos el banner
string banner = Path.GetTempFileName(); string banner = Path.GetTempFileName();
header.banner_size = Nitro.NDS.EscribirBanner(banner, romInfo.Banner); header.banner_size = Nitro.NDS.EscribirBanner(banner, romInfo.Banner);
// Escribimos el FAT (File Allocation Table) // Escribimos el FAT (File Allocation Table)
string fileFAT = Path.GetTempFileName(); string fileFAT = Path.GetTempFileName();
header.FAToffset = currPos; header.FAToffset = currPos;
@ -1865,15 +1927,8 @@ namespace Tinke
o.DefaultExt = ".nds"; o.DefaultExt = ".nds";
o.Filter = "Nintendo DS ROM (*.nds)|*.nds"; o.Filter = "Nintendo DS ROM (*.nds)|*.nds";
o.OverwritePrompt = true; o.OverwritePrompt = true;
Open_Dialog:
if (o.ShowDialog() == System.Windows.Forms.DialogResult.OK) 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) Thread saverom = new Thread(ThreadEspera)
{ {
IsBackground = true IsBackground = true
@ -1921,7 +1976,7 @@ namespace Tinke
} }
sb.Length = 0; sb.Length = 0;
} }
// Borramos archivos ya innecesarios // Borramos archivos ya innecesarios
File.Delete(header_file); File.Delete(header_file);
File.Delete(arm9Binary); File.Delete(arm9Binary);
@ -1932,10 +1987,6 @@ namespace Tinke
File.Delete(fileFAT); File.Delete(fileFAT);
File.Delete(banner); File.Delete(banner);
File.Delete(files); File.Delete(files);
//if (!isMono)
//debug.Add_Text(sb.ToString());
//sb.Length = 0;
} }
private void btnImport_Click(object sender, EventArgs e) private void btnImport_Click(object sender, EventArgs e)
{ {
@ -2249,11 +2300,7 @@ namespace Tinke
if (!isMono) if (!isMono)
{ {
try CloseEspera(wait);
{
espera.Close();
}
catch { };
debug.Add_Text(sb.ToString()); debug.Add_Text(sb.ToString());
} }
sb.Length = 0; sb.Length = 0;
@ -2502,30 +2549,10 @@ namespace Tinke
btnDesplazar.Text = ">>>>>"; 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<string> files = new List<string>(); List<string> files = new List<string>();
files = GetAllSubFiles(FBD.SelectedPath, files); files = GetAllSubFiles(files_path, files);
foreach (string currFile in files) foreach (string currFile in files)
{ {
string nstr; string nstr;
@ -2569,12 +2596,32 @@ namespace Tinke
accion.Change_File(fileToBeChanged.id, currFile); accion.Change_File(fileToBeChanged.id, currFile);
Console.WriteLine(currFile); Console.WriteLine(currFile);
} }
}
private void btnImport1_Click(object sender, EventArgs e)
{
Thread matching = new Thread(ThreadEspera)
{
IsBackground = true
};
if (!isMono) if (!isMono)
try matching.Start("S08");
{
espera.Close(); FolderBrowserDialog FBD = new FolderBrowserDialog
} {
catch { }; 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<string> GetAllSubFiles(string directoryPath, List<string> files) public static List<string> GetAllSubFiles(string directoryPath, List<string> files)
{ {

View File

@ -1,89 +1,91 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
namespace Tinke.Tools namespace Tinke.Tools
{ {
using System.IO; using System.IO;
using DSDecmp.Formats; using DSDecmp.Formats;
using Nitro; using Nitro;
class ARM9BLZ class ARM9BLZ
{ {
/// <summary> /// <summary>
/// Decompress ARM9.bin /// Decompress ARM9.bin
/// </summary> /// </summary>
/// <param name="arm9Data">Compressed ARM9.bin data</param> /// <param name="arm9Data">Compressed ARM9.bin data</param>
/// <param name="hdr">ROM header</param> /// <param name="hdr">ROM header</param>
/// <param name="decompressed">Decompressed data</param> /// <param name="decompressed">Decompressed data</param>
/// <returns>True if the decompression was successful.</returns> /// <returns>0 = uncompressed; 1 = compressed</returns>
public static bool Decompress(byte[] arm9Data, Estructuras.ROMHeader hdr, out byte[] decompressed) public static uint Decompress(byte[] arm9Data, Estructuras.ROMHeader hdr, out byte[] decompressed)
{ {
decompressed = arm9Data; decompressed = arm9Data;
uint nitrocode_length = 0; uint nitrocode_length = 0;
if (arm9Data[arm9Data.Length - 0xC] == 0x21 && arm9Data[arm9Data.Length - 0xB] == 0x06 if (arm9Data[arm9Data.Length - 0xC] == 0x21 && arm9Data[arm9Data.Length - 0xB] == 0x06
&& arm9Data[arm9Data.Length - 0xA] == 0xC0 && arm9Data[arm9Data.Length - 0x9] == 0xDE) && arm9Data[arm9Data.Length - 0xA] == 0xC0 && arm9Data[arm9Data.Length - 0x9] == 0xDE)
{ {
nitrocode_length = 0x0C; //Nitrocode found. nitrocode_length = 0x0C; //Nitrocode found.
} }
uint initptr = BitConverter.ToUInt32(hdr.reserved2, 0) & 0x3FFF; uint initptr = BitConverter.ToUInt32(hdr.reserved2, 0) & 0x3FFF;
uint hdrptr = BitConverter.ToUInt32(arm9Data, (int)initptr + 0x14); uint hdrptr = BitConverter.ToUInt32(arm9Data, (int)initptr + 0x14);
if (initptr == 0) if (initptr == 0)
{ {
hdrptr = hdr.ARM9ramAddress + hdr.ARM9size; hdrptr = hdr.ARM9ramAddress + hdr.ARM9size;
} }
uint postSize = (uint)arm9Data.Length - (hdrptr - hdr.ARM9ramAddress); uint postSize = (uint)arm9Data.Length - (hdrptr - hdr.ARM9ramAddress);
bool cmparm9 = hdrptr > hdr.ARM9ramAddress && hdrptr + nitrocode_length >= hdr.ARM9ramAddress + arm9Data.Length; bool cmparm9 = hdrptr > hdr.ARM9ramAddress && hdrptr + nitrocode_length >= hdr.ARM9ramAddress + arm9Data.Length;
if (cmparm9) if (cmparm9)
{ {
Stream input = new MemoryStream(arm9Data); Stream input = new MemoryStream(arm9Data);
MemoryStream output = new MemoryStream(); MemoryStream output = new MemoryStream();
LZOvl blz = new LZOvl(); LZOvl blz = new LZOvl();
blz.Decompress(input, hdrptr - hdr.ARM9ramAddress, output); blz.Decompress(input, hdrptr - hdr.ARM9ramAddress, output);
output.Write(arm9Data, arm9Data.Length - (int)postSize, (int)postSize); output.Write(arm9Data, arm9Data.Length - (int)postSize, (int)postSize);
input.Close(); input.Close();
decompressed = output.ToArray(); decompressed = output.ToArray();
cmparm9 = false;
input.Close();
input.Close(); output.Close();
output.Close(); return 1;
} }
return cmparm9; return 0;
} }
/// <summary> /// <summary>
/// Compress ARM9.bin /// Compress ARM9.bin
/// </summary> /// </summary>
/// <param name="arm9Data">Uncompressed ARM9.bin data</param> /// <param name="arm9Data">Uncompressed ARM9.bin data</param>
/// <param name="hdr">ROM header</param> /// <param name="hdr">ROM header</param>
/// <param name="postSize">Data size from the end what will be ignored.</param> /// <param name="postSize">Data size from the end what will be ignored.</param>
/// <returns>Compressed data with uncompressed Secure Area (first 0x4000 bytes).</returns> /// <param name="method">0 = BLZ; 1 = BLZ-Cue</param>
public static byte[] Compress(byte[] arm9Data, Estructuras.ROMHeader hdr, uint postSize = 0) /// <returns>Compressed data with uncompressed Secure Area (first 0x4000 bytes).</returns>
{ public static byte[] Compress(byte[] arm9Data, Estructuras.ROMHeader hdr, uint postSize = 0, bool method = false)
Stream input = new MemoryStream(arm9Data); {
input.Position = 0x4000; Stream input = new MemoryStream(arm9Data);
MemoryStream output = new MemoryStream(); input.Position = 0x4000;
output.Write(arm9Data, 0, 0x4000); MemoryStream output = new MemoryStream();
LZOvl blz = new LZOvl(); output.Write(arm9Data, 0, 0x4000);
blz.Compress(input, input.Length - 0x4000, output); LZOvl blz = new LZOvl();
input.Close(); LZOvl.LookAhead = method;
output.Write(arm9Data, arm9Data.Length - (int)postSize, (int)postSize); blz.Compress(input, input.Length - 0x4000, output);
byte[] result = output.ToArray(); input.Close();
output.Close(); output.Write(arm9Data, arm9Data.Length - (int)postSize, (int)postSize);
byte[] result = output.ToArray();
// Update size output.Close();
uint initptr = BitConverter.ToUInt32(hdr.reserved2, 0) & 0x3FFF;
if (initptr > 0) // Update size
{ uint initptr = BitConverter.ToUInt32(hdr.reserved2, 0) & 0x3FFF;
uint hdrptr = (uint)result.Length - postSize + hdr.ARM9ramAddress; if (initptr > 0)
Array.Copy(BitConverter.GetBytes(hdrptr), 0, result, initptr + 0x14, 4); {
} uint hdrptr = (uint)result.Length - postSize + hdr.ARM9ramAddress;
Array.Copy(BitConverter.GetBytes(hdrptr), 0, result, initptr + 0x14, 4);
return result; }
}
} return result;
} }
}
}

View File

@ -425,6 +425,8 @@
<S1C>Cancel</S1C> <S1C>Cancel</S1C>
<S1E>Safe Trim</S1E> <S1E>Safe Trim</S1E>
<S1F>Keep Original RSA SHA1 Signature</S1F> <S1F>Keep Original RSA SHA1 Signature</S1F>
<S20>Recompress ARM9 binary (BLZ)</S20>
<S21>Better compress method (BLZ-Cue)</S21>
</Dialog> </Dialog>
<VisorHex> <VisorHex>
<S00>File</S00> <S00>File</S00>

View File

@ -429,6 +429,8 @@
<S1C>Cancelar</S1C> <S1C>Cancelar</S1C>
<S1E>Safe Trim</S1E> <S1E>Safe Trim</S1E>
<S1F>Keep Original RSA SHA1 Signature</S1F> <S1F>Keep Original RSA SHA1 Signature</S1F>
<S20>Recompress ARM9 binary (BLZ)</S20>
<S21>Better compress method (BLZ-Cue)</S21>
</Dialog> </Dialog>
<VisorHex> <VisorHex>
<S00>Archivo</S00> <S00>Archivo</S00>

View File

@ -425,6 +425,8 @@
<S1C>Annuler</S1C> <S1C>Annuler</S1C>
<S1E>Safe Trim</S1E> <S1E>Safe Trim</S1E>
<S1F>Keep Original RSA SHA1 Signature</S1F> <S1F>Keep Original RSA SHA1 Signature</S1F>
<S20>Recompress ARM9 binary (BLZ)</S20>
<S21>Better compress method (BLZ-Cue)</S21>
</Dialog> </Dialog>
<VisorHex> <VisorHex>
<S00>Archive</S00> <S00>Archive</S00>

View File

@ -424,6 +424,8 @@
<S1C>Cancella</S1C> <S1C>Cancella</S1C>
<S1E>Safe Trim</S1E> <S1E>Safe Trim</S1E>
<S1F>Keep Original RSA SHA1 Signature</S1F> <S1F>Keep Original RSA SHA1 Signature</S1F>
<S20>Recompress ARM9 binary (BLZ)</S20>
<S21>Better compress method (BLZ-Cue)</S21>
</Dialog> </Dialog>
<VisorHex> <VisorHex>
<S00>File</S00> <S00>File</S00>

View File

@ -422,6 +422,8 @@
<S1C>取消</S1C> <S1C>取消</S1C>
<S1E>安全裁剪</S1E> <S1E>安全裁剪</S1E>
<S1F>保持原始的 RSA SHA1 签名</S1F> <S1F>保持原始的 RSA SHA1 签名</S1F>
<S20>重压缩 ARM9 文件 (BLZ 算法)</S20>
<S21>更好的压缩率算法 (BLZ-Cue)</S21>
</Dialog> </Dialog>
<VisorHex> <VisorHex>
<S00>文件</S00> <S00>文件</S00>

View File

@ -13,10 +13,12 @@ TinkeDSi 0.9.5 (Made by R-YaTian)
* DSDecmp: Add and use CUE's BLZ_Encoder, clean old method * 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) * Add saveoptions window before saving rom (Allow keep original RSA signature, safe trim the rom)
* Allow opening .SRL .IDS .DSI .APP files * Allow opening .SRL .IDS .DSI .APP files
* WIP: Improve ARM9BLZ compression logic * Improve ARM9BLZ compression logic
* Add McDonalds Maker Code to Estructuras.makerCode * 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 * 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 * 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) TODO: full i18n support (include plugins)
TinkeDSi 0.9.4 TinkeDSi 0.9.4

View File

@ -41,7 +41,7 @@ REM Get compiler
SET netver=v4.5 SET netver=v4.5
SET msbuild_path=%windir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe SET msbuild_path=%windir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe
SET msbuild=%msbuild_path% /p:Configuration=%conf% /p:TargetFrameworkVersion=%netver% 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 REM Compile program in standard directory, to allow plugins find Ekona
ECHO Compiling base library ECHO Compiling base library
@ -49,7 +49,7 @@ ECHO Compiling base library
REM Compiling program REM Compiling program
echo Compiling Tinke 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 REM Compiling format plugins
call :compile_plugin "Plugins\Pack\Pack.sln" call :compile_plugin "Plugins\Pack\Pack.sln"