From d0490cce4c46e273952f5c76fc4d16eed3e3923b Mon Sep 17 00:00:00 2001 From: "giantpune@gmail.com" Date: Tue, 21 Dec 2010 20:01:39 +0000 Subject: [PATCH] * fix bugs in the nandBin delete * fiix bug when writing supercluster * add macros for nand attributes * adding another example program for creating nand.bin and adding wads. it SEEMS to work as expected, but still, use it with EXTREME CAUTION * changed default NUS_Cache path in NUS downloader to parent directly so the 2 example programs can share the same cache * added "-all" argument for the nandBinchecker --- .gitattributes | 8 + WiiQt/nandbin.cpp | 205 +++------ WiiQt/nandbin.h | 9 +- WiiQt/nandspare.cpp | 2 +- WiiQt/nusdownloader.cpp | 2 +- WiiQt/settingtxtdialog.ui | 4 +- WiiQt/wad.h | 12 +- nandBinCheck/main.cpp | 15 +- nand_dump/mainwindow.cpp | 2 +- ohneschwanzenegger/main.cpp | 11 + ohneschwanzenegger/mainwindow.cpp | 662 ++++++++++++++++++++++++++++++ ohneschwanzenegger/mainwindow.h | 67 +++ ohneschwanzenegger/mainwindow.ui | 237 +++++++++++ ohneschwanzenegger/newnandbin.cpp | 123 ++++++ ohneschwanzenegger/newnandbin.h | 38 ++ ohneschwanzenegger/newnandbin.ui | 234 +++++++++++ ohneschwanzenegger/refleurii.pro | 49 +++ 17 files changed, 1520 insertions(+), 160 deletions(-) create mode 100644 ohneschwanzenegger/main.cpp create mode 100644 ohneschwanzenegger/mainwindow.cpp create mode 100644 ohneschwanzenegger/mainwindow.h create mode 100644 ohneschwanzenegger/mainwindow.ui create mode 100644 ohneschwanzenegger/newnandbin.cpp create mode 100644 ohneschwanzenegger/newnandbin.h create mode 100644 ohneschwanzenegger/newnandbin.ui create mode 100644 ohneschwanzenegger/refleurii.pro diff --git a/.gitattributes b/.gitattributes index a01cf60..4b8fe4e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -63,6 +63,14 @@ nand_dump/mainwindow.h -text nand_dump/mainwindow.ui -text nand_dump/nand.pro -text nand_dump/readmii.txt -text +ohneschwanzenegger/main.cpp -text +ohneschwanzenegger/mainwindow.cpp -text +ohneschwanzenegger/mainwindow.h -text +ohneschwanzenegger/mainwindow.ui -text +ohneschwanzenegger/newnandbin.cpp -text +ohneschwanzenegger/newnandbin.h -text +ohneschwanzenegger/newnandbin.ui -text +ohneschwanzenegger/refleurii.pro -text saveToy/includes.h -text saveToy/main.cpp -text saveToy/mainwindow.cpp -text diff --git a/WiiQt/nandbin.cpp b/WiiQt/nandbin.cpp index 1df51fe..88264b8 100755 --- a/WiiQt/nandbin.cpp +++ b/WiiQt/nandbin.cpp @@ -15,7 +15,10 @@ NandBin::NandBin( QObject * parent, const QString &path ) : QObject( parent ) NandBin::~NandBin() { if( f.isOpen() ) + { + f.flush(); f.close(); + } if( root ) delete root; @@ -147,6 +150,7 @@ bool NandBin::CreateNew( const QString &path, QByteArray keys, QByteArray first8 QTreeWidgetItem *NandBin::GetTree() { + //qDebug() << "NandBin::GetTree()"; return root->clone(); } @@ -371,7 +375,17 @@ bool NandBin::InitNand( QIcon dirs, QIcon files ) root = new QTreeWidgetItem( QStringList() << nandPath ); AddChildren( root, 0 ); +/*#ifdef NAND_BIN_CAN_WRITE + CreateEntry( "/testDir", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW ); + quint16 pp = CreateEntry( "/testDir/testFile", 0, 0, NAND_FILE, NAND_RW, NAND_RW, NAND_RW ); + qDebug() << "created entry" << pp; + Delete( "/testDir/testFile" ); + pp = CreateEntry( "/testDir/testFile", 0, 0, NAND_FILE, NAND_RW, NAND_RW, NAND_RW ); + qDebug() << "created entry" << pp; + SetData( pp, QByteArray( 0x10000, '\x0' ) ); + WriteMetaData(); +#endif*/ //checkout the blocks for boot1&2 QListblocks; @@ -390,120 +404,10 @@ bool NandBin::InitNand( QIcon dirs, QIcon files ) blocks << block; } - //debug shitzz - /*QList fffcs; - QList ffffs; - QList fffds; - for( quint16 i = 0; i < 0x8000; i++ ) - { - switch( fats.at( i ) ) - { - case 0xFFFB: - break; - case 0xFFFC: - fffcs << i; - break; - case 0xFFFD: - fffds << i; - break; - case 0xFFFE: - break; - case 0xFFFF: - ffffs << i; - break; - default: - break; - } - }*/ - /*foreach( quint16 cl, fffds ) - { - qDebug() << "bad cluster" << hex << cl; - for( quint16 i = 0; i < 8; i++ ) - { - QByteArray page = GetPage( (cl * 8 ) + i, true ); - for( quint16 j = 0; j < page.size(); j++ ) - { - if( page.at( j ) != '\0' ) - { - hexdump( page ); - break; - } - } - //hexdump( page ); - } - //break; - - }*/ - - /*qDebug() << "total ffff clusters:" << ffffs.size(); - quint16 u = 0; - while( ffffs.size() ) - { - quint16 fc = ffffs.takeFirst(); - if( fc < 0x40 || fc >= 0x7F00 ) - continue; - QByteArray cl = GetCluster( fc, false ); - while( ffffs.size() && ( ( fc / 8 ) == ( ffffs.at( 0 ) / 8 ) ) ) - { - fc = ffffs.takeFirst(); - if( fc < 0x40 || fc >= 0x7F00 ) - continue; - cl += GetCluster( fc, false ); - - } - WriteFile( QString("./aaaa_ff_%1_%2.bin" ).arg( u++).arg( fc ), cl ); - }*/ - /*QList fcBlocks; - quint16 cnt = fffcs.size(); - quint16 rr = 0; - for( quint16 i = 0; i < cnt; i++ ) - { - quint16 block = fffcs.at( i )/8; - if( !fcBlocks.contains( block ) ) - fcBlocks << block; - - if( fffcs.at( i ) < 0x40 || fffcs.at( i ) >= 0x7F00 ) - continue; - - rr++; - } - qDebug() << "fcBlocks:" << fcBlocks << "total reserved clusters:" << fffcs.size() << "reserved not used for superblock/boot" << rr;*/ - /*quint16 ppp = 0; - for( quint16 i = 0; i < fcBlocks.size(); i++ ) - { - for( quint16 j = 0; j < 8; j++ ) - { - if( !fffcs.contains( ( i * 8 ) + j ) ) - { - ppp++; - break; - } - } - } - qDebug() << "partial reserved blocks:" << ppp;*/ - /*quint16 u = 0; - while( fffcs.size() ) - { - quint16 fc = fffcs.takeFirst(); - if( fc < 0x40 || fc >= 0x7F00 ) - continue; - QByteArray cl = GetCluster( fc ); - while( fffcs.size() && ( ( fc / 8 ) == ( fffcs.at( 0 ) / 8 ) ) ) - { - fc = fffcs.takeFirst(); - if( fc < 0x40 || fc >= 0x7F00 ) - continue; - cl += GetCluster( fc ); - - } - WriteFile( QString("./aaaa_fc_%1_%2.bin" ).arg( u++).arg( fc ), cl ); - }*/ - - if( !bootBlocks.SetBlocks( blocks ) ) return false; - ShowInfo(); + //ShowInfo(); return true; } @@ -764,11 +668,7 @@ quint16 NandBin::GetFAT( quint16 fat_entry ) { if( fstInited ) return fats.at( fat_entry ); - /* - * compensate for "off-16" storage at beginning of superblock - * 53 46 46 53 XX XX XX XX 00 00 00 00 - * S F F S "version" padding? - * 1 2 3 4 5 6*/ + fat_entry += 6; // location in fat of cluster chain @@ -1127,7 +1027,7 @@ bool NandBin::WriteCluster( quint32 pageNo, const QByteArray data, const QByteAr QByteArray spareData( 0x40, '\0' ); quint8* sp = (quint8*)spareData.data(); QByteArray ecc = spare.CalcEcc( data.mid( i * 0x800, 0x800 ) ); - memcpy( sp + 0x30, ecc.data(), 0x14 ); + memcpy( sp + 0x30, ecc.data(), 0x10 ); sp[ 0 ] = 0xff; // good block if( !hmac.isEmpty() ) { @@ -1138,7 +1038,7 @@ bool NandBin::WriteCluster( quint32 pageNo, const QByteArray data, const QByteAr } else if( i == 7 ) { - memcpy( (char*)sp + 1, hmac.data() + 12, 8 ); + memcpy( (char*)sp + 1, (char*)(hmac.data()) + 12, 8 ); } } if( !WritePage( pageNo + i, data.mid( i * 0x800, 0x800 ) + spareData ) ) @@ -1192,10 +1092,11 @@ quint16 NandBin::CreateNode( const QString &name, quint32 uid, quint16 gid, quin attr = attr | ( ( user_perm & 3 ) << 6 ) | ( ( group_perm & 3 ) << 4 ) | ( ( other_perm & 3 ) << 2 ); quint32 i; + //qDebug() << "looking for first empty node"; for( i = 1; i < 0x17ff; i++ )//cant be entry 0 because that is the root { - fst_t fst = fsts[ i ]; - if( !fst.filename[ 0 ] )//this one doesnt have a filename, it cant be used already + //qDebug() << hex << i << FstName( fsts[ i ] ); + if( !fsts[ i ].filename[ 0 ] )//this one doesnt have a filename, it cant be used already break; } if( i == 0x17ff ) @@ -1291,7 +1192,7 @@ quint16 NandBin::CreateEntry( const QString &path, quint32 uid, quint16 gid, qui fsts[ entryNo ].sib = ret; } QTreeWidgetItem *child = CreateItem( par, name, 0, ret, uid, gid, 0, fsts[ ret ].attr, 0 ); - if( attr == 1 ) + if( attr == NAND_FILE ) { child->setIcon( 0, keyIcon ); } @@ -1310,13 +1211,13 @@ bool NandBin::Delete( const QString &path ) bool NandBin::DeleteItem( QTreeWidgetItem *item ) { - qDebug() << "NandBin::DeleteItem" << item->text( 0 ); if( !item ) { qWarning() << "cant delete a null item"; return false; } + qDebug() << "NandBin::DeleteItem" << item->text( 0 ); bool ok = false; quint16 idx = item->text( 1 ).toInt( &ok );//get the index of the entry to remove if( !ok || idx > 0x17fe ) @@ -1341,7 +1242,24 @@ bool NandBin::DeleteItem( QTreeWidgetItem *item ) return false;//wtf } if( fsts[ parIdx ].sub == idx ) //this is the first item in the folder, point the parent to this items first sibling + { fsts[ parIdx ].sub = fsts[ idx ].sib; + quint16 cnt = par->childCount(); + for( quint16 i = 0; i < cnt; i++ ) + { + if( par->child( i )->text( 0 ) == item->text( 0 ) ) + { + pId = i; + //qDebug() << "found the item"; + break; + } + if( i == cnt - 1 )//not found + { + qWarning() << "wtf 15" << pId << i << cnt; + return false; + } + } + } else //point the previous entry to the next one { @@ -1382,28 +1300,22 @@ bool NandBin::DeleteItem( QTreeWidgetItem *item ) { case 1: { - int q = 0; + //int q = 0; qDebug() << "deleting clusters of" << item->text( 0 ) << idx; - quint16 fat = fsts[ idx ].sub;//delete all this file's clusters - //fats.replace( fat, 0xfffe ); - do + QList toFree = GetFatsForFile( idx ); + foreach( quint16 cl, toFree ) { - fats.replace( fat, 0xfffe ); - //qDebug() << "fat" << hex << fat; - fat = GetFAT( fat ); - //fats.replace( fat, 0xfffe ); - //qDebug() << "deleting cluster" << hex << fat << "from table"; - q++; + fats.replace( cl, 0xfffe ); } - while( fat < 0x17ff ); - qDebug() << "delete loop done. freed" << q << "clusters"; + qDebug() << "delete loop done. freed" << toFree.size() << "clusters"; } break; case 2: { qDebug() << "deleting children of" << item->text( 0 ); quint32 cnt = item->childCount();//delete all the children of this item - for( quint32 i = cnt - 1; i > 0; i-- ) + qDebug() << cnt << "childern"; + for( quint32 i = cnt; i > 0; i-- ) { if( !DeleteItem( item->child( i - 1 ) ) ) { @@ -1416,7 +1328,9 @@ bool NandBin::DeleteItem( QTreeWidgetItem *item ) } memset( &fsts[ idx ], 0, sizeof( fst_t ) ); //clear this entry + fsts[ idx ].fst_pos = idx; //reset this QTreeWidgetItem *d = par->takeChild( pId ); + qDebug() << "deleting tree item" << d->text( 0 ); delete d; return true; } @@ -1425,12 +1339,18 @@ bool NandBin::SetData( const QString &path, const QByteArray data ) { QTreeWidgetItem *i = ItemFromPath( path ); if( !i ) + { + qDebug() << "!item" << path; return false; + } bool ok = false; quint16 idx = i->text( 1 ).toInt( &ok );//find the entry if( !ok || idx > 0x17fe ) + { + qDebug() << "out of range" << path; return false; + } return SetData( idx, data ); } @@ -1438,8 +1358,12 @@ bool NandBin::SetData( const QString &path, const QByteArray data ) bool NandBin::SetData( quint16 idx, const QByteArray data ) { fst_t fst = fsts[ idx ]; + qDebug() << "NandBin::SetData" << FstName( fst ); if( ( fst.attr & 3 ) != 1 ) + { + qDebug() << idx << "is a folder"; return false; + } QList fts = GetFatsForFile( idx ); //get the currently used fats and overwrite them. this doesnt serve much purpose, but it seems cleaner QByteArray pData = PaddedByteArray( data, 0x4000 );//actual data that must be written to the nand @@ -1467,7 +1391,7 @@ bool NandBin::SetData( quint16 idx, const QByteArray data ) qsrand( midnight.secsTo( QTime::currentTime() ) ); //now grab the clusters that will be used from the list - qDebug() << "trying to find" << ( clCnt - fts.size() ) << "free clusters"; + //qDebug() << "trying to find" << ( clCnt - fts.size() ) << "free clusters"; while( fts.size() < clCnt ) { if( !freeClusters.size() )//avoid endless loop in case there are some clusters that should be free, but the spare data says theyre bad @@ -1601,9 +1525,13 @@ bool NandBin::SetData( quint16 idx, const QByteArray data ) QTreeWidgetItem *i = ItemFromEntry( idx, root ); if( !i ) + { + qDebug() << "!ItemFromEntry"; return false; + } i->setText( 2, QString( "%1" ).arg( data.size(), 0, 16 ) ); + //f.flush(); return true; } @@ -1671,7 +1599,7 @@ bool NandBin::WriteMetaData() //qDebug() << "done adding shit" << hex << (quint32)b.pos(); b.close(); QByteArray hmR = spare.Get_hmac_meta( scl, nextSuperCluster ); - //qDebug() << "about to write the meta block" << hex << nextSuperCluster << nextClusterVersion << "to page" << (quint32)( nextSuperCluster * 8 ); + qDebug() << "about to write the meta block" << hex << nextSuperCluster << nextClusterVersion << "to page" << (quint32)( nextSuperCluster * 8 ); for( quint8 i = 0; i < 0x10; i++ ) { @@ -1685,6 +1613,9 @@ bool NandBin::WriteMetaData() currentSuperCluster = nextSuperCluster; superClusterVersion = nextClusterVersion; //probably need to put some magic here in case the version wraps around back to 0 + //make sure all the data is really written + f.flush(); + return true; } diff --git a/WiiQt/nandbin.h b/WiiQt/nandbin.h index 5c5d42d..bb7c9ca 100755 --- a/WiiQt/nandbin.h +++ b/WiiQt/nandbin.h @@ -27,8 +27,8 @@ struct fst_t // class to deal with an encrypted wii nand dump // basic usage... create an object, set a path, call InitNand. then you can get the detailed list of entries with GetTree() // extract files with GetFile() -//! so far, all functions for writing to the nand are just dummies. i have only run a few test with them, but now actually used them to write to a nand -//! dont try to use them yet +//! so far, all functions for writing to the nand are highly untested. it is not recommended to try to use this code productively!! +//! you should verify anything written with this code before attempting to install it on you wii //once InitNand() is called, you can get the contents of the nand in a nice QTreeWidgetItem* with GetTree() class NandBin : public QObject @@ -71,7 +71,6 @@ public: // 7 attr QTreeWidgetItem *GetTree(); - //extracts an item( and all its children ) to a directory //this function is BLOCKING and will block the current thread, so if done in the gui thread, it will freeze your GUI till it returns bool ExtractToDir( QTreeWidgetItem *item, const QString &path ); @@ -130,6 +129,7 @@ public: bool SetData( const QString &path, const QByteArray data ); //write the current changes to the metadata( if you dont do this, then none of the other stuff youve done wont be saved ) + // but at the same time, you probably dont need to overuse this. ( no need to write metadata every time you make a single change ) bool WriteMetaData(); //functions to verify spare data @@ -207,10 +207,9 @@ private: QTreeWidgetItem *ItemFromEntry( quint16 i, QTreeWidgetItem *parent = NULL ); QTreeWidgetItem *ItemFromEntry( const QString &i, QTreeWidgetItem *parent = NULL ); - - signals: //connect to these to receive messages from this object + //so far, many errors are only outputting to qDebug() and qWarning(). void SendError( QString ); void SendText( QString ); }; diff --git a/WiiQt/nandspare.cpp b/WiiQt/nandspare.cpp index 42f917f..ac6bb51 100644 --- a/WiiQt/nandspare.cpp +++ b/WiiQt/nandspare.cpp @@ -185,7 +185,7 @@ void fs_hmac_data( const unsigned char *data, quint32 uid, const unsigned char * QByteArray NandSpare::Get_hmac_data( const QByteArray cluster, quint32 uid, const unsigned char *name, quint32 entry_n, quint32 x3, quint16 blk ) { - //qDebug() << "NandSpare::Get_hmac_data" << hex << cluster.size() << uid << QString( (const char*)name ) << entry_n << x3 << blk; + //qDebug() << "NandSpare::Get_hmac_data" << hex << cluster.size() << uid << QString( QByteArray( (const char*)name, 12 ) ) << entry_n << x3 << blk; if( hmacKey.size() != 0x14 || cluster.size() != 0x4000 ) return QByteArray(); diff --git a/WiiQt/nusdownloader.cpp b/WiiQt/nusdownloader.cpp index c50eb78..4f65864 100644 --- a/WiiQt/nusdownloader.cpp +++ b/WiiQt/nusdownloader.cpp @@ -616,7 +616,7 @@ QMap< quint64, quint16 > NusDownloader::List31j() titles.insert( 0x100000022ull, 1039 );//34v1039 titles.insert( 0x100000023ull, 1040 );//35v1040 titles.insert( 0x100000024ull, 1042 );//36v1042 - //titles.insert( 0x100000025ull, 2070 );//37v2070//3.1u has this one but not 3.1j?? + //titles.insert( 0x100000025ull, 2070 );//37v2070 //3.1u has this one but not 3.1j?? titles.insert( 0x1000248415941ull, 0x1 );//photo2v1 titles.insert( 0x1000848414B4aull, 0 );//EULA - HAKJ titles.insert( 0x100024841464aull, 0x7 );// forcast v7 HAFJ diff --git a/WiiQt/settingtxtdialog.ui b/WiiQt/settingtxtdialog.ui index 123b57a..cf24ad4 100644 --- a/WiiQt/settingtxtdialog.ui +++ b/WiiQt/settingtxtdialog.ui @@ -11,7 +11,7 @@ - Dialog + Setting.txt @@ -96,7 +96,7 @@ - 123456789 + 622011873 9 diff --git a/WiiQt/wad.h b/WiiQt/wad.h index 119c4d4..2ba66ae 100644 --- a/WiiQt/wad.h +++ b/WiiQt/wad.h @@ -51,17 +51,17 @@ public: //get all the parts of this wad put together in a wad ready for writing to disc or whatever const QByteArray Data( quint32 magicWord = 0x49730000, const QByteArray footer = QByteArray() ); - //get the tmd for the wad - const QByteArray getTmd(); + //get the tmd for the wad + const QByteArray getTmd(); - //get the tik for the wad - const QByteArray getTik(); + //get the tik for the wad + const QByteArray getTik(); //get the decrypted data from a content const QByteArray Content( quint16 i ); - //get the number of contents - quint32 content_count(); + //get the number of contents + quint32 content_count(); //get the last error encountered while trying to do something const QString LastError(){ return errStr; } diff --git a/nandBinCheck/main.cpp b/nandBinCheck/main.cpp index a291870..2e0f864 100644 --- a/nandBinCheck/main.cpp +++ b/nandBinCheck/main.cpp @@ -30,6 +30,7 @@ void Usage() 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"; exit( 1 ); } @@ -340,7 +341,7 @@ bool CheckTitleIntegrity( quint64 tid ) //return false; //maye in the future this will be true, but for now, this doesnt mean it wont boot break; case ERROR_RSA_FAKESIGNED: -// qDebug() << "\t" << it << "fakesigned"; + qDebug() << "\t" << it << "fakesigned"; break; default: break; @@ -408,13 +409,13 @@ bool CheckTitleIntegrity( quint64 tid ) quint64 ios = t.IOS(); if( ios && !validIoses.contains( ios ) ) { - qDebug() << "the IOS for this title is not bootable"; + qDebug() << "\tthe IOS for this title is not bootable\n\t" << TidTxt( ios ).insert( 8, "-" ) ; return false; } quint32 uid = uidM.GetUid( tid, false ); if( !uid ) { - qDebug() << "this title has no UID entry"; + qDebug() << "\tthis title has no UID entry"; return false; } @@ -629,13 +630,13 @@ int main( int argc, char *argv[] ) root = NULL; //these only serve to show info. no action is taken - if( args.contains( "-boot", Qt::CaseInsensitive ) ) + if( args.contains( "-boot", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) { qDebug() << "checking boot1 & 2..."; ShowBootInfo( nand.Boot1Version(), nand.Boot2Infos() ); } - if( args.contains( "-fs", Qt::CaseInsensitive ) ) + if( args.contains( "-fs", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) { qDebug() << "checking uid.sys..."; QByteArray ba = nand.GetData( "/sys/uid.sys" ); @@ -662,13 +663,13 @@ int main( int argc, char *argv[] ) } } - if( args.contains( "-clInfo", Qt::CaseInsensitive ) ) + if( args.contains( "-clInfo", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) { qDebug() << "checking for lost clusters..."; CheckLostClusters(); } - if( args.contains( "-spare", Qt::CaseInsensitive ) ) + if( args.contains( "-spare", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) { qDebug() << "verifying ecc..."; CheckEcc(); diff --git a/nand_dump/mainwindow.cpp b/nand_dump/mainwindow.cpp index 53a740c..e648025 100644 --- a/nand_dump/mainwindow.cpp +++ b/nand_dump/mainwindow.cpp @@ -22,7 +22,7 @@ MainWindow::MainWindow( QWidget *parent ) : QMainWindow( parent ), ui( new Ui::M //TODO, really get these paths from settings - QString cachePath = "./NUS_cache"; + QString cachePath = "../NUS_cache"; QString nandPath = "./dump"; diff --git a/ohneschwanzenegger/main.cpp b/ohneschwanzenegger/main.cpp new file mode 100644 index 0000000..9ae175b --- /dev/null +++ b/ohneschwanzenegger/main.cpp @@ -0,0 +1,11 @@ +#include +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/ohneschwanzenegger/mainwindow.cpp b/ohneschwanzenegger/mainwindow.cpp new file mode 100644 index 0000000..65733d6 --- /dev/null +++ b/ohneschwanzenegger/mainwindow.cpp @@ -0,0 +1,662 @@ +#include "mainwindow.h" +#include "newnandbin.h" +#include "ui_mainwindow.h" + +#include "../WiiQt/settingtxtdialog.h" +#include "../WiiQt/tiktmd.h" +#include "../WiiQt/tools.h" +#include "../WiiQt/wad.h" + + +MainWindow::MainWindow( QWidget *parent ) : QMainWindow( parent ), ui( new Ui::MainWindow ), nus ( this ), nand ( this ) +{ + ui->setupUi(this); + nandInited = false; + root = NULL; + uidDirty = false; + sharedDirty = false; + nandDirty = false; + Wad::SetGlobalCert( QByteArray( (const char*)&certs_dat, CERTS_DAT_SIZE ) ); + + //connect to the nus object so we can respond to what it is saying with pretty stuff in the gui + connect( &nus, SIGNAL( SendDownloadProgress( int ) ), ui->progressBar_dl, SLOT( setValue( int ) ) ); + connect( &nus, SIGNAL( SendTitleProgress( int ) ), ui->progressBar_title, SLOT( setValue( int ) ) ); + connect( &nus, SIGNAL( SendTotalProgress( int ) ), ui->progressBar_whole, SLOT( setValue( int ) ) ); + connect( &nus, SIGNAL( SendText( QString ) ), ui->statusBar, SLOT( showMessage( QString ) ) ); + connect( &nus, SIGNAL( SendError( const QString &, NusJob ) ), this, SLOT( GetError( const QString &, NusJob ) ) ); + connect( &nus, SIGNAL( SendDone() ), this, SLOT( NusIsDone() ) ); + connect( &nus, SIGNAL( SendData( NusJob ) ), this, SLOT( ReceiveTitleFromNus( NusJob) ) ); + + //connect to the nand.bin to get text and crap from it + connect( &nand, SIGNAL( SendError( const QString & ) ), this, SLOT( GetError( const QString & ) ) ); + connect( &nand, SIGNAL( SendText( QString ) ), ui->statusBar, SLOT( showMessage( QString ) ) ); + + //TODO, really get these paths from settings + + QString cachePath = "../NUS_cache"; + QString nandPath = "./testNand.bin"; + //QString keyPath = "../keys.bin"; + + + ui->lineEdit_cachePath->setText( cachePath ); + ui->lineEdit_nandPath->setText( nandPath ); + //ui->lineEdit_keys->setText( keyPath ); + + nus.SetCachePath( cachePath ); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +//some slots to respond to the NUS downloader +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( ' ' ) ); + + 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 ); + + + ui->plainTextEdit_log->appendHtml( str ); + ui->plainTextEdit_log->appendHtml( j ); +} + +//get error from nand.bin +void MainWindow::GetError( const QString &message ) +{ + QString str = tr( "Nand object Error: %1" ).arg( message ); + ui->plainTextEdit_log->appendHtml( str ); +} + +void MainWindow::ShowMessage( const QString& mes ) +{ + QString str = mes + "
"; + ui->plainTextEdit_log->appendHtml( str ); +} + +void MainWindow::NusIsDone() +{ + QString str = tr( "NUS object is done working
" ); + ui->plainTextEdit_log->appendHtml( str ); + ui->statusBar->showMessage( tr( "Done" ), 5000 ); + + //make sure there is a setting.txt + QTreeWidgetItem *item = ItemFromPath( "/title/00000001/00000002/data/setting.txt" ); + if( !item ) + { + QByteArray ba = SettingTxtDialog::Edit( this ); //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) ) + { + ShowMessage( "Error writing data for setting.txt." ); + } + 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; + } +} + +void MainWindow::ReceiveTitleFromNus( NusJob job ) +{ + QString str = tr( "Received a completed download from NUS" ); + //QString title = QString( "%1v%2" ).arg( job.tid, 16, 16, QChar( '0' ) ).arg( job.version ); + + ui->plainTextEdit_log->appendHtml( str ); + + //do something with the data we got + if( InstallNUSItem( job ) ) + nandDirty = true; + +} + +//clicked the button to get a title +void MainWindow::on_pushButton_GetTitle_clicked() +{ + if( !nandInited && !InitNand( ui->lineEdit_nandPath->text() ) ) + return; + + bool ok = false; + bool wholeUpdate = false; + quint64 tid = 0; + quint32 ver = 0; + if( ui->lineEdit_tid->text().size() == 4 ) + { + 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; + } + } + } + //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; + } + } + else + { + nus.Get( tid, decrypt, ver ); + } +} + +//search for a path to use as the nand basepath +void MainWindow::on_pushButton_nandPath_clicked() +{ + QString f = QFileDialog::getOpenFileName( this, tr( "Select nand.bin" ) ); + if( f.isEmpty() ) + return; + + ui->lineEdit_nandPath->setText( f ); + nus.SetCachePath( ui->lineEdit_cachePath->text() ); +} + +//nand-dump -> setting.txt +void MainWindow::on_actionSetting_txt_triggered() +{ + if( !nandInited ) + 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; + } + 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-dump -> flush +void MainWindow::on_actionFlush_triggered() +{ + if( !nandInited ) + FlushNand(); +} + +//nand-dump -> ImportWad +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; + } + QString fn = QFileDialog::getOpenFileName( this, tr("Wad files(*.wad)"), QCoreApplication::applicationDirPath(), tr("WadFiles (*.wad)") ); + + if( fn.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; + } + + //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 ); + } + + job.decrypt = true; + ShowMessage( tr( "Installing %1 to nand" ).arg( fn ) ); + InstallNUSItem( job ); + +} + +void MainWindow::on_actionNew_nand_from_keys_triggered() +{ + QString path = NewNandBin::GetNewNandPath( this ); + if( path.isEmpty() ) + return; + InitNand( path ); + ui->lineEdit_nandPath->setText( path ); +} + +void MainWindow::on_pushButton_initNand_clicked() +{ + if( ui->lineEdit_nandPath->text().isEmpty() ) + { + ShowMessage( "Please enter a path for nand.bin<\b>" ); + return; + } + InitNand( ui->lineEdit_nandPath->text() ); +} + +bool MainWindow::InitNand( const QString &path ) +{ + nandInited = false; + sharedDirty = false; + nandDirty = false; + if( !nand.SetPath( path ) || !nand.InitNand() ) + return false; + + if( !UpdateTree() ) + 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; + } + else + { + 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; + } + } + 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" ); + } + //nand.Delete( "/title/00000001/00000002/content/title.tmd" ); + + nandInited = true; + ShowMessage( "Set path to nand as " + path ); + return true; +} + +//this one is kinda important +// it is in charge of writing the uid, content map, and all metadata to the nand. +//failing to do this will result in any changes not being applied +bool MainWindow::FlushNand() +{ + //qDebug() << "MainWindow::FlushNand()"; + bool r1 = true; + bool r2 = true; + if( uidDirty && !nand.SetData( "/sys/uid.sys", uid.Data() ) ) + r1 = false; + else + uidDirty = false; + + + if( sharedDirty && !nand.SetData( "/shared1/content.map", shared.Data() ) ) + r2 = false; + else + sharedDirty = false; + + return ( nand.WriteMetaData() && r1 && r2 ); +} + +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; + } + } + return NULL; +} + +QTreeWidgetItem *MainWindow::ItemFromPath( const QString &path ) +{ + QTreeWidgetItem *item = root; + if( !path.startsWith( "/" ) || path.contains( "//" )) + { + 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; + } + return item; +} + +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; + } + return ret; +} + +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; + 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; + } + root = r->takeChild( 0 ); + delete r; + + return true; +} + +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; + 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; + } + //TODO - if the item already exists, check that its attributes match the expected ones + return item->text( 1 ).toInt(); +} + +bool MainWindow::InstallSharedContent( const QByteArray stuff, const QByteArray hash ) +{ + //qDebug() << "MainWindow::InstallSharedContent"; + QByteArray h; + if( hash.isEmpty() ) + h = GetSha1( stuff ); + else + h = hash; + + QString cid = shared.GetAppFromHash( hash ); + if( !cid.isEmpty() ) //this one is already installed + return true; + //qDebug() << "will create new"; + + //get next available cid in the shared map + cid = shared.GetNextEmptyCid(); + shared.AddEntry( cid, h ); + sharedDirty = true; + //qDebug() << "next cid" << cid; + + //create the file + quint16 r = CreateIfNeeded( "/shared1/" + cid + ".app", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ); + if( !r ) + return false; + + //write the data to the file + return nand.SetData( r, stuff ); +} + +bool MainWindow::InstallNUSItem( NusJob job ) +{ + QString title = QString( "%1 v%2" ).arg( job.tid, 16, 16, QChar( '0' ) ).arg( job.version ); + qDebug() << "MainWindow::InstallNUSItem" << title; + + quint16 r; + quint32 _uid; + quint16 _gid; + quint16 cnt; + bool deleted = false; + QTreeWidgetItem *content; + if( !job.tid || !job.data.size() > 2 ) + { + 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 ); + QString lower = tid.right( 8 ); + + Tmd t( job.data.takeFirst() ); + Ticket ticket( job.data.takeFirst() ); + if( t.Tid() != job.tid || ticket.Tid() != job.tid ) + { + qWarning() << "bad tid"; + goto error; + } + cnt = t.Count(); + if( job.data.size() != cnt ) + { + qWarning() << "content count"; + goto error; + } + //qDebug() << "uidDirty" << uidDirty; + if( !uidDirty ) + { + uidDirty = !uid.GetUid( job.tid, false ); + } + //qDebug() << "uidDirty" << uidDirty; + _uid = uid.GetUid( job.tid ); + + _gid = t.Gid(); + if( !_uid ) + { + qWarning() << "no uid"; + goto error; + } + + //create all the folders + if( !CreateIfNeeded( "/ticket/" + upper, 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 ) ) + { qWarning() << "can't create ticket+upper folder";goto error;} + + if( !CreateIfNeeded( "/title/" + upper, 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_READ ) ) + { qWarning() << "can't create title+upper folder";goto error;} + + if( !CreateIfNeeded( "/title/" + upper + "/" + lower, 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_READ ) ) + { qWarning() << "can't create title+upper+lower folder";goto error;} + + if( !CreateIfNeeded( "/title/" + upper + "/" + lower + "/content", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 ) ) + { qWarning() << "can't create content folder";goto error;} + + if( !CreateIfNeeded( "/title/" + upper + "/" + lower + "/data", _uid, _gid, NAND_DIR, NAND_RW, 0, 0 ) ) + { qWarning() << "can't create data folder";goto error;} + + //delete old tmd/.apps and whatever else in the content folder + content = ItemFromPath( "/title/" + upper + "/" + lower + "/content" ); + cnt = content->childCount(); + for ( quint16 i = 0; i < cnt; i++ ) + { + if( !nand.Delete( "/title/" + upper + "/" + lower + "/content/" + content->child( i )->text( 0 ) ) ) + { qWarning() << "error deleting old title"; goto error; } + deleted = true; + } + if( deleted ) + { + //nand.WriteMetaData(); + UpdateTree(); + ShowMessage( tr( "Deleted old TMD and private contents for\n%1" ).arg( title ) ); + } + + cnt = t.Count(); + + //install ticket + r = CreateIfNeeded( "/ticket/" + upper + "/" + lower + ".tik", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ); + if( !r ) + { qWarning() << "can't create ticket";goto error;} + if( !nand.SetData( r, ticket.Data() ) ) + { qWarning() << "can't write to ticket";goto error;} + + //install tmd + r = CreateIfNeeded( "/title/" + upper + "/" + lower + "/content/title.tmd", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ); + if( !r ) + { qWarning() << "can't create tmd";goto error;} + if( !nand.SetData( r, t.Data() ) ) + { qWarning() << "can't write to tmd";goto error;} + + //install contents + //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 ) ); + } + + //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; + } + } + qDebug() << "done installing"; + ShowMessage( "Installed title " + title + " to nand" ); + + //nand.Delete( "/title/" + upper ); + //UpdateTree(); + return true; +error: + ShowMessage( "Error installing title " + title + " to nand" ); + return false; +} + +//help -> about +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" ); + QMessageBox::critical( this, tr( "About" ), txt ); +} diff --git a/ohneschwanzenegger/mainwindow.h b/ohneschwanzenegger/mainwindow.h new file mode 100644 index 0000000..6b5d078 --- /dev/null +++ b/ohneschwanzenegger/mainwindow.h @@ -0,0 +1,67 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "../WiiQt/includes.h" +#include "../WiiQt/nusdownloader.h" +#include "../WiiQt/nandbin.h" +#include "../WiiQt/uidmap.h" +#include "../WiiQt/sharedcontentmap.h" + +namespace Ui { + class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow( QWidget *parent = 0 ); + ~MainWindow(); + +private: + Ui::MainWindow *ui; + QTreeWidgetItem *root; + bool nandInited; + bool uidDirty; + bool sharedDirty; + bool nandDirty; + + NusDownloader nus; + NandBin nand; + UIDmap uid; + SharedContentMap shared; + bool FlushNand(); + + void ShowMessage( const QString& mes ); + + bool InitNand( const QString &path ); + bool UpdateTree(); + + QString PathFromItem( QTreeWidgetItem *item ); + QTreeWidgetItem *ItemFromPath( const QString &path ); + QTreeWidgetItem *FindItem( const QString &s, QTreeWidgetItem *parent ); + + bool InstallNUSItem( NusJob job ); + quint16 CreateIfNeeded( const QString &path, quint32 uid, quint16 gid, quint8 attr, quint8 user_perm, quint8 group_perm, quint8 other_perm ); + bool InstallSharedContent( const QByteArray stuff, const QByteArray hash = QByteArray() ); + +public slots: + //slots for getting info from the NUS downloader + void GetError( const QString &message, NusJob job ); + void GetError( const QString &message ); + void NusIsDone(); + void ReceiveTitleFromNus( NusJob job ); + +private slots: + void on_actionAbout_triggered(); + void on_pushButton_initNand_clicked(); + void on_actionNew_nand_from_keys_triggered(); + void on_actionFlush_triggered(); + void on_actionSetting_txt_triggered(); + void on_actionImportWad_triggered(); + void on_pushButton_nandPath_clicked(); + void on_pushButton_GetTitle_clicked(); +}; + +#endif // MAINWINDOW_H diff --git a/ohneschwanzenegger/mainwindow.ui b/ohneschwanzenegger/mainwindow.ui new file mode 100644 index 0000000..acdd896 --- /dev/null +++ b/ohneschwanzenegger/mainwindow.ui @@ -0,0 +1,237 @@ + + + MainWindow + + + + 0 + 0 + 654 + 507 + + + + NUS NandBuilder + + + + + 2 + + + + + + + + + + 16 + + + + + + + v + + + + + + + + 107 + 16777215 + + + + + + + 5 + + + + + + + Get It! + + + + + + + + + + + + + + Local Cache + + + + + + + + + + + + + Download + + + + + + + 0 + + + + + + + Title + + + + + + + 0 + + + + + + + Total + + + + + + + 0 + + + + + + + + + + + nand.bin + + + + + + + + + + + + + + Search... + + + + + + + true + + + Init Nand + + + + + + + + + + + + + + + + 0 + 0 + 654 + 27 + + + + + Nand Dump + + + + + + + + + Help + + + + + + + + + TopToolBarArea + + + false + + + + + + Setting.txt... + + + + + Flush + + + + + Import Wad + + + + + New nand... + + + Ctrl+N + + + + + About + + + + + + + diff --git a/ohneschwanzenegger/newnandbin.cpp b/ohneschwanzenegger/newnandbin.cpp new file mode 100644 index 0000000..c9cdd96 --- /dev/null +++ b/ohneschwanzenegger/newnandbin.cpp @@ -0,0 +1,123 @@ +#include "newnandbin.h" +#include "ui_newnandbin.h" +#include "../WiiQt/tools.h" + +NewNandBin::NewNandBin( QWidget *parent, QList badBlocks ) : QDialog(parent), ui(new Ui::NewNandBin), nand( this ) +{ + 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 ); + } +} + +NewNandBin::~NewNandBin() +{ + delete ui; +} + +void NewNandBin::on_pushButton_keys_clicked() +{ + QString f = QFileDialog::getOpenFileName( this, tr( "Select Keys.bin" ) ); + if( f.isEmpty() ) + return; + ui->lineEdit_keys->setText( f ); +} + +void NewNandBin::on_pushButton_boot_clicked() +{ + QString f = QFileDialog::getOpenFileName( this, tr( "Select Boot 1 & 2" ) ); + if( f.isEmpty() ) + return; + ui->lineEdit_boot->setText( f ); +} + +void NewNandBin::on_pushButton_dest_clicked() +{ + QString f = QFileDialog::getSaveFileName( this, tr( "Output file" ) ); + if( f.isEmpty() ) + return; + ui->lineEdit_dest->setText( f ); +} + +QList NewNandBin::BadBlocks() +{ + QList ret; + 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; + } + return ret; +} + +void NewNandBin::on_pushButton_bb_add_clicked() +{ + quint16 val = ui->spinBox->value(); + if( !BadBlocks().contains( val ) ) + { + ui->listWidget_badBlocks->addItem( QString( "%1" ).arg( val ) ); + //QListWidgetItem *i = new QListWidgetItem( QString( "%1" ).arg( val ), ui->listWidget_badBlocks ); + } +} + +void NewNandBin::on_pushButton_bb_rm_clicked() +{ + QList items = ui->listWidget_badBlocks->selectedItems(); + foreach( QListWidgetItem *item, items ) + { + ui->listWidget_badBlocks->removeItemWidget( item ); + delete item; + } +} + +//ok clicked +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; + } + 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; + } + if( !nand.CreateNew( ui->lineEdit_dest->text(), keys, boots, BadBlocks() ) ) + { + 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() ) + { + qWarning() << "NewNandBin::on_buttonBox_accepted -> error creating the new nand"; + return; + } + + ret = ui->lineEdit_dest->text(); +} + +QString NewNandBin::GetNewNandPath( QWidget *parent, QList badBlocks ) +{ + NewNandBin d( parent, badBlocks ); + if( !d.exec() ) + return QString(); + return d.ret; +} diff --git a/ohneschwanzenegger/newnandbin.h b/ohneschwanzenegger/newnandbin.h new file mode 100644 index 0000000..558c7a2 --- /dev/null +++ b/ohneschwanzenegger/newnandbin.h @@ -0,0 +1,38 @@ +#ifndef NEWNANDBIN_H +#define NEWNANDBIN_H + +#include "../WiiQt/includes.h" +#include "../WiiQt/nandbin.h" + +namespace Ui { + class NewNandBin; +} + +class NewNandBin : public QDialog +{ + Q_OBJECT + +public: + explicit NewNandBin( QWidget *parent = 0, QListbadBlocks = QList() ); + ~NewNandBin(); + + static QString GetNewNandPath( QWidget *parent = 0, QListbadBlocks = QList() ); + +private: + Ui::NewNandBin *ui; + QList BadBlocks(); + + NandBin nand; + + QString ret; + +private slots: + void on_buttonBox_accepted(); + void on_pushButton_bb_rm_clicked(); + void on_pushButton_bb_add_clicked(); + void on_pushButton_dest_clicked(); + void on_pushButton_boot_clicked(); + void on_pushButton_keys_clicked(); +}; + +#endif // NEWNANDBIN_H diff --git a/ohneschwanzenegger/newnandbin.ui b/ohneschwanzenegger/newnandbin.ui new file mode 100644 index 0000000..5943d28 --- /dev/null +++ b/ohneschwanzenegger/newnandbin.ui @@ -0,0 +1,234 @@ + + + NewNandBin + + + + 0 + 0 + 427 + 290 + + + + New Nand + + + + + + + + Keys + + + + + + + + + + + + + + Boot 1 && 2 + + + + + + + + + + + + + + Destination + + + + + + + ./testNand.bin + + + + + + + + + Bad Blocks + + + + 2 + + + 2 + + + + + 2 + + + + + 2 + + + + + 2 + + + + + + 90 + 0 + + + + 8 + + + 4079 + + + + + + + 2 + + + + + + 37 + 16777215 + + + + >> + + + + + + + + 37 + 16777215 + + + + << + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 100 + 16777215 + + + + Qt::RightToLeft + + + + + + + + + + + + Qt::Horizontal + + + + 149 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + NewNandBin + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + NewNandBin + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ohneschwanzenegger/refleurii.pro b/ohneschwanzenegger/refleurii.pro new file mode 100644 index 0000000..95fb087 --- /dev/null +++ b/ohneschwanzenegger/refleurii.pro @@ -0,0 +1,49 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2010-12-02T23:30:12 +# +#------------------------------------------------- + +QT += core gui\ + network + +TARGET = ohneschwanzenegger +TEMPLATE = app +DEFINES += NAND_BIN_CAN_WRITE + + +SOURCES += main.cpp\ + mainwindow.cpp \ + ../WiiQt/tools.cpp \ + ../WiiQt/sharedcontentmap.cpp \ + ../WiiQt/tiktmd.cpp \ + ../WiiQt/nusdownloader.cpp \ + ../WiiQt/uidmap.cpp \ + ../WiiQt/nanddump.cpp \ + ../WiiQt/settingtxtdialog.cpp \ + ../WiiQt/wad.cpp \ + ../WiiQt/aes.c \ + ../WiiQt/sha1.c \ + newnandbin.cpp \ + ../WiiQt/nandbin.cpp \ + ../WiiQt/nandspare.cpp\ + ../WiiQt/blocks0to7.cpp + +HEADERS += mainwindow.h \ + ../WiiQt/tools.h \ + ../WiiQt/uidmap.h \ + ../WiiQt/sharedcontentmap.h \ + ../WiiQt/tiktmd.h \ + ../WiiQt/nusdownloader.h \ + ../WiiQt/uidmap.h \ + ../WiiQt/nanddump.h \ + ../WiiQt/settingtxtdialog.h \ + ../WiiQt/wad.h \ + newnandbin.h \ + ../WiiQt/nandbin.h \ + ../WiiQt/nandspare.h\ + ../WiiQt/blocks0to7.h + +FORMS += mainwindow.ui \ + ../WiiQt/settingtxtdialog.ui \ + newnandbin.ui