From 7ed92b3fdaa2b857ca4e50bdb3acc73b6bcad233 Mon Sep 17 00:00:00 2001 From: "giantpune@gmail.com" Date: Sat, 15 Jan 2011 22:21:43 +0000 Subject: [PATCH] * fix bug in NUS downloader that added some titles to the list and then used another list, forgetting about the first 2 titles * fix bug in nandBin class when the current superblock was the last one --- WiiQt/nandbin.cpp | 322 +++++++++++++++++++++--------- WiiQt/nusdownloader.cpp | 14 +- nandBinCheck/main.cpp | 19 +- ohneschwanzenegger/mainwindow.cpp | 93 ++++++--- ohneschwanzenegger/mainwindow.h | 3 + saveToy/ngdialog.cpp | 24 ++- 6 files changed, 336 insertions(+), 139 deletions(-) diff --git a/WiiQt/nandbin.cpp b/WiiQt/nandbin.cpp index 2b9bc1c..8cf4817 100755 --- a/WiiQt/nandbin.cpp +++ b/WiiQt/nandbin.cpp @@ -48,115 +48,241 @@ bool NandBin::SetPath( const QString &path ) return ret; } - +#if 0 // apparently you dont need any extra reserved blocks for the thing to boot? bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList &badBlocks ) { #ifndef NAND_BIN_CAN_WRITE - qWarning() << __FILE__ << "was built without write support"; - return false; + qWarning() << __FILE__ << "was built without write support"; + return false; #endif - if( keys.size() != 0x400 || first8.size() != 0x108000 ) - { - qWarning() << "NandBin::CreateNew -> bad sizes" << hex << keys.size() << first8.size(); - return false; - } + if( keys.size() != 0x400 || first8.size() != 0x108000 ) + { + qWarning() << "NandBin::CreateNew -> bad sizes" << hex << keys.size() << first8.size(); + return false; + } - if( f.isOpen() ) - f.close(); + if( f.isOpen() ) + f.close(); - //create the new file, write the first 8 blocks, fill it with 0xff, and write the keys.bin at the end - f.setFileName( path ); - if( !f.open( QIODevice::ReadWrite | QIODevice::Truncate ) ) - { - qWarning() << "NandBin::CreateNew -> can't create file" << path; - return false; - } + //create the new file, write the first 8 blocks, fill it with 0xff, and write the keys.bin at the end + f.setFileName( path ); + if( !f.open( QIODevice::ReadWrite | QIODevice::Truncate ) ) + { + qWarning() << "NandBin::CreateNew -> can't create file" << path; + return false; + } - f.write( first8 ); - QByteArray block( 0x4200, 0xff );//generic empty block - for( quint16 i = 0; i < 0x7fc0; i++ ) - f.write( block ); + f.write( first8 ); + QByteArray block( 0x4200, 0xff );//generic empty block + for( quint16 i = 0; i < 0x7fc0; i++ ) + f.write( block ); - f.write( keys ); - if( f.pos() != 0x21000400 )//no room left on the drive? - { - qWarning() << "NandBin::CreateNew -> dump size is wrong" << (quint32)f.pos(); - return false; - } + f.write( keys ); + if( f.pos() != 0x21000400 )//no room left on the drive? + { + qWarning() << "NandBin::CreateNew -> dump size is wrong" << (quint32)f.pos(); + return false; + } - //setup variables - nandPath = path; - currentSuperCluster = 0x7f00; - superClusterVersion = 1; - type = 2; - fats.clear(); - memset( &fsts, 0, sizeof( fst_t ) * 0x17ff ); + //setup variables + nandPath = path; + currentSuperCluster = 0x7f00; + superClusterVersion = 0xf0000000; + type = 2; + 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++ ) - { - fats << 0xfffc; - } - //find 90 blocks to reserve. they always appear to be close to the end of the nand - //TODO - this isnt always 90, all my nands have a different number, and 90 is right in the middle - quint16 bCnt = badBlocks.size(); - quint16 offset = 0; - for( quint16 i = 0; i < bCnt; i++ ) - { - if( i >= 3998 ) - offset++; - } + //reserve blocks 0 - 7 + for( quint16 i = 0; i < 0x40; i++ ) + { + fats << 0xfffc; + } + //find 90 blocks to reserve. they always appear to be close to the end of the nand + //TODO - this isnt always 90, all my nands have a different number, and 90 is right in the middle + //quint16 bCnt = badBlocks.size(); + /*quint16 offset = 0; + for( quint16 i = 0; i < bCnt; i++ ) + { + if( i >= 3998 ) + offset++; + }*/ - //mark all the "normal" blocks - free, or bad - for( quint16 i = 0x40; i < 0x7cf0 - bCnt; i++ ) - { - if( badBlocks.contains( i / 8 ) ) - fats << 0xfffd; - else - fats << 0xfffe; + //mark all the "normal" blocks - free, or bad + for( quint16 i = 0x40; i < 0x7f00; i++ ) + { + if( badBlocks.contains( i / 8 ) ) + fats << 0xfffd; + else + fats << 0xfffe; - } - //mark the 90 reserved ones from above and reserve the superclusters - for( quint16 i = 0x7cf0 - bCnt; i < 0x8000; i++ ) - { - fats << 0xfffc; - } + } + //mark the 90 reserved ones from above and reserve the superclusters + for( quint16 i = 0x7f00; i < 0x8000; i++ ) + { + fats << 0xfffc; + } - //make the root item - fsts[ 0 ].filename[ 0 ] = '/'; - fsts[ 0 ].attr = 0x16; - fsts[ 0 ].sib = 0xffff; - fsts[ 0 ].sub = 0xffff; + //make the root item + fsts[ 0 ].filename[ 0 ] = '/'; + fsts[ 0 ].attr = 0x16; + fsts[ 0 ].sib = 0xffff; + fsts[ 0 ].sub = 0xffff; - fstInited = true; + fstInited = true; - //set keys - QByteArray hmacKey = keys.mid( 0x144, 0x14 ); - spare.SetHMacKey( hmacKey );//set the hmac key for calculating spare data - key = keys.mid( 0x158, 0x10 ); + //set keys + QByteArray hmacKey = keys.mid( 0x144, 0x14 ); + spare.SetHMacKey( hmacKey );//set the hmac key for calculating spare data + key = keys.mid( 0x158, 0x10 ); - //write the metada to each of the superblocks - for( quint8 i = 0; i < 0x10; i++ ) - { - if( !WriteMetaData() ) - { - qWarning() << "NandBin::CreateNew -> error writing superblock" << i; - return false; - } - } + //write the metada to each of the superblocks + for( quint8 i = 0; i < 0x10; i++ ) + { + if( !WriteMetaData() ) + { + qWarning() << "NandBin::CreateNew -> error writing superblock" << i; + return false; + } + } - //build the tree - if( root ) - delete root; - root = new QTreeWidgetItem( QStringList() << nandPath ); - AddChildren( root, 0 ); + //build the tree + if( root ) + delete root; + root = new QTreeWidgetItem( QStringList() << nandPath ); + AddChildren( root, 0 ); - return true; + return true; } +#endif +//#if 0 // this boots ok on real HW +bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList &badBlocks ) +{ +#ifndef NAND_BIN_CAN_WRITE + qWarning() << __FILE__ << "was built without write support"; + return false; +#endif + if( keys.size() != 0x400 || first8.size() != 0x108000 ) + { + qWarning() << "NandBin::CreateNew -> bad sizes" << hex << keys.size() << first8.size(); + return false; + } + for( quint16 i = 0; i < 0x40; i++ ) + { + if( badBlocks.contains( i / 8 ) ) + { + qWarning() << "NandBin::CreateNew -> creating a nand with bad blocks in the first 8 is not supported"; + return false; + } + } + for( quint16 i = 0x7f00; i < 0x8000; i++ ) + { + if( badBlocks.contains( i / 8 ) ) + { + qWarning() << "NandBin::CreateNew -> creating a nand with bad blocks in the superclusters not supported"; + return false; + } + } + + if( f.isOpen() ) + f.close(); + + //create the new file, write the first 8 blocks, fill it with 0xff, and write the keys.bin at the end + f.setFileName( path ); + if( !f.open( QIODevice::ReadWrite | QIODevice::Truncate ) ) + { + qWarning() << "NandBin::CreateNew -> can't create file" << path; + return false; + } + + f.write( first8 ); + QByteArray block( 0x4200, 0xff );//generic empty block + for( quint16 i = 0; i < 0x7fc0; i++ ) + f.write( block ); + + f.write( keys ); + if( f.pos() != 0x21000400 )//no room left on the drive? + { + qWarning() << "NandBin::CreateNew -> dump size is wrong" << (quint32)f.pos(); + return false; + } + + //setup variables + nandPath = path; + currentSuperCluster = 0x7f00; + superClusterVersion = 1; + type = 2; + 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++ ) + { + fats << 0xfffc; + } + //find 90 blocks to reserve. they always appear to be close to the end of the nand + //TODO - this isnt always 90, all my nands have a different number, and 90 is right in the middle + quint16 bCnt = badBlocks.size(); + quint16 offset = 0; + for( quint16 i = 0; i < bCnt; i++ ) + { + if( i >= 3998 ) + offset++; + } + + //mark all the "normal" blocks - free, or bad + for( quint16 i = 0x40; i < 0x7cf0 - offset; i++ ) + { + if( badBlocks.contains( i / 8 ) ) + fats << 0xfffd; + else + fats << 0xfffe; + + } + //mark the 90 reserved ones from above and reserve the superclusters + for( quint16 i = 0x7cf0 - offset; i < 0x8000; i++ ) + { + fats << 0xfffc; + } + + //make the root item + fsts[ 0 ].filename[ 0 ] = '/'; + fsts[ 0 ].attr = 0x16; + fsts[ 0 ].sib = 0xffff; + fsts[ 0 ].sub = 0xffff; + + fstInited = true; + + //set keys + QByteArray hmacKey = keys.mid( 0x144, 0x14 ); + spare.SetHMacKey( hmacKey );//set the hmac key for calculating spare data + key = keys.mid( 0x158, 0x10 ); + + //write the metada to each of the superblocks + for( quint8 i = 0; i < 0x10; i++ ) + { + if( !WriteMetaData() ) + { + qWarning() << "NandBin::CreateNew -> error writing superblock" << i; + return false; + } + } + + //build the tree + if( root ) + delete root; + root = new QTreeWidgetItem( QStringList() << nandPath ); + AddChildren( root, 0 ); + + return true; +} +//#endif QTreeWidgetItem *NandBin::GetTree() { //qDebug() << "NandBin::GetTree()"; @@ -334,8 +460,9 @@ bool NandBin::ExtractFile( fst_t fst, const QString &parent ) emit SendText( tr( "Extracting \"%1\"" ).arg( fi.absoluteFilePath() ) ); QByteArray data = GetFile( fst ); - if( fst.size && !data.size() )//dont worry if files dont have anything in them anyways - return false; + if( fst.size && !data.size() )//dont worry if files dont have anything in them anyways + //return true; + return false; if( !WriteFile( fi.absoluteFilePath(), data ) ) { @@ -588,28 +715,36 @@ qint32 NandBin::FindSuperblock() f.read( (char*)¤t, 4 ); current = qFromBigEndian( current ); - //qDebug() << "superblock" << hex << current << currentSuperCluster << loc; + //qDebug() << "superblock" << hex << current << currentSuperCluster << loc; if( current > superClusterVersion ) superClusterVersion = current; else { //qDebug() << "using superblock" << hex << superClusterVersion << currentSuperCluster - 0x10 << f.pos() - n_len[ type ]; - currentSuperCluster -= ( 0x10 * rewind ); - loc -= ( n_len[ type ] * rewind ); + //currentSuperCluster -= ( 0x10 * rewind ); + //loc -= ( n_len[ type ] * rewind ); + rewind = 1; break; } + if( loc == n_end[ type ] ) + { + rewind = 1; + } } if( !superClusterVersion ) return -1; - //qDebug() << "using superblock" << hex << superClusterVersion << currentSuperCluster << "page:" << ( loc / 0x840 ); + currentSuperCluster -= ( 0x10 * rewind ); + loc -= ( n_len[ type ] * rewind ); + + //qDebug() << "using superblock" << hex << superClusterVersion << currentSuperCluster << "page:" << ( loc / 0x840 ); return loc; } fst_t NandBin::GetFST( quint16 entry ) { - //qDebug() << "NandBin::GetFST(" << hex << entry << ")"; + //qDebug() << "NandBin::GetFST(" << hex << entry << ")"; fst_t fst; if( entry >= 0x17FF ) { @@ -627,6 +762,7 @@ fst_t NandBin::GetFST( quint16 entry ) int loc_entry = ( ( ( entry / 0x40 ) * n_fst[ type ] ) + entry ) * 0x20; if( (quint32)f.size() < loc_fst + loc_entry + sizeof( fst_t ) ) { + qDebug() << hex << (quint32)f.size() << loc_fst << loc_entry << type << n_fst[ type ]; emit SendError( tr( "Tried to read fst_t beyond size of nand.bin" ) ); fst.filename[ 0 ] = '\0'; return fst; diff --git a/WiiQt/nusdownloader.cpp b/WiiQt/nusdownloader.cpp index 11f11c4..16ba989 100644 --- a/WiiQt/nusdownloader.cpp +++ b/WiiQt/nusdownloader.cpp @@ -531,11 +531,7 @@ bool NusDownloader::GetUpdate( const QString & upd, bool decrypt ) QString s = upd.toLower(); QMap< quint64, quint16 > titles; - //hell, give everybody these. - titles.insert( 0x1000248414741ull, 0x3 );//news channel HAGA - titles.insert( 0x1000248414641ull, 0x3 );//Weather Channel HAFA - - if( s == "2.1e" ) titles = List21e(); + if( s == "2.1e" ) titles = List21e(); else if( s == "3.0e" ) titles = List30e(); else if( s == "3.1e" ) titles = List31e(); else if( s == "3.3e" ) titles = List33e(); @@ -572,6 +568,10 @@ bool NusDownloader::GetUpdate( const QString & upd, bool decrypt ) else return false;//unknown update + //hell, give everybody these. + titles.insert( 0x1000248414741ull, 0x3 );//news channel HAGA + titles.insert( 0x1000248414641ull, 0x3 );//Weather Channel HAFA + QMap< quint64, quint16 >::ConstIterator i = titles.begin(); while( i != titles.end() ) { @@ -855,8 +855,8 @@ QMap< quint64, quint16 > NusDownloader::List30e() titles.insert( 0x1000248414341ull, 4 );//nigaoeNRv4 - MII titles.insert( 0x1000248414141ull, 0x1 );//photov1 titles.insert( 0x1000248414241ull, 7 );//shoppingv7 - titles.insert( 0x1000248414741ull, 0x3 );//news channel HAGA - titles.insert( 0x1000248414641ull, 0x3 );//Weather Channel HAFA +// titles.insert( 0x1000248414741ull, 0x3 );//news channel HAGA +// titles.insert( 0x1000248414641ull, 0x3 );//Weather Channel HAFA return titles; } diff --git a/nandBinCheck/main.cpp b/nandBinCheck/main.cpp index 01b90ab..a49852f 100644 --- a/nandBinCheck/main.cpp +++ b/nandBinCheck/main.cpp @@ -14,6 +14,7 @@ QList< quint64 > tids; QList< quint64 > validIoses;//dont put stubs in this list. QTreeWidgetItem *root; QList fats; +quint32 verbose = 0; bool CheckTitleIntegrity( quint64 tid ); @@ -29,8 +30,9 @@ void Usage() qDebug() << " check installed titles for required IOS, proper uid & gid"; qDebug() << " -clInfo shows free, used, and lost ( marked used, but dont belong to any file ) clusters"; qDebug() << " -spare calculate & compare ecc for all pages in the nand"; - qDebug() << " calculate & compare hmac signatures for all files and superblocks"; - qDebug() << " -all does all of the above"; + qDebug() << " calculate & compare hmac signatures for all files and superblocks"; + qDebug() << " -all does all of the above"; + qDebug() << " -v increase verbosity"; exit( 1 ); } @@ -370,18 +372,23 @@ bool CheckTitleIntegrity( quint64 tid ) t = Tmd( ba ); if( t.Tid() != tid ) { - qDebug() << "the TMD contains the wrong TID"; + qDebug() << "\tthe TMD contains the wrong TID"; return false; } + if( verbose ) + { + qDebug() << "\tversion:" << t.Version() << hex << t.Version(); + qDebug() << "\taccess :" << hex << t.AccessFlags(); + } } else { Ticket ticket( ba, false ); if( ticket.Tid() != tid ) { - qDebug() << "the ticket contains the wrong TID"; + qDebug() << "\tthe ticket contains the wrong TID"; return false; - } + } } } @@ -650,6 +657,8 @@ int main( int argc, char *argv[] ) root = NULL; + verbose = args.count( "-v" ); + //these only serve to show info. no action is taken if( args.contains( "-boot", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) { diff --git a/ohneschwanzenegger/mainwindow.cpp b/ohneschwanzenegger/mainwindow.cpp index 94c7b1d..1178da0 100644 --- a/ohneschwanzenegger/mainwindow.cpp +++ b/ohneschwanzenegger/mainwindow.cpp @@ -146,7 +146,7 @@ void MainWindow::NusIsDone() //make sure there is a setting.txt QTreeWidgetItem *item = ItemFromPath( "/title/00000001/00000002/data/setting.txt" ); - if( !item ) + if( !item && ItemFromPath( "/title/00000001/00000002/data" ) )//only try to make setting.txt if it is missing and there is a folder to hold it { quint8 reg = SETTING_TXT_UNK; if( ui->lineEdit_tid->text().endsWith( "e", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 ) @@ -165,7 +165,7 @@ void MainWindow::NusIsDone() } else { - if( !nand.SetData( r, ba) ) + if( !nand.SetData( r, ba ) ) { ShowMessage( "Error writing data for setting.txt." ); } @@ -176,7 +176,7 @@ void MainWindow::NusIsDone() } } } - } + } //nand.Delete( "/title/00000001/00000002/content/title.tmd" ); if( nandDirty ) @@ -310,40 +310,43 @@ void MainWindow::on_actionImportWad_triggered() { 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)") ); + } + //QString fn = QFileDialog::getOpenFileName( this, tr("Wad files(*.wad)"), QCoreApplication::applicationDirPath(), tr("WadFiles (*.wad)") ); + QStringList fns = QFileDialog::getOpenFileNames( this, tr("Wad files(*.wad)"), QCoreApplication::applicationDirPath(), tr("WadFiles (*.wad)") ); - if( fn.isEmpty() ) + if( fns.isEmpty() ) return; + foreach( QString fn, fns ) + { + QByteArray data = ReadFile( fn ); + if( data.isEmpty() ) + return; - QByteArray data = ReadFile( fn ); - if( data.isEmpty() ) - return; + Wad wad( data ); + if( !wad.IsOk() ) + { + ShowMessage( tr( "Wad data not ok for \"%1\"" ).arg( fn ) ); + return; + } - Wad wad( data ); - if( !wad.IsOk() ) - { - 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 + NusJob job; + job.tid = wad.Tid(); + job.data << wad.getTmd(); + job.data << wad.getTik(); - //work smart, not hard... just turn the wad into a NUSJob and reused the same code to install it - NusJob job; - job.tid = wad.Tid(); - job.data << wad.getTmd(); - job.data << wad.getTik(); + Tmd t( wad.getTmd() ); + job.version = t.Version(); + quint16 cnt = t.Count(); + for( quint16 i = 0; i < cnt; i++ ) + { + job.data << wad.Content( i ); + } - Tmd t( wad.getTmd() ); - job.version = t.Version(); - quint16 cnt = t.Count(); - for( quint16 i = 0; i < cnt; i++ ) - { - job.data << wad.Content( i ); - } - - job.decrypt = true; - ShowMessage( tr( "Installing %1 to nand" ).arg( fn ) ); - InstallNUSItem( job ); + job.decrypt = true; + ShowMessage( tr( "Installing %1 to nand" ).arg( fn ) ); + InstallNUSItem( job ); + } } @@ -438,7 +441,7 @@ bool MainWindow::InitNand( const QString &path ) //nand.Delete( "/title/00000001/00000002/content/title.tmd" ); nandInited = true; - ShowMessage( "Set path to nand as " + path ); + ShowMessage( "Set path to nand as " + path ); return true; } @@ -756,3 +759,29 @@ void MainWindow::on_actionAbout_triggered() "
giantpune" ); QMessageBox::critical( this, tr( "About" ), txt ); } + +#if 0 +//add a default settings file if there is one laying around +void MainWindow::TryToAddDefaultSettings() +{ + if( ItemFromPath( "/shared2/sys/SYSCONF" ) ) + return; + + QByteArray stuff = ReadFile( "./default_SYSCONF" ); + if( stuff.isEmpty() ) + return; + + quint32 uiD = uid.GetUid( NAND_TEST_OWNER ); + if( !CreateIfNeeded( "/shared2/sys", uiD, NAND_TEST_GROUP, NAND_DIR, NAND_RW, NAND_RW, NAND_RW ) ) + return; + + quint16 handle = nand.CreateEntry( "/shared2/sys/SYSCONF", uiD, NAND_TEST_GROUP, NAND_FILE, NAND_RW, NAND_RW, NAND_RW ); + if( !handle || !nand.SetData( handle, stuff ) || !nand.WriteMetaData() ) + { + ShowMessage( "Error adding the default settings" ); + return; + } + UpdateTree(); + ShowMessage( "Wrote /shared2/sys/SYSCONF" ); +} +#endif diff --git a/ohneschwanzenegger/mainwindow.h b/ohneschwanzenegger/mainwindow.h index 8ec2b89..69dca1d 100644 --- a/ohneschwanzenegger/mainwindow.h +++ b/ohneschwanzenegger/mainwindow.h @@ -48,6 +48,9 @@ private: void SaveSettings(); void LoadSettings(); +#if 0 + void TryToAddDefaultSettings(); +#endif public slots: //slots for getting info from the NUS downloader diff --git a/saveToy/ngdialog.cpp b/saveToy/ngdialog.cpp index b7aa8e6..1855f66 100644 --- a/saveToy/ngdialog.cpp +++ b/saveToy/ngdialog.cpp @@ -145,8 +145,28 @@ void NgDialog::on_pushButton_keys_clicked() if( fn.isEmpty() ) return; - QByteArray ba = ReadFile( fn ); - if( ba.size() != 0x400 ) + QFile file( fn ); + QByteArray ba; + switch( file.size() ) + { + case 0x400: + if( !file.open( QIODevice::ReadOnly ) ) + break; + ba = file.readAll(); + file.close(); + break; + case 0x21000400: + if( !file.open( QIODevice::ReadOnly ) ) + break; + file.seek( 0x21000000 ); + ba = file.read( 0x400 ); + file.close(); + break; + default: + break; + } + + if( ba.size() != 0x400 ) { ui->label_message->setText( tr( "keys.bin should be 0x400 bytes" ) ); return;