2009-06-11 03:16:49 +02:00
using System ;
using System.Windows.Forms ;
using System.IO ;
using System.Net ;
using System.Security.Cryptography ;
using System.Xml ;
2009-07-09 04:11:22 +02:00
using System.Drawing ;
2009-08-04 20:17:21 +02:00
using System.Text.RegularExpressions ;
using System.ComponentModel ;
using System.Threading ;
2009-08-06 04:37:39 +02:00
using System.Text ;
2009-08-24 01:16:23 +02:00
using wyDay.Controls ;
2009-06-11 03:16:49 +02:00
2010-07-01 02:40:30 +02:00
using System.Diagnostics ;
2009-07-17 18:22:58 +02:00
2009-06-11 03:16:49 +02:00
namespace NUS_Downloader
{
public partial class Form1 : Form
{
const string NUSURL = "http://nus.cdn.shop.wii.com/ccs/download/" ;
const string DSiNUSURL = "http://nus.cdn.t.shop.nintendowifi.net/ccs/download/" ;
2010-06-27 20:43:36 +02:00
2009-07-09 04:11:22 +02:00
// TODO: Always remember to change version!
2010-07-01 02:40:30 +02:00
string version = "v1.5a (Beta)" ;
2009-06-11 03:16:49 +02:00
WebClient generalWC = new WebClient ( ) ;
static RijndaelManaged rijndaelCipher ;
static bool dsidecrypt = false ;
2010-07-01 02:40:30 +02:00
// Cross-thread Windows Formsing
delegate void AddToolStripItemToStripCallback ( int type , ToolStripMenuItem additionitem , XmlAttributeCollection attributes ) ; //TODO
2009-07-14 21:38:18 +02:00
2009-07-09 04:11:22 +02:00
// Images do not compare unless globalized...
Image green = Properties . Resources . bullet_green ;
Image orange = Properties . Resources . bullet_orange ;
Image redorb = Properties . Resources . bullet_red ;
Image redgreen = Properties . Resources . bullet_redgreen ;
Image redorange = Properties . Resources . bullet_redorange ;
2009-08-07 22:06:34 +02:00
// Certs storage
byte [ ] cert_CA = new byte [ 0x400 ] ;
byte [ ] cert_CACP = new byte [ 0x300 ] ;
byte [ ] cert_CAXS = new byte [ 0x300 ] ;
byte [ ] cert_CA_sha1 = new byte [ 20 ] { 0x5B , 0x7D , 0x3E , 0xE2 , 0x87 , 0x06 , 0xAD , 0x8D , 0xA2 , 0xCB , 0xD5 , 0xA6 , 0xB7 , 0x5C , 0x15 , 0xD0 , 0xF9 , 0xB6 , 0xF3 , 0x18 } ;
byte [ ] cert_CACP_sha1 = new byte [ 20 ] { 0x68 , 0x24 , 0xD6 , 0xDA , 0x4C , 0x25 , 0x18 , 0x4F , 0x0D , 0x6D , 0xAF , 0x6E , 0xDB , 0x9C , 0x0F , 0xC5 , 0x75 , 0x22 , 0xA4 , 0x1C } ;
byte [ ] cert_CAXS_sha1 = new byte [ 20 ] { 0x09 , 0x78 , 0x70 , 0x45 , 0x03 , 0x71 , 0x21 , 0x47 , 0x78 , 0x24 , 0xBC , 0x6A , 0x3E , 0x5E , 0x07 , 0x61 , 0x56 , 0x57 , 0x3F , 0x8A } ;
byte [ ] cert_total_sha1 = new byte [ 20 ] { 0xAC , 0xE0 , 0xF1 , 0x5D , 0x2A , 0x85 , 0x1C , 0x38 , 0x3F , 0xE4 , 0x65 , 0x7A , 0xFC , 0x38 , 0x40 , 0xD6 , 0xFF , 0xE3 , 0x0A , 0xD0 } ;
2009-08-18 07:02:23 +02:00
string WAD_Saveas_Filename ;
2009-08-20 19:41:08 +02:00
2009-08-28 00:52:11 +02:00
// TODO: OOP scripting
string script_filename ;
2009-08-28 05:12:10 +02:00
bool script_mode = false ;
2009-08-28 00:52:11 +02:00
2009-08-20 19:41:08 +02:00
// Proxy stuff...
string proxy_url ;
string proxy_usr ;
string proxy_pwd ;
2009-08-24 01:16:23 +02:00
2010-06-29 18:06:15 +02:00
// Database thread
private BackgroundWorker fds ;
2009-08-24 01:16:23 +02:00
// Common Key hash
byte [ ] wii_commonkey_sha1 = new byte [ 20 ] { 0xEB , 0xEA , 0xE6 , 0xD2 , 0x76 , 0x2D , 0x4D , 0x3E , 0xA1 , 0x60 , 0xA6 , 0xD8 , 0x32 , 0x7F , 0xAC , 0x9A , 0x25 , 0xF8 , 0x06 , 0x2B } ;
2010-06-27 20:43:36 +02:00
byte [ ] wii_commonkey_sha1_asstring = new byte [ 20 ] { 0x56 , 0xdd , 0x4e , 0xb3 , 0x59 , 0x75 , 0xc2 , 0xfd , 0x5a , 0xe8 , 0xba , 0x8c , 0x7d , 0x89 , 0x9a , 0xc5 , 0xe6 , 0x17 , 0x54 , 0x19 } ;
2009-08-18 07:02:23 +02:00
/ *
2009-06-11 03:16:49 +02:00
public struct WADHeader
{
public int HeaderSize ;
public int WadType ;
public int CertChainSize ;
public int Reserved ;
public int TicketSize ;
public int TMDSize ;
public int DataSize ;
public int FooterSize ;
2009-08-18 07:02:23 +02:00
} ; * /
2009-06-11 03:16:49 +02:00
2009-07-17 18:22:58 +02:00
public struct TitleContent
{
public byte [ ] ContentID ;
public byte [ ] Index ;
public byte [ ] Type ;
public byte [ ] Size ;
public byte [ ] SHAHash ;
} ;
public enum ContentTypes : int {
Shared = 0x8001 , Normal = 0x0001
}
2009-07-10 02:56:17 +02:00
// This is the standard entry to the GUI
2009-06-11 03:16:49 +02:00
public Form1 ( )
{
InitializeComponent ( ) ;
2010-06-29 18:06:15 +02:00
this . fds = new BackgroundWorker ( ) ;
this . fds . DoWork + = new DoWorkEventHandler ( DoAllDatabaseyStuff ) ;
this . fds . RunWorkerCompleted + = new RunWorkerCompletedEventHandler ( DoAllDatabaseyStuff_Completed ) ;
this . fds . ProgressChanged + = new ProgressChangedEventHandler ( DoAllDatabaseyStuff_ProgressChanged ) ;
this . fds . WorkerReportsProgress = true ;
2009-06-11 03:16:49 +02:00
BootChecks ( ) ;
}
2009-07-10 02:56:17 +02:00
// CLI Mode
2009-06-11 03:16:49 +02:00
public Form1 ( string [ ] args )
{
InitializeComponent ( ) ;
2009-08-07 22:06:34 +02:00
Application . DoEvents ( ) ;
2009-06-11 03:16:49 +02:00
2009-08-20 19:41:08 +02:00
BootChecks ( ) ;
2009-08-30 02:43:24 +02:00
// Fix proxy entry.
if ( ! ( String . IsNullOrEmpty ( proxy_url ) ) )
while ( String . IsNullOrEmpty ( proxy_pwd ) )
Thread . Sleep ( 1000 ) ;
if ( ( args . Length = = 1 ) & & ( File . Exists ( args [ 0 ] ) ) )
{
script_filename = args [ 0 ] ;
BackgroundWorker scripter = new BackgroundWorker ( ) ;
scripter . DoWork + = new DoWorkEventHandler ( RunScript ) ;
scripter . RunWorkerAsync ( ) ;
}
2009-08-20 19:41:08 +02:00
2009-08-30 02:43:24 +02:00
/ * CLI MODE DEPRECATED . . .
2009-06-11 03:16:49 +02:00
// Vars
bool startnow = false ;
2009-07-04 20:32:52 +02:00
bool endafter = false ;
2009-06-11 03:16:49 +02:00
// Fix'd
localuse . Checked = false ;
// Switch through arguments
for ( int i = 0 ; i < args . Length ; i + + )
{
switch ( args [ i ] )
{
case "-t" :
if ( args [ i + 1 ] . Length = = 16 )
titleidbox . Text = args [ i + 1 ] ;
else
{
WriteStatus ( "Title ID: Your Doing It Wrong (c)" ) ;
WriteStatus ( "ex: -t 0000000100000002" ) ;
}
break ;
case "-v" :
titleversion . Text = args [ i + 1 ] ;
break ;
case "-s" :
startnow = true ;
break ;
2009-07-04 20:32:52 +02:00
case "-close" :
endafter = true ;
break ;
2009-06-11 03:16:49 +02:00
case "-d" :
decryptbox . Checked = true ;
break ;
case "-ticket" :
ignoreticket . Checked = true ;
break ;
case "-local" :
localuse . Checked = true ;
break ;
case "-p" :
packbox . Checked = true ;
wadnamebox . Text = args [ i + 1 ] ;
break ;
case "-dsi" :
radioButton2 . Checked = true ;
break ;
default :
break ;
}
}
// Start doing stuff...
if ( ( startnow ) & & ( titleidbox . Text . Length ! = 0 ) )
{
// Prevent mass deletion
if ( ( titleidbox . Text = = "" ) & & ( titleversion . Text = = "" ) )
{
WriteStatus ( "Please enter SOME info..." ) ;
return ;
}
2009-07-10 02:56:17 +02:00
else
{
if ( ! statusbox . Lines [ 0 ] . StartsWith ( " ---" ) )
statusbox . Text = " --- " + titleidbox . Text + " ---" ;
}
2009-06-11 03:16:49 +02:00
// Running Downloads in background so no form freezing
NUSDownloader . RunWorkerAsync ( ) ;
}
2009-07-04 20:32:52 +02:00
// Close if specified
while ( NUSDownloader . IsBusy )
2009-08-07 22:06:34 +02:00
{
Thread . Sleep ( 1000 ) ;
2009-07-04 20:32:52 +02:00
}
if ( ( NUSDownloader . IsBusy = = false ) & & ( endafter = = true ) )
{
Application . Exit ( ) ;
2009-08-30 02:43:24 +02:00
} * /
2009-06-11 03:16:49 +02:00
}
private void Form1_Load ( object sender , EventArgs e )
{
this . Text = "NUSD - " + version + " - WB3000" ;
2009-06-19 03:57:52 +02:00
this . Size = this . MinimumSize ;
2009-06-11 03:16:49 +02:00
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Checks certain file existances, etc.
/// </summary>
/// <returns></returns>
2009-08-20 19:41:08 +02:00
private void BootChecks ( )
2009-06-11 03:16:49 +02:00
{
// Directory stuff
2010-07-01 23:35:12 +02:00
string currentdir = Directory . GetCurrentDirectory ( ) ;
2009-10-16 00:23:08 +02:00
2009-10-14 22:52:16 +02:00
if ( currentdir . EndsWith ( Convert . ToString ( Path . DirectorySeparatorChar . ToString ( ) ) ) = = false )
currentdir + = Path . DirectorySeparatorChar . ToString ( ) ;
2009-06-11 03:16:49 +02:00
// Check for Wii common key bin file...
if ( File . Exists ( currentdir + "key.bin" ) = = false )
{
WriteStatus ( "Common Key (key.bin) missing! Decryption disabled!" ) ;
2010-06-27 20:43:36 +02:00
WriteStatus ( " - To enable it, why not try choosing \"Retrieve Common Key\" from the Extras menu?" ) ;
2009-06-11 03:16:49 +02:00
decryptbox . Visible = false ;
}
else
{
WriteStatus ( "Common Key detected." ) ;
2009-08-24 01:16:23 +02:00
if ( ( Convert . ToBase64String ( ComputeSHA ( LoadCommonKey ( "key.bin" ) ) ) ) ! = ( Convert . ToBase64String ( wii_commonkey_sha1 ) ) )
2010-06-27 20:43:36 +02:00
{ // Hmm, seems to be a bad hash
// Let's check if it matches the hex string version...
if ( ( Convert . ToBase64String ( ComputeSHA ( LoadCommonKey ( "key.bin" ) ) ) ) ! = ( Convert . ToBase64String ( wii_commonkey_sha1_asstring ) ) )
WriteStatus ( " - (PS: Your common key isn't hashing right!)" ) ;
else
{
WriteStatus ( " - Converting your key.bin file to the correct format..." ) ;
// Directory stuff
2010-07-01 23:35:12 +02:00
string keydir = Directory . GetCurrentDirectory ( ) ;
2010-06-27 20:43:36 +02:00
if ( ! ( keydir . EndsWith ( Path . DirectorySeparatorChar . ToString ( ) ) ) | | ! ( keydir . EndsWith ( Path . AltDirectorySeparatorChar . ToString ( ) ) ) )
keydir + = Path . DirectorySeparatorChar . ToString ( ) ;
TextReader ckreader = new StreamReader ( currentdir + "key.bin" ) ;
String ckashex = ckreader . ReadLine ( ) ;
ckreader . Close ( ) ;
File . Delete ( currentdir + "key.bin" ) ;
WriteCommonKey ( "key.bin" , HexStringToByteArray ( ckashex ) ) ;
}
}
2009-06-11 03:16:49 +02:00
}
2009-06-13 18:04:54 +02:00
// Check for Wii KOR common key bin file...
2009-08-20 19:41:08 +02:00
if ( File . Exists ( currentdir + "kkey.bin" ) = = true )
2009-06-13 18:04:54 +02:00
{
WriteStatus ( "Korean Common Key detected." ) ;
}
2009-06-11 03:16:49 +02:00
// Check for DSi common key bin file...
2009-08-20 19:41:08 +02:00
if ( File . Exists ( currentdir + "dsikey.bin" ) = = true )
2009-06-11 03:16:49 +02:00
{
WriteStatus ( "DSi Common Key detected." ) ;
dsidecrypt = true ;
}
// Check for database.xml
if ( File . Exists ( currentdir + "database.xml" ) = = false )
{
WriteStatus ( "Database.xml not found. Title database not usable!" ) ;
databaseButton . Visible = false ;
2009-08-06 04:37:39 +02:00
Extrasbtn . Size = new System . Drawing . Size ( 134 , 20 ) ;
2010-06-29 18:06:15 +02:00
updateDatabaseToolStripMenuItem . Text = "Download Database" ;
2009-06-11 03:16:49 +02:00
}
else
{
2009-08-04 20:17:21 +02:00
string version = GetDatabaseVersion ( "database.xml" ) ;
2009-06-11 03:16:49 +02:00
WriteStatus ( "Database.xml detected." ) ;
2009-08-04 20:17:21 +02:00
WriteStatus ( " - Version: " + version ) ;
2010-06-29 18:06:15 +02:00
databaseButton . Enabled = false ;
databaseButton . Text = "DB Loading" ;
2009-06-11 03:16:49 +02:00
// Load it up...
2010-06-29 18:06:15 +02:00
this . fds . RunWorkerAsync ( ) ;
2009-06-11 03:16:49 +02:00
}
2009-08-20 19:41:08 +02:00
// Check for Proxy Settings file...
if ( File . Exists ( currentdir + "proxy.txt" ) = = true )
{
WriteStatus ( "Proxy settings detected." ) ;
string [ ] proxy_file = File . ReadAllLines ( currentdir + "proxy.txt" ) ;
proxy_url = proxy_file [ 0 ] ;
if ( proxy_file . Length > 1 )
{
proxy_usr = proxy_file [ 1 ] ;
SetAllEnabled ( false ) ;
ProxyVerifyBox . Visible = true ; ProxyVerifyBox . Enabled = true ;
ProxyPwdBox . Enabled = true ; SaveProxyBtn . Enabled = true ;
ProxyVerifyBox . Select ( ) ;
}
}
}
2010-06-29 18:06:15 +02:00
private void DoAllDatabaseyStuff ( object sender , System . ComponentModel . DoWorkEventArgs e )
{
BackgroundWorker worker = sender as BackgroundWorker ;
ClearDatabaseStrip ( ) ;
FillDatabaseStrip ( worker ) ;
LoadRegionCodes ( ) ;
ShowInnerToolTips ( false ) ;
}
private void DoAllDatabaseyStuff_Completed ( object sender , System . ComponentModel . RunWorkerCompletedEventArgs e )
{
this . databaseButton . Enabled = true ;
this . databaseButton . Text = "Database..." ;
}
private void DoAllDatabaseyStuff_ProgressChanged ( object sender , System . ComponentModel . ProgressChangedEventArgs e )
{
this . databaseButton . Text = "DB: " + e . ProgressPercentage + "%" ;
}
2009-08-20 19:41:08 +02:00
private void SetAllEnabled ( bool enabled )
{
for ( int a = 0 ; a < this . Controls . Count ; a + + )
{
try
{
this . Controls [ a ] . Enabled = enabled ;
}
catch
{
// ...
}
}
2009-06-11 03:16:49 +02:00
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Gets the database version.
/// </summary>
/// <param name="file">The database file.</param>
/// <returns></returns>
2009-08-04 20:17:21 +02:00
private string GetDatabaseVersion ( string file )
{
// Read version of Database.xml
XmlDocument xDoc = new XmlDocument ( ) ;
if ( file . Contains ( "<" ) )
xDoc . LoadXml ( file ) ;
else
2010-06-29 18:06:15 +02:00
{
if ( File . Exists ( file ) )
{
xDoc . Load ( file ) ;
}
else
{
return "None Found" ;
}
}
2009-08-04 20:17:21 +02:00
XmlNodeList DatabaseList = xDoc . GetElementsByTagName ( "database" ) ;
XmlAttributeCollection Attributes = DatabaseList [ 0 ] . Attributes ;
return Attributes [ 0 ] . Value ;
}
2009-06-11 03:16:49 +02:00
private void button1_Click ( object sender , EventArgs e )
2009-08-06 04:37:39 +02:00
{
// Show extras menu
extrasStrip . Show ( Extrasbtn , 2 , 2 ) ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Loads the title info from TMD.
/// </summary>
2009-08-06 04:37:39 +02:00
private void LoadTitleFromTMD ( )
2009-06-11 03:16:49 +02:00
{
// Show dialog for opening TMD file...
OpenFileDialog opentmd = new OpenFileDialog ( ) ;
opentmd . Filter = "TMD Files|tmd" ;
opentmd . Title = "Open TMD" ;
if ( opentmd . ShowDialog ( ) ! = DialogResult . Cancel )
{
// Read the tmd as a stream...
2009-07-10 02:56:17 +02:00
byte [ ] tmd = FileLocationToByteArray ( opentmd . FileName ) ;
2009-06-11 03:16:49 +02:00
WriteStatus ( "TMD Loaded (" + tmd . Length + " bytes)" ) ;
// Read ID...
for ( int x = 396 ; x < 404 ; x + + )
{
titleidbox . Text + = MakeProperLength ( ConvertToHex ( Convert . ToString ( tmd [ x ] ) ) ) ;
}
WriteStatus ( "Title ID: " + titleidbox . Text ) ;
// Show TitleID Type/likelyhood of NUS existance...
ReadIDType ( titleidbox . Text ) ;
// Read Title Version...
string tmdversion = "" ;
for ( int x = 476 ; x < 478 ; x + + )
{
tmdversion + = MakeProperLength ( ConvertToHex ( Convert . ToString ( tmd [ x ] ) ) ) ;
}
titleversion . Text = Convert . ToString ( int . Parse ( tmdversion , System . Globalization . NumberStyles . HexNumber ) ) ;
// Read System Version (Needed IOS)
2009-07-14 21:38:18 +02:00
string sysversion = IOSNeededFromTMD ( tmd ) ;
2009-06-11 03:16:49 +02:00
if ( sysversion ! = "0" )
WriteStatus ( "Requires: IOS" + sysversion ) ;
// Read Content #...
2009-07-14 21:38:18 +02:00
int nbr_cont = ContentCount ( tmd ) ;
/ * string contentstrnum = "" ;
2009-06-11 03:16:49 +02:00
for ( int x = 478 ; x < 480 ; x + + )
{
contentstrnum + = TrimLeadingZeros ( Convert . ToString ( tmd [ x ] ) ) ;
2009-07-14 21:38:18 +02:00
} * /
WriteStatus ( "Content Count: " + nbr_cont ) ;
2009-06-11 03:16:49 +02:00
2009-07-14 21:38:18 +02:00
string [ ] tmdcontents = GetContentNames ( tmd , nbr_cont ) ;
string [ ] tmdsizes = GetContentSizes ( tmd , nbr_cont ) ;
byte [ ] tmdhashes = GetContentHashes ( tmd , nbr_cont ) ;
byte [ ] tmdindices = GetContentIndices ( tmd , nbr_cont ) ;
2009-07-17 18:22:58 +02:00
int [ ] tmdtypes = GetContentTypes ( tmd , nbr_cont ) ;
2009-06-11 03:16:49 +02:00
// Loop through each content and display name, hash, index
2009-07-14 21:38:18 +02:00
for ( int i = 0 ; i < nbr_cont ; i + + )
2009-06-11 03:16:49 +02:00
{
WriteStatus ( " Content " + ( i + 1 ) + ": " + tmdcontents [ i ] + " (" + Convert . ToString ( int . Parse ( tmdsizes [ i ] , System . Globalization . NumberStyles . HexNumber ) ) + " bytes)" ) ;
byte [ ] hash = new byte [ 20 ] ;
for ( int x = 0 ; x < 20 ; x + + )
{
2009-08-06 04:37:39 +02:00
hash [ x ] = tmdhashes [ ( i * 20 ) + x ] ;
2009-06-11 03:16:49 +02:00
}
2009-07-17 18:22:58 +02:00
WriteStatus ( " - Hash: " + DisplayBytes ( hash , "" ) . Substring ( 0 , 8 ) + "..." ) ;
2009-06-11 03:16:49 +02:00
WriteStatus ( " - Index: " + tmdindices [ i ] ) ;
2009-07-17 18:22:58 +02:00
WriteStatus ( " - Shared: " + ( tmdtypes [ i ] = = 0x8001 ) ) ;
2009-06-11 03:16:49 +02:00
}
}
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Returns needed IOS from TMD.
/// </summary>
/// <param name="tmd">The TMD.</param>
/// <returns></returns>
2009-07-14 21:38:18 +02:00
private string IOSNeededFromTMD ( byte [ ] tmd )
{
string sysversion = "" ;
for ( int i = 0 ; i < 8 ; i + + )
{
sysversion + = MakeProperLength ( ConvertToHex ( Convert . ToString ( tmd [ 0x184 + i ] ) ) ) ;
}
sysversion = Convert . ToString ( int . Parse ( sysversion . Substring ( 14 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ) ;
return sysversion ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Returns content count of TMD
/// </summary>
/// <param name="tmd">The TMD.</param>
/// <returns>int Count of Contents</returns>
2009-07-14 21:38:18 +02:00
private int ContentCount ( byte [ ] tmd )
{
// nbr_cont (0xDE) len=0x02
int nbr_cont = 0 ;
nbr_cont = ( tmd [ 0x1DE ] * 256 ) + tmd [ 0x1DF ] ;
return nbr_cont ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Gets a TMD Boot Index
/// </summary>
/// <param name="tmd">The TMD.</param>
/// <returns>int BootIndex</returns>
2009-07-23 00:22:04 +02:00
private int GetBootIndex ( byte [ ] tmd )
2009-07-14 21:38:18 +02:00
{
// nbr_cont (0xE0) len=0x02
int bootidx = 0 ;
bootidx = ( tmd [ 0x1E0 ] * 256 ) + tmd [ 0x1E1 ] ;
return bootidx ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Sets the Boot index of a TMD.
/// </summary>
/// <param name="tmd">The TMD.</param>
/// <param name="bootindex">Index to set it too</param>
/// <returns>Edited TMD</returns>
2009-07-23 00:22:04 +02:00
private byte [ ] SetBootIndex ( byte [ ] tmd , int bootindex )
{
// nbr_cont (0xE0) len=0x02
byte [ ] bootbytes = NewIntegertoByteArray ( bootindex , 2 ) ;
tmd [ 0x1E0 ] = bootbytes [ 0 ] ;
tmd [ 0x1E1 ] = bootbytes [ 1 ] ;
return tmd ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Writes the status to the statusbox.
/// </summary>
/// <param name="Update">The update.</param>
public void WriteStatus ( string Update )
2009-06-11 03:16:49 +02:00
{
2009-07-10 02:56:17 +02:00
// Small function for writing text to the statusbox...
2009-06-11 03:16:49 +02:00
if ( statusbox . Text = = "" )
statusbox . Text = Update ;
else
statusbox . Text + = "\r\n" + Update ;
// Scroll to end of text box.
statusbox . SelectionStart = statusbox . TextLength ;
statusbox . ScrollToCaret ( ) ;
}
/// <summary>
/// Reads data from a stream until the end is reached. The
/// data is returned as a byte array. An IOException is
/// thrown if any of the underlying IO calls fail.
/// </summary>
/// <param name="stream">The stream to read data from</param>
/// <param name="initialLength">The initial buffer length</param>
public static byte [ ] ReadFully ( Stream stream , int initialLength )
{
// If we've been passed an unhelpful initial length, just
// use 32K.
if ( initialLength < 1 )
{
initialLength = 32768 ;
}
byte [ ] buffer = new byte [ initialLength ] ;
int read = 0 ;
int chunk ;
while ( ( chunk = stream . Read ( buffer , read , buffer . Length - read ) ) > 0 )
{
read + = chunk ;
// If we've reached the end of our buffer, check to see if there's
// any more information
if ( read = = buffer . Length )
{
int nextByte = stream . ReadByte ( ) ;
// End of stream? If so, we're done
if ( nextByte = = - 1 )
{
return buffer ;
}
// Nope. Resize the buffer, put in the byte we've just
// read, and continue
byte [ ] newBuffer = new byte [ buffer . Length * 2 ] ;
Array . Copy ( buffer , newBuffer , buffer . Length ) ;
newBuffer [ read ] = ( byte ) nextByte ;
buffer = newBuffer ;
read + + ;
}
}
// Buffer is now too big. Shrink it.
byte [ ] ret = new byte [ read ] ;
Array . Copy ( buffer , ret , read ) ;
return ret ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Makes a hex string the correct length.
/// </summary>
/// <param name="hex">The hex.</param>
/// <returns></returns>
2009-06-11 03:16:49 +02:00
private string MakeProperLength ( string hex )
{
// If hex is like, 'A', makes it '0A', etc.
if ( hex . Length = = 1 )
hex = "0" + hex ;
return hex ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Converts to hex.
/// </summary>
/// <param name="decval">The string.</param>
/// <returns>hex string</returns>
2009-06-11 03:16:49 +02:00
private string ConvertToHex ( string decval )
{
// Convert text string to unsigned integer
2009-07-10 02:56:17 +02:00
int uiDecimal = System . Convert . ToInt32 ( decval ) ;
return String . Format ( "{0:x2}" , uiDecimal ) ;
2009-06-11 03:16:49 +02:00
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Reads the type of the Title ID.
/// </summary>
/// <param name="ttlid">The TitleID.</param>
2009-06-11 03:16:49 +02:00
private void ReadIDType ( string ttlid )
{
/ * Wiibrew TitleID Info . . .
# 3 00000001 : Essential system titles
# 4 00010000 and 00010004 : Disc - based games
# 5 00010001 : Downloaded channels
* 5.1 000010001 - Cxxx : Commodore 64 Games
* 5.2 000010001 - Exxx : NeoGeo Games
* 5.3 000010001 - Fxxx : NES Games
* 5.4 000010001 - Hxxx : Channels
* 5.5 000010001 - Jxxx : SNES Games
* 5.6 000010001 - Nxxx : Nintendo 64 Games
* 5.7 000010001 - Wxxx : WiiWare
# 6 00010002 : System channels
# 7 00010004 : Game channels and games that use them
# 8 00010005 : Downloaded Game Content
# 9 00010008 : "Hidden" channels
* /
if ( ttlid . Substring ( 0 , 8 ) = = "00000001" )
WriteStatus ( "ID Type: System Title. BE CAREFUL!" ) ;
else if ( ( ttlid . Substring ( 0 , 8 ) = = "00010000" ) | | ( ttlid . Substring ( 0 , 8 ) = = "00010004" ) )
WriteStatus ( "ID Type: Disc-Based Game. Unlikely NUS Content!" ) ;
else if ( ttlid . Substring ( 0 , 8 ) = = "00010001" )
WriteStatus ( "ID Type: Downloaded Channel. Possible NUS Content." ) ;
else if ( ttlid . Substring ( 0 , 8 ) = = "00010002" )
WriteStatus ( "ID Type: System Channel. BE CAREFUL!" ) ;
else if ( ttlid . Substring ( 0 , 8 ) = = "00010004" )
WriteStatus ( "ID Type: Game Channel. Unlikely NUS Content!" ) ;
else if ( ttlid . Substring ( 0 , 8 ) = = "00010005" )
WriteStatus ( "ID Type: Downloaded Game Content. Unlikely NUS Content!" ) ;
else if ( ttlid . Substring ( 0 , 8 ) = = "00010008" )
WriteStatus ( "ID Type: 'Hidden' Channel. Unlikely NUS Content!" ) ;
else
WriteStatus ( "ID Type: Unknown. Unlikely NUS Content!" ) ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Trims the leading zeros of a string.
/// </summary>
/// <param name="num">The string with leading zeros.</param>
/// <returns>no-0-string</returns>
2009-06-11 03:16:49 +02:00
private string TrimLeadingZeros ( string num )
{
int startindex = 0 ;
for ( int i = 0 ; i < num . Length ; i + + )
{
if ( ( num [ i ] = = 0 ) | | ( num [ i ] = = '0' ) )
startindex + = 1 ;
else
break ;
}
return num . Substring ( startindex , ( num . Length - startindex ) ) ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Gets the content names in a TMD.
/// </summary>
/// <param name="tmdfile">The TMD.</param>
/// <param name="length">The TMD contentcount.</param>
/// <returns>Array of Content names</returns>
2009-06-11 03:16:49 +02:00
private string [ ] GetContentNames ( byte [ ] tmdfile , int length )
{
string [ ] contentnames = new string [ length ] ;
int startoffset = 484 ;
for ( int i = 0 ; i < length ; i + + )
{
contentnames [ i ] = MakeProperLength ( ConvertToHex ( Convert . ToString ( tmdfile [ startoffset ] ) ) ) +
MakeProperLength ( ConvertToHex ( Convert . ToString ( tmdfile [ startoffset + 1 ] ) ) ) +
MakeProperLength ( ConvertToHex ( Convert . ToString ( tmdfile [ startoffset + 2 ] ) ) ) +
MakeProperLength ( ConvertToHex ( Convert . ToString ( tmdfile [ startoffset + 3 ] ) ) ) ;
startoffset + = 36 ;
}
return contentnames ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Gets the content sizes in a TMD.
/// </summary>
/// <param name="tmdfile">The TMD.</param>
/// <param name="length">The TMD contentcount.</param>
/// <returns></returns>
2009-06-11 03:16:49 +02:00
private string [ ] GetContentSizes ( byte [ ] tmdfile , int length )
{
string [ ] contentsizes = new string [ length ] ;
int startoffset = 492 ;
for ( int i = 0 ; i < length ; i + + )
{
contentsizes [ i ] = MakeProperLength ( ConvertToHex ( Convert . ToString ( tmdfile [ startoffset ] ) ) ) +
MakeProperLength ( ConvertToHex ( Convert . ToString ( tmdfile [ startoffset + 1 ] ) ) ) +
MakeProperLength ( ConvertToHex ( Convert . ToString ( tmdfile [ startoffset + 2 ] ) ) ) +
MakeProperLength ( ConvertToHex ( Convert . ToString ( tmdfile [ startoffset + 3 ] ) ) ) +
MakeProperLength ( ConvertToHex ( Convert . ToString ( tmdfile [ startoffset + 4 ] ) ) ) +
MakeProperLength ( ConvertToHex ( Convert . ToString ( tmdfile [ startoffset + 5 ] ) ) ) +
MakeProperLength ( ConvertToHex ( Convert . ToString ( tmdfile [ startoffset + 6 ] ) ) ) +
MakeProperLength ( ConvertToHex ( Convert . ToString ( tmdfile [ startoffset + 7 ] ) ) ) ;
contentsizes [ i ] = TrimLeadingZeros ( contentsizes [ i ] ) ;
/ * contentsizes [ i ] = Convert . ToString ( tmdfile [ startoffset ] ) +
Convert . ToString ( tmdfile [ startoffset + 1 ] ) +
Convert . ToString ( tmdfile [ startoffset + 2 ] ) +
Convert . ToString ( tmdfile [ startoffset + 3 ] ) +
Convert . ToString ( tmdfile [ startoffset + 4 ] ) +
Convert . ToString ( tmdfile [ startoffset + 5 ] ) +
Convert . ToString ( tmdfile [ startoffset + 6 ] ) +
Convert . ToString ( tmdfile [ startoffset + 7 ] ) ;
contentsizes [ i ] = TrimLeadingZeros ( contentsizes [ i ] ) ; * /
startoffset + = 36 ;
}
return contentsizes ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Gets the content hashes.
/// </summary>
/// <param name="tmdfile">The tmd.</param>
/// <param name="length">The content_count.</param>
/// <returns></returns>
2009-06-11 03:16:49 +02:00
private byte [ ] GetContentHashes ( byte [ ] tmdfile , int length )
{
byte [ ] contenthashes = new byte [ length * 20 ] ;
int startoffset = 500 ;
for ( int i = 0 ; i < length ; i + + )
{
for ( int x = 0 ; x < 20 ; x + + )
{
contenthashes [ ( i * 20 ) + x ] = tmdfile [ startoffset + x ] ;
}
startoffset + = 36 ;
}
return contenthashes ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Gets the content types.
/// </summary>
/// <param name="tmdfile">The tmd.</param>
/// <param name="length">The content_count.</param>
/// <returns></returns>
2009-07-17 18:22:58 +02:00
private int [ ] GetContentTypes ( byte [ ] tmdfile , int length )
{
int [ ] contenttypes = new int [ length ] ;
int startoffset = 0x1EA ;
for ( int i = 0 ; i < length ; i + + )
{
if ( tmdfile [ startoffset ] = = 0x80 )
contenttypes [ i ] = ( int ) ContentTypes . Shared ;
else
contenttypes [ i ] = ( int ) ContentTypes . Normal ;
startoffset + = 36 ;
}
return contenttypes ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Gets the content indices.
/// </summary>
/// <param name="tmdfile">The tmd.</param>
/// <param name="length">The contentcount.</param>
/// <returns></returns>
2009-06-11 03:16:49 +02:00
private byte [ ] GetContentIndices ( byte [ ] tmdfile , int length )
{
byte [ ] contentindices = new byte [ length ] ;
int startoffset = 0x1E9 ;
for ( int i = 0 ; i < length ; i + + )
{
contentindices [ i ] = tmdfile [ startoffset ] ;
startoffset + = 36 ;
}
return contentindices ;
}
private void button3_Click ( object sender , EventArgs e )
{
// Prevent mass deletion
if ( ( titleidbox . Text = = "" ) & & ( titleversion . Text = = "" ) )
{
WriteStatus ( "Please enter SOME info..." ) ;
return ;
}
2009-08-28 05:12:10 +02:00
else if ( ! ( script_mode ) )
2009-07-09 04:11:22 +02:00
{
2009-07-14 21:38:18 +02:00
try
{
if ( ! statusbox . Lines [ 0 ] . StartsWith ( " ---" ) )
statusbox . Text = " --- " + titleidbox . Text + " ---" ;
}
catch // No lines present...
{
2009-07-10 02:56:17 +02:00
statusbox . Text = " --- " + titleidbox . Text + " ---" ;
2009-07-14 21:38:18 +02:00
}
2009-07-09 04:11:22 +02:00
}
2009-08-28 05:12:10 +02:00
else
statusbox . Text + = "\r\n --- " + titleidbox . Text + " ---" ;
2009-06-11 03:16:49 +02:00
2009-08-18 07:02:23 +02:00
// Handle SaveAs here so it shows up properly...
if ( saveaswadbox . Checked )
{
SaveFileDialog wad_saveas = new SaveFileDialog ( ) ;
wad_saveas . Title = "Save WAD File..." ;
wad_saveas . Filter = "WAD Files|*.wad|All Files|*.*" ;
wad_saveas . AddExtension = true ;
DialogResult dres = wad_saveas . ShowDialog ( ) ;
if ( dres ! = DialogResult . Cancel )
WAD_Saveas_Filename = wad_saveas . FileName ;
}
else
WAD_Saveas_Filename = "" ;
2009-06-11 03:16:49 +02:00
// Running Downloads in background so no form freezing
NUSDownloader . RunWorkerAsync ( ) ;
}
private void NUSDownloader_DoWork ( object sender , System . ComponentModel . DoWorkEventArgs e )
{
// Preparations for Downloading
Control . CheckForIllegalCrossThreadCalls = false ;
2009-08-28 05:12:10 +02:00
if ( ! ( script_mode ) )
WriteStatus ( "Starting NUS Download. Please be patient!" ) ;
2009-07-08 01:41:38 +02:00
SetEnableforDownload ( false ) ;
2009-06-19 03:57:52 +02:00
downloadstartbtn . Text = "Starting NUS Download!" ;
2009-06-11 03:16:49 +02:00
// Current directory...
2010-07-01 23:35:12 +02:00
string currentdir = Directory . GetCurrentDirectory ( ) ;
2009-10-16 00:23:08 +02:00
2009-10-14 22:52:16 +02:00
if ( ! ( currentdir . EndsWith ( Path . DirectorySeparatorChar . ToString ( ) ) ) | | ! ( currentdir . EndsWith ( Path . AltDirectorySeparatorChar . ToString ( ) ) ) )
currentdir + = Path . DirectorySeparatorChar . ToString ( ) ;
2009-06-11 03:16:49 +02:00
// Prevent crossthread issues
string titleid = titleidbox . Text ;
// Creates the directory
CreateTitleDirectory ( ) ;
// Wii / DSi
bool wiimode = radioButton1 . Checked ;
// Set UserAgent to Wii value
2009-08-01 19:48:32 +02:00
generalWC . Headers . Add ( "User-Agent" , "wii libnup/1.0" ) ;
2009-06-11 03:16:49 +02:00
2009-08-19 18:40:43 +02:00
// Proxy
2009-08-20 19:41:08 +02:00
if ( ! ( String . IsNullOrEmpty ( proxy_url ) ) )
{
WebProxy customproxy = new WebProxy ( ) ;
customproxy . Address = new Uri ( proxy_url ) ;
if ( String . IsNullOrEmpty ( proxy_usr ) )
customproxy . UseDefaultCredentials = true ;
else
{
NetworkCredential cred = new NetworkCredential ( ) ;
cred . UserName = proxy_usr ;
2009-08-25 18:41:49 +02:00
if ( ! ( String . IsNullOrEmpty ( proxy_pwd ) ) )
2009-08-20 19:41:08 +02:00
cred . Password = proxy_pwd ;
customproxy . Credentials = cred ;
}
generalWC . Proxy = customproxy ;
WriteStatus ( "Custom proxy settings applied!" ) ;
}
else
{
generalWC . Proxy = WebRequest . GetSystemWebProxy ( ) ;
generalWC . UseDefaultCredentials = true ;
}
2009-08-19 18:40:43 +02:00
2009-06-11 03:16:49 +02:00
// Get placement directory early...
string titledirectory ;
if ( titleversion . Text = = "" )
2009-10-14 22:52:16 +02:00
titledirectory = currentdir + titleid + Path . DirectorySeparatorChar . ToString ( ) ;
2009-06-11 03:16:49 +02:00
else
2009-10-14 22:52:16 +02:00
titledirectory = currentdir + titleid + "v" + titleversion . Text + Path . DirectorySeparatorChar . ToString ( ) ;
2009-06-11 03:16:49 +02:00
2009-06-19 03:57:52 +02:00
downloadstartbtn . Text = "Prerequisites: (0/2)" ;
2009-06-11 03:16:49 +02:00
2009-08-24 01:16:23 +02:00
// Windows 7?
if ( IsWin7 ( ) )
{
// Windows 7 Taskbar progress can be used.
dlprogress . ShowInTaskbar = true ;
}
2009-06-11 03:16:49 +02:00
// Download TMD before the rest...
string tmdfull = "tmd" ;
if ( titleversion . Text ! = "" )
tmdfull + = "." + titleversion . Text ;
try
{
DownloadNUSFile ( titleid , tmdfull , titledirectory , 0 , wiimode ) ;
}
catch ( Exception ex )
{
WriteStatus ( "Download Failed: " + tmdfull ) ;
WriteStatus ( " - Reason: " + ex . Message . ToString ( ) . Replace ( "The remote server returned an error: " , "" ) ) ;
2009-07-08 01:41:38 +02:00
SetEnableforDownload ( true ) ;
2009-06-19 03:57:52 +02:00
downloadstartbtn . Text = "Start NUS Download!" ;
2009-06-11 03:16:49 +02:00
dlprogress . Value = 0 ;
DeleteTitleDirectory ( ) ;
return ;
}
2009-06-19 03:57:52 +02:00
downloadstartbtn . Text = "Prerequisites: (1/2)" ;
2009-06-11 03:16:49 +02:00
dlprogress . Value = 50 ;
// Download CETK after tmd...
2009-10-16 00:23:08 +02:00
bool ticket_exists = true ;
2009-06-11 03:16:49 +02:00
try
{
DownloadNUSFile ( titleid , "cetk" , titledirectory , 0 , wiimode ) ;
}
catch ( Exception ex )
{
if ( ignoreticket . Checked = = false )
{
WriteStatus ( "Download Failed: cetk" ) ;
WriteStatus ( " - Reason: " + ex . Message . ToString ( ) . Replace ( "The remote server returned an error: " , "" ) ) ;
WriteStatus ( "You may be able to retrieve the contents by Ignoring the Ticket (Check below)" ) ;
2009-07-08 01:41:38 +02:00
SetEnableforDownload ( true ) ;
2009-06-19 03:57:52 +02:00
downloadstartbtn . Text = "Start NUS Download!" ;
2009-06-11 03:16:49 +02:00
dlprogress . Value = 0 ;
DeleteTitleDirectory ( ) ;
return ;
}
else
{
WriteStatus ( "Ticket not found! Continuing, however WAD packing and decryption are not possible!" ) ;
packbox . Checked = false ;
decryptbox . Checked = false ;
2009-10-16 00:23:08 +02:00
ticket_exists = false ;
2009-06-11 03:16:49 +02:00
}
}
2009-06-19 03:57:52 +02:00
downloadstartbtn . Text = "Prerequisites: (2/2)" ;
2009-06-11 03:16:49 +02:00
dlprogress . Value = 100 ;
2009-10-16 00:23:08 +02:00
byte [ ] cetkbuf = new byte [ 0 ] ;
byte [ ] titlekey = new byte [ 0 ] ;
if ( ticket_exists )
{
// Create ticket file holder
cetkbuf = FileLocationToByteArray ( titledirectory + Path . DirectorySeparatorChar . ToString ( ) + @"cetk" ) ;
2009-08-07 22:06:34 +02:00
2009-10-16 00:23:08 +02:00
// Obtain TitleKey
titlekey = new byte [ 16 ] ;
if ( decryptbox . Checked = = true )
{
// Load TitleKey into it's byte[]
// It is currently encrypted...
for ( int i = 0 ; i < 16 ; i + + )
{
titlekey [ i ] = cetkbuf [ 0x1BF + i ] ;
}
2009-06-11 03:16:49 +02:00
2009-10-16 00:23:08 +02:00
// IV (TITLEID+0000s)
byte [ ] iv = new byte [ 16 ] ;
for ( int i = 0 ; i < 8 ; i + + )
{
iv [ i ] = cetkbuf [ 0x1DC + i ] ;
}
for ( int i = 0 ; i < 8 ; i + + )
{
iv [ i + 8 ] = 0x00 ;
}
2009-06-11 03:16:49 +02:00
2009-10-16 00:23:08 +02:00
// Standard/Korea Common Key
byte [ ] keyBytes ;
if ( cetkbuf [ 0x01F1 ] = = 0x01 )
{
WriteStatus ( "Key Type: Korean" ) ;
keyBytes = LoadCommonKey ( Path . DirectorySeparatorChar . ToString ( ) + @"kkey.bin" ) ;
}
2009-07-10 02:56:17 +02:00
else
2009-10-16 00:23:08 +02:00
{
WriteStatus ( "Key Type: Standard" ) ;
if ( wiimode )
keyBytes = LoadCommonKey ( Path . DirectorySeparatorChar . ToString ( ) + @"key.bin" ) ;
else
keyBytes = LoadCommonKey ( Path . DirectorySeparatorChar . ToString ( ) + @"dsikey.bin" ) ;
}
2009-06-11 03:16:49 +02:00
2009-10-16 00:23:08 +02:00
initCrypt ( iv , keyBytes ) ;
WriteStatus ( "Title Key: " + DisplayBytes ( Decrypt ( titlekey ) , "" ) ) ;
titlekey = Decrypt ( titlekey ) ;
}
2009-06-11 03:16:49 +02:00
}
// Read the tmd as a stream...
2009-07-10 02:56:17 +02:00
byte [ ] tmd = FileLocationToByteArray ( titledirectory + tmdfull ) ;
2009-06-11 03:16:49 +02:00
2009-10-16 00:23:08 +02:00
if ( ticket_exists = = true )
2009-08-07 22:06:34 +02:00
{
2009-10-16 00:23:08 +02:00
// Locate Certs **************************************
if ( ! ( CertsValid ( ) ) )
{
WriteStatus ( "Searching for certs..." ) ;
ScanForCerts ( tmd ) ;
ScanForCerts ( cetkbuf ) ;
}
else
WriteStatus ( "Using cached certs..." ) ;
// /Locate Cert **************************************
2009-08-07 22:06:34 +02:00
}
2009-06-11 03:16:49 +02:00
// Read Title Version...
string tmdversion = "" ;
for ( int x = 476 ; x < 478 ; x + + )
{
tmdversion + = MakeProperLength ( ConvertToHex ( Convert . ToString ( tmd [ x ] ) ) ) ;
}
titleversion . Text = Convert . ToString ( int . Parse ( tmdversion , System . Globalization . NumberStyles . HexNumber ) ) ;
2009-07-14 21:38:18 +02:00
//Read System Version (Needed IOS)
string sysversion = IOSNeededFromTMD ( tmd ) ;
2009-07-09 04:11:22 +02:00
if ( sysversion ! = "0" )
WriteStatus ( "Requires: IOS" + sysversion ) ;
2009-10-16 00:23:08 +02:00
// Renaming would be ideal, but gives too many permission errors...
2009-10-14 22:52:16 +02:00
/ * if ( ( currentdir + titleid + "v" + titleversion . Text + Path . DirectorySeparatorChar . ToString ( ) ) ! = titledirectory )
2009-10-16 00:23:08 +02:00
{
Directory . Move ( titledirectory , currentdir + titleid + "v" + titleversion . Text + Path . DirectorySeparatorChar . ToString ( ) ) ;
titledirectory = currentdir + titleid + "v" + titleversion . Text + Path . DirectorySeparatorChar . ToString ( ) ;
2009-06-11 03:16:49 +02:00
} * /
// Read Content #...
string contentstrnum = "" ;
for ( int x = 478 ; x < 480 ; x + + )
{
contentstrnum + = TrimLeadingZeros ( Convert . ToString ( tmd [ x ] ) ) ;
}
WriteStatus ( "Content #: " + contentstrnum ) ;
2009-06-19 03:57:52 +02:00
downloadstartbtn . Text = "Content: (0/" + contentstrnum + ")" ;
2009-06-11 03:16:49 +02:00
dlprogress . Value = 0 ;
// Gather information...
string [ ] tmdcontents = GetContentNames ( tmd , Convert . ToInt32 ( contentstrnum ) ) ;
string [ ] tmdsizes = GetContentSizes ( tmd , Convert . ToInt32 ( contentstrnum ) ) ;
byte [ ] tmdhashes = GetContentHashes ( tmd , Convert . ToInt32 ( contentstrnum ) ) ;
byte [ ] tmdindices = GetContentIndices ( tmd , Convert . ToInt32 ( contentstrnum ) ) ;
// Progress bar total size tally info...
float totalcontentsize = 0 ;
float currentcontentlocation = 0 ;
for ( int i = 0 ; i < tmdsizes . Length ; i + + )
{
totalcontentsize + = int . Parse ( tmdsizes [ i ] , System . Globalization . NumberStyles . HexNumber ) ;
}
WriteStatus ( "Total Size: " + ( long ) totalcontentsize + " bytes" ) ;
for ( int i = 0 ; i < tmdcontents . Length ; i + + )
{
try
{
// If it exists we leave it...
if ( ( localuse . Checked ) & & ( File . Exists ( titledirectory + tmdcontents [ i ] ) ) )
{
WriteStatus ( "Leaving local " + tmdcontents [ i ] + "." ) ;
}
else
{
DownloadNUSFile ( titleid , tmdcontents [ i ] , titledirectory , int . Parse ( tmdsizes [ i ] , System . Globalization . NumberStyles . HexNumber ) , wiimode ) ;
}
}
catch ( Exception ex )
{
WriteStatus ( "Download Failed: " + tmdcontents [ i ] ) ;
WriteStatus ( " - Reason: " + ex . Message . ToString ( ) . Replace ( "The remote server returned an error: " , "" ) ) ;
2009-07-08 01:41:38 +02:00
SetEnableforDownload ( true ) ;
2009-06-19 03:57:52 +02:00
downloadstartbtn . Text = "Start NUS Download!" ;
2009-06-11 03:16:49 +02:00
dlprogress . Value = 0 ;
DeleteTitleDirectory ( ) ;
return ;
}
// Progress reporting advances...
2009-10-14 22:52:16 +02:00
downloadstartbtn . Text = "Content: (" + ( i + 1 ) + Path . AltDirectorySeparatorChar . ToString ( ) + contentstrnum + ")" ;
2009-06-11 03:16:49 +02:00
currentcontentlocation + = int . Parse ( tmdsizes [ i ] , System . Globalization . NumberStyles . HexNumber ) ;
// Decrypt stuff...
if ( decryptbox . Checked = = true )
{
// Create content file holder
2009-10-14 22:52:16 +02:00
byte [ ] contbuf = FileLocationToByteArray ( titledirectory + Path . DirectorySeparatorChar . ToString ( ) + tmdcontents [ i ] ) ;
2009-06-11 03:16:49 +02:00
// IV (00+IDX+more000)
byte [ ] iv = new byte [ 16 ] ;
2009-07-17 18:22:58 +02:00
for ( int x = 0 ; x < 16 ; x + + )
2009-06-11 03:16:49 +02:00
{
iv [ x ] = 0x00 ;
}
iv [ 1 ] = tmdindices [ i ] ;
2009-10-16 00:23:08 +02:00
initCrypt ( iv , titlekey ) ;
2009-06-11 03:16:49 +02:00
2009-07-17 18:22:58 +02:00
/ * Create decrypted file
2009-06-11 03:16:49 +02:00
string zeros = "000000" ;
2009-10-14 22:52:16 +02:00
FileStream decfs = new FileStream ( titledirectory + Path . DirectorySeparatorChar . ToString ( ) + zeros + i . ToString ( "X2" ) + ".app" , FileMode . Create ) ;
2009-07-17 18:22:58 +02:00
decfs . Write ( Decrypt ( contbuf ) , 0 , int . Parse ( tmdsizes [ i ] , System . Globalization . NumberStyles . HexNumber ) ) ;
decfs . Close ( ) ;
WriteStatus ( " - Decrypted: " + zeros + i . ToString ( "X2" ) + ".app" ) ; * /
2009-10-14 22:52:16 +02:00
FileStream decfs = new FileStream ( titledirectory + Path . DirectorySeparatorChar . ToString ( ) + tmdcontents [ i ] + ".app" , FileMode . Create ) ;
2009-06-11 03:16:49 +02:00
decfs . Write ( Decrypt ( contbuf ) , 0 , int . Parse ( tmdsizes [ i ] , System . Globalization . NumberStyles . HexNumber ) ) ;
decfs . Close ( ) ;
2009-07-17 18:22:58 +02:00
WriteStatus ( " - Decrypted: " + tmdcontents [ i ] + ".app" ) ;
2009-06-11 03:16:49 +02:00
// Hash Check...
byte [ ] hash = new byte [ 20 ] ;
for ( int x = 0 ; x < 20 ; x + + )
{
hash [ x ] = tmdhashes [ ( i * 20 ) + x ] ;
}
byte [ ] deccont = Decrypt ( contbuf ) ;
Array . Resize ( ref deccont , int . Parse ( tmdsizes [ i ] , System . Globalization . NumberStyles . HexNumber ) ) ;
if ( ( Convert . ToBase64String ( ComputeSHA ( deccont ) ) ) = = Convert . ToBase64String ( hash ) )
{
WriteStatus ( " - Hash Check: Pass" ) ;
}
else
{
WriteStatus ( " - Hash Check: Fail" ) ;
2009-07-10 02:56:17 +02:00
WriteStatus ( " - True Hash: " + DisplayBytes ( hash , "" ) ) ;
WriteStatus ( " - You Have: " + DisplayBytes ( ComputeSHA ( Decrypt ( contbuf ) ) , "" ) ) ;
2009-06-11 03:16:49 +02:00
}
}
dlprogress . Value = Convert . ToInt32 ( ( ( currentcontentlocation / totalcontentsize ) * 100 ) ) ;
}
WriteStatus ( "NUS Download Finished." ) ;
2009-06-17 00:25:19 +02:00
// Trucha signing...
if ( ( truchabox . Checked = = true ) & & ( wiimode = = true ) )
{
2009-06-19 03:57:52 +02:00
// Read information from TMD into signing GUI...
requiredIOSbox . Text = Convert . ToString ( tmd [ 0x18B ] ) ;
2009-07-08 01:41:38 +02:00
tmdversiontrucha . Text = Convert . ToString ( ( tmd [ 0x1DC ] * 256 ) + tmd [ 0x1DD ] ) ;
2009-06-19 03:57:52 +02:00
newtitleidbox . Text = titleid ;
2009-07-14 21:38:18 +02:00
// Add contents to contentEdit...
FillContentInfo ( tmd ) ;
2009-07-04 20:32:52 +02:00
// Setup for NO IOS
if ( requiredIOSbox . Text = = "0" )
requiredIOSbox . Enabled = false ;
else
requiredIOSbox . Enabled = true ;
2009-06-19 03:57:52 +02:00
// Read information from TIK into signing GUI...
// Titlekey
for ( int i = 0 ; i < 16 ; i + + )
{
2009-08-07 22:06:34 +02:00
titlekey [ i ] = cetkbuf [ 0x1BF + i ] ;
2009-06-19 03:57:52 +02:00
}
//titlekeybox.Text = DisplayBytes(titlekey).Replace(" ", "");
titlekeybox . Text = System . Text . Encoding . UTF7 . GetString ( titlekey ) ;
// IV (TITLEID+00000000s)
byte [ ] iv = new byte [ 16 ] ;
for ( int i = 0 ; i < 8 ; i + + )
{
2009-08-07 22:06:34 +02:00
iv [ i ] = cetkbuf [ 0x1DC + i ] ;
2009-06-19 03:57:52 +02:00
}
for ( int i = 0 ; i < 8 ; i + + )
{
iv [ i + 8 ] = 0x00 ;
}
2009-07-10 02:56:17 +02:00
titleIDIV . Text = DisplayBytes ( iv , "" ) ;
2009-06-19 03:57:52 +02:00
//DLC
2009-08-07 22:06:34 +02:00
dlcamntbox . Text = Convert . ToString ( ( cetkbuf [ 0x1E6 ] * 256 ) + cetkbuf [ 0x1E7 ] ) ;
2009-06-19 03:57:52 +02:00
//keyindex
2009-08-07 22:06:34 +02:00
if ( cetkbuf [ 0x1F1 ] = = 0x00 )
2009-06-19 03:57:52 +02:00
ckeyindexcb . SelectedIndex = 0 ;
2009-08-07 22:06:34 +02:00
else if ( cetkbuf [ 0x1F1 ] = = 0x01 )
2009-06-19 03:57:52 +02:00
ckeyindexcb . SelectedIndex = 1 ;
else
ckeyindexcb . SelectedIndex = 0 ;
//time enabled
2009-08-07 22:06:34 +02:00
if ( cetkbuf [ 0x247 ] = = 0x00 )
2009-06-19 03:57:52 +02:00
timelimitenabledcb . SelectedIndex = 0 ;
2009-08-07 22:06:34 +02:00
else if ( cetkbuf [ 0x247 ] = = 0x01 )
2009-06-19 03:57:52 +02:00
timelimitenabledcb . SelectedIndex = 1 ;
else
timelimitenabledcb . SelectedIndex = 0 ;
//time in seconds
byte [ ] timelimit = new byte [ 4 ] ;
for ( int i = 0 ; i < timelimit . Length ; i + + )
{
2009-08-07 22:06:34 +02:00
timelimit [ i ] = cetkbuf [ 0x248 + 1 ] ;
2009-06-19 03:57:52 +02:00
}
timelimitsecs . Text = Convert . ToString ( System . BitConverter . ToInt32 ( timelimit , 0 ) ) ;
// Resize form to max to show trucha options...
this . Size = this . MaximumSize ;
2009-07-04 20:32:52 +02:00
shamelessvariablelabel . Text = String . Format ( "{0},{1},{2}" , titledirectory , tmdfull , contentstrnum ) ;
2009-06-19 03:57:52 +02:00
2009-07-08 01:41:38 +02:00
// Loop until user is finished...
2009-06-19 03:57:52 +02:00
while ( this . Size = = this . MaximumSize )
{
System . Threading . Thread . Sleep ( 1000 ) ;
}
2009-08-18 07:02:23 +02:00
/ * Re - Gather information . . .
2009-07-21 23:53:27 +02:00
byte [ ] tmdrefresh = FileLocationToByteArray ( titledirectory + tmdfull ) ;
tmdcontents = GetContentNames ( tmd , ContentCount ( tmdrefresh ) ) ;
tmdsizes = GetContentSizes ( tmd , ContentCount ( tmdrefresh ) ) ;
tmdhashes = GetContentHashes ( tmd , ContentCount ( tmdrefresh ) ) ;
2009-08-18 07:02:23 +02:00
tmdindices = GetContentIndices ( tmd , ContentCount ( tmdrefresh ) ) ; * /
2009-07-21 23:53:27 +02:00
2009-06-19 03:57:52 +02:00
/ *
2009-06-17 00:25:19 +02:00
WriteStatus ( "Trucha Signing TMD..." ) ;
2009-06-19 03:57:52 +02:00
Array . Resize ( ref tmd , 484 + ( Convert . ToInt32 ( contentstrnum ) * 36 ) ) ;
2009-06-17 00:25:19 +02:00
tmd = ZeroSignature ( tmd ) ;
tmd = TruchaSign ( tmd ) ;
FileStream testtmd = new FileStream ( titledirectory + tmdfull , FileMode . Open ) ;
testtmd . Write ( tmd , 0 , tmd . Length ) ;
testtmd . Close ( ) ;
WriteStatus ( "Trucha Signing Ticket..." ) ;
// Create ticket file holder
FileStream cetkf = File . OpenRead ( titledirectory + @"\cetk" ) ;
byte [ ] cetkbuff = ReadFully ( cetkf , 20 ) ;
cetkf . Close ( ) ;
Array . Resize ( ref cetkbuff , 0x2A4 ) ;
2009-06-19 03:57:52 +02:00
2009-06-17 00:25:19 +02:00
cetkbuff = ZeroSignature ( cetkbuff ) ;
cetkbuff = TruchaSign ( cetkbuff ) ;
FileStream testtik = new FileStream ( titledirectory + "cetk" , FileMode . Open ) ;
testtik . Write ( cetkbuff , 0 , cetkbuff . Length ) ;
2009-06-19 03:57:52 +02:00
testtik . Close ( ) ; * /
2009-06-17 00:25:19 +02:00
}
2009-06-11 03:16:49 +02:00
if ( ( packbox . Checked = = true ) & & ( wiimode = = true ) )
{
2009-08-18 07:02:23 +02:00
PackWAD ( titleid , tmdfull , titledirectory ) ;
2009-06-11 03:16:49 +02:00
}
2009-07-08 01:41:38 +02:00
SetEnableforDownload ( true ) ;
2009-06-19 03:57:52 +02:00
downloadstartbtn . Text = "Start NUS Download!" ;
2009-06-11 03:16:49 +02:00
dlprogress . Value = 0 ;
2009-08-24 01:16:23 +02:00
if ( IsWin7 ( ) )
dlprogress . ShowInTaskbar = false ;
2009-06-11 03:16:49 +02:00
2009-08-28 05:12:10 +02:00
if ( script_mode )
statusbox . Text = "" ;
2009-06-11 03:16:49 +02:00
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Creates the title directory.
/// </summary>
2009-06-11 03:16:49 +02:00
private void CreateTitleDirectory ( )
{
// Creates the directory for the downloaded title...
2010-07-01 23:35:12 +02:00
string currentdir = Directory . GetCurrentDirectory ( ) ;
2009-10-14 22:52:16 +02:00
if ( currentdir . EndsWith ( Convert . ToString ( Path . DirectorySeparatorChar . ToString ( ) ) ) = = false )
currentdir + = Path . DirectorySeparatorChar . ToString ( ) ;
2009-06-11 03:16:49 +02:00
// Get placement directory early...
string titledirectory ;
if ( titleversion . Text = = "" )
2009-10-14 22:52:16 +02:00
titledirectory = Path . Combine ( currentdir , titleidbox . Text + Path . DirectorySeparatorChar . ToString ( ) ) ;
2009-06-11 03:16:49 +02:00
else
2009-10-14 22:52:16 +02:00
titledirectory = Path . Combine ( currentdir , titleidbox . Text + "v" + titleversion . Text + Path . DirectorySeparatorChar . ToString ( ) ) ;
2009-06-11 03:16:49 +02:00
// Keep local directory if present and checked out...
if ( ( localuse . Checked ) & & ( Directory . Exists ( titledirectory ) ) )
{
//WriteStatus("Using Local Files");
}
else
{
if ( Directory . Exists ( titledirectory ) )
Directory . Delete ( titledirectory , true ) ;
Directory . CreateDirectory ( titledirectory ) ;
}
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Deletes the title directory.
/// </summary>
2009-06-11 03:16:49 +02:00
private void DeleteTitleDirectory ( )
{
2010-07-01 23:35:12 +02:00
string currentdir = Directory . GetCurrentDirectory ( ) ;
2009-10-14 22:52:16 +02:00
if ( currentdir . EndsWith ( Convert . ToString ( Path . DirectorySeparatorChar . ToString ( ) ) ) = = false )
currentdir + = Path . DirectorySeparatorChar . ToString ( ) ;
2009-06-11 03:16:49 +02:00
// Get placement directory early...
string titledirectory ;
if ( titleversion . Text = = "" )
2009-10-14 22:52:16 +02:00
titledirectory = Path . Combine ( currentdir , titleidbox . Text + Path . DirectorySeparatorChar . ToString ( ) ) ;
2009-06-11 03:16:49 +02:00
else
2009-10-14 22:52:16 +02:00
titledirectory = Path . Combine ( currentdir , titleidbox . Text + "v" + titleversion . Text + Path . DirectorySeparatorChar . ToString ( ) ) ;
2009-06-11 03:16:49 +02:00
if ( Directory . Exists ( titledirectory ) )
Directory . Delete ( titledirectory , true ) ;
//Directory.CreateDirectory(currentdir + titleidbox.Text);
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Downloads the NUS file.
/// </summary>
/// <param name="titleid">The titleid.</param>
/// <param name="filename">The filename.</param>
/// <param name="placementdir">The placementdir.</param>
/// <param name="sizeinbytes">The sizeinbytes.</param>
/// <param name="iswiititle">if set to <c>true</c> [iswiititle].</param>
2009-06-11 03:16:49 +02:00
private void DownloadNUSFile ( string titleid , string filename , string placementdir , int sizeinbytes , bool iswiititle )
{
// Create NUS URL...
string nusfileurl ;
if ( iswiititle )
2009-10-14 22:52:16 +02:00
nusfileurl = NUSURL + titleid + Path . AltDirectorySeparatorChar . ToString ( ) + filename ;
2009-06-11 03:16:49 +02:00
else
2009-10-14 22:52:16 +02:00
nusfileurl = DSiNUSURL + titleid + Path . AltDirectorySeparatorChar . ToString ( ) + filename ;
2009-06-11 03:16:49 +02:00
WriteStatus ( "Grabbing " + filename + "..." ) ;
// State size of file...
if ( sizeinbytes ! = 0 )
statusbox . Text + = " (" + Convert . ToString ( sizeinbytes ) + " bytes)" ;
// Download NUS file...
generalWC . DownloadFile ( nusfileurl , placementdir + filename ) ;
}
2009-08-18 07:02:23 +02:00
void StatusChange ( string status )
{
WriteStatus ( status ) ;
}
/// <summary>
/// Packs the WAD.
/// </summary>
/// <param name="titleid">The titleid.</param>
/// <param name="tmdfilename">The tmdfilename.</param>
/// <param name="totaldirectory">The working directory.</param>
public void PackWAD ( string titleid , string tmdfilename , string totaldirectory )
2009-06-11 03:16:49 +02:00
{
2009-08-07 22:06:34 +02:00
WriteStatus ( "Beginning WAD Pack..." ) ;
2009-08-18 07:16:04 +02:00
// Obtain Current Directory
2010-07-01 23:35:12 +02:00
string currentdir = Directory . GetCurrentDirectory ( ) ;
2009-10-14 22:52:16 +02:00
if ( ! ( currentdir . EndsWith ( Path . DirectorySeparatorChar . ToString ( ) ) ) | | ! ( currentdir . EndsWith ( Path . AltDirectorySeparatorChar . ToString ( ) ) ) )
currentdir + = Path . DirectorySeparatorChar . ToString ( ) ;
2009-06-11 03:16:49 +02:00
2009-08-18 07:16:04 +02:00
// Create instance of WAD Packing class
2009-08-18 07:02:23 +02:00
WADPacker packer = new WADPacker ( ) ;
packer . StatusChanged + = WriteStatus ;
2009-08-18 07:16:04 +02:00
// Mash together certs into one array.
2009-08-07 22:06:34 +02:00
byte [ ] certsbuf = new byte [ 0xA00 ] ;
if ( ! ( CertsValid ( ) ) )
{
WriteStatus ( "Error: NUSD could not locate cached certs!" ) ;
return ;
}
for ( int c = 0 ; c < cert_CA . Length ; c + + )
certsbuf [ c ] = cert_CA [ c ] ;
for ( int c = 0 ; c < cert_CACP . Length ; c + + )
certsbuf [ c + 0x400 ] = cert_CACP [ c ] ;
for ( int c = 0 ; c < cert_CAXS . Length ; c + + )
certsbuf [ c + 0x700 ] = cert_CAXS [ c ] ;
if ( ! ( TotalCertValid ( certsbuf ) ) )
{
WriteStatus ( "Error: Cert array did not hash properly!" ) ;
return ;
}
2009-08-18 07:02:23 +02:00
packer . Certs = certsbuf ;
2009-08-18 07:16:04 +02:00
// Read TMD/TIK into Packer.
2009-10-14 22:52:16 +02:00
packer . Ticket = FileLocationToByteArray ( totaldirectory + Path . DirectorySeparatorChar . ToString ( ) + @"cetk" ) ;
packer . TMD = FileLocationToByteArray ( totaldirectory + Path . DirectorySeparatorChar . ToString ( ) + tmdfilename ) ;
2009-08-18 07:02:23 +02:00
// Get the TMD variables in here instead...
int contentcount = ContentCount ( packer . TMD ) ;
string [ ] contentnames = GetContentNames ( packer . TMD , contentcount ) ;
2009-08-18 07:16:04 +02:00
2009-08-18 07:02:23 +02:00
packer . tmdnames = GetContentNames ( packer . TMD , contentcount ) ;
packer . tmdsizes = GetContentSizes ( packer . TMD , contentcount ) ;
2009-06-11 03:16:49 +02:00
if ( wadnamebox . Text . Contains ( "[v]" ) = = true )
wadnamebox . Text = wadnamebox . Text . Replace ( "[v]" , "v" + titleversion . Text ) ;
2009-08-18 07:02:23 +02:00
if ( ! ( String . IsNullOrEmpty ( WAD_Saveas_Filename ) ) )
{
packer . FileName = System . IO . Path . GetFileName ( WAD_Saveas_Filename ) ;
packer . Directory = WAD_Saveas_Filename . Replace ( packer . FileName , "" ) ;
}
else
{
2009-10-14 22:52:16 +02:00
string wad_filename = totaldirectory + Path . DirectorySeparatorChar . ToString ( ) + RemoveIllegalCharacters ( wadnamebox . Text ) ;
2009-08-18 07:02:23 +02:00
packer . Directory = totaldirectory ;
packer . FileName = System . IO . Path . GetFileName ( wad_filename ) ;
}
// Gather contents...
byte [ ] [ ] contents_array = new byte [ contentcount ] [ ] ;
for ( int a = 0 ; a < contentcount ; a + + )
{
contents_array [ a ] = FileLocationToByteArray ( totaldirectory + contentnames [ a ] ) ;
}
packer . Contents = contents_array ;
2009-08-18 07:16:04 +02:00
// Send operations over to the packer...
2009-08-18 07:02:23 +02:00
packer . PackWAD ( ) ;
2009-08-18 07:16:04 +02:00
2009-08-18 07:02:23 +02:00
// Delete contents now...
if ( deletecontentsbox . Checked )
{
WriteStatus ( "Deleting contents..." ) ;
2009-10-14 22:52:16 +02:00
File . Delete ( totaldirectory + Path . DirectorySeparatorChar . ToString ( ) + tmdfilename ) ;
File . Delete ( totaldirectory + Path . DirectorySeparatorChar . ToString ( ) + @"cetk" ) ;
2009-08-18 07:02:23 +02:00
for ( int a = 0 ; a < contentnames . Length ; a + + )
2009-10-14 22:52:16 +02:00
File . Delete ( totaldirectory + Path . DirectorySeparatorChar . ToString ( ) + contentnames [ a ] ) ;
2009-08-18 07:02:23 +02:00
WriteStatus ( " - Contents have been deleted." ) ;
string [ ] leftovers = Directory . GetFiles ( totaldirectory ) ;
if ( leftovers . Length < = 0 )
{
WriteStatus ( " - Title directory was empty; Deleted." ) ;
Directory . Delete ( totaldirectory ) ;
}
WriteStatus ( "All deletion completed." ) ;
}
2009-06-11 03:16:49 +02:00
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Returns next 0x40 padded length.
/// </summary>
/// <param name="currentlength">The currentlength.</param>
/// <returns></returns>
2009-06-11 03:16:49 +02:00
private long ByteBoundary ( int currentlength )
{
// Gets the next 0x40 offset.
long thelength = currentlength - 1 ;
long remainder = 1 ;
while ( remainder ! = 0 )
{
thelength + = 1 ;
remainder = thelength % 0x40 ;
}
//WriteStatus("Initial Size: " + currentlength);
//WriteStatus("0x40 Size: " + thelength);
return ( long ) thelength ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Int -> Byte[] (OLD)
/// </summary>
/// <param name="inte">The int.</param>
/// <param name="arraysize">The array length.</param>
/// <returns></returns>
2009-06-19 03:57:52 +02:00
private byte [ ] InttoByteArray ( int inte , int arraysize )
2009-06-11 03:16:49 +02:00
{
// Take integer and make into byte array
2009-06-19 03:57:52 +02:00
byte [ ] b = new byte [ arraysize ] ;
b = BitConverter . GetBytes ( inte ) ;
2009-06-11 03:16:49 +02:00
if ( BitConverter . IsLittleEndian )
Array . Reverse ( b ) ;
return b ;
}
private void radioButton2_CheckedChanged ( object sender , EventArgs e )
{
if ( radioButton2 . Checked = = true )
{
// Cannot Pack WADs
packbox . Checked = false ;
packbox . Enabled = false ;
// Can decrypt if key exists...lulz
if ( dsidecrypt = = false )
{
decryptbox . Checked = false ;
decryptbox . Enabled = false ;
}
wadnamebox . Enabled = false ;
wadnamebox . Text = "" ;
2009-08-18 07:02:23 +02:00
// Cannot doit
truchabox . Enabled = false ;
2009-06-11 03:16:49 +02:00
}
}
private void radioButton1_CheckedChanged ( object sender , EventArgs e )
{
if ( radioButton1 . Checked = = true )
{
// Can pack WADs
// packbox.Checked = true;
packbox . Enabled = true ;
decryptbox . Enabled = true ;
2009-08-18 07:02:23 +02:00
truchabox . Enabled = true ;
2009-06-11 03:16:49 +02:00
}
}
private void button2_Click ( object sender , EventArgs e )
{
// Display About Text...
statusbox . Text = "" ;
WriteStatus ( "NUS Downloader (NUSD)" ) ;
WriteStatus ( "You are running version: " + version ) ;
2009-07-21 23:53:27 +02:00
WriteStatus ( "This application created by WB3000" ) ;
2010-07-01 02:40:30 +02:00
WriteStatus ( "Various sections contributed by lukegb" ) ;
2009-06-11 03:16:49 +02:00
WriteStatus ( "" ) ;
2010-07-01 23:35:12 +02:00
string currentdir = Directory . GetCurrentDirectory ( ) ;
2009-10-14 22:52:16 +02:00
if ( currentdir . EndsWith ( Convert . ToString ( Path . DirectorySeparatorChar . ToString ( ) ) ) = = false )
currentdir + = Path . DirectorySeparatorChar . ToString ( ) ;
2009-06-11 03:16:49 +02:00
if ( File . Exists ( currentdir + "key.bin" ) = = false )
WriteStatus ( "Wii Decryption: Need (key.bin)" ) ;
else
WriteStatus ( "Wii Decryption: OK" ) ;
2009-06-13 18:04:54 +02:00
if ( File . Exists ( currentdir + "kkey.bin" ) = = false )
WriteStatus ( "Wii Korea Decryption: Need (kkey.bin)" ) ;
else
WriteStatus ( "Wii Korea Decryption: OK" ) ;
2009-07-09 04:11:22 +02:00
if ( File . Exists ( currentdir + "dsikey.bin" ) = = false )
WriteStatus ( "DSi Decryption: Need (dsikey.bin)" ) ;
2009-06-11 03:16:49 +02:00
else
WriteStatus ( "DSi Decryption: OK" ) ;
2009-06-13 18:04:54 +02:00
if ( File . Exists ( currentdir + "database.xml" ) = = false )
WriteStatus ( "Database: Need (database.xml)" ) ;
else
WriteStatus ( "Database: OK" ) ;
2009-07-17 18:22:58 +02:00
2009-08-24 01:16:23 +02:00
if ( IsWin7 ( ) )
WriteStatus ( "Windows 7 Features: Enabled" ) ;
2009-06-11 03:16:49 +02:00
WriteStatus ( "" ) ;
WriteStatus ( "Special thanks to:" ) ;
WriteStatus ( " * Crediar for his wadmaker tool + source, and for the advice!" ) ;
2009-06-19 03:57:52 +02:00
WriteStatus ( " * SquidMan/Galaxy/comex/Xuzz for advice/sources." ) ;
2009-06-13 18:04:54 +02:00
WriteStatus ( " * Pasta for database compilation assistance." ) ;
2009-07-09 04:11:22 +02:00
WriteStatus ( " * #WiiDev for answering the tough questions." ) ;
WriteStatus ( " * Anyone who helped beta test on GBATemp!" ) ;
WriteStatus ( " * Famfamfam for the Silk Icon Set." ) ;
2009-08-24 01:16:23 +02:00
WriteStatus ( " * Wyatt O'Day for the Windows7ProgressBar Control." ) ;
2009-08-25 18:41:49 +02:00
WriteStatus ( " * Napo7 for testing proxy usage." ) ;
2009-06-11 03:16:49 +02:00
}
2009-07-17 18:22:58 +02:00
2009-06-11 03:16:49 +02:00
private void packbox_CheckedChanged ( object sender , EventArgs e )
{
if ( packbox . Checked = = true )
{
wadnamebox . Enabled = true ;
// Change WAD name if applicable
2009-07-10 02:56:17 +02:00
UpdatePackedName ( ) ;
2009-06-11 03:16:49 +02:00
}
else
{
wadnamebox . Enabled = false ;
wadnamebox . Text = "" ;
}
2009-08-18 07:02:23 +02:00
2009-06-11 03:16:49 +02:00
}
private void titleidbox_TextChanged ( object sender , EventArgs e )
{
2009-07-10 02:56:17 +02:00
UpdatePackedName ( ) ;
2009-06-11 03:16:49 +02:00
}
private void titleversion_TextChanged ( object sender , EventArgs e )
{
2009-07-10 02:56:17 +02:00
UpdatePackedName ( ) ;
2009-06-11 03:16:49 +02:00
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Inits the crypto stuffz.
/// </summary>
/// <param name="iv">The iv.</param>
/// <param name="key">The key.</param>
2009-06-11 03:16:49 +02:00
public void initCrypt ( byte [ ] iv , byte [ ] key )
{
rijndaelCipher = new RijndaelManaged ( ) ;
rijndaelCipher . Mode = CipherMode . CBC ;
rijndaelCipher . Padding = PaddingMode . None ;
rijndaelCipher . KeySize = 128 ;
rijndaelCipher . BlockSize = 128 ;
rijndaelCipher . Key = key ;
rijndaelCipher . IV = iv ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Encrypts the specified plain bytes.
/// </summary>
/// <param name="plainBytes">The plain bytes.</param>
/// <returns></returns>
2009-06-11 03:16:49 +02:00
public byte [ ] Encrypt ( byte [ ] plainBytes )
{
ICryptoTransform transform = rijndaelCipher . CreateEncryptor ( ) ;
using ( MemoryStream ms = new MemoryStream ( plainBytes ) )
{
using ( CryptoStream cs = new CryptoStream ( ms , transform , CryptoStreamMode . Read ) )
{
return ReadFully ( cs ) ;
}
}
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Decrypts the specified encrypted data.
/// </summary>
/// <param name="encryptedData">The encrypted data.</param>
/// <returns></returns>
2009-06-11 03:16:49 +02:00
public byte [ ] Decrypt ( byte [ ] encryptedData )
{
ICryptoTransform transform = rijndaelCipher . CreateDecryptor ( ) ;
using ( MemoryStream ms = new MemoryStream ( encryptedData ) )
{
using ( CryptoStream cs = new CryptoStream ( ms , transform , CryptoStreamMode . Read ) )
{
return ReadFully ( cs ) ;
}
}
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Reads the stream.
/// </summary>
/// <param name="stream">The stream.</param>
/// <returns></returns>
2009-06-11 03:16:49 +02:00
public byte [ ] ReadFully ( Stream stream )
{
byte [ ] buffer = new byte [ 32768 ] ;
using ( MemoryStream ms = new MemoryStream ( ) )
{
while ( true )
{
int read = stream . Read ( buffer , 0 , buffer . Length ) ;
if ( read < = 0 )
return ms . ToArray ( ) ;
ms . Write ( buffer , 0 , read ) ;
}
}
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Displays the bytes.
/// </summary>
/// <param name="bytes">The bytes.</param>
/// <param name="spacer">What separates the bytes</param>
/// <returns></returns>
2009-07-10 02:56:17 +02:00
public string DisplayBytes ( byte [ ] bytes , string spacer )
2009-06-11 03:16:49 +02:00
{
string output = "" ;
for ( int i = 0 ; i < bytes . Length ; + + i )
{
2009-07-10 02:56:17 +02:00
output + = bytes [ i ] . ToString ( "X2" ) + spacer ;
2009-06-11 03:16:49 +02:00
}
return output ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Computes the SHA-1 Hash.
/// </summary>
/// <param name="data">A byte[].</param>
/// <returns></returns>
2009-06-11 03:16:49 +02:00
static public byte [ ] ComputeSHA ( byte [ ] data )
{
SHA1 sha = new SHA1CryptoServiceProvider ( ) ;
// This is one implementation of the abstract class SHA1.
return sha . ComputeHash ( data ) ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Loads the common key from disc.
/// </summary>
2010-06-27 20:43:36 +02:00
/// <param name="keyfile">The keyfile filename.</param>
2009-08-18 07:02:23 +02:00
/// <returns></returns>
2009-06-11 03:16:49 +02:00
public byte [ ] LoadCommonKey ( string keyfile )
{
// Directory stuff
2010-07-01 23:35:12 +02:00
string currentdir = Directory . GetCurrentDirectory ( ) ;
2009-10-14 22:52:16 +02:00
if ( ! ( currentdir . EndsWith ( Path . DirectorySeparatorChar . ToString ( ) ) ) | | ! ( currentdir . EndsWith ( Path . AltDirectorySeparatorChar . ToString ( ) ) ) )
currentdir + = Path . DirectorySeparatorChar . ToString ( ) ;
2009-06-11 03:16:49 +02:00
if ( File . Exists ( currentdir + keyfile ) = = true )
{
2009-07-10 02:56:17 +02:00
// Read common key byte[]
return FileLocationToByteArray ( currentdir + keyfile ) ;
2009-06-11 03:16:49 +02:00
}
else
return null ;
}
2010-06-27 20:43:36 +02:00
/// <summary>
/// Writes/overwrites the common key onto disc.
/// </summary>
/// <param name="keyfile">The keyfile filename.</param>
/// <param name="commonkey">The byte array of the common key.</param>
/// <returns></returns>
public bool WriteCommonKey ( string keyfile , byte [ ] commonkey )
{
// Directory stuff
2010-07-01 23:35:12 +02:00
string currentdir = Directory . GetCurrentDirectory ( ) ;
2010-06-27 20:43:36 +02:00
if ( ! ( currentdir . EndsWith ( Path . DirectorySeparatorChar . ToString ( ) ) ) | | ! ( currentdir . EndsWith ( Path . AltDirectorySeparatorChar . ToString ( ) ) ) )
currentdir + = Path . DirectorySeparatorChar . ToString ( ) ;
if ( File . Exists ( currentdir + keyfile ) = = true )
{
WriteStatus ( "Overwriting old key.bin..." ) ;
}
try
{
FileStream fs = File . OpenWrite ( currentdir + keyfile ) ;
fs . Write ( commonkey , 0 , commonkey . Length ) ;
fs . Close ( ) ;
WriteStatus ( "key.bin written - reloading..." ) ;
return true ;
}
catch ( IOException e )
{
2010-06-29 18:06:15 +02:00
WriteStatus ( "Error: couldn't write key.bin: " + e . Message ) ;
2010-06-27 20:43:36 +02:00
}
return false ;
}
2009-06-11 03:16:49 +02:00
private void button4_Click ( object sender , EventArgs e )
{
// Open Database button menu...
databaseStrip . Show ( databaseButton , 2 , 2 ) ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Clears the database strip.
/// </summary>
2009-06-11 03:16:49 +02:00
private void ClearDatabaseStrip ( )
{
SystemMenuList . DropDownItems . Clear ( ) ;
IOSMenuList . DropDownItems . Clear ( ) ;
WiiWareMenuList . DropDownItems . Clear ( ) ;
// VC Games Sections...
C64MenuList . DropDownItems . Clear ( ) ;
NeoGeoMenuList . DropDownItems . Clear ( ) ;
NESMenuList . DropDownItems . Clear ( ) ;
SNESMenuList . DropDownItems . Clear ( ) ;
N64MenuList . DropDownItems . Clear ( ) ;
TurboGrafx16MenuList . DropDownItems . Clear ( ) ;
TurboGrafxCDMenuList . DropDownItems . Clear ( ) ;
MSXMenuList . DropDownItems . Clear ( ) ;
SegaMSMenuList . DropDownItems . Clear ( ) ;
GenesisMenuList . DropDownItems . Clear ( ) ;
VCArcadeMenuList . DropDownItems . Clear ( ) ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Fills the database strip.
/// </summary>
2010-06-29 18:06:15 +02:00
private void FillDatabaseStrip ( BackgroundWorker worker )
2009-06-11 03:16:49 +02:00
{
XmlDocument xDoc = new XmlDocument ( ) ;
xDoc . Load ( "database.xml" ) ;
// Variables
2010-07-01 23:35:12 +02:00
string [ ] XMLNodeTypes = new string [ 5 ] { "SYS" , "IOS" , "VC" , "WW" , "UPD" } ;
2009-06-11 03:16:49 +02:00
2010-06-29 18:06:15 +02:00
int totalLength = xDoc . SelectNodes ( "/database/*" ) . Count ;
int rnt = 0 ;
2009-06-11 03:16:49 +02:00
// Loop through XMLNodeTypes
for ( int i = 0 ; i < XMLNodeTypes . Length ; i + + )
{
XmlNodeList XMLSpecificNodeTypeList = xDoc . GetElementsByTagName ( XMLNodeTypes [ i ] ) ;
for ( int x = 0 ; x < XMLSpecificNodeTypeList . Count ; x + + )
{
ToolStripMenuItem XMLToolStripItem = new ToolStripMenuItem ( ) ;
XmlAttributeCollection XMLAttributes = XMLSpecificNodeTypeList [ x ] . Attributes ;
string titleID = "" ;
2010-07-01 23:35:12 +02:00
string updateScript ;
2009-06-11 03:16:49 +02:00
string descname = "" ;
2009-07-09 04:11:22 +02:00
bool dangerous = false ;
bool ticket = true ;
2010-06-29 18:06:15 +02:00
// Okay, so now report the progress...
rnt = rnt + 1 ;
float currentProgress = ( ( float ) rnt / ( float ) totalLength ) * ( float ) 100 ;
worker . ReportProgress ( Convert . ToInt16 ( Math . Round ( currentProgress ) ) ) ;
2009-07-09 04:11:22 +02:00
2009-06-11 03:16:49 +02:00
// Lol.
XmlNodeList ChildrenOfTheNode = XMLSpecificNodeTypeList [ x ] . ChildNodes ;
for ( int z = 0 ; z < ChildrenOfTheNode . Count ; z + + )
{
switch ( ChildrenOfTheNode [ z ] . Name )
{
case "name" :
descname = ChildrenOfTheNode [ z ] . InnerText ;
break ;
case "titleID" :
titleID = ChildrenOfTheNode [ z ] . InnerText ;
break ;
2010-07-01 23:35:12 +02:00
case "titleIDs" :
updateScript = ChildrenOfTheNode [ z ] . InnerText ;
break ;
2009-06-11 03:16:49 +02:00
case "version" :
string [ ] versions = ChildrenOfTheNode [ z ] . InnerText . Split ( ',' ) ;
2009-07-21 23:53:27 +02:00
// Add to region things?
if ( XMLToolStripItem . DropDownItems . Count > 0 )
{
for ( int b = 0 ; b < XMLToolStripItem . DropDownItems . Count ; b + + )
{
if ( ChildrenOfTheNode [ z ] . InnerText ! = "" )
{
ToolStripMenuItem regitem = ( ToolStripMenuItem ) XMLToolStripItem . DropDownItems [ b ] ;
regitem . DropDownItems . Add ( "Latest Version" ) ;
for ( int y = 0 ; y < versions . Length ; y + + )
{
regitem . DropDownItems . Add ( "v" + versions [ y ] ) ;
}
2009-08-01 19:48:32 +02:00
regitem . DropDownItemClicked + = new ToolStripItemClickedEventHandler ( deepitem_clicked ) ;
2009-07-21 23:53:27 +02:00
}
}
}
else
2009-06-11 03:16:49 +02:00
{
2009-07-21 23:53:27 +02:00
XMLToolStripItem . DropDownItems . Add ( "Latest Version" ) ;
if ( ChildrenOfTheNode [ z ] . InnerText ! = "" )
2009-06-11 03:16:49 +02:00
{
2009-07-21 23:53:27 +02:00
for ( int y = 0 ; y < versions . Length ; y + + )
{
XMLToolStripItem . DropDownItems . Add ( "v" + versions [ y ] ) ;
}
2009-06-11 03:16:49 +02:00
}
}
break ;
case "region" :
string [ ] regions = ChildrenOfTheNode [ z ] . InnerText . Split ( ',' ) ;
if ( ChildrenOfTheNode [ z ] . InnerText ! = "" )
{
for ( int y = 0 ; y < regions . Length ; y + + )
{
XMLToolStripItem . DropDownItems . Add ( RegionFromIndex ( Convert . ToInt32 ( regions [ y ] ) , xDoc ) ) ;
}
}
break ;
default :
break ;
case "ticket" :
2009-07-09 04:11:22 +02:00
ticket = Convert . ToBoolean ( ChildrenOfTheNode [ z ] . InnerText ) ;
break ;
case "danger" :
dangerous = true ;
2009-07-10 02:56:17 +02:00
XMLToolStripItem . ToolTipText = ChildrenOfTheNode [ z ] . InnerText ;
2009-06-11 03:16:49 +02:00
break ;
}
2009-07-09 04:11:22 +02:00
XMLToolStripItem . Image = SelectItemImage ( ticket , dangerous ) ;
2010-07-01 23:35:12 +02:00
if ( titleID ! = "" )
{
XMLToolStripItem . Text = String . Format ( "{0} - {1}" , titleID , descname ) ;
}
else
{
XMLToolStripItem . Text = descname ;
}
2009-06-11 03:16:49 +02:00
}
AddToolStripItemToStrip ( i , XMLToolStripItem , XMLAttributes ) ;
}
}
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Adds the tool strip item to strip.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="additionitem">The additionitem.</param>
/// <param name="attributes">The attributes.</param>
2009-06-11 03:16:49 +02:00
void AddToolStripItemToStrip ( int type , ToolStripMenuItem additionitem , XmlAttributeCollection attributes )
2010-07-01 02:40:30 +02:00
{
Debug . WriteLine ( "Adding item..." ) ;
// Check if thread-safe
if ( this . InvokeRequired )
{
Debug . WriteLine ( "InvokeRequired..." ) ;
AddToolStripItemToStripCallback atsitsc = new AddToolStripItemToStripCallback ( AddToolStripItemToStrip ) ;
this . Invoke ( atsitsc , new object [ ] { type , additionitem , attributes } ) ;
return ;
}
2009-06-11 03:16:49 +02:00
// Deal with VC list depth...
if ( type = = 2 )
{
2010-07-01 02:40:30 +02:00
Debug . WriteLine ( "Adding:" ) ;
Debug . WriteLine ( additionitem ) ;
2009-06-11 03:16:49 +02:00
switch ( attributes [ 0 ] . Value )
{
2009-07-09 04:11:22 +02:00
case "C64" :
2009-06-11 03:16:49 +02:00
C64MenuList . DropDownItems . Add ( additionitem ) ;
break ;
2009-07-09 04:11:22 +02:00
case "NEO" :
2009-06-11 03:16:49 +02:00
NeoGeoMenuList . DropDownItems . Add ( additionitem ) ;
break ;
case "NES" :
NESMenuList . DropDownItems . Add ( additionitem ) ;
break ;
case "SNES" :
SNESMenuList . DropDownItems . Add ( additionitem ) ;
break ;
case "N64" :
N64MenuList . DropDownItems . Add ( additionitem ) ;
break ;
2009-07-09 04:11:22 +02:00
case "TG16" :
2009-06-11 03:16:49 +02:00
TurboGrafx16MenuList . DropDownItems . Add ( additionitem ) ;
break ;
2009-07-09 04:11:22 +02:00
case "TGCD" :
2009-06-11 03:16:49 +02:00
TurboGrafxCDMenuList . DropDownItems . Add ( additionitem ) ;
break ;
case "MSX" :
MSXMenuList . DropDownItems . Add ( additionitem ) ;
break ;
case "SMS" :
SegaMSMenuList . DropDownItems . Add ( additionitem ) ;
break ;
2009-07-09 04:11:22 +02:00
case "GEN" :
2009-06-11 03:16:49 +02:00
GenesisMenuList . DropDownItems . Add ( additionitem ) ;
break ;
2009-07-09 04:11:22 +02:00
case "ARC" :
2009-06-11 03:16:49 +02:00
VCArcadeMenuList . DropDownItems . Add ( additionitem ) ;
break ;
default :
break ;
}
2010-07-01 23:35:12 +02:00
additionitem . DropDownItemClicked + = new ToolStripItemClickedEventHandler ( wwitem_regionclicked ) ;
}
else if ( type = = 4 )
{
// I am a brand new combine harvester
//MassUpdateList.DropDownItems.Add(additionitem);
switch ( attributes [ 0 ] . Value )
{
case "KOR" :
KoreaMassUpdate . DropDownItems . Add ( additionitem ) ;
break ;
case "PAL" :
PALMassUpdate . DropDownItems . Add ( additionitem ) ;
break ;
case "NTSC" :
NTSCMassUpdate . DropDownItems . Add ( additionitem ) ;
break ;
default :
Debug . WriteLine ( "Oops - database error" ) ;
return ;
}
additionitem . Click + = new ToolStripItemClickedEventHandler ( upditem_itemclicked ) ;
2009-06-11 03:16:49 +02:00
}
else
{
// Add SYS, IOS, WW items
// I thought using index would work in .Items, but I
// guess this switch will have to do...
switch ( type )
{
case 0 :
SystemMenuList . DropDownItems . Add ( additionitem ) ;
break ;
case 1 :
IOSMenuList . DropDownItems . Add ( additionitem ) ;
break ;
case 3 :
WiiWareMenuList . DropDownItems . Add ( additionitem ) ;
break ;
}
additionitem . DropDownItemClicked + = new ToolStripItemClickedEventHandler ( sysitem_versionclicked ) ;
}
}
2009-08-01 19:48:32 +02:00
void deepitem_clicked ( object sender , ToolStripItemClickedEventArgs e )
{
titleidbox . Text = e . ClickedItem . OwnerItem . OwnerItem . Text . Substring ( 0 , 16 ) ;
titleidbox . Text = titleidbox . Text . Replace ( "XX" , e . ClickedItem . OwnerItem . Text . Substring ( 0 , 2 ) ) ;
if ( e . ClickedItem . Text ! = "Latest Version" )
{
if ( e . ClickedItem . Text . Contains ( "v" ) )
{
if ( e . ClickedItem . Text . Contains ( " " ) )
titleversion . Text = e . ClickedItem . Text . Substring ( 1 , e . ClickedItem . Text . IndexOf ( ' ' ) - 1 ) ;
else
titleversion . Text = e . ClickedItem . Text . Substring ( 1 , e . ClickedItem . Text . Length - 1 ) ;
}
}
else
{
titleversion . Text = "" ;
}
// Prepare StatusBox...
string titlename = e . ClickedItem . OwnerItem . OwnerItem . Text . Substring ( 19 , ( e . ClickedItem . OwnerItem . OwnerItem . Text . Length - 19 ) ) ;
statusbox . Text = " --- " + titlename + " ---" ;
// Check if a ticket is present...
if ( ( e . ClickedItem . OwnerItem . OwnerItem . Image ) = = ( orange ) | | ( e . ClickedItem . OwnerItem . OwnerItem . Image ) = = ( redorange ) )
{
ignoreticket . Checked = true ;
WriteStatus ( "Note: This title has no ticket and cannot be packed/decrypted!" ) ;
packbox . Checked = false ;
decryptbox . Checked = false ;
}
else
{
ignoreticket . Checked = false ;
}
// Change WAD name if packed is already checked...
if ( packbox . Checked )
{
2009-08-07 22:51:53 +02:00
OfficialWADNaming ( titlename ) ;
2009-08-01 19:48:32 +02:00
}
// Check for danger item
if ( ( e . ClickedItem . OwnerItem . OwnerItem . Image ) = = ( redgreen ) | | ( e . ClickedItem . OwnerItem . OwnerItem . Image ) = = ( redorange ) )
{
WriteStatus ( "\r\n" + e . ClickedItem . OwnerItem . OwnerItem . ToolTipText ) ;
}
}
2009-08-07 22:51:53 +02:00
2009-08-18 07:02:23 +02:00
/// <summary>
/// Mods WAD names to be official.
/// </summary>
/// <param name="titlename">The titlename.</param>
2009-08-07 22:51:53 +02:00
public void OfficialWADNaming ( string titlename )
{
if ( titlename . Contains ( "IOS" ) )
wadnamebox . Text = titlename + "-64-[v].wad" ;
else if ( titlename . Contains ( "System Menu" ) )
wadnamebox . Text = "RVL-WiiSystemmenu-[v].wad" ;
else
wadnamebox . Text = titlename + "-NUS-[v].wad" ;
if ( titleversion . Text ! = "" )
wadnamebox . Text = wadnamebox . Text . Replace ( "[v]" , "v" + titleversion . Text ) ;
}
2009-06-11 03:16:49 +02:00
void wwitem_regionclicked ( object sender , ToolStripItemClickedEventArgs e )
{
titleidbox . Text = e . ClickedItem . OwnerItem . Text . Substring ( 0 , 16 ) ;
titleversion . Text = "" ;
titleidbox . Text = titleidbox . Text . Replace ( "XX" , e . ClickedItem . Text . Substring ( 0 , 2 ) ) ;
2009-07-09 04:11:22 +02:00
// Prepare StatusBox...
2009-07-10 02:56:17 +02:00
string titlename = e . ClickedItem . OwnerItem . Text . Substring ( 19 , ( e . ClickedItem . OwnerItem . Text . Length - 19 ) ) ;
statusbox . Text = " --- " + titlename + " ---" ;
2009-07-09 04:11:22 +02:00
// Check if a ticket is present...
if ( ( e . ClickedItem . OwnerItem . Image ) = = ( orange ) | | ( e . ClickedItem . OwnerItem . Image ) = = ( redorange ) )
2009-06-11 03:16:49 +02:00
{
ignoreticket . Checked = true ;
WriteStatus ( "Note: This title has no ticket and cannot be packed/decrypted!" ) ;
packbox . Checked = false ;
decryptbox . Checked = false ;
}
else
{
ignoreticket . Checked = false ;
}
2009-07-09 04:11:22 +02:00
2009-07-10 02:56:17 +02:00
// Change WAD name if packed is already checked...
if ( packbox . Checked )
{
2009-08-07 22:51:53 +02:00
OfficialWADNaming ( titlename ) ;
2009-07-10 02:56:17 +02:00
}
2009-07-09 04:11:22 +02:00
// Check for danger item
if ( ( e . ClickedItem . OwnerItem . Image ) = = ( redgreen ) | | ( e . ClickedItem . OwnerItem . Image ) = = ( redorange ) )
{
WriteStatus ( "\r\n" + e . ClickedItem . OwnerItem . ToolTipText ) ;
}
2009-06-11 03:16:49 +02:00
}
void sysitem_versionclicked ( object sender , ToolStripItemClickedEventArgs e )
{
titleidbox . Text = e . ClickedItem . OwnerItem . Text . Substring ( 0 , 16 ) ;
2009-07-21 23:53:27 +02:00
2009-06-11 03:16:49 +02:00
if ( e . ClickedItem . Text ! = "Latest Version" )
{
if ( e . ClickedItem . Text . Contains ( "v" ) )
{
if ( e . ClickedItem . Text . Contains ( " " ) )
2009-07-17 18:22:58 +02:00
titleversion . Text = e . ClickedItem . Text . Substring ( 1 , e . ClickedItem . Text . IndexOf ( ' ' ) - 1 ) ;
2009-06-11 03:16:49 +02:00
else
titleversion . Text = e . ClickedItem . Text . Substring ( 1 , e . ClickedItem . Text . Length - 1 ) ;
}
else
{
2009-07-17 18:22:58 +02:00
// Apparently it's a region code..
2009-06-11 03:16:49 +02:00
titleidbox . Text = titleidbox . Text . Replace ( "XX" , e . ClickedItem . Text . Substring ( 0 , 2 ) ) ;
titleversion . Text = "" ;
}
}
else
{
titleversion . Text = "" ;
}
2009-07-09 04:11:22 +02:00
// Prepare StatusBox...
2009-07-10 02:56:17 +02:00
string titlename = e . ClickedItem . OwnerItem . Text . Substring ( 19 , ( e . ClickedItem . OwnerItem . Text . Length - 19 ) ) ;
statusbox . Text = " --- " + titlename + " ---" ;
2009-07-09 04:11:22 +02:00
if ( ( e . ClickedItem . OwnerItem . Image ) = = ( orange ) | | ( e . ClickedItem . OwnerItem . Image ) = = ( redorange ) )
2009-06-11 03:16:49 +02:00
{
ignoreticket . Checked = true ;
WriteStatus ( "Note: This title has no ticket and cannot be packed/decrypted!" ) ;
packbox . Checked = false ;
decryptbox . Checked = false ;
}
else
{
ignoreticket . Checked = false ;
}
2009-07-21 23:53:27 +02:00
2009-07-10 02:56:17 +02:00
// Change WAD name if packed is already checked...
if ( packbox . Checked )
{
if ( titlename . Contains ( "IOS" ) )
wadnamebox . Text = titlename + "-64-[v].wad" ;
else
wadnamebox . Text = titlename + "-NUS-[v].wad" ;
if ( titleversion . Text ! = "" )
wadnamebox . Text = wadnamebox . Text . Replace ( "[v]" , "v" + titleversion . Text ) ;
}
2009-07-09 04:11:22 +02:00
// Check for danger item
if ( ( e . ClickedItem . OwnerItem . Image ) = = ( redgreen ) | | ( e . ClickedItem . OwnerItem . Image ) = = ( redorange ) )
{
WriteStatus ( "\n" + e . ClickedItem . OwnerItem . ToolTipText ) ;
}
2009-06-11 03:16:49 +02:00
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Gathers the region based on index
/// </summary>
/// <param name="index">The index.</param>
/// <param name="databasexml">XmlDocument with database inside</param>
/// <returns>Region desc</returns>
2009-06-11 03:16:49 +02:00
string RegionFromIndex ( int index , XmlDocument databasexml )
{
/ * Typical Region XML
* < REGIONS >
2009-06-13 18:04:54 +02:00
< region index = "0" > 41 ( All / System ) < / region >
2009-06-11 03:16:49 +02:00
< region index = 1 > 44 ( German ) < / region >
< region index = 2 > 45 ( USA / NTSC ) < / region >
< region index = 3 > 46 ( French ) < / region >
< region index = 4 > 4 A ( Japan ) < / region >
< region index = 5 > 4 B ( Korea ) < / region >
< region index = 6 > 4 C ( Japanese Import to Europe / Australia / PAL ) < / region >
< region index = 7 > 4D ( American Import to Europe / Australia / PAL ) < / region >
< region index = 8 > 4 E ( Japanese Import to USA / NTSC ) < / region >
< region index = 9 > 50 ( Europe / PAL ) < / region >
< region index = 10 > 51 ( Korea w / Japanese Language ) < / region >
< region index = 11 > 54 ( Korea w / English Language ) < / region >
< region index = 12 > 58 ( Some Homebrew ) < / region >
< / REGIONS >
* /
XmlNodeList XMLRegionList = databasexml . GetElementsByTagName ( "REGIONS" ) ;
XmlNodeList ChildrenOfTheNode = XMLRegionList [ 0 ] . ChildNodes ;
// For each child node (region node)
for ( int z = 0 ; z < ChildrenOfTheNode . Count ; z + + )
{
// Gather attributes (index='x')
XmlAttributeCollection XMLAttributes = ChildrenOfTheNode [ z ] . Attributes ;
// Return value of node if index matches
if ( Convert . ToInt32 ( XMLAttributes [ 0 ] . Value ) = = index )
return ChildrenOfTheNode [ z ] . InnerText ;
}
return "XX (Error)" ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Loads the region codes.
/// </summary>
2009-06-11 03:16:49 +02:00
private void LoadRegionCodes ( )
{
XmlDocument xDoc = new XmlDocument ( ) ;
xDoc . Load ( "database.xml" ) ;
XmlNodeList XMLRegionList = xDoc . GetElementsByTagName ( "REGIONS" ) ;
XmlNodeList ChildrenOfTheNode = XMLRegionList [ 0 ] . ChildNodes ;
// For each child node (region node)
for ( int z = 0 ; z < ChildrenOfTheNode . Count ; z + + )
{
RegionCodesList . DropDownItems . Add ( ChildrenOfTheNode [ z ] . InnerText ) ;
}
}
private void RegionCodesList_DropDownItemClicked ( object sender , ToolStripItemClickedEventArgs e )
{
if ( titleidbox . Text . Length = = 16 )
titleidbox . Text = titleidbox . Text . Substring ( 0 , 14 ) + e . ClickedItem . Text . Substring ( 0 , 2 ) ;
}
2009-06-17 00:25:19 +02:00
2009-08-18 07:02:23 +02:00
/// <summary>
/// Removes the illegal characters.
/// </summary>
/// <param name="databasestr">removes the illegal chars</param>
/// <returns>legal string</returns>
2009-07-14 21:38:18 +02:00
private string RemoveIllegalCharacters ( string databasestr )
{
// Database strings must contain filename-legal characters.
foreach ( char illegalchar in System . IO . Path . GetInvalidFileNameChars ( ) )
{
if ( databasestr . Contains ( illegalchar . ToString ( ) ) )
databasestr = databasestr . Replace ( illegalchar , '-' ) ;
}
return databasestr ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Zeroes the signature in TMD/TIK.
/// </summary>
/// <param name="tmdortik">TMD/TIK</param>
/// <returns>Zeroed TMD/TIK</returns>
2009-06-17 00:25:19 +02:00
private byte [ ] ZeroSignature ( byte [ ] tmdortik )
{
// Write all 0x00 to signature...
// Sig starts at 0x04 in both TMD/TIK
for ( int i = 0 ; i < 256 ; i + + )
{
tmdortik [ i + 4 ] = 0x00 ;
}
WriteStatus ( " - Signature Emptied..." ) ;
return tmdortik ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Trucha Signs a TMD/TIK
/// </summary>
/// <param name="tmdortik">The tmdortik.</param>
/// <returns>Fake-signed byte[]</returns>
2009-06-17 00:25:19 +02:00
private byte [ ] TruchaSign ( byte [ ] tmdortik )
{
// Loop through 2 bytes worth of numbers until hash starts with 0x00...
// Padding starts at 0x104 in both TMD/TIK, seems like a good place to me...
byte [ ] payload = new byte [ 2 ] ;
byte [ ] hashobject = new byte [ tmdortik . Length - 0x104 ] ;
for ( int i = 0 ; i < 65535 ; i + + )
{
payload = incrementAtIndex ( payload , 1 ) ;
tmdortik [ 0x104 ] = payload [ 0 ] ;
tmdortik [ 0x105 ] = payload [ 1 ] ;
for ( int x = 0 ; x < ( tmdortik . Length - 0x104 ) ; x + + )
{
hashobject [ x ] = tmdortik [ 0x104 + x ] ;
}
if ( ComputeSHA ( hashobject ) [ 0 ] = = 0x00 )
{
WriteStatus ( " - Successfully Trucha Signed." ) ;
return tmdortik ;
}
}
WriteStatus ( " - Sign FAIL!" ) ;
return tmdortik ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Increments at an index.
/// </summary>
/// <param name="array">The array.</param>
/// <param name="index">The index.</param>
/// <returns></returns>
2009-06-17 00:25:19 +02:00
static public byte [ ] incrementAtIndex ( byte [ ] array , int index )
{
if ( array [ index ] = = byte . MaxValue )
{
array [ index ] = 0 ;
if ( index > 0 )
incrementAtIndex ( array , index - 1 ) ;
}
else
{
array [ index ] + + ;
}
return array ;
}
2009-06-19 03:57:52 +02:00
private void button6_Click ( object sender , EventArgs e )
{
// Revert to TMD information...
string [ ] fileinfo = shamelessvariablelabel . Text . Split ( ',' ) ;
// Read the tmd as a stream...
2009-07-10 02:56:17 +02:00
byte [ ] tmd = FileLocationToByteArray ( fileinfo [ 0 ] + fileinfo [ 1 ] ) ;
2009-06-19 03:57:52 +02:00
// Read information from TMD into signing GUI...
requiredIOSbox . Text = Convert . ToString ( tmd [ 0x18B ] ) ;
2009-07-08 01:41:38 +02:00
// Lulzy cheap way of getting version... *256
tmdversiontrucha . Text = Convert . ToString ( ( ( tmd [ 0x1DC ] * 256 ) + tmd [ 0x1DD ] ) ) ;
2009-06-19 03:57:52 +02:00
newtitleidbox . Text = titleidbox . Text ;
2009-07-04 20:32:52 +02:00
// Setup for NO IOS
if ( requiredIOSbox . Text = = "0" )
requiredIOSbox . Enabled = false ;
else
requiredIOSbox . Enabled = true ;
2009-06-19 03:57:52 +02:00
}
private void button5_Click ( object sender , EventArgs e )
{
// Revert to Ticket information...
string [ ] fileinfo = shamelessvariablelabel . Text . Split ( ',' ) ;
// Create ticket file holder
2009-10-14 22:52:16 +02:00
byte [ ] cetkbuff = FileLocationToByteArray ( fileinfo [ 0 ] + Path . DirectorySeparatorChar . ToString ( ) + @"cetk" ) ;
2009-06-19 03:57:52 +02:00
// Titlekey
byte [ ] titlekey = new byte [ 16 ] ;
for ( int i = 0 ; i < 16 ; i + + )
{
titlekey [ i ] = cetkbuff [ 0x1BF + i ] ;
}
titlekeybox . Text = System . Text . Encoding . UTF7 . GetString ( titlekey ) ;
// IV (TITLEID+00000000s)
byte [ ] iv = new byte [ 16 ] ;
for ( int i = 0 ; i < 8 ; i + + )
{
iv [ i ] = cetkbuff [ 0x1DC + i ] ;
}
for ( int i = 0 ; i < 8 ; i + + )
{
iv [ i + 8 ] = 0x00 ;
}
2009-07-10 02:56:17 +02:00
titleIDIV . Text = DisplayBytes ( iv , "" ) ;
2009-06-19 03:57:52 +02:00
//DLC
2009-07-08 01:41:38 +02:00
dlcamntbox . Text = Convert . ToString ( ( cetkbuff [ 0x1E6 ] * 256 ) + cetkbuff [ 0x1E7 ] ) ;
2009-06-19 03:57:52 +02:00
//keyindex
if ( cetkbuff [ 0x1F1 ] = = 0x00 )
ckeyindexcb . SelectedIndex = 0 ;
else if ( cetkbuff [ 0x1F1 ] = = 0x01 )
ckeyindexcb . SelectedIndex = 1 ;
else
ckeyindexcb . SelectedIndex = 0 ;
//time enabled
if ( cetkbuff [ 0x247 ] = = 0x00 )
timelimitenabledcb . SelectedIndex = 0 ;
else if ( cetkbuff [ 0x247 ] = = 0x01 )
timelimitenabledcb . SelectedIndex = 1 ;
else
timelimitenabledcb . SelectedIndex = 0 ;
//time in seconds
byte [ ] timelimit = new byte [ 4 ] ;
for ( int i = 0 ; i < timelimit . Length ; i + + )
{
2009-07-04 20:32:52 +02:00
timelimit [ i ] = cetkbuff [ 0x248 + i ] ;
2009-06-19 03:57:52 +02:00
}
timelimitsecs . Text = Convert . ToString ( System . BitConverter . ToInt32 ( timelimit , 0 ) ) ;
}
private void button1_Click_1 ( object sender , EventArgs e )
{
// Write Trucha changes to TMD...
2009-07-04 20:32:52 +02:00
WriteStatus ( "Trucha Signing TMD..." ) ;
// Cheezy file info
string [ ] fileinfo = shamelessvariablelabel . Text . Split ( ',' ) ;
// Read the tmd as a stream...
2009-07-10 02:56:17 +02:00
byte [ ] tmd = FileLocationToByteArray ( fileinfo [ 0 ] + fileinfo [ 1 ] ) ;
2009-07-04 20:32:52 +02:00
// Resize to just TMD...
Array . Resize ( ref tmd , 484 + ( Convert . ToInt32 ( fileinfo [ 2 ] ) * 36 ) ) ;
// Change Required IOS
if ( requiredIOSbox . Text ! = "0" )
{
tmd [ 0x18B ] = Convert . ToByte ( requiredIOSbox . Text ) ;
}
// Change Title Version
byte [ ] version = new byte [ 2 ] ;
version = InttoByteArray ( Convert . ToInt32 ( tmdversiontrucha . Text ) , version . Length ) ;
tmd [ 0x1DC ] = version [ version . Length - 2 ] ;
tmd [ 0x1DD ] = version [ version . Length - 1 ] ;
// Change Title ID
tmd [ 0x18C ] = byte . Parse ( newtitleidbox . Text . Substring ( 0 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
tmd [ 0x18D ] = byte . Parse ( newtitleidbox . Text . Substring ( 2 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
tmd [ 0x18E ] = byte . Parse ( newtitleidbox . Text . Substring ( 4 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
tmd [ 0x18F ] = byte . Parse ( newtitleidbox . Text . Substring ( 6 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
tmd [ 0x190 ] = byte . Parse ( newtitleidbox . Text . Substring ( 8 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
tmd [ 0x191 ] = byte . Parse ( newtitleidbox . Text . Substring ( 10 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
tmd [ 0x192 ] = byte . Parse ( newtitleidbox . Text . Substring ( 12 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
tmd [ 0x193 ] = byte . Parse ( newtitleidbox . Text . Substring ( 14 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
tmd = ZeroSignature ( tmd ) ;
tmd = TruchaSign ( tmd ) ;
2009-07-17 18:22:58 +02:00
FileStream testtmd = new FileStream ( fileinfo [ 0 ] + fileinfo [ 1 ] , FileMode . Open ) ;
2009-07-04 20:32:52 +02:00
testtmd . Write ( tmd , 0 , tmd . Length ) ;
testtmd . Close ( ) ;
}
private void button4_Click_1 ( object sender , EventArgs e )
{
// Write Trucha changes to Ticket...
WriteStatus ( "Trucha Signing Ticket..." ) ;
// Cheezy file info
string [ ] fileinfo = shamelessvariablelabel . Text . Split ( ',' ) ;
// Create ticket file holder
2009-10-14 22:52:16 +02:00
byte [ ] cetkbuff = FileLocationToByteArray ( fileinfo [ 0 ] + Path . DirectorySeparatorChar . ToString ( ) + @"cetk" ) ;
2009-07-04 20:32:52 +02:00
// Resize Ticket to actual size.
Array . Resize ( ref cetkbuff , 0x2A4 ) ;
// TODO: Title Key and IV changes!
2009-08-01 19:48:32 +02:00
WriteStatus ( "Title Key / IV are not available to change in this release :(" ) ;
2009-07-04 20:32:52 +02:00
// Write DLC Amount.
byte [ ] dlcamount = new byte [ 2 ] ;
dlcamount = InttoByteArray ( Convert . ToInt32 ( dlcamntbox . Text ) , dlcamount . Length ) ;
cetkbuff [ 0x1E6 ] = dlcamount [ dlcamount . Length - 2 ] ;
cetkbuff [ 0x1E7 ] = dlcamount [ dlcamount . Length - 1 ] ;
// Common Key index.
if ( ckeyindexcb . SelectedIndex = = 0 )
cetkbuff [ 0x1F1 ] = 0x00 ;
else if ( ckeyindexcb . SelectedIndex = = 1 )
cetkbuff [ 0x1F1 ] = 0x01 ;
else
cetkbuff [ 0x1F1 ] = 0x00 ;
// Time limit enable.
if ( timelimitenabledcb . SelectedIndex = = 0 )
cetkbuff [ 0x247 ] = 0x00 ;
else if ( timelimitenabledcb . SelectedIndex = = 1 )
cetkbuff [ 0x247 ] = 0x01 ;
else
cetkbuff [ 0x247 ] = 0x00 ;
// The amount of time for the limit.
byte [ ] limitseconds = new byte [ 4 ] ;
limitseconds = InttoByteArray ( Convert . ToInt32 ( timelimitsecs . Text ) , 4 ) ;
2009-08-04 02:01:01 +02:00
2009-07-04 20:32:52 +02:00
for ( int i = 0 ; i < 4 ; i + + )
{
cetkbuff [ 0x248 + i ] = limitseconds [ i ] ;
}
// Trucha (Fake) Sign
cetkbuff = ZeroSignature ( cetkbuff ) ;
cetkbuff = TruchaSign ( cetkbuff ) ;
// Write changes to cetk.
2009-07-17 18:22:58 +02:00
FileStream testtik = new FileStream ( fileinfo [ 0 ] + "cetk" , FileMode . Open ) ;
2009-07-04 20:32:52 +02:00
testtik . Write ( cetkbuff , 0 , cetkbuff . Length ) ;
testtik . Close ( ) ;
}
private void button7_Click ( object sender , EventArgs e )
{
// Proceed with process (BG worker waits for form to resize)
WriteStatus ( "Trucha modifications complete." ) ;
this . Size = this . MinimumSize ;
2009-06-19 03:57:52 +02:00
}
2009-07-04 20:32:52 +02:00
private void button3_Click_1 ( object sender , EventArgs e )
{
// Clear Statusbox.text
statusbox . Text = "" ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Makes everything disabled/enabled.
/// </summary>
/// <param name="enabled">if set to <c>true</c> [enabled].</param>
2009-07-08 01:41:38 +02:00
private void SetEnableforDownload ( bool enabled )
{
2009-07-09 04:11:22 +02:00
// Disable things the user should not mess with during download...
2009-07-08 01:41:38 +02:00
downloadstartbtn . Enabled = enabled ;
titleidbox . Enabled = enabled ;
titleversion . Enabled = enabled ;
2009-08-06 04:37:39 +02:00
Extrasbtn . Enabled = enabled ;
2009-07-08 01:41:38 +02:00
databaseButton . Enabled = enabled ;
2009-07-09 04:11:22 +02:00
packbox . Enabled = enabled ;
localuse . Enabled = enabled ;
ignoreticket . Enabled = enabled ;
truchabox . Enabled = enabled ;
decryptbox . Enabled = enabled ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Makes tooltips disappear in the database, as many contain danger tag info.
/// </summary>
/// <param name="enabled">if set to <c>true</c> [enabled].</param>
2009-07-09 04:11:22 +02:00
private void ShowInnerToolTips ( bool enabled )
{
// Force tooltips to GTFO in sub menus...
foreach ( ToolStripItem item in databaseStrip . Items )
{
try
{
ToolStripMenuItem menuitem = ( ToolStripMenuItem ) item ;
menuitem . DropDown . ShowItemToolTips = false ;
}
catch ( Exception )
{
// Do nothing, some objects will not cast.
}
}
2009-07-08 01:41:38 +02:00
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Selects the database item image.
/// </summary>
/// <param name="ticket">if set to <c>true</c> [ticket].</param>
/// <param name="danger">if set to <c>true</c> [danger].</param>
/// <returns>Correct Image</returns>
2009-07-09 04:11:22 +02:00
private System . Drawing . Image SelectItemImage ( bool ticket , bool danger )
{
// All is good, go green...
if ( ( ticket ) & & ( ! danger ) )
return green ;
// There's no ticket, but danger is clear...
if ( ( ! ticket ) & & ( ! danger ) )
return orange ;
// DANGER WILL ROBINSON...
if ( ( ticket ) & & ( danger ) )
return redgreen ;
// Double bad...
if ( ( ! ticket ) & & ( danger ) )
return redorange ;
return null ;
}
2009-07-10 02:56:17 +02:00
2009-08-18 07:02:23 +02:00
/// <summary>
/// Loads a file into a byte[]
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>byte[] of file contents</returns>
2009-07-10 02:56:17 +02:00
private byte [ ] FileLocationToByteArray ( string filename )
{
FileStream fs = File . OpenRead ( filename ) ;
byte [ ] filebytearray = ReadFully ( fs , 460 ) ;
fs . Close ( ) ;
return filebytearray ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Updates the name of the packed WAD in the textbox.
/// </summary>
2009-07-10 02:56:17 +02:00
private void UpdatePackedName ( )
{
// Change WAD name if applicable
2009-08-07 22:51:53 +02:00
string title_name = null ;
2009-07-10 02:56:17 +02:00
if ( ( titleidbox . Enabled = = true ) & & ( packbox . Checked = = true ) )
{
if ( titleversion . Text ! = "" )
{
wadnamebox . Text = titleidbox . Text + "-NUS-v" + titleversion . Text + ".wad" ;
}
else
{
wadnamebox . Text = titleidbox . Text + "-NUS-[v]" + titleversion . Text + ".wad" ;
}
2009-08-07 22:51:53 +02:00
if ( ( File . Exists ( "database.xml" ) = = true ) & & ( titleidbox . Text . Length = = 16 ) )
title_name = NameFromDatabase ( titleidbox . Text ) ;
if ( title_name ! = null )
{
wadnamebox . Text = wadnamebox . Text . Replace ( titleidbox . Text , title_name ) ;
OfficialWADNaming ( title_name ) ;
}
2009-07-10 02:56:17 +02:00
}
2009-07-14 21:38:18 +02:00
wadnamebox . Text = RemoveIllegalCharacters ( wadnamebox . Text ) ;
2009-08-07 22:51:53 +02:00
2009-07-14 21:38:18 +02:00
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Generates a ticket from TitleKey/ID
/// </summary>
/// <param name="EncTitleKey">The enc title key.</param>
/// <param name="TitleID">The title ID.</param>
/// <returns>New Ticket</returns>
2009-07-14 21:38:18 +02:00
private byte [ ] GenerateTicket ( byte [ ] EncTitleKey , byte [ ] TitleID )
{
byte [ ] Ticket = new byte [ 0x2A4 ] ;
// RSA Signature Heading...
Ticket [ 1 ] = 0x01 ; Ticket [ 3 ] = 0x01 ;
// Signature Issuer... (Root-CA00000001-XS00000003)
byte [ ] SignatureIssuer = new byte [ 0x1A ] { 0x52 , 0x6F , 0x6F , 0x74 , 0x2D , 0x43 , 0x41 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x31 , 0x2D , 0x58 , 0x53 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x33 } ;
for ( int a = 0 ; a < 0x40 ; a + + )
{
Ticket [ 0x140 + a ] = SignatureIssuer [ a ] ;
}
// Encrypted TitleKey...
for ( int b = 0 ; b < 0x10 ; b + + )
{
Ticket [ 0x1BF + b ] = EncTitleKey [ b ] ;
}
// Ticket ID...
for ( int c = 0 ; c < 0x08 ; c + + )
{
Ticket [ 0x1D0 + c ] = 0x49 ;
}
// Title ID...
for ( int d = 0 ; d < 0x08 ; d + + )
{
Ticket [ 0x1DC + d ] = TitleID [ d ] ;
}
// Misc FF...
Ticket [ 0x1E4 ] = 0xFF ; Ticket [ 0x1E5 ] = 0xFF ;
Ticket [ 0x1E6 ] = 0xFF ; Ticket [ 0x1E7 ] = 0xFF ;
// Unknown 0x01...
Ticket [ 0x221 ] = 0x01 ;
// Misc FF...
for ( int e = 0 ; e < 0x20 ; e + + )
{
Ticket [ 0x222 + e ] = 0xFF ;
}
return Ticket ;
}
private void button15_Click ( object sender , EventArgs e )
{
// Read Content info from TMD again (revert)
string [ ] fileinfo = shamelessvariablelabel . Text . Split ( ',' ) ;
// Read the tmd as a stream...
byte [ ] tmd = FileLocationToByteArray ( fileinfo [ 0 ] + fileinfo [ 1 ] ) ;
FillContentInfo ( tmd ) ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Fills the content editor with info from TMD
/// </summary>
/// <param name="tmd">The TMD.</param>
2009-07-14 21:38:18 +02:00
private void FillContentInfo ( byte [ ] tmd )
{
// Clear anything existing...
contentsEdit . Items . Clear ( ) ;
// # of Contents and BootIndex
int nbr_cont = ContentCount ( tmd ) ;
2009-08-01 19:48:32 +02:00
int boot_idx = GetBootIndex ( tmd ) ;
2009-07-14 21:38:18 +02:00
string [ ] tmdcontents = GetContentNames ( tmd , nbr_cont ) ;
byte [ ] tmdindices = GetContentIndices ( tmd , nbr_cont ) ;
2009-07-17 18:22:58 +02:00
int [ ] tmdtypes = GetContentTypes ( tmd , nbr_cont ) ;
2009-07-14 21:38:18 +02:00
// Loop and add contents to listbox...
for ( int a = 0 ; a < nbr_cont ; a + + )
{
contentsEdit . Items . Add ( String . Format ( "[{0}] [{1}]" , tmdindices [ a ] , tmdcontents [ a ] ) ) ;
2009-07-17 18:22:58 +02:00
if ( tmdtypes [ a ] = = 0x8001 )
contentsEdit . Items [ a ] + = " [S]" ;
2009-07-14 21:38:18 +02:00
}
2009-07-17 18:22:58 +02:00
2009-07-14 21:38:18 +02:00
// Identify Boot Content...
contentsEdit . Items [ boot_idx ] + = " [BOOT]" ;
}
private void button8_Click ( object sender , EventArgs e )
{
// Move selected content upwards (down an index)...
2009-07-17 20:57:47 +02:00
if ( contentsEdit . SelectedIndex < = 0 )
2009-07-14 21:38:18 +02:00
return ;
2009-07-22 20:07:55 +02:00
int sel_index = contentsEdit . SelectedIndex ;
object sel_item = contentsEdit . SelectedItem ;
contentsEdit . Items . RemoveAt ( sel_index ) ;
contentsEdit . Items . Insert ( sel_index - 1 , sel_item ) ;
string sel_itm = contentsEdit . Items [ sel_index ] . ToString ( ) ;
string other_itm = contentsEdit . Items [ sel_index - 1 ] . ToString ( ) ;
sel_itm = sel_itm . Replace ( "[" , "" ) ; sel_itm = sel_itm . Replace ( "]" , "" ) ;
other_itm = other_itm . Replace ( "[" , "" ) ; other_itm = other_itm . Replace ( "]" , "" ) ;
string [ ] selarray = sel_itm . Split ( ' ' ) ;
string [ ] otherary = other_itm . Split ( ' ' ) ;
contentsEdit . Items [ sel_index ] = String . Format ( "[{0}]" , sel_index ) ;
contentsEdit . Items [ sel_index - 1 ] = String . Format ( "[{0}]" , sel_index - 1 ) ;
for ( int a = 0 ; a < selarray . Length ; a + + )
{
if ( a ! = 0 )
contentsEdit . Items [ sel_index ] + = String . Format ( " [{0}]" , selarray [ a ] ) ;
}
for ( int b = 0 ; b < otherary . Length ; b + + )
{
if ( b ! = 0 )
contentsEdit . Items [ sel_index - 1 ] + = String . Format ( " [{0}]" , otherary [ b ] ) ;
}
/ * int sel_idx = contentsEdit . SelectedIndex ;
2009-07-14 21:38:18 +02:00
string sel_item = contentsEdit . Items [ sel_idx ] . ToString ( ) ;
string lower_item = contentsEdit . Items [ sel_idx - 1 ] . ToString ( ) ;
2009-07-22 20:07:55 +02:00
contentsEdit . Items [ sel_idx ] = String . Format ( "[{0}]{1}" , sel_idx , lower_item . Substring ( contentsEdit . SelectedItem . ToString ( ) . IndexOf ( " [" ) , lower_item . Length - contentsEdit . SelectedItem . ToString ( ) . IndexOf ( " [" ) ) ) ;
contentsEdit . Items [ sel_idx - 1 ] = String . Format ( "[{0}]{1}" , sel_idx - 1 , sel_item . Substring ( contentsEdit . SelectedItem . ToString ( ) . IndexOf ( " [" ) , sel_item . Length - contentsEdit . SelectedItem . ToString ( ) . IndexOf ( " [" ) ) ) ;
* /
contentsEdit . SelectedIndex = sel_index - 1 ;
2009-07-14 21:38:18 +02:00
}
private void button9_Click ( object sender , EventArgs e )
{
// Move selected content down (up an index)...
if ( contentsEdit . SelectedIndex > = contentsEdit . Items . Count - 1 )
return ;
2009-07-22 20:07:55 +02:00
int sel_index = contentsEdit . SelectedIndex ;
object sel_item = contentsEdit . SelectedItem ;
contentsEdit . Items . RemoveAt ( sel_index ) ;
contentsEdit . Items . Insert ( sel_index + 1 , sel_item ) ;
string sel_itm = contentsEdit . Items [ sel_index ] . ToString ( ) ;
string other_itm = contentsEdit . Items [ sel_index + 1 ] . ToString ( ) ;
sel_itm = sel_itm . Replace ( "[" , "" ) ; sel_itm = sel_itm . Replace ( "]" , "" ) ;
other_itm = other_itm . Replace ( "[" , "" ) ; other_itm = other_itm . Replace ( "]" , "" ) ;
string [ ] selarray = sel_itm . Split ( ' ' ) ;
string [ ] otherary = other_itm . Split ( ' ' ) ;
contentsEdit . Items [ sel_index ] = String . Format ( "[{0}]" , sel_index ) ;
contentsEdit . Items [ sel_index + 1 ] = String . Format ( "[{0}]" , sel_index + 1 ) ;
for ( int a = 0 ; a < selarray . Length ; a + + )
{
if ( a ! = 0 )
contentsEdit . Items [ sel_index ] + = String . Format ( " [{0}]" , selarray [ a ] ) ;
}
for ( int b = 0 ; b < otherary . Length ; b + + )
{
if ( b ! = 0 )
contentsEdit . Items [ sel_index + 1 ] + = String . Format ( " [{0}]" , otherary [ b ] ) ;
}
/ * int sel_idx = contentsEdit . SelectedIndex ;
2009-07-14 21:38:18 +02:00
string sel_item = contentsEdit . Items [ sel_idx ] . ToString ( ) ;
string upper_item = contentsEdit . Items [ sel_idx + 1 ] . ToString ( ) ;
2009-07-22 20:07:55 +02:00
contentsEdit . Items [ sel_idx ] = String . Format ( "[{0}]{1}" , sel_idx , upper_item . Substring ( contentsEdit . SelectedItem . ToString ( ) . IndexOf ( " [" ) , upper_item . Length - contentsEdit . SelectedItem . ToString ( ) . IndexOf ( " [" ) ) ) ;
contentsEdit . Items [ sel_idx + 1 ] = String . Format ( "[{0}]{1}" , sel_idx + 1 , sel_item . Substring ( contentsEdit . SelectedItem . ToString ( ) . IndexOf ( " [" ) , sel_item . Length - contentsEdit . SelectedItem . ToString ( ) . IndexOf ( " [" ) ) ) ;
* /
contentsEdit . SelectedIndex = sel_index + 1 ;
2009-07-14 21:38:18 +02:00
}
private void button12_Click ( object sender , EventArgs e )
{
// Set a new boot index...
2009-07-22 20:07:55 +02:00
// Handle help info first...
if ( Control . ModifierKeys = = Keys . Shift )
{
WriteStatus ( "[HELP INFO] Select a content, and press this to make it the 'boot' content. The boot content is the" +
" DOL file which is ran when the channel is started." ) ;
return ;
}
2009-07-17 18:22:58 +02:00
if ( contentsEdit . SelectedIndex < 0 )
2009-07-14 21:38:18 +02:00
return ;
for ( int a = 0 ; a < contentsEdit . Items . Count ; a + + )
{
if ( contentsEdit . Items [ a ] . ToString ( ) . Contains ( " [BOOT]" ) )
contentsEdit . Items [ a ] = contentsEdit . Items [ a ] . ToString ( ) . Substring ( 0 , contentsEdit . Items [ a ] . ToString ( ) . Length - 7 ) ;
}
contentsEdit . Items [ contentsEdit . SelectedIndex ] + = " [BOOT]" ;
}
private void button11_Click ( object sender , EventArgs e )
{
// Add a file to the contents...
2009-07-22 20:07:55 +02:00
// Handle help info first...
if ( Control . ModifierKeys = = Keys . Shift )
{
WriteStatus ( "[HELP INFO] This button will allow you to add a content to the title. You can browse " +
"and select an .app file (a decrypted content) to insert into the contents list." ) ;
return ;
}
2009-07-14 21:38:18 +02:00
OpenFileDialog opencont = new OpenFileDialog ( ) ;
2009-07-17 18:22:58 +02:00
opencont . Filter = "Decrypted Contents|*.app|All Files|*" ;
2009-07-14 21:38:18 +02:00
opencont . Multiselect = false ;
opencont . Title = "Locate a Content" ;
if ( opencont . ShowDialog ( ) ! = DialogResult . Cancel )
{
2009-07-22 20:07:55 +02:00
// OK WE MUST PREVENT:
// - NON HEX NAMING
// - FILE EXISTING WITH THE SAME NAME && THAT FILE != NEW FILE
// -
2009-07-17 18:22:58 +02:00
if ( ( OnlyHexInString ( opencont . SafeFileName . Substring ( 0 , 8 ) ) = = false ) )
2009-07-14 21:38:18 +02:00
{
2009-07-17 18:22:58 +02:00
MessageBox . Show ( "Please locate/rename a file to be (8 HEX CHARACTERS) long + (.app) extention!" , "Bad!" , MessageBoxButtons . OK ) ;
2009-07-14 21:38:18 +02:00
return ;
}
for ( int i = 0 ; i < contentsEdit . Items . Count ; i + + )
{
if ( contentsEdit . Items [ i ] . ToString ( ) . Contains ( opencont . SafeFileName ) )
{
MessageBox . Show ( "A file already exists in the title with that filename!" , "Bad!" , MessageBoxButtons . OK ) ;
return ;
}
}
// D: TODO?
string [ ] fileinfo = shamelessvariablelabel . Text . Split ( ',' ) ;
2009-07-17 18:22:58 +02:00
if ( File . Exists ( fileinfo [ 0 ] + opencont . SafeFileName ) )
{
MessageBox . Show ( "Rename the file you are adding, it already exists in the title directory!" , "Bad!" , MessageBoxButtons . OK ) ;
return ;
}
2009-07-14 21:38:18 +02:00
if ( fileinfo [ 0 ] + opencont . SafeFileName ! = opencont . FileName )
{
// Move the file into the directory...
File . Copy ( opencont . FileName , fileinfo [ 0 ] + opencont . SafeFileName ) ;
}
contentsEdit . Items . Add ( String . Format ( "[{0}] [{1}]" , contentsEdit . Items . Count , opencont . SafeFileName ) ) ;
}
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Checks for a hex string.
/// </summary>
/// <param name="test">The test string</param>
/// <returns>Whether string is hex or not.</returns>
2009-07-14 21:38:18 +02:00
public bool OnlyHexInString ( string test )
{
return System . Text . RegularExpressions . Regex . IsMatch ( test , @"\A\b[0-9a-fA-F]+\b\Z" ) ;
}
private void button10_Click ( object sender , EventArgs e )
{
// Remove a content from the list...
2009-07-22 20:07:55 +02:00
// Handle help info first...
if ( Control . ModifierKeys = = Keys . Shift )
{
WriteStatus ( "[HELP INFO] This button will allow you to remove a content from the title. Be careful, " +
"as most contents are necessary for proper channel usage!" ) ;
return ;
}
2009-07-17 18:22:58 +02:00
if ( ( contentsEdit . SelectedIndex < 0 ) | | ( contentsEdit . Items . Count < = 1 ) )
2009-07-14 21:38:18 +02:00
return ;
string [ ] fileinfo = shamelessvariablelabel . Text . Split ( ',' ) ;
DialogResult question = MessageBox . Show ( "Delete the actual file as well?" , "Delete content?" , MessageBoxButtons . YesNoCancel ) ;
if ( question = = DialogResult . Yes )
File . Delete ( fileinfo [ 0 ] + contentsEdit . SelectedItem . ToString ( ) . Substring ( contentsEdit . SelectedItem . ToString ( ) . IndexOf ( "] [" ) + 3 , 8 ) ) ;
if ( question ! = DialogResult . Cancel )
contentsEdit . Items . RemoveAt ( contentsEdit . SelectedIndex ) ;
2009-07-22 20:07:55 +02:00
RecalculateIndices ( ) ;
2009-07-10 02:56:17 +02:00
}
2009-07-14 21:38:18 +02:00
2009-07-17 18:22:58 +02:00
private void button14_Click ( object sender , EventArgs e )
2009-08-02 20:12:05 +02:00
{
UpdateTMDContents ( ) ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Updates the TMD contents.
/// </summary>
2009-08-02 20:12:05 +02:00
private void UpdateTMDContents ( )
2009-07-17 18:22:58 +02:00
{
// Write changes to TMD of contents...
WriteStatus ( "Updating TMD with content information..." ) ;
string [ ] fileinfo = shamelessvariablelabel . Text . Split ( ',' ) ;
2009-07-18 05:00:09 +02:00
WriteStatus ( " - Loading Title Key from Ticket..." ) ;
2009-07-17 18:22:58 +02:00
byte [ ] ticket = FileLocationToByteArray ( fileinfo [ 0 ] + "cetk" ) ;
byte [ ] etitlekey = new byte [ 16 ] ;
for ( int a = 0 ; a < 16 ; a + + )
{
etitlekey [ a ] = ticket [ 0x1BF + a ] ;
}
// TODO: Add more key support
2009-10-14 22:52:16 +02:00
byte [ ] commonkey = LoadCommonKey ( Path . DirectorySeparatorChar . ToString ( ) + @"key.bin" ) ;
2009-07-17 18:22:58 +02:00
// IV (TITLEID00000000)
byte [ ] iv = new byte [ 16 ] ;
for ( int b = 0 ; b < 8 ; b + + )
2009-08-02 20:12:05 +02:00
{
2009-07-17 18:22:58 +02:00
iv [ b ] = ticket [ 0x1DC + b ] ;
2009-08-02 20:12:05 +02:00
}
2009-07-17 18:22:58 +02:00
for ( int c = 0 ; c < 8 ; c + + )
2009-08-02 20:12:05 +02:00
{
iv [ c + 8 ] = 0x00 ;
}
2009-07-17 18:22:58 +02:00
initCrypt ( iv , commonkey ) ;
byte [ ] dtitlekey = Decrypt ( etitlekey ) ;
// Holds all the content data...
TitleContent [ ] contents = new TitleContent [ contentsEdit . Items . Count ] ;
// Previous TMD for analysis
byte [ ] tmd = FileLocationToByteArray ( fileinfo [ 0 ] + fileinfo [ 1 ] ) ;
for ( int c = 0 ; c < contentsEdit . Items . Count ; c + + )
{
string itemstr = contentsEdit . Items [ c ] . ToString ( ) ;
contents [ c ] = new TitleContent ( ) ;
2009-07-23 00:22:04 +02:00
// Set boot index...
if ( itemstr . Contains ( " [BOOT]" ) )
{
tmd = SetBootIndex ( tmd , c ) ;
}
2009-07-17 18:22:58 +02:00
if ( itemstr . Contains ( ".app" ) )
{
// This is already decrypted, we're going to add it to the TMD...
2009-07-22 20:07:55 +02:00
string filename = itemstr . Substring ( itemstr . IndexOf ( "] [" ) + 3 , 12 ) ;
2009-07-17 18:22:58 +02:00
byte [ ] contentbytes = FileLocationToByteArray ( fileinfo [ 0 ] + filename ) ;
2009-07-18 05:00:09 +02:00
WriteStatus ( filename + " is a decrypted file..." ) ;
2009-07-17 18:22:58 +02:00
WriteStatus ( " - Encrypting " + filename + "..." ) ;
// Gather the contentID (crappy way to do it)...
contents [ c ] . ContentID = new byte [ 4 ] ;
contents [ c ] . ContentID [ 0 ] = byte . Parse ( filename . Substring ( 0 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
contents [ c ] . ContentID [ 1 ] = byte . Parse ( filename . Substring ( 2 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
contents [ c ] . ContentID [ 2 ] = byte . Parse ( filename . Substring ( 4 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
contents [ c ] . ContentID [ 3 ] = byte . Parse ( filename . Substring ( 6 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
// Grab SHA1/size of file
contents [ c ] . SHAHash = new byte [ 20 ] ;
contents [ c ] . SHAHash = ComputeSHA ( contentbytes ) ;
contents [ c ] . Size = new byte [ 8 ] ;
// TODOCHECK THIS OVER
2009-07-21 23:53:27 +02:00
contents [ c ] . Size = NewIntegertoByteArray ( contentbytes . Length , 8 ) ;
2009-08-02 20:12:05 +02:00
2009-07-17 18:22:58 +02:00
contents [ c ] . Index = new byte [ 2 ] ;
2009-07-21 23:53:27 +02:00
contents [ c ] . Index = NewIntegertoByteArray ( c , 2 ) ;
2009-07-17 18:22:58 +02:00
contents [ c ] . Type = new byte [ 2 ] ;
contents [ c ] . Type [ 1 ] = 0x01 ;
if ( contentsEdit . Items [ c ] . ToString ( ) . Contains ( " [S]" ) )
contents [ c ] . Type [ 0 ] = 0x80 ;
else
contents [ c ] . Type [ 0 ] = 0x00 ;
// Pad to be 16 byte aligned
2009-07-17 20:57:47 +02:00
contentbytes = PadToMultipleOf ( contentbytes , 16 ) ;
2009-07-17 18:22:58 +02:00
// Encrypt with correct index IV/titlekey
byte [ ] ivindex = new byte [ 16 ] ;
for ( int d = 0 ; d < ivindex . Length ; d + + )
{
ivindex [ d ] = 0x00 ;
}
ivindex [ 0 ] = contents [ c ] . Index [ 0 ] ;
ivindex [ 1 ] = contents [ c ] . Index [ 1 ] ;
initCrypt ( ivindex , dtitlekey ) ;
FileStream encryptwrite = new FileStream ( fileinfo [ 0 ] + filename . Substring ( 0 , 8 ) , FileMode . Create ) ;
encryptwrite . Write ( Encrypt ( contentbytes ) , 0 , contentbytes . Length ) ;
encryptwrite . Close ( ) ;
WriteStatus ( " - " + filename . Substring ( 0 , 8 ) + " written!" ) ;
}
else
2009-08-02 20:12:05 +02:00
{
2009-07-18 05:00:09 +02:00
// An encrypted content...it was from the original TMD
2009-07-22 20:07:55 +02:00
string filename = itemstr . Substring ( itemstr . IndexOf ( "] [" ) + 3 , 8 ) ;
2009-07-17 18:22:58 +02:00
byte [ ] contentbytes = FileLocationToByteArray ( fileinfo [ 0 ] + filename ) ;
2009-07-18 05:00:09 +02:00
WriteStatus ( filename + " is encrypted and from the original TMD..." ) ;
WriteStatus ( " - Gathering " + filename + " information..." ) ;
2009-07-17 18:22:58 +02:00
// Grab previous values from TMD...
int nbr_cont = ContentCount ( tmd ) ;
string [ ] tmdoldcontents = GetContentNames ( tmd , nbr_cont ) ;
string [ ] tmdsizes = GetContentSizes ( tmd , nbr_cont ) ;
byte [ ] tmdhashes = GetContentHashes ( tmd , nbr_cont ) ;
int thiscontentidx = 0 ;
for ( int f = 0 ; f < nbr_cont ; f + + )
{
if ( tmdoldcontents [ f ] = = filename )
thiscontentidx = f ;
}
2009-07-18 05:00:09 +02:00
// if index has been changed...
2009-07-17 18:22:58 +02:00
if ( thiscontentidx ! = c )
{
// We have to decrypt the content, and then encrypt to keep IV in line...
2009-07-18 05:00:09 +02:00
WriteStatus ( " - Index altered. Must change IV..." ) ;
2009-07-17 18:22:58 +02:00
byte [ ] ivindex = new byte [ 16 ] ;
for ( int d = 0 ; d < ivindex . Length ; d + + )
{
ivindex [ d ] = 0x00 ;
}
// TODO: Complete this...
ivindex [ 0 ] = 0x00 ;
ivindex [ 1 ] = ( byte ) thiscontentidx ;
2009-07-14 21:38:18 +02:00
2009-07-17 18:22:58 +02:00
initCrypt ( ivindex , dtitlekey ) ;
byte [ ] hash = new byte [ 20 ] ;
for ( int x = 0 ; x < 20 ; x + + )
{
hash [ x ] = tmdhashes [ ( thiscontentidx * 20 ) + x ] ;
}
byte [ ] decContent = Decrypt ( contentbytes ) ;
2009-07-17 20:57:47 +02:00
Array . Resize ( ref decContent , int . Parse ( tmdsizes [ thiscontentidx ] , System . Globalization . NumberStyles . HexNumber ) ) ;
2009-07-18 05:00:09 +02:00
contents [ c ] . Size = NewIntegertoByteArray ( decContent . Length , 8 ) ;
2009-07-17 18:22:58 +02:00
if ( ( Convert . ToBase64String ( ComputeSHA ( decContent ) ) ) = = Convert . ToBase64String ( hash ) )
{
2009-07-17 20:57:47 +02:00
WriteStatus ( " - Hash Check: Content is Unchanged..." ) ;
2009-07-17 18:22:58 +02:00
contents [ c ] . SHAHash = hash ;
2009-07-18 05:00:09 +02:00
//WriteStatus("HASH: " + DisplayBytes(hash, ""));
2009-07-17 18:22:58 +02:00
}
else
{
2009-07-18 05:00:09 +02:00
WriteStatus ( " - Hash Check: Content changed (did you add an encrypted file from another title?)..." ) ;
2009-07-17 18:22:58 +02:00
contents [ c ] . SHAHash = ComputeSHA ( decContent ) ;
}
// Re-encrypt
byte [ ] newiv = new byte [ 16 ] ;
for ( int g = 0 ; g < newiv . Length ; g + + )
{
newiv [ g ] = 0x00 ;
}
2009-07-18 05:00:09 +02:00
byte [ ] smallix = NewIntegertoByteArray ( c , 2 ) ;
ivindex [ 0 ] = smallix [ 0 ] ;
ivindex [ 1 ] = smallix [ 1 ] ;
//WriteStatus(" - Old Index: " + thiscontentidx + "; New Index: " + c);
2009-07-17 18:22:58 +02:00
// Pad back to 0x16 alignment
2009-07-17 20:57:47 +02:00
//AlignByteArray(decContent, 0x16
decContent = PadToMultipleOf ( decContent , 16 ) ;
2009-07-17 18:22:58 +02:00
initCrypt ( newiv , dtitlekey ) ;
byte [ ] encContent = Encrypt ( decContent ) ;
File . Delete ( fileinfo [ 0 ] + filename . Substring ( 0 , 8 ) ) ;
FileStream encryptwrite = new FileStream ( fileinfo [ 0 ] + filename . Substring ( 0 , 8 ) , FileMode . OpenOrCreate ) ;
encryptwrite . Write ( encContent , 0 , encContent . Length ) ;
encryptwrite . Close ( ) ;
WriteStatus ( " - Encrypted Content Again!" ) ;
}
else
2009-08-02 20:12:05 +02:00
{
2009-07-17 18:22:58 +02:00
// Hopefully this content has not been touched...
2009-07-18 05:00:09 +02:00
WriteStatus ( " - Content has not changed Index." ) ;
byte [ ] hash = new byte [ 20 ] ;
for ( int x = 0 ; x < 20 ; x + + )
{
hash [ x ] = tmdhashes [ ( c * 20 ) + x ] ;
}
contents [ c ] . SHAHash = hash ;
contents [ c ] . Size = NewIntegertoByteArray ( int . Parse ( tmdsizes [ c ] , System . Globalization . NumberStyles . HexNumber ) , 8 ) ;
2009-07-17 18:22:58 +02:00
}
contents [ c ] . ContentID = new byte [ 4 ] ;
contents [ c ] . ContentID [ 0 ] = byte . Parse ( filename . Substring ( 0 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
contents [ c ] . ContentID [ 1 ] = byte . Parse ( filename . Substring ( 2 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
contents [ c ] . ContentID [ 2 ] = byte . Parse ( filename . Substring ( 4 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
contents [ c ] . ContentID [ 3 ] = byte . Parse ( filename . Substring ( 6 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ;
2009-08-02 20:12:05 +02:00
2009-07-17 18:22:58 +02:00
contents [ c ] . Index = new byte [ 2 ] ;
2009-07-17 20:57:47 +02:00
contents [ c ] . Index = NewIntegertoByteArray ( c , 2 ) ;
2009-08-02 20:12:05 +02:00
2009-07-17 18:22:58 +02:00
contents [ c ] . Type = new byte [ 2 ] ;
2009-07-17 20:57:47 +02:00
contents [ c ] . Type [ 1 ] = 0x01 ;
2009-07-17 18:22:58 +02:00
if ( contentsEdit . Items [ c ] . ToString ( ) . Contains ( " [S]" ) )
contents [ c ] . Type [ 0 ] = 0x80 ;
else
2009-08-02 20:12:05 +02:00
contents [ c ] . Type [ 0 ] = 0x00 ;
2009-07-17 18:22:58 +02:00
}
2009-07-17 20:57:47 +02:00
}
2009-08-02 20:12:05 +02:00
2009-07-23 00:22:04 +02:00
// Collect everything into a single byte[]...
byte [ ] contentSection = new byte [ contents . Length * 36 ] ;
for ( int h = 0 ; h < contents . Length ; h + + )
{
for ( int i = 0 ; i < contents [ h ] . ContentID . Length ; i + + )
2009-07-17 18:22:58 +02:00
{
2009-07-23 00:22:04 +02:00
contentSection [ ( h * 36 ) + i ] = contents [ h ] . ContentID [ i ] ;
}
2009-07-17 18:22:58 +02:00
2009-07-23 00:22:04 +02:00
for ( int j = 0 ; j < contents [ h ] . Index . Length ; j + + )
{
contentSection [ ( h * 36 ) + ( contents [ h ] . ContentID . Length + j ) ] = contents [ h ] . Index [ j ] ;
}
2009-07-17 18:22:58 +02:00
2009-07-23 00:22:04 +02:00
for ( int k = 0 ; k < contents [ h ] . Type . Length ; k + + )
{
contentSection [ ( h * 36 ) + ( contents [ h ] . ContentID . Length + contents [ h ] . Index . Length + k ) ] = contents [ h ] . Type [ k ] ;
}
2009-07-17 18:22:58 +02:00
2009-07-23 00:22:04 +02:00
for ( int l = 0 ; l < contents [ h ] . Size . Length ; l + + )
{
contentSection [ ( h * 36 ) + ( contents [ h ] . ContentID . Length + contents [ h ] . Index . Length + contents [ h ] . Type . Length + l ) ] = contents [ h ] . Size [ l ] ;
2009-07-17 18:22:58 +02:00
}
2009-07-23 00:22:04 +02:00
for ( int m = 0 ; m < contents [ h ] . SHAHash . Length ; m + + )
2009-07-17 18:22:58 +02:00
{
2009-07-23 00:22:04 +02:00
contentSection [ ( h * 36 ) + ( contents [ h ] . ContentID . Length + contents [ h ] . Index . Length + contents [ h ] . Type . Length + contents [ h ] . Size . Length + m ) ] = contents [ h ] . SHAHash [ m ] ;
2009-07-17 18:22:58 +02:00
}
2009-07-23 00:22:04 +02:00
}
2009-07-17 18:22:58 +02:00
2009-07-23 00:22:04 +02:00
for ( int n = 0 ; n < contentSection . Length ; n + + )
{
tmd [ 0x1E4 + n ] = contentSection [ n ] ;
}
2009-07-17 18:22:58 +02:00
2009-07-23 00:22:04 +02:00
// Fakesign the TMD again...
tmd = ZeroSignature ( tmd ) ;
tmd = TruchaSign ( tmd ) ;
// Write all this stuff to the TMD...
FileStream testtmd = new FileStream ( fileinfo [ 0 ] + fileinfo [ 1 ] , FileMode . Open ) ;
testtmd . Write ( tmd , 0 , tmd . Length ) ;
testtmd . Close ( ) ;
2009-07-17 18:22:58 +02:00
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Pads to multiple of....
/// </summary>
/// <param name="src">The binary.</param>
/// <param name="pad">The pad amount.</param>
/// <returns>Padded byte[]</returns>
2009-07-17 20:57:47 +02:00
private byte [ ] PadToMultipleOf ( byte [ ] src , int pad )
{
int len = ( src . Length + pad - 1 ) / pad * pad ;
Array . Resize ( ref src , len ) ;
return src ;
2009-07-17 18:22:58 +02:00
}
2009-07-17 20:57:47 +02:00
2009-07-17 18:22:58 +02:00
private void button17_Click ( object sender , EventArgs e )
{
// Move groupbox to display title modder...
2009-08-01 19:48:32 +02:00
if ( button17 . Text = = "Modify Individual Contents..." )
{
contentModBox . Location = new Point ( 278 , 12 ) ;
contentModBox . Visible = true ;
contentModBox . BringToFront ( ) ;
button17 . Text = "Trucha Sign Title..." ;
}
else if ( button17 . Text = = "Trucha Sign Title..." )
{
//contentModBox.Location = new Point(300, 300);
contentModBox . Visible = false ;
contentModBox . SendToBack ( ) ;
button17 . Text = "Modify Individual Contents..." ;
}
2009-07-17 18:22:58 +02:00
}
private void button13_Click ( object sender , EventArgs e )
{
// Share/Unshare Contents in the list...
2009-07-22 20:07:55 +02:00
// Handle help info first...
if ( Control . ModifierKeys = = Keys . Shift )
{
WriteStatus ( "[HELP INFO] Toggles the shared state of the content." ) ;
return ;
}
2009-07-17 18:22:58 +02:00
if ( contentsEdit . SelectedIndex < 0 )
return ;
if ( contentsEdit . Items [ contentsEdit . SelectedIndex ] . ToString ( ) . Contains ( " [S]" ) )
contentsEdit . Items [ contentsEdit . SelectedIndex ] = contentsEdit . SelectedItem . ToString ( ) . Replace ( " [S]" , "" ) ;
else
{
if ( contentsEdit . Items [ contentsEdit . SelectedIndex ] . ToString ( ) . Contains ( " [BOOT]" ) )
contentsEdit . Items [ contentsEdit . SelectedIndex ] = contentsEdit . SelectedItem . ToString ( ) . Replace ( " [BOOT]" , "" ) + " [S] [BOOT]" ;
else
contentsEdit . Items [ contentsEdit . SelectedIndex ] = contentsEdit . SelectedItem . ToString ( ) + " [S]" ;
}
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Determines whether OS is win7.
/// </summary>
/// <returns>
/// <c>true</c> if OS = win7; otherwise, <c>false</c>.
/// </returns>
2009-07-17 18:22:58 +02:00
private bool IsWin7 ( )
{
return ( Environment . OSVersion . VersionString . Contains ( "6.1" ) = = true ) ;
}
2009-07-17 20:57:47 +02:00
private byte [ ] NewIntegertoByteArray ( int theInt , int arrayLen )
{
byte [ ] resultArray = new byte [ arrayLen ] ;
for ( int i = arrayLen - 1 ; i > = 0 ; i - - )
{
resultArray [ i ] = ( byte ) ( ( theInt > > ( 8 * i ) ) & 0xFF ) ;
}
Array . Reverse ( resultArray ) ;
// Fix duplication, rewrite extra to 0x00;
if ( arrayLen > 4 )
{
for ( int i = 0 ; i < ( arrayLen - 4 ) ; i + + )
{
resultArray [ i ] = 0x00 ;
}
}
return resultArray ;
}
2009-07-21 23:53:27 +02:00
private void button16_Click ( object sender , EventArgs e )
{
// add trucha bug to content...
2009-07-22 20:07:55 +02:00
// Handle help info first...
if ( Control . ModifierKeys = = Keys . Shift )
{
WriteStatus ( "[HELP INFO] Inserts the trucha bug into the selected content, if the bug was fixed previously." ) ;
return ;
}
2009-07-21 23:53:27 +02:00
if ( contentsEdit . SelectedIndex < 0 )
return ;
WriteStatus ( "Attempting to add 'bugs' back into content..." ) ;
string [ ] fileinfo = shamelessvariablelabel . Text . Split ( ',' ) ;
byte [ ] new_hash_check = new byte [ ] { 0x20 , 0x07 , 0x4B , 0x0B } ;
byte [ ] old_hash_check = new byte [ ] { 0x20 , 0x07 , 0x23 , 0xA2 } ;
// If decrypted...
// - check right away for bug...
// - add bug, then end...
// if encrypted...
// - decrypt content...
// - find bug/patch...
// - recalculate hash...
// - write back into TMD...
// - trucha sign content...
if ( contentsEdit . Items [ contentsEdit . SelectedIndex ] . ToString ( ) . Contains ( ".app" ) )
{
// Content is decrypted/new to the title...
string filename = contentsEdit . Items [ contentsEdit . SelectedIndex ] . ToString ( ) . Substring ( contentsEdit . Items [ contentsEdit . SelectedIndex ] . ToString ( ) . IndexOf ( "] [" ) + 3 , 12 ) ;
byte [ ] contentbt = FileLocationToByteArray ( fileinfo [ 0 ] + filename ) ;
2009-08-04 02:01:01 +02:00
byte [ ] newvalues = new byte [ 4 ] ;
newvalues [ 1 ] = 0x00 ;
2009-07-21 23:53:27 +02:00
int [ ] oldresults = ByteArrayContainsByteArray ( contentbt , old_hash_check ) ;
int [ ] newresults = ByteArrayContainsByteArray ( contentbt , new_hash_check ) ;
if ( oldresults [ 0 ] ! = 0 )
{
WriteStatus ( String . Format ( " - {0} Old-school ES Signing Fix(es) Found..." , oldresults [ 0 ] ) ) ;
for ( int s = 1 ; s < oldresults . Length - 1 ; s + + )
{
2009-08-04 02:01:01 +02:00
contentbt = PatchBinary ( contentbt , oldresults [ s ] , newvalues ) ;
2009-07-21 23:53:27 +02:00
WriteStatus ( String . Format ( " - Bug restored at 0x{0}" , int . Parse ( oldresults [ s ] . ToString ( ) , System . Globalization . NumberStyles . HexNumber ) ) ) ;
}
}
2009-08-04 02:01:01 +02:00
2009-07-21 23:53:27 +02:00
if ( newresults [ 0 ] ! = 0 )
{
WriteStatus ( String . Format ( " - {0} New-school ES Signing Fix(es) Found..." , newresults [ 0 ] ) ) ;
for ( int s = 1 ; s < newresults . Length - 1 ; s + + )
{
2009-08-04 02:01:01 +02:00
contentbt = PatchBinary ( contentbt , newresults [ s ] , newvalues ) ;
2009-07-21 23:53:27 +02:00
WriteStatus ( String . Format ( " + Bug restored at 0x{0}." , int . Parse ( newresults [ s ] . ToString ( ) , System . Globalization . NumberStyles . HexNumber ) ) ) ;
}
}
}
else
2009-08-04 02:01:01 +02:00
{
WriteStatus ( " - The file you selected was encrypted, attempting to decrypt and patch..." ) ;
2009-07-21 23:53:27 +02:00
string filename = contentsEdit . Items [ contentsEdit . SelectedIndex ] . ToString ( ) . Substring ( contentsEdit . Items [ contentsEdit . SelectedIndex ] . ToString ( ) . IndexOf ( "] [" ) + 3 , 8 ) ;
byte [ ] ticket = FileLocationToByteArray ( fileinfo [ 0 ] + "cetk" ) ;
2009-08-02 20:12:05 +02:00
byte [ ] tmd = FileLocationToByteArray ( fileinfo [ 0 ] + fileinfo [ 1 ] ) ;
2009-07-21 23:53:27 +02:00
byte [ ] etitlekey = new byte [ 16 ] ;
for ( int a = 0 ; a < 16 ; a + + )
{
etitlekey [ a ] = ticket [ 0x1BF + a ] ;
}
// TODO: Add more key support
2009-10-14 22:52:16 +02:00
byte [ ] commonkey = LoadCommonKey ( Path . DirectorySeparatorChar . ToString ( ) + @"key.bin" ) ;
2009-07-21 23:53:27 +02:00
// IV (TITLEID00000000)
byte [ ] iv = new byte [ 16 ] ;
for ( int b = 0 ; b < 8 ; b + + )
{
iv [ b ] = ticket [ 0x1DC + b ] ;
}
for ( int c = 0 ; c < 8 ; c + + )
{
iv [ c + 8 ] = 0x00 ;
}
initCrypt ( iv , commonkey ) ;
2009-08-02 20:12:05 +02:00
byte [ ] dtitlekey = Decrypt ( etitlekey ) ;
// Decrypt this content (determine index)
string [ ] tmdcontents = GetContentNames ( tmd , ContentCount ( tmd ) ) ;
byte [ ] tmdindices = GetContentIndices ( tmd , ContentCount ( tmd ) ) ;
byte [ ] tmdhashes = GetContentHashes ( tmd , ContentCount ( tmd ) ) ;
string [ ] tmdsizes = GetContentSizes ( tmd , ContentCount ( tmd ) ) ;
iv = new byte [ 16 ] ;
2009-08-04 02:01:01 +02:00
for ( int f = 0 ; f < 16 ; f + + )
2009-08-02 20:12:05 +02:00
{
2009-08-04 02:01:01 +02:00
iv [ f ] = 0x00 ;
2009-08-02 20:12:05 +02:00
}
byte [ ] hash = new byte [ 20 ] ;
for ( int d = 0 ; d < tmdcontents . Length ; d + + )
{
if ( tmdcontents [ d ] = = filename )
{
iv [ 0 ] = 0x00 ; // TODO: Add double index byte support
iv [ 1 ] = tmdindices [ d ] ;
for ( int x = 0 ; x < 20 ; x + + )
{
hash [ x ] = tmdhashes [ ( d * 20 ) + x ] ;
}
}
}
initCrypt ( iv , commonkey ) ;
2009-08-04 02:01:01 +02:00
//DEBUG
WriteStatus ( DisplayBytes ( iv , " " ) ) ;
2009-08-02 20:12:05 +02:00
byte [ ] decContent = Decrypt ( FileLocationToByteArray ( fileinfo [ 0 ] + filename ) ) ;
2009-08-04 02:01:01 +02:00
Array . Resize ( ref decContent , int . Parse ( tmdsizes [ 14 ] , System . Globalization . NumberStyles . HexNumber ) ) ;
2009-08-02 20:12:05 +02:00
if ( ( Convert . ToBase64String ( ComputeSHA ( decContent ) ) ) = = Convert . ToBase64String ( hash ) )
{
2009-08-04 02:01:01 +02:00
WriteStatus ( " - Hash Check: Content is Unchanged..." ) ;
2009-08-02 20:12:05 +02:00
}
else
{
2009-08-04 02:01:01 +02:00
WriteStatus ( " - Hash Check: Content changed (did you add an encrypted file from another title?)..." ) ;
WriteStatus ( " - Content Hash: " + DisplayBytes ( ComputeSHA ( decContent ) , "" ) ) ;
WriteStatus ( " - TMD Hash: " + DisplayBytes ( hash , "" ) ) ;
2009-08-02 20:12:05 +02:00
}
2009-08-04 02:01:01 +02:00
if ( File . Exists ( fileinfo [ 0 ] + filename + ".app" ) )
2009-08-02 20:12:05 +02:00
{
2009-08-04 02:01:01 +02:00
if ( MessageBox . Show ( fileinfo [ 0 ] + filename + ".app Exists! Delete the current file so we can move on?" , "File Conflict" , MessageBoxButtons . YesNo ) = = DialogResult . Yes )
File . Delete ( fileinfo [ 0 ] + filename + ".app" ) ;
else
return ;
2009-08-02 20:12:05 +02:00
}
2009-08-04 02:01:01 +02:00
byte [ ] newvalues = new byte [ 4 ] ;
newvalues [ 1 ] = 0x00 ;
2009-08-02 20:12:05 +02:00
2009-08-04 02:01:01 +02:00
int [ ] oldresults = ByteArrayContainsByteArray ( decContent , old_hash_check ) ;
int [ ] newresults = ByteArrayContainsByteArray ( decContent , new_hash_check ) ;
2009-08-02 20:12:05 +02:00
2009-08-04 02:01:01 +02:00
if ( oldresults [ 0 ] ! = 0 )
{
WriteStatus ( String . Format ( " - {0} Old-school ES Signing Fix(es) Found..." , oldresults [ 0 ] ) ) ;
for ( int s = 1 ; s < oldresults . Length - 1 ; s + + )
{
decContent = PatchBinary ( decContent , oldresults [ s ] , newvalues ) ;
WriteStatus ( String . Format ( " - Bug restored at 0x{0}" , int . Parse ( oldresults [ s ] . ToString ( ) , System . Globalization . NumberStyles . HexNumber ) ) ) ;
}
}
2009-08-01 19:48:32 +02:00
2009-08-04 02:01:01 +02:00
if ( newresults [ 0 ] ! = 0 )
{
WriteStatus ( String . Format ( " - {0} New-school ES Signing Fix(es) Found..." , newresults [ 0 ] ) ) ;
for ( int s = 1 ; s < newresults . Length - 1 ; s + + )
{
decContent = PatchBinary ( decContent , newresults [ s ] , newvalues ) ;
WriteStatus ( String . Format ( " + Bug restored at 0x{0}." , int . Parse ( newresults [ s ] . ToString ( ) , System . Globalization . NumberStyles . HexNumber ) ) ) ;
}
}
2009-08-02 20:12:05 +02:00
2009-08-04 02:01:01 +02:00
File . WriteAllBytes ( fileinfo [ 0 ] + filename + ".app" , decContent ) ;
2009-08-02 20:12:05 +02:00
2009-08-04 02:01:01 +02:00
contentsEdit . Items [ contentsEdit . SelectedIndex ] = contentsEdit . Items [ contentsEdit . SelectedIndex ] . ToString ( ) . Replace ( filename , filename + ".app" ) ;
2009-08-02 20:12:05 +02:00
2009-08-04 02:01:01 +02:00
UpdateTMDContents ( ) ;
2009-08-02 20:12:05 +02:00
2009-08-04 02:01:01 +02:00
WriteStatus ( "Trucha signing complete!" ) ;
2009-07-21 23:53:27 +02:00
}
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Does byte[] contain byte[]?
/// </summary>
/// <param name="bigboy">The large byte[].</param>
/// <param name="littleman">Small byte[] which may be in large one.</param>
/// <returns>messed up int[] with offsets.</returns>
2009-07-21 23:53:27 +02:00
private int [ ] ByteArrayContainsByteArray ( byte [ ] bigboy , byte [ ] littleman )
{
// bigboy.Contains(littleman);
// returns offset { cnt , ofst };
int [ ] offset = new int [ 5 ] ;
for ( int a = 0 ; a < ( bigboy . Length - littleman . Length ) ; a + + )
{
int matches = 0 ;
for ( int b = 0 ; b < littleman . Length ; b + + )
{
if ( bigboy [ a + b ] = = littleman [ b ] )
matches + = 1 ;
}
if ( matches = = littleman . Length )
{
offset [ offset [ 0 ] + 1 ] = a ;
offset [ 0 ] + = 1 ;
}
}
return offset ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Patches the binary.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="offset">The offset.</param>
/// <param name="newvalues">The newvalues.</param>
/// <returns></returns>
2009-08-04 02:01:01 +02:00
private byte [ ] PatchBinary ( byte [ ] content , int offset , byte [ ] newvalues )
2009-07-21 23:53:27 +02:00
{
2009-08-04 02:01:01 +02:00
for ( int a = 0 ; a < newvalues . Length ; a + + )
2009-07-21 23:53:27 +02:00
{
2009-08-04 02:01:01 +02:00
if ( newvalues [ a ] > = 0 )
content [ offset + a ] = newvalues [ a ] ;
2009-07-21 23:53:27 +02:00
}
return content ;
}
2009-07-22 20:07:55 +02:00
2009-08-18 07:02:23 +02:00
/// <summary>
/// Recalculates the indices.
/// </summary>
2009-07-22 20:07:55 +02:00
private void RecalculateIndices ( )
{
for ( int a = 0 ; a < contentsEdit . Items . Count ; a + + )
{
string item = contentsEdit . Items [ a ] . ToString ( ) ;
item = item . Replace ( "[" , "" ) ; item = item . Replace ( "]" , "" ) ;
string [ ] itemparts = item . Split ( ' ' ) ;
contentsEdit . Items [ a ] = String . Format ( "[{0}]" , a ) ;
for ( int b = 0 ; b < itemparts . Length ; b + + )
{
if ( b ! = 0 )
contentsEdit . Items [ a ] + = String . Format ( " [{0}]" , itemparts [ b ] ) ;
}
}
}
2009-08-04 20:17:21 +02:00
2009-08-18 07:02:23 +02:00
/// <summary>
/// Retrieves the new database via WiiBrew.
/// </summary>
/// <returns>Database as a String</returns>
2010-06-29 18:06:15 +02:00
private void RetrieveNewDatabase ( object sender , DoWorkEventArgs e )
2009-08-04 20:17:21 +02:00
{
// Retrieve Wiibrew database page source code
WebClient databasedl = new WebClient ( ) ;
2010-06-29 18:06:15 +02:00
//statusbox.Refresh();
2009-08-28 00:52:11 +02:00
// Proxy
if ( ! ( String . IsNullOrEmpty ( proxy_url ) ) )
{
WebProxy customproxy = new WebProxy ( ) ;
customproxy . Address = new Uri ( proxy_url ) ;
if ( String . IsNullOrEmpty ( proxy_usr ) )
customproxy . UseDefaultCredentials = true ;
else
{
NetworkCredential cred = new NetworkCredential ( ) ;
cred . UserName = proxy_usr ;
if ( ! ( String . IsNullOrEmpty ( proxy_pwd ) ) )
cred . Password = proxy_pwd ;
customproxy . Credentials = cred ;
}
databasedl . Proxy = customproxy ;
WriteStatus ( " - Custom proxy settings applied!" ) ;
}
else
{
databasedl . Proxy = WebRequest . GetSystemWebProxy ( ) ;
databasedl . UseDefaultCredentials = true ;
}
2009-10-14 22:52:16 +02:00
string wiibrewsource = databasedl . DownloadString ( "http://www.wiibrew.org/wiki/NUS_Downloader/database?cachesmash=" + System . DateTime . Now . ToString ( ) ) ;
2010-06-29 18:06:15 +02:00
//statusbox.Refresh();
2009-08-04 20:17:21 +02:00
// Strip out HTML
wiibrewsource = Regex . Replace ( wiibrewsource , @"<(.|\n)*?>" , "" ) ;
// Shrink to fix only the database
string startofdatabase = "<database v" ;
string endofdatabase = "</database>" ;
wiibrewsource = wiibrewsource . Substring ( wiibrewsource . IndexOf ( startofdatabase ) , wiibrewsource . Length - wiibrewsource . IndexOf ( startofdatabase ) ) ;
wiibrewsource = wiibrewsource . Substring ( 0 , wiibrewsource . IndexOf ( endofdatabase ) + endofdatabase . Length ) ;
2009-08-06 04:37:39 +02:00
// Fix ", <, >, and spaces
2009-08-04 20:17:21 +02:00
wiibrewsource = wiibrewsource . Replace ( "<" , "<" ) ;
wiibrewsource = wiibrewsource . Replace ( ">" , ">" ) ;
wiibrewsource = wiibrewsource . Replace ( """ , '"' . ToString ( ) ) ;
2009-10-16 00:23:08 +02:00
wiibrewsource = wiibrewsource . Replace ( " " , " " ) ; // Shouldn't occur, but they happen...
2009-08-04 20:17:21 +02:00
// Return parsed xml database...
2010-06-29 18:06:15 +02:00
e . Result = wiibrewsource ;
2009-08-04 20:17:21 +02:00
}
2010-06-29 18:06:15 +02:00
private void RetrieveNewDatabase_Completed ( object sender , RunWorkerCompletedEventArgs e )
2009-08-04 20:17:21 +02:00
{
2010-06-29 18:06:15 +02:00
string database = e . Result . ToString ( ) ;
2009-08-04 20:17:21 +02:00
string currentversion = GetDatabaseVersion ( "database.xml" ) ;
string onlineversion = GetDatabaseVersion ( database ) ;
2009-08-06 04:37:39 +02:00
WriteStatus ( " - Database successfully parsed!" ) ;
WriteStatus ( " - Current Database Version: " + currentversion ) ;
WriteStatus ( " - Online Database Version: " + onlineversion ) ;
2009-08-04 20:17:21 +02:00
if ( currentversion = = onlineversion )
{
WriteStatus ( " - You have the latest database version!" ) ;
return ;
}
2010-06-29 18:06:15 +02:00
bool isCreation = false ;
if ( File . Exists ( "database.xml" ) )
{
WriteStatus ( " - Overwriting your current database.xml..." ) ;
WriteStatus ( " - The old database will become 'olddatabase.xml' in case the new one is faulty." ) ;
2009-08-04 20:17:21 +02:00
2010-06-29 18:06:15 +02:00
string olddatabase = File . ReadAllText ( "database.xml" ) ;
File . WriteAllText ( "olddatabase.xml" , olddatabase ) ;
File . Delete ( "database.xml" ) ;
File . WriteAllText ( "database.xml" , database ) ;
}
else
{
WriteStatus ( " - database.xml has been created." ) ;
File . WriteAllText ( "database.xml" , database ) ;
isCreation = true ;
}
2009-08-04 20:17:21 +02:00
2009-10-16 00:23:08 +02:00
// Load it up...
2010-06-29 18:06:15 +02:00
this . fds . RunWorkerAsync ( ) ;
if ( isCreation )
{
WriteStatus ( "Database successfully created!" ) ;
2010-06-29 18:56:17 +02:00
databaseButton . Visible = true ;
databaseButton . Enabled = false ;
Extrasbtn . Size = new System . Drawing . Size ( 55 , 20 ) ;
updateDatabaseToolStripMenuItem . Text = "Download Database" ;
2010-06-29 18:06:15 +02:00
}
else
{
WriteStatus ( "Database successfully updated!" ) ;
}
2009-10-16 00:23:08 +02:00
2010-06-29 18:06:15 +02:00
}
private void updateDatabaseToolStripMenuItem_Click ( object sender , EventArgs e )
{
statusbox . Text = "" ;
WriteStatus ( "Updating your database.xml from Wiibrew.org" ) ;
BackgroundWorker dbFetcher = new BackgroundWorker ( ) ;
dbFetcher . DoWork + = new DoWorkEventHandler ( RetrieveNewDatabase ) ;
dbFetcher . RunWorkerCompleted + = new RunWorkerCompletedEventHandler ( RetrieveNewDatabase_Completed ) ;
dbFetcher . RunWorkerAsync ( ) ;
2010-06-29 18:56:17 +02:00
/ * while ( dbFetcher . IsBusy )
2010-06-29 18:06:15 +02:00
{
statusbox . Text + = "." ;
2010-06-29 18:56:17 +02:00
} * /
2009-08-04 20:17:21 +02:00
}
2009-08-06 04:37:39 +02:00
private void loadInfoFromTMDToolStripMenuItem_Click ( object sender , EventArgs e )
{
// Extras menu -> Load TMD...
LoadTitleFromTMD ( ) ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Sends the SOAP request to NUS.
/// </summary>
/// <param name="soap_xml">The Request</param>
/// <returns></returns>
2009-08-06 04:37:39 +02:00
public string SendSOAPRequest ( string soap_xml )
{
System . Net . HttpWebRequest req = ( System . Net . HttpWebRequest ) System . Net . HttpWebRequest . Create ( "http://nus.shop.wii.com:80/nus/services/NetUpdateSOAP" ) ;
req . Method = "POST" ;
req . UserAgent = "wii libnup/1.0" ;
req . Headers . Add ( "SOAPAction" , '"' + "urn:nus.wsapi.broadon.com/" + '"' ) ;
2009-08-28 00:52:11 +02:00
// Proxy
if ( ! ( String . IsNullOrEmpty ( proxy_url ) ) )
{
WebProxy customproxy = new WebProxy ( ) ;
customproxy . Address = new Uri ( proxy_url ) ;
if ( String . IsNullOrEmpty ( proxy_usr ) )
customproxy . UseDefaultCredentials = true ;
else
{
NetworkCredential cred = new NetworkCredential ( ) ;
cred . UserName = proxy_usr ;
if ( ! ( String . IsNullOrEmpty ( proxy_pwd ) ) )
cred . Password = proxy_pwd ;
customproxy . Credentials = cred ;
}
req . Proxy = customproxy ;
WriteStatus ( " - Custom proxy settings applied!" ) ;
}
else
{
req . Proxy = WebRequest . GetSystemWebProxy ( ) ;
req . UseDefaultCredentials = true ;
}
2009-08-06 04:37:39 +02:00
Stream writeStream = req . GetRequestStream ( ) ;
UTF8Encoding encoding = new UTF8Encoding ( ) ;
byte [ ] bytes = encoding . GetBytes ( soap_xml ) ;
req . ContentType = "text/xml; charset=utf-8" ;
//req.ContentLength = bytes.Length;
writeStream . Write ( bytes , 0 , bytes . Length ) ;
writeStream . Close ( ) ;
Application . DoEvents ( ) ;
try
{
string result ;
System . Net . HttpWebResponse resp = ( System . Net . HttpWebResponse ) req . GetResponse ( ) ;
using ( Stream responseStream = resp . GetResponseStream ( ) )
{
using ( StreamReader readStream = new StreamReader ( responseStream , Encoding . UTF8 ) )
{
result = readStream . ReadToEnd ( ) ;
}
}
req . Abort ( ) ;
Application . DoEvents ( ) ;
return result ;
}
catch ( Exception ex )
{
req . Abort ( ) ;
return ex . Message . ToString ( ) ;
}
}
private void emulateUpdate_DropDownItemClicked ( object sender , ToolStripItemClickedEventArgs e )
{
// Begin Wii System Update
2009-08-28 00:52:11 +02:00
statusbox . Text = "" ;
2009-08-06 04:37:39 +02:00
WriteStatus ( "Starting Wii System Update..." ) ;
2009-08-28 00:52:11 +02:00
extrasStrip . Close ( ) ;
2009-08-06 04:37:39 +02:00
string deviceID = "4362227770" ;
string messageID = "13198105123219138" ;
string attr = "2" ;
2009-08-28 00:52:11 +02:00
string RegionID = e . ClickedItem . Text . Substring ( 0 , 3 ) ;
if ( RegionID = = "JAP" ) // Japan fix, only region not w/ 1st 3 letters same as ID.
RegionID = "JPN" ;
string CountryCode = RegionID . Substring ( 0 , 2 ) ;
/ * [ 14 : 26 ] < Galaxy | > RegionID : USA , Country : US ;
RegionID : JPN , Country : JP ;
RegionID : EUR , Country : EU ;
RegionID : KOR , Country : KO ; * /
2009-08-06 04:37:39 +02:00
string soap_req = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"" +
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
"<soapenv:Body>\n<GetSystemUpdateRequest xmlns=\"urn:nus.wsapi.broadon.com\">\n" +
"<Version>1.0</Version>\n<MessageId>" + messageID + "</MessageId>\n<DeviceId>" + deviceID + "</DeviceId>\n" +
"<RegionId>" + RegionID + "</RegionId>\n<CountryCode>" + CountryCode + "</CountryCode>\n<TitleVersion>\n<TitleId>0000000100000001</TitleId>\n" +
"<Version>2</Version>\n</TitleVersion>\n<TitleVersion>\n<TitleId>0000000100000002</TitleId>\n" +
"<Version>33</Version>\n</TitleVersion>\n<TitleVersion>\n<TitleId>0000000100000009</TitleId>\n" +
"<Version>516</Version>\n</TitleVersion>\n<Attribute>" + attr + "</Attribute>\n<AuditData></AuditData>\n" +
"</GetSystemUpdateRequest>\n</soapenv:Body>\n</soapenv:Envelope>" ;
WriteStatus ( " - Sending SOAP Request to NUS..." ) ;
2009-08-28 00:52:11 +02:00
WriteStatus ( " - Region: " + RegionID ) ;
2009-08-06 04:37:39 +02:00
string update_xml = SendSOAPRequest ( soap_req ) ;
if ( update_xml ! = null )
WriteStatus ( " - Recieved Update Info!" ) ;
else
{
WriteStatus ( " - Fail." ) ;
return ;
}
2009-08-30 02:43:24 +02:00
WriteStatus ( " - Title information:" ) ;
2009-08-06 04:37:39 +02:00
2009-08-28 05:12:10 +02:00
string script_text = "" ;
2009-08-06 04:37:39 +02:00
XmlDocument xDoc = new XmlDocument ( ) ;
xDoc . LoadXml ( update_xml ) ;
XmlNodeList TitleList = xDoc . GetElementsByTagName ( "TitleVersion" ) ;
for ( int a = 0 ; a < TitleList . Count ; a + + )
{
XmlNodeList TitleInfo = TitleList [ a ] . ChildNodes ;
string TitleID = "" ;
string Version = "" ;
for ( int b = 0 ; b < TitleInfo . Count ; b + + )
{
switch ( TitleInfo [ b ] . Name )
{
case "TitleId" :
TitleID = TitleInfo [ b ] . InnerText ;
break ;
case "Version" :
Version = TitleInfo [ b ] . InnerText ;
break ;
default :
break ;
}
}
2009-08-30 02:43:24 +02:00
WriteStatus ( String . Format ( " - {0} [v{1}]" , TitleID , Version ) ) ;
2009-08-28 00:52:11 +02:00
if ( ( File . Exists ( "database.xml" ) = = true ) & & ( ( ! ( String . IsNullOrEmpty ( NameFromDatabase ( TitleID ) ) ) ) ) )
statusbox . Text + = String . Format ( " [{0}]" , NameFromDatabase ( TitleID ) ) ;
2009-08-28 05:12:10 +02:00
script_text + = String . Format ( "{0} {1}\n" , TitleID , DisplayBytes ( NewIntegertoByteArray ( Convert . ToInt32 ( Version ) , 2 ) , "" ) ) ;
2009-08-06 04:37:39 +02:00
}
2009-08-28 05:12:10 +02:00
WriteStatus ( " - Outputting results to NUS script..." ) ;
// Current directory...
2010-07-01 23:35:12 +02:00
string currentdir = Directory . GetCurrentDirectory ( ) ;
2009-10-14 22:52:16 +02:00
if ( ! ( currentdir . EndsWith ( Path . DirectorySeparatorChar . ToString ( ) ) ) | | ! ( currentdir . EndsWith ( Path . AltDirectorySeparatorChar . ToString ( ) ) ) )
currentdir + = Path . DirectorySeparatorChar . ToString ( ) ;
2009-08-28 05:12:10 +02:00
if ( ! ( Directory . Exists ( currentdir + "scripts" ) ) )
{
Directory . CreateDirectory ( currentdir + "scripts" ) ;
2009-10-16 00:23:08 +02:00
WriteStatus ( " - Created 'scripts\' directory." ) ;
2009-08-28 05:12:10 +02:00
}
string time = RemoveIllegalCharacters ( DateTime . Now . ToShortTimeString ( ) ) ;
File . WriteAllText ( String . Format ( currentdir + "scripts\\{0}_Update_{1}_{2}_{3} {4}.nus" , RegionID , DateTime . Now . Month , DateTime . Now . Day , DateTime . Now . Year , time ) , script_text ) ;
WriteStatus ( " - Script written!" ) ;
2009-08-30 02:43:24 +02:00
WriteStatus ( " - Run this script if you feel like downloading the update!" ) ;
2009-08-06 04:37:39 +02:00
}
2009-08-07 22:06:34 +02:00
2009-08-18 07:02:23 +02:00
/// <summary>
/// Scans for certs in TMD/TIK.
/// </summary>
/// <param name="tmdortik">The tmdortik.</param>
2009-08-07 22:06:34 +02:00
private void ScanForCerts ( byte [ ] tmdortik )
{
// For some reason a few 00s are cut off, so pad it up to be safe.
tmdortik = PadToMultipleOf ( tmdortik , 16 ) ;
// Search for cert_CACP
if ( ! ( tmdortik . Length < 0x300 ) )
for ( int a = 0 ; a < ( tmdortik . Length - 0x300 ) ; a + + )
{
byte [ ] chunk = new byte [ 0x300 ] ;
for ( int b = 0 ; b < 0x300 ; b + + )
{
chunk [ b ] = tmdortik [ a + b ] ;
}
if ( Convert . ToBase64String ( ComputeSHA ( chunk ) ) = = Convert . ToBase64String ( cert_CACP_sha1 ) )
{
cert_CACP = chunk ;
WriteStatus ( " - Cert CA-CP Located!" ) ;
break ;
}
}
// Search for cert_CAXS
if ( ! ( tmdortik . Length < 0x300 ) )
for ( int a = 0 ; a < ( tmdortik . Length - 0x300 ) ; a + + )
{
byte [ ] chunk = new byte [ 0x300 ] ;
for ( int b = 0 ; b < 0x300 ; b + + )
{
chunk [ b ] = tmdortik [ a + b ] ;
}
if ( Convert . ToBase64String ( ComputeSHA ( chunk ) ) = = Convert . ToBase64String ( cert_CAXS_sha1 ) )
{
cert_CAXS = chunk ;
WriteStatus ( " - Cert CA-XS Located!" ) ;
break ;
}
}
// Search for cert_CA
2009-08-18 07:02:23 +02:00
if ( ( ! ( tmdortik . Length < 0x400 ) ) & & ( ( Convert . ToBase64String ( ComputeSHA ( cert_CA ) ) ! = Convert . ToBase64String ( cert_CA_sha1 ) ) ) )
2009-08-07 22:06:34 +02:00
{
for ( int a = 0 ; a < ( tmdortik . Length - 0x400 ) ; a + + )
{
byte [ ] chunk = new byte [ 0x400 ] ;
for ( int b = 0 ; b < 0x400 ; b + + )
{
chunk [ b ] = tmdortik [ a + b ] ;
}
if ( Convert . ToBase64String ( ComputeSHA ( chunk ) ) = = Convert . ToBase64String ( cert_CA_sha1 ) )
{
cert_CA = chunk ;
WriteStatus ( " - Cert CA Located!" ) ;
break ;
}
}
}
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Checks whether the certs are obtained.
/// </summary>
/// <returns></returns>
2009-08-07 22:06:34 +02:00
private bool CertsValid ( )
{
if ( Convert . ToBase64String ( ComputeSHA ( cert_CA ) ) ! = Convert . ToBase64String ( cert_CA_sha1 ) )
return false ;
if ( Convert . ToBase64String ( ComputeSHA ( cert_CACP ) ) ! = Convert . ToBase64String ( cert_CACP_sha1 ) )
return false ;
if ( Convert . ToBase64String ( ComputeSHA ( cert_CAXS ) ) ! = Convert . ToBase64String ( cert_CAXS_sha1 ) )
return false ;
return true ;
}
2009-08-18 07:02:23 +02:00
/// <summary>
/// Checks the whole cert file for validity.
/// </summary>
/// <param name="cert_sys">The cert_sys.</param>
/// <returns>Valid Cert state.</returns>
2009-08-07 22:06:34 +02:00
private bool TotalCertValid ( byte [ ] cert_sys )
{
if ( Convert . ToBase64String ( ComputeSHA ( cert_sys ) ) ! = Convert . ToBase64String ( cert_total_sha1 ) )
return false ;
return true ;
}
2009-08-07 22:51:53 +02:00
2009-08-18 07:02:23 +02:00
/// <summary>
/// Looks for a title's name by TitleID in Database.
/// </summary>
/// <param name="titleid">The titleid.</param>
/// <returns>Existing name; else null</returns>
2009-08-07 22:51:53 +02:00
private string NameFromDatabase ( string titleid )
{
2009-08-28 00:52:11 +02:00
// DANGER: BAD h4x HERE!!
// Fix MIOS/BC naming
if ( titleid = = "0000000100000101" )
return "MIOS" ;
else if ( titleid = = "0000000100000100" )
return "BC" ;
2009-08-07 22:51:53 +02:00
XmlDocument xDoc = new XmlDocument ( ) ;
xDoc . Load ( "database.xml" ) ;
// Variables
string [ ] XMLNodeTypes = new string [ 4 ] { "SYS" , "IOS" , "VC" , "WW" } ;
// Loop through XMLNodeTypes
for ( int i = 0 ; i < XMLNodeTypes . Length ; i + + ) // FOR THE FOUR TYPES OF NODES
{
XmlNodeList XMLSpecificNodeTypeList = xDoc . GetElementsByTagName ( XMLNodeTypes [ i ] ) ;
2009-08-28 00:52:11 +02:00
for ( int x = 0 ; x < XMLSpecificNodeTypeList . Count ; x + + ) // FOR EACH ITEM IN THE LIST OF A NODE TYPE
2009-08-07 22:51:53 +02:00
{
bool found_it = false ;
// Lol.
XmlNodeList ChildrenOfTheNode = XMLSpecificNodeTypeList [ x ] . ChildNodes ;
for ( int z = 0 ; z < ChildrenOfTheNode . Count ; z + + ) // FOR EACH CHILD NODE
{
switch ( ChildrenOfTheNode [ z ] . Name )
{
case "titleID" :
if ( ChildrenOfTheNode [ z ] . InnerText = = titleid )
found_it = true ;
else if ( ( ChildrenOfTheNode [ z ] . InnerText . Substring ( 0 , 14 ) + "XX" ) = = ( titleid . Substring ( 0 , 14 ) + "XX" ) & & ( titleid . Substring ( 0 , 14 ) ! = "00000001000000" ) )
found_it = true ;
else
found_it = false ;
break ;
default :
break ;
}
}
if ( found_it )
{
for ( int z = 0 ; z < ChildrenOfTheNode . Count ; z + + ) // FOR EACH CHILD NODE
{
switch ( ChildrenOfTheNode [ z ] . Name )
{
case "name" :
return ChildrenOfTheNode [ z ] . InnerText ;
2009-08-18 07:02:23 +02:00
default :
2009-08-07 22:51:53 +02:00
break ;
}
}
}
}
}
return null ;
}
2009-08-18 07:02:23 +02:00
private void packbox_EnabledChanged ( object sender , EventArgs e )
{
saveaswadbox . Enabled = packbox . Enabled ;
deletecontentsbox . Enabled = packbox . Enabled ;
}
2009-08-19 18:40:43 +02:00
private void saveaswadbox_Paint ( object sender , PaintEventArgs e )
{
//e.Graphics.
/ * Rectangle rect = new Rectangle ( 0 , 0 , 16 , 16 ) ;
if ( saveaswadbox . Checked )
e . Graphics . DrawImageUnscaledAndClipped ( green , rect ) ;
else
e . Graphics . DrawImageUnscaled ( orange , - 7 , - 5 ) ; * /
}
2009-08-20 19:41:08 +02:00
private void SaveProxyBtn_Click ( object sender , EventArgs e )
{
// Current directory...
2010-07-01 23:35:12 +02:00
string currentdir = Directory . GetCurrentDirectory ( ) ;
2009-10-14 22:52:16 +02:00
if ( ! ( currentdir . EndsWith ( Path . DirectorySeparatorChar . ToString ( ) ) ) | | ! ( currentdir . EndsWith ( Path . AltDirectorySeparatorChar . ToString ( ) ) ) )
currentdir + = Path . DirectorySeparatorChar . ToString ( ) ;
2009-08-20 19:41:08 +02:00
if ( ( String . IsNullOrEmpty ( ProxyURL . Text ) ) & & ( String . IsNullOrEmpty ( ProxyUser . Text ) ) & & ( ( File . Exists ( currentdir + "proxy.txt" ) ) ) )
{
File . Delete ( currentdir + "proxy.txt" ) ;
proxyBox . Visible = false ;
proxy_usr = "" ; proxy_url = "" ; proxy_pwd = "" ;
WriteStatus ( "Proxy settings deleted!" ) ;
return ;
}
else if ( ( String . IsNullOrEmpty ( ProxyURL . Text ) ) & & ( String . IsNullOrEmpty ( ProxyUser . Text ) ) & & ( ( ! ( File . Exists ( currentdir + "proxy.txt" ) ) ) ) )
{
proxyBox . Visible = false ;
WriteStatus ( "No proxy settings saved!" ) ;
return ;
}
string proxy_file = "" ;
if ( ! ( String . IsNullOrEmpty ( ProxyURL . Text ) ) )
{
proxy_file + = ProxyURL . Text + "\n" ;
proxy_url = ProxyURL . Text ;
}
if ( ! ( String . IsNullOrEmpty ( ProxyUser . Text ) ) )
{
proxy_file + = ProxyUser . Text ;
proxy_usr = ProxyUser . Text ;
}
if ( ! ( String . IsNullOrEmpty ( proxy_file ) ) )
{
File . WriteAllText ( currentdir + "proxy.txt" , proxy_file ) ;
WriteStatus ( "Proxy settings saved!" ) ;
}
proxyBox . Visible = false ;
SetAllEnabled ( false ) ;
ProxyVerifyBox . Visible = true ; ProxyVerifyBox . Enabled = true ;
ProxyPwdBox . Enabled = true ; SaveProxyBtn . Enabled = true ;
ProxyVerifyBox . Select ( ) ;
}
private void proxySettingsToolStripMenuItem_Click ( object sender , EventArgs e )
{
// Current directory...
2010-07-01 23:35:12 +02:00
string currentdir = Directory . GetCurrentDirectory ( ) ;
2009-10-14 22:52:16 +02:00
if ( ! ( currentdir . EndsWith ( Path . DirectorySeparatorChar . ToString ( ) ) ) | | ! ( currentdir . EndsWith ( Path . AltDirectorySeparatorChar . ToString ( ) ) ) )
currentdir + = Path . DirectorySeparatorChar . ToString ( ) ;
2009-08-20 19:41:08 +02:00
// Check for Proxy Settings file...
if ( File . Exists ( currentdir + "proxy.txt" ) = = true )
{
string [ ] proxy_file = File . ReadAllLines ( currentdir + "proxy.txt" ) ;
ProxyURL . Text = proxy_file [ 0 ] ;
if ( proxy_file . Length > 1 )
{
ProxyUser . Text = proxy_file [ 1 ] ;
}
}
proxyBox . Visible = true ;
}
private void button18_Click ( object sender , EventArgs e )
{
proxy_pwd = ProxyPwdBox . Text ;
ProxyVerifyBox . Visible = false ;
SetAllEnabled ( true ) ;
}
private void ProxyPwdBox_KeyPress ( object sender , KeyPressEventArgs e )
{
if ( e . KeyChar = = Convert . ToChar ( Keys . Enter ) )
button18_Click ( "LOLWUT" , EventArgs . Empty ) ;
}
2009-08-24 01:16:23 +02:00
private void ProxyAssistBtn_Click ( object sender , EventArgs e )
{
MessageBox . Show ( "If you are behind a proxy, set these settings to get through to NUS." +
" If you have an alternate port for accessing your proxy, add ':' followed by the port." +
" You will be prompted for your password each time you run NUSD, for privacy purposes." ) ;
}
2009-08-28 00:52:11 +02:00
private void enableBETATruchaFeaturesToolStripMenuItem_Click ( object sender , EventArgs e )
{
truchabox . Visible = true ;
}
private void loadNUSScriptToolStripMenuItem_Click ( object sender , EventArgs e )
{
// Current directory...
2010-07-01 23:35:12 +02:00
string currentdir = Directory . GetCurrentDirectory ( ) ;
2009-10-14 22:52:16 +02:00
if ( ! ( currentdir . EndsWith ( Path . DirectorySeparatorChar . ToString ( ) ) ) | | ! ( currentdir . EndsWith ( Path . AltDirectorySeparatorChar . ToString ( ) ) ) )
currentdir + = Path . DirectorySeparatorChar . ToString ( ) ;
2009-08-28 00:52:11 +02:00
// Open a NUS script.
OpenFileDialog ofd = new OpenFileDialog ( ) ;
ofd . Multiselect = false ;
ofd . Filter = "NUS Scripts|*.nus|All Files|*.*" ;
if ( Directory . Exists ( currentdir + "scripts" ) )
ofd . InitialDirectory = currentdir + "scripts" ;
ofd . Title = "Load a NUS/Wiimpersonator script." ;
if ( ofd . ShowDialog ( ) ! = DialogResult . Cancel )
{
script_filename = ofd . FileName ;
BackgroundWorker scripter = new BackgroundWorker ( ) ;
scripter . DoWork + = new DoWorkEventHandler ( RunScript ) ;
scripter . RunWorkerAsync ( ) ;
}
}
2009-08-30 02:43:24 +02:00
/// <summary>
/// Runs a NUS script (BG).
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> instance containing the event data.</param>
2009-08-28 00:52:11 +02:00
private void RunScript ( object sender , System . ComponentModel . DoWorkEventArgs e )
{
Control . CheckForIllegalCrossThreadCalls = false ;
2009-08-28 05:12:10 +02:00
script_mode = true ;
2009-08-30 02:43:24 +02:00
statusbox . Text = "" ;
2009-08-28 00:52:11 +02:00
WriteStatus ( "Starting script download. Please be patient!" ) ;
string [ ] NUS_Entries = File . ReadAllLines ( script_filename ) ;
WriteStatus ( String . Format ( " - Script loaded ({0} Titles)" , NUS_Entries . Length ) ) ;
for ( int a = 0 ; a < NUS_Entries . Length ; a + + )
{
// Download the title
2009-08-30 02:43:24 +02:00
WriteStatus ( String . Format ( "===== Running Download ({0}/{1}) =====" , a + 1 , NUS_Entries . Length ) ) ;
2009-08-28 00:52:11 +02:00
string [ ] title_info = NUS_Entries [ a ] . Split ( ' ' ) ;
2009-08-30 02:43:24 +02:00
// don't let the delete issue reappear...
if ( string . IsNullOrEmpty ( title_info [ 0 ] ) )
break ;
2009-08-28 00:52:11 +02:00
titleidbox . Text = title_info [ 0 ] ;
titleversion . Text = Convert . ToString ( 256 * ( byte . Parse ( title_info [ 1 ] . Substring ( 0 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ) ) ;
titleversion . Text = Convert . ToString ( Convert . ToInt32 ( titleversion . Text ) + byte . Parse ( title_info [ 1 ] . Substring ( 2 , 2 ) , System . Globalization . NumberStyles . HexNumber ) ) ;
button3_Click ( "Scripter" , EventArgs . Empty ) ;
Thread . Sleep ( 1000 ) ;
while ( NUSDownloader . IsBusy )
{
Thread . Sleep ( 1000 ) ;
}
}
2009-08-28 05:12:10 +02:00
script_mode = false ;
2009-08-28 00:52:11 +02:00
WriteStatus ( "Script completed!" ) ;
}
2009-10-14 22:52:16 +02:00
2010-06-27 20:43:36 +02:00
private void getCommonKeyMenuItem_Click ( object sender , EventArgs e )
{
WriteStatus ( "Preparing to retrieve common key..." ) ;
// Begin the epic grab for freedom
WebClient databasedl = new WebClient ( ) ;
statusbox . Refresh ( ) ;
// Proxy
if ( ! ( String . IsNullOrEmpty ( proxy_url ) ) )
{
WebProxy customproxy = new WebProxy ( ) ;
customproxy . Address = new Uri ( proxy_url ) ;
if ( String . IsNullOrEmpty ( proxy_usr ) )
customproxy . UseDefaultCredentials = true ;
else
{
NetworkCredential cred = new NetworkCredential ( ) ;
cred . UserName = proxy_usr ;
if ( ! ( String . IsNullOrEmpty ( proxy_pwd ) ) )
cred . Password = proxy_pwd ;
customproxy . Credentials = cred ;
}
databasedl . Proxy = customproxy ;
WriteStatus ( " - Custom proxy settings applied!" ) ;
}
else
{
databasedl . Proxy = WebRequest . GetSystemWebProxy ( ) ;
databasedl . UseDefaultCredentials = true ;
}
string keyspostsource = databasedl . DownloadString ( "http://hackmii.com/2008/04/keys-keys-keys/" ) ;
statusbox . Refresh ( ) ;
// Find our start point
string startofcommonkey = "Common key (" ;
keyspostsource = keyspostsource . Substring ( keyspostsource . IndexOf ( startofcommonkey ) + startofcommonkey . Length , 32 ) ;
WriteStatus ( "Got the common key as: " + keyspostsource ) ;
byte [ ] commonkey = HexStringToByteArray ( keyspostsource ) ;
if ( WriteCommonKey ( "key.bin" , commonkey ) )
{
BootChecks ( ) ;
}
}
public static string ByteArrayToHexString ( byte [ ] Bytes )
{
StringBuilder Result = new StringBuilder ( ) ;
string HexAlphabet = "0123456789ABCDEF" ;
foreach ( byte B in Bytes )
{
Result . Append ( HexAlphabet [ ( int ) ( B > > 4 ) ] ) ;
Result . Append ( HexAlphabet [ ( int ) ( B & 0xF ) ] ) ;
}
return Result . ToString ( ) ;
}
public static byte [ ] HexStringToByteArray ( string Hex )
{
byte [ ] Bytes = new byte [ Hex . Length / 2 ] ;
2010-06-29 18:06:15 +02:00
int [ ] HexValue = new int [ ] { 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 , 0x08 , 0x09 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x0A , 0x0B , 0x0C , 0x0D ,
2010-06-27 20:43:36 +02:00
0x0E , 0x0F } ;
for ( int x = 0 , i = 0 ; i < Hex . Length ; i + = 2 , x + = 1 )
{
Bytes [ x ] = ( byte ) ( HexValue [ Char . ToUpper ( Hex [ i + 0 ] ) - '0' ] < < 4 |
HexValue [ Char . ToUpper ( Hex [ i + 1 ] ) - '0' ] ) ;
}
return Bytes ;
2010-06-29 18:06:15 +02:00
}
2010-06-27 20:43:36 +02:00
2009-10-14 22:52:16 +02:00
2009-06-11 03:16:49 +02:00
}
}