From 1801f7f8cf8ecd2c195ef3626398a92e55e83ed3 Mon Sep 17 00:00:00 2001 From: "giantpune@gmail.com" Date: Mon, 3 Jan 2011 04:02:00 +0000 Subject: [PATCH] * fix bug in nand.bin class: when creating a new nand.bin, initialize fst_pos in fst entries * insert new entries in nand.bin at the start of the chain instead of at the end ( to closer mimic IOS FS behavior ) * oneswanzenegger: create /sys/cert.sys when creating a new nand.bin git-svn-id: http://wiiqt.googlecode.com/svn/trunk@42 389f4c8b-5dfe-645f-db0e-df882bc27289 --- WiiQt/nandbin.cpp | 10 +- ohneschwanzenegger/mainwindow.cpp | 430 +++++++++++++++--------------- ohneschwanzenegger/newnandbin.cpp | 97 ++++--- saveToy/readmii.txt | 11 +- 4 files changed, 288 insertions(+), 260 deletions(-) diff --git a/WiiQt/nandbin.cpp b/WiiQt/nandbin.cpp index 5c46b26..4939733 100755 --- a/WiiQt/nandbin.cpp +++ b/WiiQt/nandbin.cpp @@ -90,6 +90,9 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt fats.clear(); memset( &fsts, 0, sizeof( fst_t ) * 0x17ff ); + for( quint16 i = 0; i < 0x17ff; i++ ) + fsts[ i ].fst_pos = i; + //reserve blocks 0 - 7 for( quint16 i = 0; i < 0x40; i++ ) { @@ -1193,7 +1196,12 @@ quint16 NandBin::CreateEntry( const QString &path, quint32 uid, quint16 gid, qui if( !ret ) return 0; - fsts[ entryNo ].sib = ret; + //method 1: this works, and the nand is bootable. but doesnt mimic the IOS FS driver. ( my entries appear in reversed order when walking the FS ) + //fsts[ entryNo ].sib = ret; + + //method 2: trying to mimic the IOS FS driver ( insert new entries at the start of the chain, instead of the end ) + fsts[ ret ].sib = fsts[ parIdx ].sub; + fsts[ parIdx ].sub = ret; } QTreeWidgetItem *child = CreateItem( par, name, 0, ret, uid, gid, 0, fsts[ ret ].attr, 0 ); if( attr == NAND_FILE ) diff --git a/ohneschwanzenegger/mainwindow.cpp b/ohneschwanzenegger/mainwindow.cpp index 3090956..1d23433 100644 --- a/ohneschwanzenegger/mainwindow.cpp +++ b/ohneschwanzenegger/mainwindow.cpp @@ -56,13 +56,13 @@ void MainWindow::GetError( const QString &message, NusJob job ) { QString dataStuff = QString( "%1 items:" ).arg( job.data.size() ); for( int i = 0; i < job.data.size(); i++ ) - dataStuff += QString( " %1" ).arg( job.data.at( i ).size(), 0, 16, QChar( ' ' ) ); + dataStuff += QString( " %1" ).arg( job.data.at( i ).size(), 0, 16, QChar( ' ' ) ); QString str = tr( "Error getting title from NUS: %1" ).arg( message ); QString j = QString( "NusJob( %1, %2, %3, %4 )
" ) - .arg( job.tid, 16, 16, QChar( '0' ) ) - .arg( job.version ).arg( job.decrypt ? "decrypted" : "encrypted" ) - .arg( dataStuff ); + .arg( job.tid, 16, 16, QChar( '0' ) ) + .arg( job.version ).arg( job.decrypt ? "decrypted" : "encrypted" ) + .arg( dataStuff ); ui->plainTextEdit_log->appendHtml( str ); @@ -92,44 +92,44 @@ void MainWindow::NusIsDone() QTreeWidgetItem *item = ItemFromPath( "/title/00000001/00000002/data/setting.txt" ); if( !item ) { - quint8 reg = SETTING_TXT_UNK; - if( ui->lineEdit_tid->text().endsWith( "e", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 ) - reg = SETTING_TXT_PAL; - if( ui->lineEdit_tid->text().endsWith( "j", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 ) - reg = SETTING_TXT_JAP; - if( ui->lineEdit_tid->text().endsWith( "k", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 ) - reg = SETTING_TXT_KOR; - QByteArray ba = SettingTxtDialog::Edit( this, QByteArray(), reg ); //call a dialog to create a new setting.txt - if( !ba.isEmpty() ) //if the dialog returned anything ( cancel wasnt pressed ) write that new setting.txt to the nand - { - quint16 r = nand.CreateEntry( "/title/00000001/00000002/data/setting.txt", 0x1000, 1, NAND_FILE, NAND_READ, NAND_READ, NAND_READ ); - if( !r ) - { - ShowMessage( "Error creating setting.txt. maybe some folders are missing?" ); - } - else - { - if( !nand.SetData( r, ba) ) + quint8 reg = SETTING_TXT_UNK; + if( ui->lineEdit_tid->text().endsWith( "e", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 ) + reg = SETTING_TXT_PAL; + if( ui->lineEdit_tid->text().endsWith( "j", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 ) + reg = SETTING_TXT_JAP; + if( ui->lineEdit_tid->text().endsWith( "k", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 ) + reg = SETTING_TXT_KOR; + QByteArray ba = SettingTxtDialog::Edit( this, QByteArray(), reg ); //call a dialog to create a new setting.txt + if( !ba.isEmpty() ) //if the dialog returned anything ( cancel wasnt pressed ) write that new setting.txt to the nand { - ShowMessage( "Error writing data for setting.txt." ); + quint16 r = nand.CreateEntry( "/title/00000001/00000002/data/setting.txt", 0x1000, 1, NAND_FILE, NAND_READ, NAND_READ, NAND_READ ); + if( !r ) + { + ShowMessage( "Error creating setting.txt. maybe some folders are missing?" ); + } + else + { + if( !nand.SetData( r, ba) ) + { + ShowMessage( "Error writing data for setting.txt." ); + } + else + { + nandDirty = true; + UpdateTree(); + } + } } - else - { - nandDirty = true; - UpdateTree(); - } - } - } } //nand.Delete( "/title/00000001/00000002/content/title.tmd" ); if( nandDirty ) { - if( !FlushNand() ) - { - ShowMessage( "Error flushing nand. Maybe you used too much TP?" ); - } - nandDirty = false; + if( !FlushNand() ) + { + ShowMessage( "Error flushing nand. Maybe you used too much TP?" ); + } + nandDirty = false; } } @@ -142,7 +142,7 @@ void MainWindow::ReceiveTitleFromNus( NusJob job ) //do something with the data we got if( InstallNUSItem( job ) ) - nandDirty = true; + nandDirty = true; } @@ -150,7 +150,7 @@ void MainWindow::ReceiveTitleFromNus( NusJob job ) void MainWindow::on_pushButton_GetTitle_clicked() { if( !nandInited && !InitNand( ui->lineEdit_nandPath->text() ) ) - return; + return; bool ok = false; bool wholeUpdate = false; @@ -158,46 +158,46 @@ void MainWindow::on_pushButton_GetTitle_clicked() quint32 ver = 0; if( ui->lineEdit_tid->text().size() == 4 ) { - wholeUpdate = true; + wholeUpdate = true; } else { - tid = ui->lineEdit_tid->text().toLongLong( &ok, 16 ); - if( !ok ) - { - ShowMessage( "Error converting \"" + ui->lineEdit_tid->text() + "\" to a hex number." ); - return; - } - ver = TITLE_LATEST_VERSION; - if( !ui->lineEdit_version->text().isEmpty() ) - { - ver = ui->lineEdit_version->text().toInt( &ok, 10 ); - if( !ok ) - { - ShowMessage( "Error converting \"" + ui->lineEdit_version->text() + "\" to a decimal number." ); - return; - } - if( ver > 0xffff ) - { - ShowMessage( tr( "Version %1 is too high. Max is 65535" ).arg( ver ) ); - return; - } - } + tid = ui->lineEdit_tid->text().toLongLong( &ok, 16 ); + if( !ok ) + { + ShowMessage( "Error converting \"" + ui->lineEdit_tid->text() + "\" to a hex number." ); + return; + } + ver = TITLE_LATEST_VERSION; + if( !ui->lineEdit_version->text().isEmpty() ) + { + ver = ui->lineEdit_version->text().toInt( &ok, 10 ); + if( !ok ) + { + ShowMessage( "Error converting \"" + ui->lineEdit_version->text() + "\" to a decimal number." ); + return; + } + if( ver > 0xffff ) + { + ShowMessage( tr( "Version %1 is too high. Max is 65535" ).arg( ver ) ); + return; + } + } } //decide how we want nus to give us the title bool decrypt = true; nus.SetCachePath( ui->lineEdit_cachePath->text() ); if( wholeUpdate ) { - if( !nus.GetUpdate( ui->lineEdit_tid->text(), decrypt ) ) - { - ShowMessage( tr( "I dont know the titles that were in the %1 update" ).arg( ui->lineEdit_tid->text() ) ); - return; - } + if( !nus.GetUpdate( ui->lineEdit_tid->text(), decrypt ) ) + { + ShowMessage( tr( "I dont know the titles that were in the %1 update" ).arg( ui->lineEdit_tid->text() ) ); + return; + } } else { - nus.Get( tid, decrypt, ver ); + nus.Get( tid, decrypt, ver ); } } @@ -206,7 +206,7 @@ void MainWindow::on_pushButton_nandPath_clicked() { QString f = QFileDialog::getOpenFileName( this, tr( "Select nand.bin" ) ); if( f.isEmpty() ) - return; + return; ui->lineEdit_nandPath->setText( f ); } @@ -215,7 +215,7 @@ void MainWindow::on_pushButton_CachePathBrowse_clicked() { QString f = QFileDialog::getExistingDirectory( this, tr( "Select NUS Cache base folder" ) ); if( f.isEmpty() ) - return; + return; ui->lineEdit_cachePath->setText( f ); nus.SetCachePath( ui->lineEdit_cachePath->text() ); @@ -225,26 +225,26 @@ void MainWindow::on_pushButton_CachePathBrowse_clicked() void MainWindow::on_actionSetting_txt_triggered() { if( !nandInited ) - return; + return; QTreeWidgetItem *it = ItemFromPath( "/title/00000001/00000002/data/setting.txt" ); if( !it ) { - ShowMessage( tr( "There is no setting.txt found in %1" ) - .arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) ); - return; + ShowMessage( tr( "There is no setting.txt found in %1" ) + .arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) ); + return; } QByteArray ba = nand.GetData( "/title/00000001/00000002/data/setting.txt" ); //read the current setting.txt ba = SettingTxtDialog::Edit( this, ba ); //call a dialog to edit that existing file and store the result in the same bytearray if( !ba.isEmpty() ) //if the dialog returned anything ( cancel wasnt pressed ) write that new setting.txt to the nand dump - nand.SetData( "/title/00000001/00000002/data/setting.txt", ba ); + nand.SetData( "/title/00000001/00000002/data/setting.txt", ba ); } //nand-dump -> flush void MainWindow::on_actionFlush_triggered() { if( !nandInited ) - FlushNand(); + FlushNand(); } //nand-dump -> ImportWad @@ -252,23 +252,23 @@ void MainWindow::on_actionImportWad_triggered() { if( !nandInited && !InitNand( ui->lineEdit_nandPath->text() ) ) { - ShowMessage( tr( "Error setting the basepath of the nand to %1" ).arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) ); - return; + ShowMessage( tr( "Error setting the basepath of the nand to %1" ).arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) ); + return; } QString fn = QFileDialog::getOpenFileName( this, tr("Wad files(*.wad)"), QCoreApplication::applicationDirPath(), tr("WadFiles (*.wad)") ); if( fn.isEmpty() ) - return; + return; QByteArray data = ReadFile( fn ); if( data.isEmpty() ) - return; + return; Wad wad( data ); if( !wad.IsOk() ) { - ShowMessage( tr( "Wad data not ok for \"%1\"" ).arg( fn ) ); - return; + ShowMessage( tr( "Wad data not ok for \"%1\"" ).arg( fn ) ); + return; } //work smart, not hard... just turn the wad into a NUSJob and reused the same code to install it @@ -282,7 +282,7 @@ void MainWindow::on_actionImportWad_triggered() quint16 cnt = t.Count(); for( quint16 i = 0; i < cnt; i++ ) { - job.data << wad.Content( i ); + job.data << wad.Content( i ); } job.decrypt = true; @@ -295,7 +295,7 @@ void MainWindow::on_actionNew_nand_from_keys_triggered() { QString path = NewNandBin::GetNewNandPath( this ); if( path.isEmpty() ) - return; + return; InitNand( path ); ui->lineEdit_nandPath->setText( path ); } @@ -304,8 +304,8 @@ void MainWindow::on_pushButton_initNand_clicked() { if( ui->lineEdit_nandPath->text().isEmpty() ) { - ShowMessage( "Please enter a path for nand.bin<\b>" ); - return; + ShowMessage( "Please enter a path for nand.bin<\b>" ); + return; } InitNand( ui->lineEdit_nandPath->text() ); } @@ -316,45 +316,45 @@ bool MainWindow::InitNand( const QString &path ) sharedDirty = false; nandDirty = false; if( !nand.SetPath( path ) || !nand.InitNand() ) - return false; + return false; if( !UpdateTree() ) - return false; + return false; //setup the uid QTreeWidgetItem *it = ItemFromPath( "/sys/uid.sys" ); if( !it ) { - uid.CreateNew( true ); - if( !nand.CreateEntry( "/sys/uid.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) ) - { - ShowMessage( "Error creating new uid.sys" ); - return false; - } - uidDirty = true; + uid.CreateNew( true ); + if( !nand.CreateEntry( "/sys/uid.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) ) + { + ShowMessage( "Error creating new uid.sys" ); + return false; + } + uidDirty = true; } else { - QByteArray ba = nand.GetData( "/sys/uid.sys" ); - uid = UIDmap( ba ); + QByteArray ba = nand.GetData( "/sys/uid.sys" ); + uid = UIDmap( ba ); } //set up the shared map it = ItemFromPath( "/shared1/content.map" ); if( !it ) { - if( !nand.CreateEntry( "/shared1/content.map", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) ) - { - sharedDirty = true; - ShowMessage( "Error creating new content.map" ); - return false; - } + if( !nand.CreateEntry( "/shared1/content.map", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) ) + { + sharedDirty = true; + ShowMessage( "Error creating new content.map" ); + return false; + } } else { - QByteArray ba = nand.GetData( "/shared1/content.map" ); - shared = SharedContentMap( ba ); - if( !shared.Check() )//i really dont want to create a new one and rewrite all the contents to match it - ShowMessage( "Something about the shared map isnt right, but im using it anyways" ); + QByteArray ba = nand.GetData( "/shared1/content.map" ); + shared = SharedContentMap( ba ); + if( !shared.Check() )//i really dont want to create a new one and rewrite all the contents to match it + ShowMessage( "Something about the shared map isnt right, but im using it anyways" ); } //nand.Delete( "/title/00000001/00000002/content/title.tmd" ); @@ -372,15 +372,15 @@ bool MainWindow::FlushNand() bool r1 = true; bool r2 = true; if( uidDirty && !nand.SetData( "/sys/uid.sys", uid.Data() ) ) - r1 = false; + r1 = false; else - uidDirty = false; + uidDirty = false; if( sharedDirty && !nand.SetData( "/shared1/content.map", shared.Data() ) ) - r2 = false; + r2 = false; else - sharedDirty = false; + sharedDirty = false; return ( nand.WriteMetaData() && r1 && r2 ); } @@ -390,11 +390,11 @@ QTreeWidgetItem *MainWindow::FindItem( const QString &s, QTreeWidgetItem *parent int cnt = parent->childCount(); for( int i = 0; i child( i ); - if( r->text( 0 ) == s ) - { - return r; - } + QTreeWidgetItem *r = parent->child( i ); + if( r->text( 0 ) == s ) + { + return r; + } } return NULL; } @@ -404,20 +404,20 @@ QTreeWidgetItem *MainWindow::ItemFromPath( const QString &path ) QTreeWidgetItem *item = root; if( !path.startsWith( "/" ) || path.contains( "//" )) { - return NULL; + return NULL; } int slash = 1; while( slash ) { - int nextSlash = path.indexOf( "/", slash + 1 ); - QString lookingFor = path.mid( slash, nextSlash - slash ); - item = FindItem( lookingFor, item ); - if( !item ) - { - //qWarning() << "ItemFromPath ->item not found" << path; - return NULL; - } - slash = nextSlash + 1; + int nextSlash = path.indexOf( "/", slash + 1 ); + QString lookingFor = path.mid( slash, nextSlash - slash ); + item = FindItem( lookingFor, item ); + if( !item ) + { + //qWarning() << "ItemFromPath ->item not found" << path; + return NULL; + } + slash = nextSlash + 1; } return item; } @@ -427,10 +427,10 @@ QString MainWindow::PathFromItem( QTreeWidgetItem *item ) QString ret; while( item ) { - ret.prepend( "/" + item->text( 0 ) ); - item = item->parent(); - if( item->text( 0 ) == "/" )// dont add the root - break; + ret.prepend( "/" + item->text( 0 ) ); + item = item->parent(); + if( item->text( 0 ) == "/" )// dont add the root + break; } return ret; } @@ -439,12 +439,12 @@ bool MainWindow::UpdateTree() { //set up the tree so we know what all is in the nand without asking for it every time if( root ) - delete root; + delete root; QTreeWidgetItem *r = nand.GetTree(); if( r->childCount() != 1 || r->child( 0 )->text( 0 ) != "/" ) { - ShowMessage( "The nand FS is seriously broken. I Couldn't even find a correct root" ); - return false; + ShowMessage( "The nand FS is seriously broken. I Couldn't even find a correct root" ); + return false; } root = r->takeChild( 0 ); delete r; @@ -454,14 +454,14 @@ bool MainWindow::UpdateTree() quint16 MainWindow::CreateIfNeeded( const QString &path, quint32 uid, quint16 gid, quint8 attr, quint8 user_perm, quint8 group_perm, quint8 other_perm ) { -// qDebug() << "MainWindow::CreateIfNeeded" << path; + // qDebug() << "MainWindow::CreateIfNeeded" << path; QTreeWidgetItem *item = ItemFromPath( path ); if( !item ) { - quint16 ret = nand.CreateEntry( path, uid, gid, attr, user_perm, group_perm, other_perm ); - if( ret && UpdateTree() ) - return ret; - return 0; + quint16 ret = nand.CreateEntry( path, uid, gid, attr, user_perm, group_perm, other_perm ); + if( ret && UpdateTree() ) + return ret; + return 0; } //TODO - if the item already exists, check that its attributes match the expected ones return item->text( 1 ).toInt(); @@ -472,13 +472,13 @@ bool MainWindow::InstallSharedContent( const QByteArray stuff, const QByteArray //qDebug() << "MainWindow::InstallSharedContent"; QByteArray h; if( hash.isEmpty() ) - h = GetSha1( stuff ); + h = GetSha1( stuff ); else - h = hash; + h = hash; QString cid = shared.GetAppFromHash( hash ); if( !cid.isEmpty() ) //this one is already installed - return true; + return true; //qDebug() << "will create new"; //get next available cid in the shared map @@ -490,7 +490,7 @@ bool MainWindow::InstallSharedContent( const QByteArray stuff, const QByteArray //create the file quint16 r = CreateIfNeeded( "/shared1/" + cid + ".app", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ); if( !r ) - return false; + return false; //write the data to the file return nand.SetData( r, stuff ); @@ -509,9 +509,9 @@ bool MainWindow::InstallNUSItem( NusJob job ) QTreeWidgetItem *content; if( !job.tid || !job.data.size() > 2 ) { - qWarning() << "bad sizes"; - ShowMessage( "Error installing title " + title + " to nand" ); - return false; + qWarning() << "bad sizes"; + ShowMessage( "Error installing title " + title + " to nand" ); + return false; } QString tid = QString( "%1" ).arg( job.tid, 16, 16, QChar( '0' ) ); QString upper = tid.left( 8 ); @@ -521,19 +521,19 @@ bool MainWindow::InstallNUSItem( NusJob job ) Ticket ticket( job.data.takeFirst() ); if( t.Tid() != job.tid || ticket.Tid() != job.tid ) { - qWarning() << "bad tid"; - goto error; + qWarning() << "bad tid"; + goto error; } cnt = t.Count(); if( job.data.size() != cnt ) { - qWarning() << "content count"; - goto error; + qWarning() << "content count"; + goto error; } //qDebug() << "uidDirty" << uidDirty; if( !uidDirty ) { - uidDirty = !uid.GetUid( job.tid, false ); + uidDirty = !uid.GetUid( job.tid, false ); } //qDebug() << "uidDirty" << uidDirty; _uid = uid.GetUid( job.tid ); @@ -541,8 +541,8 @@ bool MainWindow::InstallNUSItem( NusJob job ) _gid = t.Gid(); if( !_uid ) { - qWarning() << "no uid"; - goto error; + qWarning() << "no uid"; + goto error; } //create all the folders @@ -566,15 +566,15 @@ bool MainWindow::InstallNUSItem( NusJob job ) cnt = content->childCount(); for ( quint16 i = 0; i < cnt; i++ ) { - if( !nand.Delete( "/title/" + upper + "/" + lower + "/content/" + content->child( i )->text( 0 ) ) ) + if( !nand.Delete( "/title/" + upper + "/" + lower + "/content/" + content->child( i )->text( 0 ) ) ) { qWarning() << "error deleting old title"; goto error; } - deleted = true; + deleted = true; } if( deleted ) { - //nand.WriteMetaData(); - UpdateTree(); - ShowMessage( tr( "Deleted old TMD and private contents for
%1" ).arg( title ) ); + //nand.WriteMetaData(); + UpdateTree(); + ShowMessage( tr( "Deleted old TMD and private contents for
%1" ).arg( title ) ); } cnt = t.Count(); @@ -597,64 +597,64 @@ bool MainWindow::InstallNUSItem( NusJob job ) //qDebug() << "will install" << cnt << "contents"; for( quint16 i = 0; i < cnt; i++ ) { - //qDebug() << "installing" << i; - //make sure the data is decrypted - QByteArray decData; - QByteArray hash; - if( job.decrypt ) - { - decData = job.data.takeFirst(); - if( (quint32)decData.size() != t.Size( i ) ) - { - qDebug() << "wtf - size"; - decData.resize( t.Size( i ) ); - } - } - else - { - //decrypt the data - QByteArray encData = job.data.takeFirst(); - AesSetKey( ticket.DecryptedKey() ); - decData = AesDecrypt( i, encData ); - decData.resize( t.Size( i ) ); - } + //qDebug() << "installing" << i; + //make sure the data is decrypted + QByteArray decData; + QByteArray hash; + if( job.decrypt ) + { + decData = job.data.takeFirst(); + if( (quint32)decData.size() != t.Size( i ) ) + { + qDebug() << "wtf - size"; + decData.resize( t.Size( i ) ); + } + } + else + { + //decrypt the data + QByteArray encData = job.data.takeFirst(); + AesSetKey( ticket.DecryptedKey() ); + decData = AesDecrypt( i, encData ); + decData.resize( t.Size( i ) ); + } - //check the hash - hash = GetSha1( decData ); - if( hash != t.Hash( i ) ) - { - qWarning() << "hash" << i << "\n" << hash.toHex() << "\n" << t.Hash( i ).toHex(); - goto error; - } + //check the hash + hash = GetSha1( decData ); + if( hash != t.Hash( i ) ) + { + qWarning() << "hash" << i << "\n" << hash.toHex() << "\n" << t.Hash( i ).toHex(); + goto error; + } - //install the content - if( t.Type( i ) == 1 )//private - { - r = CreateIfNeeded( "/title/" + upper + "/" + lower + "/content/" + t.Cid( i ) + ".app" , 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ); - if( !r ) - { - qWarning() << "cant create content" << i; - goto error; - } - if ( !nand.SetData( r, decData ) ) - { - qWarning() << "cant write content" << i; - goto error; - } - } - else if( t.Type( i ) == 0x8001 )//shared - { - if ( !InstallSharedContent( decData, hash ) ) - { - qWarning() << "error installing shared" << i << hash.toHex(); - goto error; - } - } - else - { - qWarning() << "type" << hex << t.Type( i ); - goto error; - } + //install the content + if( t.Type( i ) == 1 )//private + { + r = CreateIfNeeded( "/title/" + upper + "/" + lower + "/content/" + t.Cid( i ) + ".app" , 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ); + if( !r ) + { + qWarning() << "cant create content" << i; + goto error; + } + if ( !nand.SetData( r, decData ) ) + { + qWarning() << "cant write content" << i; + goto error; + } + } + else if( t.Type( i ) == 0x8001 )//shared + { + if ( !InstallSharedContent( decData, hash ) ) + { + qWarning() << "error installing shared" << i << hash.toHex(); + goto error; + } + } + else + { + qWarning() << "type" << hex << t.Type( i ); + goto error; + } } qDebug() << "done installing"; ShowMessage( "Installed title " + title + " to nand" ); @@ -662,7 +662,7 @@ bool MainWindow::InstallNUSItem( NusJob job ) //nand.Delete( "/title/" + upper ); //UpdateTree(); return true; -error: + error: ShowMessage( "Error installing title " + title + " to nand" ); return false; } @@ -671,9 +671,9 @@ error: void MainWindow::on_actionAbout_triggered() { QString txt = tr( "This is an example program from WiiQt. It is designed to write titles to a nand.bin and even create one from scratch." - "

PLEASE BE AWARE, THIS IS NOT VERY WELL TESTED AND AS OF RIGHT NOW." - " IT SHOULD ONLY BE USED BY PEOPLE THAT KNOW HOW TO VERIFY THE FILES IT PRODUCES. AND HAVE A WAY TO FIX A BRICKED WII SHOULD THIS PROGRAM HAVE BUGS" - "

YOU HAVE BEEN WARNED" - "
giantpune" ); + "

PLEASE BE AWARE, THIS IS NOT VERY WELL TESTED AND AS OF RIGHT NOW." + " IT SHOULD ONLY BE USED BY PEOPLE THAT KNOW HOW TO VERIFY THE FILES IT PRODUCES. AND HAVE A WAY TO FIX A BRICKED WII SHOULD THIS PROGRAM HAVE BUGS" + "

YOU HAVE BEEN WARNED" + "
giantpune" ); QMessageBox::critical( this, tr( "About" ), txt ); } diff --git a/ohneschwanzenegger/newnandbin.cpp b/ohneschwanzenegger/newnandbin.cpp index da295d1..aefb633 100644 --- a/ohneschwanzenegger/newnandbin.cpp +++ b/ohneschwanzenegger/newnandbin.cpp @@ -8,9 +8,9 @@ NewNandBin::NewNandBin( QWidget *parent, QList badBlocks ) : QDialog(pa ui->setupUi(this); foreach( quint16 block, badBlocks ) { - QString txt = QString( "%1" ).arg( block ); - if( !ui->listWidget_badBlocks->findItems( txt, Qt::MatchExactly ).isEmpty() ) - ui->listWidget_badBlocks->addItem( txt ); + QString txt = QString( "%1" ).arg( block ); + if( !ui->listWidget_badBlocks->findItems( txt, Qt::MatchExactly ).isEmpty() ) + ui->listWidget_badBlocks->addItem( txt ); } } @@ -23,7 +23,7 @@ void NewNandBin::on_pushButton_keys_clicked() { QString f = QFileDialog::getOpenFileName( this, tr( "Select Keys.bin" ), dir ); if( f.isEmpty() ) - return; + return; ui->lineEdit_keys->setText( f ); dir = QFileInfo( f ).canonicalPath(); } @@ -32,7 +32,7 @@ void NewNandBin::on_pushButton_boot_clicked() { QString f = QFileDialog::getOpenFileName( this, tr( "Select Boot 1 & 2" ), dir ); if( f.isEmpty() ) - return; + return; ui->lineEdit_boot->setText( f ); dir = QFileInfo( f ).canonicalPath(); } @@ -41,7 +41,7 @@ void NewNandBin::on_pushButton_dest_clicked() { QString f = QFileDialog::getSaveFileName( this, tr( "Output file" ), dir ); if( f.isEmpty() ) - return; + return; ui->lineEdit_dest->setText( f ); dir = QFileInfo( f ).canonicalPath(); } @@ -52,10 +52,10 @@ QList NewNandBin::BadBlocks() quint16 cnt = ui->listWidget_badBlocks->count(); for( quint16 i = 0; i < cnt; i++ ) { - bool ok = false; - quint16 num = ui->listWidget_badBlocks->item( i )->text().toInt( &ok ); - if( ok ) - ret << num; + bool ok = false; + quint16 num = ui->listWidget_badBlocks->item( i )->text().toInt( &ok ); + if( ok ) + ret << num; } return ret; } @@ -65,7 +65,7 @@ void NewNandBin::on_pushButton_bb_add_clicked() quint16 val = ui->spinBox->value(); if( !BadBlocks().contains( val ) ) { - ui->listWidget_badBlocks->addItem( QString( "%1" ).arg( val ) ); + ui->listWidget_badBlocks->addItem( QString( "%1" ).arg( val ) ); } } @@ -74,8 +74,8 @@ void NewNandBin::on_pushButton_bb_rm_clicked() QList items = ui->listWidget_badBlocks->selectedItems(); foreach( QListWidgetItem *item, items ) { - ui->listWidget_badBlocks->removeItemWidget( item ); - delete item; + ui->listWidget_badBlocks->removeItemWidget( item ); + delete item; } } @@ -84,35 +84,48 @@ void NewNandBin::on_buttonBox_accepted() { if( ui->lineEdit_keys->text().isEmpty() || ui->lineEdit_boot->text().isEmpty() || ui->lineEdit_dest->text().isEmpty() ) { - QMessageBox::warning( this, tr( "Error" ), tr( "Required feilds are empty" ) ); - return; + QMessageBox::warning( this, tr( "Error" ), tr( "Required feilds are empty" ) ); + return; } QByteArray keys = ReadFile( ui->lineEdit_keys->text() ); QByteArray boots = ReadFile( ui->lineEdit_boot->text() ); if( keys.size() != 0x400 || boots.size() != 0x108000 ) { - QMessageBox::warning( this, tr( "Error" ), tr( "The keys or boot1/2 is not correct" ) ); - return; + QMessageBox::warning( this, tr( "Error" ), tr( "The keys or boot1/2 is not correct" ) ); + return; } if( !nand.CreateNew( ui->lineEdit_dest->text(), keys, boots, BadBlocks() ) ) { - qDebug() << "error creating nand.bin"; - return; + qDebug() << "error creating nand.bin"; + return; } //qDebug() << "created nand, trying to add default entries"; if( !nand.CreateEntry( "/sys", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 ) - || !nand.CreateEntry( "/ticket", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 ) - || !nand.CreateEntry( "/title", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_READ ) - || !nand.CreateEntry( "/shared1", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 ) - || !nand.CreateEntry( "/shared2", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW ) - || !nand.CreateEntry( "/import", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 ) - || !nand.CreateEntry( "/meta", 0x1000, 1, NAND_DIR, NAND_RW, NAND_RW, NAND_RW ) - || !nand.CreateEntry( "/tmp", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW ) - || !nand.WriteMetaData() ) + || !nand.CreateEntry( "/ticket", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 ) + || !nand.CreateEntry( "/title", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_READ ) + || !nand.CreateEntry( "/shared1", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 ) + || !nand.CreateEntry( "/shared2", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW ) + || !nand.CreateEntry( "/import", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 ) + || !nand.CreateEntry( "/meta", 0x1000, 1, NAND_DIR, NAND_RW, NAND_RW, NAND_RW ) + || !nand.CreateEntry( "/tmp", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW ) + || !nand.WriteMetaData() ) { - qWarning() << "NewNandBin::on_buttonBox_accepted -> error creating the new nand"; - return; + qWarning() << "NewNandBin::on_buttonBox_accepted -> error creating directories in the new nand"; + return; } + //add cert.sys + quint16 handle = nand.CreateEntry( "/sys/cert.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, NAND_READ ); + if( !handle || !nand.SetData( "/sys/cert.sys", QByteArray( (const char*)&certs_dat, CERTS_DAT_SIZE ) ) ) + { + qWarning() << "NewNandBin::on_buttonBox_accepted -> error creating cert in the new nand"; + return; + } + //commit changes to metadata + if( !nand.WriteMetaData() ) + { + qWarning() << "NewNandBin::on_buttonBox_accepted -> error writing metadata"; + return; + } ret = ui->lineEdit_dest->text(); } @@ -121,7 +134,7 @@ QString NewNandBin::GetNewNandPath( QWidget *parent, QList badBlocks ) { NewNandBin d( parent, badBlocks ); if( !d.exec() ) - return QString(); + return QString(); return d.ret; } @@ -130,13 +143,13 @@ void NewNandBin::on_pushButton_badBlockFile_clicked() { QString f = QFileDialog::getOpenFileName( this, tr( "Select File with Bad Block List" ), dir ); if( f.isEmpty() ) - return; + return; dir = QFileInfo( f ).canonicalPath(); QString str = QString( ReadFile( f ) ); if( str.isEmpty() ) { - qWarning() << "NewNandBin::on_pushButton_badBlockFile_clicked -> error reading file"; - return; + qWarning() << "NewNandBin::on_pushButton_badBlockFile_clicked -> error reading file"; + return; } ui->listWidget_badBlocks->clear(); @@ -144,17 +157,17 @@ void NewNandBin::on_pushButton_badBlockFile_clicked() QStringList lines = str.split( "\n", QString::SkipEmptyParts ); foreach( QString line, lines ) { - if( line.size() > 5 ) - continue; - bool ok = false; + if( line.size() > 5 ) + continue; + bool ok = false; - if( ui->listWidget_badBlocks->findItems( line, Qt::MatchExactly ).size() )//this one is already in the list - continue; + if( ui->listWidget_badBlocks->findItems( line, Qt::MatchExactly ).size() )//this one is already in the list + continue; - quint16 bb = line.toInt( &ok ); - if( !ok || bb < 8 || bb > 4079 ) - continue; + quint16 bb = line.toInt( &ok ); + if( !ok || bb < 8 || bb > 4079 ) + continue; - ui->listWidget_badBlocks->addItem( line ); + ui->listWidget_badBlocks->addItem( line ); } } diff --git a/saveToy/readmii.txt b/saveToy/readmii.txt index 0d22e39..b985f87 100644 --- a/saveToy/readmii.txt +++ b/saveToy/readmii.txt @@ -1,4 +1,11 @@ -this is a tool to list saves in an extracted nand dump +this is a tool to list/extract/delete saves to/from an extracted nand dump. saves are extracted, packed into a data.bin, zipped up with a txt file + that says a bit about the save, and then stored in a folder. you must designate a folder and provide the necessary keys before extracting saves +will work. i chose to go with data.bin as it is a way to store the entire save in 1 file and also allow the save to be installed using the +system menu. and i went with the zip format 1) to save space, and 2) to keep a save and the description all in 1 compact file. + +saves are extracted to "///#.zip". the # is chosen by the lowest available number starting with 1. +there is no need for the saves to be in numerical order, if you have 10 zips for the same game and you decide to delete "3.zip", it will cause +no issues, and next time you extract a save for this game, it will use the filename "3.zip". TODO: -add some sort of extract/delete/install functionality +installing saves back to sneek nand still isnt done