From 1ee50ec16ff6635e379ec12173c9ed45909b8e02 Mon Sep 17 00:00:00 2001 From: "giantpune@gmail.com" Date: Fri, 21 Jan 2011 06:21:28 +0000 Subject: [PATCH] * Tmd class: change name of bootindex/index to match libogc and avoid confusion * nandChecker: add korean brick checking ( still untested with a real korean dump ) --- WiiQt/nandbin.cpp | 42 ++++ WiiQt/nandbin.h | 3 + WiiQt/tiktmd.cpp | 9 +- WiiQt/tiktmd.h | 3 +- WiiQt/tools.h | 2 + WiiQt/wad.cpp | 10 +- nandBinCheck/main.cpp | 370 ++++++++++++++++++++---------- nandBinCheck/nandBinCheck.pro | 4 +- ohneschwanzenegger/mainwindow.cpp | 4 +- 9 files changed, 317 insertions(+), 130 deletions(-) diff --git a/WiiQt/nandbin.cpp b/WiiQt/nandbin.cpp index 81000bd..94118dd 100755 --- a/WiiQt/nandbin.cpp +++ b/WiiQt/nandbin.cpp @@ -713,6 +713,48 @@ bool NandBin::GetKey( int type ) return true; } +const QByteArray NandBin::Keys() +{ + QByteArray ret; + switch( type ) + { + case 0: + case 1: + { + QString keyPath = nandPath; + int sl = keyPath.lastIndexOf( "/" ); + if( sl == -1 ) + { + emit SendError( tr( "Error getting path of keys.bin" ) ); + return false; + } + keyPath.resize( sl + 1 ); + keyPath += "keys.bin"; + + ret = ReadFile( keyPath ); + } + break; + case 2: + { + if( !f.isOpen() ) + { + emit SendError( tr( "Tried to read keys from unopened file" ) ); + return false; + } + f.seek( 0x21000000 ); + ret = f.read( 0x400 ); + } + break; + default: + emit SendError( tr( "Tried to read keys for unknown dump type" ) ); + return QByteArray(); + break; + } + if( ret.size() != 0x400 ) + return QByteArray(); + return ret; +} + const QByteArray NandBin::ReadKeyfile( const QString &path, quint8 type ) { QByteArray retval; diff --git a/WiiQt/nandbin.h b/WiiQt/nandbin.h index a159afc..915f2d6 100755 --- a/WiiQt/nandbin.h +++ b/WiiQt/nandbin.h @@ -142,6 +142,9 @@ public: //get the path of this nand const QString FilePath(); + //get the keys.bin for this object + const QByteArray Keys(); + private: QByteArray key; diff --git a/WiiQt/tiktmd.cpp b/WiiQt/tiktmd.cpp index 0d66256..37bcf4e 100644 --- a/WiiQt/tiktmd.cpp +++ b/WiiQt/tiktmd.cpp @@ -162,13 +162,20 @@ bool Tmd::SetSize( quint16 cid, quint32 size ) return true; } -quint16 Tmd::BootIndex( quint16 i ) +quint16 Tmd::Index( quint16 i ) { if( !p_tmd || i > qFromBigEndian( p_tmd->num_contents ) ) return 0; return qFromBigEndian( p_tmd->contents[ i ].index ); } +quint16 Tmd::BootIndex() +{ + if( !p_tmd ) + return 0; + return qFromBigEndian( p_tmd->boot_index ); +} + quint16 Tmd::Type( quint16 i ) { if( !p_tmd || i > qFromBigEndian( p_tmd->num_contents ) ) diff --git a/WiiQt/tiktmd.h b/WiiQt/tiktmd.h index e15801b..8cd2c81 100644 --- a/WiiQt/tiktmd.h +++ b/WiiQt/tiktmd.h @@ -186,7 +186,8 @@ public: //returned in host endian quint64 Size( quint16 i ); quint16 Type( quint16 i ); - quint16 BootIndex( quint16 i ); + quint16 BootIndex(); + quint16 Index( quint16 i ); quint64 Tid(); quint64 IOS(); quint16 Gid(); diff --git a/WiiQt/tools.h b/WiiQt/tools.h index 1fa2896..5ebc842 100644 --- a/WiiQt/tools.h +++ b/WiiQt/tools.h @@ -22,6 +22,8 @@ #define NAND_ATTR_OTHER( attr ) ( ( attr >> 2 ) & 3 ) #define COMMON_KEY { 0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4, 0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7 } +#define KOREAN_KEY { 0x63, 0xb8, 0x2b, 0xb4, 0xf4, 0x61, 0x4e, 0x2e, 0x13, 0xf2, 0xfe, 0xfb, 0xba, 0x4c, 0x9b, 0x7e } + #define SD_KEY { 0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08, 0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d }; #define SD_IV { 0x21, 0x67, 0x12, 0xe6, 0xaa, 0x1f, 0x68, 0x9f, 0x95, 0xc5, 0xa2, 0x23, 0x24, 0xdc, 0x6a, 0x98 }; diff --git a/WiiQt/wad.cpp b/WiiQt/wad.cpp index 6b1babe..dd8d883 100644 --- a/WiiQt/wad.cpp +++ b/WiiQt/wad.cpp @@ -121,7 +121,7 @@ Wad::Wad( const QByteArray &stuff ) //is using the AES that would change the key on us AesSetKey( ticket.DecryptedKey() ); - QByteArray decData = AesDecrypt( t.BootIndex( i ), encData ); + QByteArray decData = AesDecrypt( t.Index( i ), encData ); decData.resize( t.Size( i ) ); QByteArray realHash = GetSha1( decData ); if( realHash != t.Hash( i ) ) @@ -171,7 +171,7 @@ Wad::Wad( const QList< QByteArray > &stuff, bool encrypted ) QByteArray decDataPadded = PaddedByteArray( stuff.at( i + 2 ), 0x40 ); //doing this here in case there is some other object that is using the AES that would change the key on us AesSetKey( ticket.DecryptedKey() ); - encData = AesEncrypt( t.BootIndex( i ), decDataPadded ); + encData = AesEncrypt( t.Index( i ), decDataPadded ); } partsEnc << encData; } @@ -233,7 +233,7 @@ Wad::Wad( QDir dir ) } AesSetKey( ticket.DecryptedKey() ); appD = PaddedByteArray( appD, 0x40 ); - QByteArray encData = AesEncrypt( t.BootIndex( i ), appD ); + QByteArray encData = AesEncrypt( t.Index( i ), appD ); partsEnc << encData; } //if something in the tmd changed, fakesign it @@ -311,7 +311,7 @@ const QByteArray Wad::Content( quint16 i ) AesSetKey( ticket.DecryptedKey() ); - QByteArray decData = AesDecrypt( t.BootIndex( i ), encData ); + QByteArray decData = AesDecrypt( t.Index( i ), encData ); decData.resize( t.Size( i ) ); QByteArray realHash = GetSha1( decData ); if( realHash != t.Hash( i ) ) @@ -809,7 +809,7 @@ bool Wad::ReplaceContent( quint16 idx, const QByteArray &ba ) AesSetKey( ti.DecryptedKey() ); QByteArray decDataPadded = PaddedByteArray( ba, 0x40 ); - QByteArray encData = AesEncrypt( t.BootIndex( idx ), decDataPadded ); + QByteArray encData = AesEncrypt( t.Index( idx ), decDataPadded ); partsEnc.replace( idx, encData ); return true; diff --git a/nandBinCheck/main.cpp b/nandBinCheck/main.cpp index c5faad8..cc1a74f 100644 --- a/nandBinCheck/main.cpp +++ b/nandBinCheck/main.cpp @@ -6,7 +6,7 @@ #include "../WiiQt/tiktmd.h" #include "../WiiQt/settingtxtdialog.h" #include "../WiiQt/u8.h" - +#include "../WiiQt/keysbin.h" //yippie for global variables QStringList args; @@ -20,10 +20,15 @@ QList fats; quint32 verbose = 0; bool tryToKeepGoing = false; bool color = true; +bool calcRsa = false; QByteArray sysMenuResource; +QByteArray sysMenuExe; +quint64 sysMenuIos; + +bool CheckTitleIntegrity( quint64 tid ); #ifdef Q_WS_WIN -#include // WinApi header +#include #define C_STICKY 31 #define C_CAP 192 @@ -34,10 +39,10 @@ int GetColor() { WORD wColor = 0; - HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE ); CONSOLE_SCREEN_BUFFER_INFO csbi; //We use csbi for the wAttributes word. - if( GetConsoleScreenBufferInfo(hStdOut, &csbi ) ) + if( GetConsoleScreenBufferInfo( hStdOut, &csbi ) ) { wColor = csbi.wAttributes; } @@ -64,19 +69,19 @@ struct bin_str static struct bin_str color_indicator[] = { { LEN_STR_PAIR ("\033[") }, /* lc: Left of color sequence */ - { LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */ - { 0, NULL }, /* ec: End color (replaces lc+no+rc) */ - { LEN_STR_PAIR ("0") }, /* rs: Reset to ordinary colors */ - { 0, NULL }, /* no: Normal */ - { 0, NULL }, /* fi: File: default */ + { LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */ + { 0, NULL }, /* ec: End color (replaces lc+no+rc) */ + { LEN_STR_PAIR ("0") }, /* rs: Reset to ordinary colors */ + { 0, NULL }, /* no: Normal */ + { 0, NULL }, /* fi: File: default */ { LEN_STR_PAIR ("01;34") }, /* di: Directory: bright blue */ { LEN_STR_PAIR ("01;36") }, /* ln: Symlink: bright cyan */ { LEN_STR_PAIR ("33") }, /* pi: Pipe: yellow/brown */ { LEN_STR_PAIR ("01;35") }, /* so: Socket: bright magenta */ { LEN_STR_PAIR ("01;33") }, /* bd: Block device: bright yellow */ { LEN_STR_PAIR ("01;33") }, /* cd: Char device: bright yellow */ - { 0, NULL }, /* mi: Missing file: undefined */ - { 0, NULL }, /* or: Orphaned symlink: undefined */ + { 0, NULL }, /* mi: Missing file: undefined */ + { 0, NULL }, /* or: Orphaned symlink: undefined */ { LEN_STR_PAIR ("01;32") }, /* ex: Executable: bright green */ { LEN_STR_PAIR ("01;35") }, /* do: Door: bright magenta */ { LEN_STR_PAIR ("37;41") }, /* su: setuid: white on red */ @@ -85,7 +90,7 @@ static struct bin_str color_indicator[] = { LEN_STR_PAIR ("34;42") }, /* ow: other-writable: blue on green */ { LEN_STR_PAIR ("30;42") }, /* tw: ow w/ sticky: black on green */ { LEN_STR_PAIR ("30;41") }, /* ca: black on red */ - { 0, NULL }, /* mh: disabled by default */ + { 0, NULL }, /* mh: disabled by default */ { LEN_STR_PAIR ("\033[K") }, /* cl: clear to end of line */ }; @@ -102,26 +107,31 @@ void PrintColoredString( const char *msg, int highlite ) } else { - QString m( msg ); - QString m2 = m.trimmed(); - m.resize( m.indexOf( m2 ) ); - printf( "%s", m.toLatin1().data() ); //print all leading whitespace + QString str( msg ); + QStringList list = str.split( "\n", QString::SkipEmptyParts ); + foreach( QString s, list ) + { + QString m = s; + QString m2 = s.trimmed(); + m.resize( m.indexOf( m2 ) ); + printf( "%s", m.toLatin1().data() ); //print all leading whitespace #ifdef Q_WS_WIN - SetConsoleTextAttribute( hConsole, highlite ); + SetConsoleTextAttribute( hConsole, highlite ); #else - put_indicator( &color_indicator[ C_LEFT ] ); - put_indicator( &color_indicator[ highlite ] ); //change color - put_indicator( &color_indicator[ C_RIGHT ] ); + put_indicator( &color_indicator[ C_LEFT ] ); + put_indicator( &color_indicator[ highlite ] ); //change color + put_indicator( &color_indicator[ C_RIGHT ] ); #endif - printf( "%s", m2.toLatin1().data() ); //print text + printf( "%s", m2.toLatin1().data() ); //print text #ifdef Q_WS_WIN - SetConsoleTextAttribute( hConsole, origColor ); + SetConsoleTextAttribute( hConsole, origColor ); #else - put_indicator( &color_indicator[ C_LEFT ] ); - put_indicator( &color_indicator[ C_NORM ] ); //reset color - put_indicator( &color_indicator[ C_RIGHT ] ); + put_indicator( &color_indicator[ C_LEFT ] ); + put_indicator( &color_indicator[ C_NORM ] ); //reset color + put_indicator( &color_indicator[ C_RIGHT ] ); #endif - printf( "\n" ); + printf( "\n" ); + } } fflush( stdout ); } @@ -134,21 +144,19 @@ void DebugHandler( QtMsgType type, const char *msg ) case QtDebugMsg: printf( "%s\n", msg ); break; - case QtWarningMsg: - PrintColoredString( msg, C_STICKY ); + case QtWarningMsg: + PrintColoredString( msg, C_STICKY ); break; - case QtCriticalMsg: - PrintColoredString( msg, C_CAP ); + case QtCriticalMsg: + PrintColoredString( msg, C_CAP ); break; case QtFatalMsg: - fprintf(stderr, "Fatal Error: %s\n", msg); + fprintf( stderr, "Fatal Error: %s\n", msg ); abort(); break; } } -bool CheckTitleIntegrity( quint64 tid ); - void Usage() { qWarning() << "usage:" << QCoreApplication::arguments().at( 0 ) << "nand.bin" << ""; @@ -157,12 +165,14 @@ void Usage() qDebug() << ""; qDebug() << " -fs verify the filesystem is in tact"; qDebug() << " verifies presence of uid & content.map & checks the hashes in the content.map"; - qDebug() << " check all titles with a ticket for RSA & sha1 validity"; + qDebug() << " check sha1 hashes for title private contents"; qDebug() << " check all titles with a ticket titles for required IOS, proper uid & gid"; qDebug() << ""; - qDebug() << " -settingtxt check setting.txt itself and against system menu resources. this must be combined with \"-fs\""; - qDebug() << ""; - qDebug() << " -uid Look any titles in the uid.sys, check signatures and whatnot. this must be combined with \"-fs\""; + qDebug() << " -settingtxt check setting.txt itself and against system menu resources. this must be combined with \"-fs\""; + qDebug() << ""; + qDebug() << " -uid Look any titles in the uid.sys, check signatures and whatnot. this must be combined with \"-fs\""; + qDebug() << ""; + qDebug() << " -rsa Calculate and compare RSA signatures. this must be combined with \"-fs\""; qDebug() << ""; qDebug() << " -clInfo shows free, used, and lost ( marked used, but dont belong to any file ) clusters"; qDebug() << ""; @@ -173,12 +183,26 @@ void Usage() qDebug() << ""; qDebug() << " -v increase verbosity"; qDebug() << ""; - qDebug() << " -continue try to keep going as fas as possible on errors that should be fatal"; - qDebug() << ""; - qDebug() << " -nocolor don\'t use terminal color trickery"; + qDebug() << " -continue try to keep going as fas as possible on errors that should be fatal"; + qDebug() << ""; + qDebug() << " -nocolor don\'t use terminal color trickery"; + qDebug() << ""; + qDebug() << " -about info about this program"; exit( 1 ); } +void About() +{ + qCritical() << " (c) giantpune 2010, 2011"; + qCritical() << " http://code.google.com/p/wiiqt/"; + qCritical() << " built:" << __DATE__ << __TIME__; + qWarning() << "This software is licensed under GPLv2. It comes with no guarentee that it will work,"; + qWarning() << "or that it will work well."; + qDebug() << ""; + qDebug() << "This program is designed to gather information about a nand dump for a Nintendo Wii"; + exit( 1 ); +} + void Fail( const QString& str ) { qCritical() << str; @@ -217,7 +241,7 @@ void ShowBootInfo( quint8 boot1, QList boot2stuff ) qDebug() << "Boot1 D (fixed)"; break; default: - qDebug() << "unrecognized boot1 version"; + qWarning() << "unrecognized boot1 version"; break; } quint16 cnt = boot2stuff.size(); @@ -321,8 +345,8 @@ QTreeWidgetItem *ItemFromPath( const QString &path ) item = FindItem( lookingFor, item ); if( !item ) { - // if( verbose ) - // qWarning() << "ItemFromPath ->item not found" << path; + //if( verbose ) + // qWarning() << "ItemFromPath ->item not found" << path; return NULL; } slash = nextSlash + 1; @@ -366,32 +390,27 @@ QList< quint64 > InstalledTitles() for( quint16 j = 0; j < subfc2; j++ ) { QTreeWidgetItem *tikI = subF->child( j ); - QString name = tikI->text( 0 ); - //qDebug() << "checking item" << subF->text( 0 ) + "/" + name; + QString name = tikI->text( 0 ); if( !name.endsWith( ".tik" ) ) - { - //qDebug() << "!tik"; + { continue; } name.resize( 8 ); quint32 lower = name.toUInt( &ok, 16 ); if( !ok ) - { - //qDebug() << "!ok"; + { continue; } //now see if there is a tmd QTreeWidgetItem *tmdI = ItemFromPath( "/title/" + subF->text( 0 ) + "/" + name + "/content/title.tmd" ); if( !tmdI ) - { - //qDebug() << "no tmd"; + { continue; } - quint64 tid = (( (quint64)upper << 32) | lower ); - //qDebug() << "adding item to list" << TidTxt( tid ); + quint64 tid = ( ( (quint64)upper << 32) | lower ); ret << tid; } } @@ -442,9 +461,9 @@ void BuildGoodIosList() if( ba.isEmpty() ) continue; - Tmd t( ba ); //skip stubbzzzzz - if( !( t.Version() % 0x100 ) && //version is a nice pretty round number - t.Count() == 3 && //3 contents, 1 private and 2 shared + Tmd t( ba ); //skip stubbzzzzz + if( !( t.Version() % 0x100 ) && //version is a nice pretty round number + t.Count() == 3 && //3 contents, 1 private and 2 shared t.Type( 0 ) == 1 && t.Type( 1 ) == 0x8001 && t.Type( 2 ) == 0x8001 ) @@ -454,7 +473,7 @@ void BuildGoodIosList() if( !CheckTitleIntegrity( tid ) ) continue; - validIoses << tid;//seems good enough. add it to the list + validIoses << tid; //seems good enough. add it to the list } } @@ -509,6 +528,115 @@ void PrintName( const QByteArray &app ) qDebug() << "\tname: " << desc; } +bool CheckArm003( const QByteArray &stuff ) +{ + qint32 esTag = MAX( stuff.indexOf( "$IOSVersion: ES" ), stuff.indexOf( "$IOSVersion: ES" ) ); + if( esTag < 0 ) + { + qWarning() << "\tFailed to find the ES module in the kernel"; + return false; + } + QByteArray start = stuff.left( esTag ); //drop the remaining modules + qint32 prevTag = start.lastIndexOf( "$IOSVersion:", esTag - 1 ); + if( prevTag > 0 ) + start.remove( 0, prevTag ); + if( start.contains( QByteArray::fromHex( "e2511cb1d7fbbef8d7f97db5a1d81694" ) ) //1337 buffer #1 + || start.contains( QByteArray::fromHex( "3f5b8cc9ea855a0afa7347d23e8d664e" ) ) //1337 buffer #2 + || start.contains( QByteArray::fromHex( "b570b08868851c01310c22c0005218ab681b2b00d10248bff001f852680b2b45" ) ) )//blablabla, CMP R3, #0x45 + { + if( verbose > 1 ) + qWarning() << "\tSystem menu IOS supports the Korean-key check"; + return true; + } + if( verbose > 1 ) + qDebug() << "\tSystem menu IOS does not appear to support the Korean-key check"; + + return false; + +} + +void Check003() +{ + qDebug() << "Checking for 003 error ..."; + if( sysMenuExe.isEmpty() ) + { + qWarning() << "can\'t check 003 error for empty data"; + return; + } + bool brick = true; + + //check the PPC half + if( !sysMenuExe.contains( "3880004538A0000038C00000" ) ) //li %r4, 0x45 + { //li %r5, 0 + brick = false; //li %r6, 0 + if( verbose > 1 ) + qDebug() << "\tThe system menu doesn\'t appear to perform the Korean-key check"; + } + else if( verbose > 1 ) + qWarning() << "\tThe system menu performs the Korean-key check"; + + //check the ARM half + QString iosStr = TidTxt( sysMenuIos ); + iosStr.insert( 8, "/" ); + iosStr.prepend( "/title/" ); + iosStr += "/content/"; + QByteArray tmdD = nand.GetData( iosStr + "title.tmd" ); + if( tmdD.isEmpty() ) + { + qWarning() << "\tcan\'t read systemmenu-ios's TMD"; + return; + } + Tmd t( tmdD ); + QByteArray iosKernel; + QString kernelPath; + quint16 cnt = t.Count(); + if( t.BootIndex() >= cnt ) //in case there is some really fucked up TMD + { + Fail( "\tThe system menu ios bootindex is fucked up pretty bad" ); + return; + } + if( t.Type( t.BootIndex() ) == 0x8001 ) + { + QString appname = sharedM.GetAppFromHash( t.Hash( t.BootIndex() ) ); + if( appname.isEmpty() ) + { + Fail( "\tError reading the system menu ios" ); + return; + } + + kernelPath = "/shared1/" + appname + ".app"; + } + else + { + kernelPath = iosStr + t.Cid( t.BootIndex() ) + ".app"; + } + iosKernel = nand.GetData( kernelPath ); + if( iosKernel.isEmpty() ) + { + Fail( "\tError reading the system menu ios data" ); + return; + } + if( !CheckArm003( iosKernel ) ) + brick = false; + + //look for korean keys in keys.bin + QByteArray keys = nand.Keys(); + if( keys.size() != 0x400 ) + { + Fail( "\tError getting nand keys" ); + return; + } + quint8 k_key[ 16 ] = KOREAN_KEY; + if( !keys.contains( QByteArray( (const char*)&k_key, 16 ) ) ) + { + brick = false; + if( verbose > 1 ) + qDebug() << "\tThe korean key is not present in this wii"; + } + if( brick ) + Fail( "\tThis wii will likely show the 003 error" ); +} + bool CheckTitleIntegrity( quint64 tid ) { if( validIoses.contains( tid ) )//this one has already been checked @@ -541,24 +669,27 @@ bool CheckTitleIntegrity( quint64 tid ) qDebug() << "error getting" << it << "data"; return false; } - qint32 ch = check_cert_chain( ba ); - switch( ch ) - { - case ERROR_SIG_TYPE: - case ERROR_SUB_TYPE: - case ERROR_RSA_HASH: - case ERROR_RSA_TYPE_UNKNOWN: - case ERROR_RSA_TYPE_MISMATCH: - case ERROR_CERT_NOT_FOUND: - qWarning().nospace() << "\t" << qPrintable( it ) << " RSA signature isn't even close ( " << ch << " )"; - //return false; //maye in the future this will be true, but for now, this doesnt mean it wont boot - break; - case ERROR_RSA_FAKESIGNED: - qWarning().nospace() << "\t" << qPrintable( it ) << " fakesigned"; - break; - default: - break; - } + if( calcRsa ) + { + qint32 ch = check_cert_chain( ba ); + switch( ch ) + { + case ERROR_SIG_TYPE: + case ERROR_SUB_TYPE: + case ERROR_RSA_HASH: + case ERROR_RSA_TYPE_UNKNOWN: + case ERROR_RSA_TYPE_MISMATCH: + case ERROR_CERT_NOT_FOUND: + qWarning().nospace() << "\t" << qPrintable( it ) << " RSA signature isn't even close ( " << ch << " )"; + //return false; //maye in the future this will be true, but for now, this doesnt mean it wont boot + break; + case ERROR_RSA_FAKESIGNED: + qWarning().nospace() << "\t" << qPrintable( it ) << " fakesigned"; + break; + default: + break; + } + } if( i ) { t = Tmd( ba ); @@ -591,7 +722,7 @@ bool CheckTitleIntegrity( quint64 tid ) { qWarning() << "\tone of the shared contents is missing"; return false; - } + } } else//private { @@ -616,20 +747,23 @@ bool CheckTitleIntegrity( quint64 tid ) //if we are going to check the setting.txt stuff, we need to get the system menu resource file to compare ( check for opera bricks ) //so far, i think this file is always boot index 1, type 1 - if( tid == 0x100000002ull && t.BootIndex( i ) == 1 && - ( args.contains( "-settingtxt", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) ) - { - sysMenuResource = ba; - } + if( tid == 0x100000002ull ) + { + if( t.Index( i ) == 1 && + ( args.contains( "-settingtxt", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) ) + { + sysMenuResource = ba; + } + else if( t.Index( i ) == t.BootIndex() ) + sysMenuExe = ba; + } //print a description of this title - if( verbose > 1 && t.BootIndex( i ) == 0 ) + if( verbose > 1 && t.Index( i ) == 0 ) { PrintName( ba ); - } + } } - - } //print version @@ -649,9 +783,11 @@ bool CheckTitleIntegrity( quint64 tid ) qWarning() << "\tthe IOS for this title is not bootable\n\t" << TidTxt( ios ).insert( 8, "-" ); return false; } + if( tid == 0x100000002ull ) + sysMenuIos = ios; - if( verbose > 1 && upper != 1 ) - qDebug() << "\trequires IOS" << ((quint32)( ios & 0xffffffff ));// << TidTxt( ios ).insert( 8, "-" ); + if( verbose > 1 && ( upper != 1 || tid == 0x100000002ull ) ) + qDebug() << "\trequires IOS" << ((quint32)( ios & 0xffffffff )); quint32 uid = uidM.GetUid( tid, false ); if( !uid ) { @@ -673,14 +809,7 @@ bool CheckTitleIntegrity( quint64 tid ) if( dataI->text( 3 ) != uidS || !dataI->text( 4 ).startsWith( gidS ) )//dont necessarily fail for this. the title will still be bootable without its data qWarning() << "\tincorrect uid/gid for data folder"; - RecurseCheckGidUid( dataI, uidS, gidS, "data/" ); - /*quint16 cnt = dataI->childCount(); - for( quint16 i = 0; i < cnt; i++ ) - { - QTreeWidgetItem *item = dataI->child( i ); - if( item->text( 3 ) != uidS || !item->text( 4 ).startsWith( gidS ) ) - qDebug() << "\tincorrect uid/gid for" << QString( "data/" + item->text( 0 ) ); - }*/ + RecurseCheckGidUid( dataI, uidS, gidS, "data/" ); } dataP.resize( 25 ); dataP += "content"; @@ -762,7 +891,7 @@ void ListDeletedTitles() qWarning() << "\tError reading TMD for" << qPrintable( TidTxt( tid ).insert( 8, "-" ) + ( upper != 1 ? " (" + AsciiTxt( lower ) + ")" : "" ) ); deleted = true; } - else + else if( calcRsa ) { qint32 ch = check_cert_chain( ba ); switch( ch ) @@ -803,7 +932,7 @@ void ListDeletedTitles() qWarning() << "\tError reading ticket for" << qPrintable( TidTxt( tid ).insert( 8, "-" ) + ( upper != 1 ? " (" + AsciiTxt( lower ) + ")" : "" ) ); deleted = true; } - else + else if( calcRsa ) { qint32 ch = check_cert_chain( ba ); switch( ch ) @@ -834,7 +963,8 @@ void ListDeletedTitles() void CheckLostClusters() { QList u = nand.GetFatsForEntry( 0 );//all clusters actually used for a file - qDebug() << "total used clusters" << hex << u.size() << "of 0x8000"; + if( verbose ) + qDebug() << "total used clusters" << hex << u.size() << "of 0x8000"; quint16 lost = 0; QList ffs; QList frs; @@ -875,8 +1005,7 @@ void CheckEcc() for( quint16 i = 0; i < 0x8000; i++ ) { if( fats.at( i ) == 0xfffd || fats.at( i ) == 0xfffe ) - continue; - //qDebug() << hex << i; + continue; for( quint8 j = 0; j < 8; j++, checked += 8 ) { @@ -896,24 +1025,17 @@ void CheckEcc() { quint16 p = clustersCpy.takeFirst(); if( fats.at( p ) < 0xfff0 ) - badClustersNotSpecial ++; - //qDebug() << p << hex << fats.at( p ); + badClustersNotSpecial++; + quint16 block = p/8; if( !blocks.contains( block ) ) blocks << block; - } - /*QList< quint32 > badCpy = bad; - while( badCpy.size() ) - { - quint16 p = badCpy.takeFirst(); - quint16 block = p/64; - if( !blocks.contains( block ) ) - blocks << block; - }*/ + } + qDebug() << bad.size() << "out of" << checked << "pages had incorrect ecc.\nthey were spread through" << clusters.size() << "clusters in" << blocks.size() << "blocks:\n" << blocks; - qDebug() << badClustersNotSpecial << "of those clusters are non-special (they belong to the fs)"; - //qDebug() << bad; + qDebug() << badClustersNotSpecial << "of those clusters are non-special (they belong to the fs)"; + } void SetUpTree() @@ -1119,7 +1241,7 @@ void CheckSettingTxt() qDebug() << qPrintable( str ); } return; - error: +error: qCritical() << "Something is wrong with this setting.txt"; if( !shownSetting ) { @@ -1135,12 +1257,18 @@ int main( int argc, char *argv[] ) origColor = GetColor(); hConsole = GetStdHandle( STD_OUTPUT_HANDLE ); #endif - qInstallMsgHandler( DebugHandler ); + qInstallMsgHandler( DebugHandler ); + qCritical() << "** nandBinCheck : Wii nand info tool **"; + qCritical() << " from giantpune"; + qCritical() << " built:" << __DATE__ << __TIME__; args = QCoreApplication::arguments(); - if( args.contains( "-nocolor", Qt::CaseInsensitive ) ) + if( args.contains( "-nocolor", Qt::CaseInsensitive ) ) color = false; + if( args.contains( "-about", Qt::CaseInsensitive ) ) + About(); + if( args.size() < 3 ) Usage(); @@ -1152,10 +1280,13 @@ int main( int argc, char *argv[] ) root = NULL; - verbose = args.count( "-v" ); + verbose = args.count( "-v" ); - if( args.contains( "-continue", Qt::CaseInsensitive ) ) - tryToKeepGoing = true; + if( args.contains( "-continue", Qt::CaseInsensitive ) ) + tryToKeepGoing = true; + + if( args.contains( "-rsa", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) + calcRsa = true; //these only serve to show info. no action is taken if( args.contains( "-boot", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) @@ -1189,6 +1320,7 @@ int main( int argc, char *argv[] ) //if( !CheckTitleIntegrity( tid ) && tid == 0x100000002ull ) //well, this SHOULD be the case. but nintendo doesnt care so much about //Fail( "The System menu isnt valid" ); //checking signatures & hashes as the rest of us. } + Check003(); if( args.contains( "-settingtxt", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) { CheckSettingTxt(); diff --git a/nandBinCheck/nandBinCheck.pro b/nandBinCheck/nandBinCheck.pro index 03f4887..8851902 100644 --- a/nandBinCheck/nandBinCheck.pro +++ b/nandBinCheck/nandBinCheck.pro @@ -28,7 +28,7 @@ SOURCES += main.cpp \ ../WiiQt/settingtxtdialog.cpp \ ../WiiQt/u8.cpp \ ../WiiQt/lz77.cpp \ - ../WiiQt/ash.cpp + ../WiiQt/ash.cpp HEADERS += ../WiiQt/tiktmd.h \ ../WiiQt/nandbin.h \ @@ -40,7 +40,7 @@ HEADERS += ../WiiQt/tiktmd.h \ ../WiiQt/settingtxtdialog.h \ ../WiiQt/u8.h \ ../WiiQt/lz77.h \ - ../WiiQt/ash.h + ../WiiQt/ash.h FORMS += \ ../WiiQt/settingtxtdialog.ui diff --git a/ohneschwanzenegger/mainwindow.cpp b/ohneschwanzenegger/mainwindow.cpp index 182d7d9..8dc2add 100644 --- a/ohneschwanzenegger/mainwindow.cpp +++ b/ohneschwanzenegger/mainwindow.cpp @@ -971,13 +971,13 @@ void MainWindow::on_actionFormat_triggered() shared = SharedContentMap(); if( !nand.CreateEntry( "/sys/uid.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) ) { - ShowMessage( "Error! Can't /sys/uid.sys" ); + ShowMessage( "Error! Can't create /sys/uid.sys" ); return; } //clear content.map if( !nand.CreateEntry( "/shared1/content.map", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) ) { - ShowMessage( "Error! Can't /shared1/content.map" ); + ShowMessage( "Error! Can't create /shared1/content.map" ); return; }