mirror of
https://github.com/R-YaTian/TinkeDSi.git
synced 2025-06-18 08:35:35 -04:00
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:
parent
7ac89ea4dc
commit
a39ebedf66
@ -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
|
||||
|
40
Tinke/Dialog/SaveOptions.Designer.cs
generated
40
Tinke/Dialog/SaveOptions.Designer.cs
generated
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,83 +1,83 @@
|
||||
// ----------------------------------------------------------------------
|
||||
// <copyright file="TWL.cs" company="none">
|
||||
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// </copyright>
|
||||
|
||||
// <author>MetLob</author>
|
||||
// <email>metlob@mail333.com</email>
|
||||
// <date>13/10/2017 18:53:14</date>
|
||||
// -----------------------------------------------------------------------
|
||||
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 file="TWL.cs" company="none">
|
||||
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// </copyright>
|
||||
|
||||
// <author>MetLob</author>
|
||||
// <email>metlob@mail333.com</email>
|
||||
// <date>13/10/2017 18:53:14</date>
|
||||
// -----------------------------------------------------------------------
|
||||
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<sFile> 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<sFile> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
/// <summary>
|
||||
/// Punto de entrada principal para la aplicación.
|
||||
/// </summary>
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
151
Tinke/Sistema.cs
151
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 = "<br>";
|
||||
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<string> files = new List<string>();
|
||||
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<string> GetAllSubFiles(string directoryPath, List<string> files)
|
||||
{
|
||||
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Decompress ARM9.bin
|
||||
/// </summary>
|
||||
/// <param name="arm9Data">Compressed ARM9.bin data</param>
|
||||
/// <param name="hdr">ROM header</param>
|
||||
/// <param name="decompressed">Decompressed data</param>
|
||||
/// <returns>True if the decompression was successful.</returns>
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Decompress ARM9.bin
|
||||
/// </summary>
|
||||
/// <param name="arm9Data">Compressed ARM9.bin data</param>
|
||||
/// <param name="hdr">ROM header</param>
|
||||
/// <param name="decompressed">Decompressed data</param>
|
||||
/// <returns>0 = uncompressed; 1 = compressed</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compress ARM9.bin
|
||||
/// </summary>
|
||||
/// <param name="arm9Data">Uncompressed ARM9.bin data</param>
|
||||
/// <param name="hdr">ROM header</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>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compress ARM9.bin
|
||||
/// </summary>
|
||||
/// <param name="arm9Data">Uncompressed ARM9.bin data</param>
|
||||
/// <param name="hdr">ROM header</param>
|
||||
/// <param name="postSize">Data size from the end what will be ignored.</param>
|
||||
/// <param name="method">0 = BLZ; 1 = BLZ-Cue</param>
|
||||
/// <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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -425,6 +425,8 @@
|
||||
<S1C>Cancel</S1C>
|
||||
<S1E>Safe Trim</S1E>
|
||||
<S1F>Keep Original RSA SHA1 Signature</S1F>
|
||||
<S20>Recompress ARM9 binary (BLZ)</S20>
|
||||
<S21>Better compress method (BLZ-Cue)</S21>
|
||||
</Dialog>
|
||||
<VisorHex>
|
||||
<S00>File</S00>
|
||||
|
@ -429,6 +429,8 @@
|
||||
<S1C>Cancelar</S1C>
|
||||
<S1E>Safe Trim</S1E>
|
||||
<S1F>Keep Original RSA SHA1 Signature</S1F>
|
||||
<S20>Recompress ARM9 binary (BLZ)</S20>
|
||||
<S21>Better compress method (BLZ-Cue)</S21>
|
||||
</Dialog>
|
||||
<VisorHex>
|
||||
<S00>Archivo</S00>
|
||||
|
@ -425,6 +425,8 @@
|
||||
<S1C>Annuler</S1C>
|
||||
<S1E>Safe Trim</S1E>
|
||||
<S1F>Keep Original RSA SHA1 Signature</S1F>
|
||||
<S20>Recompress ARM9 binary (BLZ)</S20>
|
||||
<S21>Better compress method (BLZ-Cue)</S21>
|
||||
</Dialog>
|
||||
<VisorHex>
|
||||
<S00>Archive</S00>
|
||||
|
@ -424,6 +424,8 @@
|
||||
<S1C>Cancella</S1C>
|
||||
<S1E>Safe Trim</S1E>
|
||||
<S1F>Keep Original RSA SHA1 Signature</S1F>
|
||||
<S20>Recompress ARM9 binary (BLZ)</S20>
|
||||
<S21>Better compress method (BLZ-Cue)</S21>
|
||||
</Dialog>
|
||||
<VisorHex>
|
||||
<S00>File</S00>
|
||||
|
@ -422,6 +422,8 @@
|
||||
<S1C>取消</S1C>
|
||||
<S1E>安全裁剪</S1E>
|
||||
<S1F>保持原始的 RSA SHA1 签名</S1F>
|
||||
<S20>重压缩 ARM9 文件 (BLZ 算法)</S20>
|
||||
<S21>更好的压缩率算法 (BLZ-Cue)</S21>
|
||||
</Dialog>
|
||||
<VisorHex>
|
||||
<S00>文件</S00>
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user