* 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 )

git-svn-id: http://wiiqt.googlecode.com/svn/trunk@67 389f4c8b-5dfe-645f-db0e-df882bc27289
This commit is contained in:
giantpune@gmail.com 2011-01-21 06:21:28 +00:00
parent 0c84a11f79
commit 2ef8140044
9 changed files with 317 additions and 130 deletions

View File

@ -713,6 +713,48 @@ bool NandBin::GetKey( int type )
return true; 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 ) const QByteArray NandBin::ReadKeyfile( const QString &path, quint8 type )
{ {
QByteArray retval; QByteArray retval;

View File

@ -142,6 +142,9 @@ public:
//get the path of this nand //get the path of this nand
const QString FilePath(); const QString FilePath();
//get the keys.bin for this object
const QByteArray Keys();
private: private:
QByteArray key; QByteArray key;

View File

@ -162,13 +162,20 @@ bool Tmd::SetSize( quint16 cid, quint32 size )
return true; return true;
} }
quint16 Tmd::BootIndex( quint16 i ) quint16 Tmd::Index( quint16 i )
{ {
if( !p_tmd || i > qFromBigEndian( p_tmd->num_contents ) ) if( !p_tmd || i > qFromBigEndian( p_tmd->num_contents ) )
return 0; return 0;
return qFromBigEndian( p_tmd->contents[ i ].index ); 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 ) quint16 Tmd::Type( quint16 i )
{ {
if( !p_tmd || i > qFromBigEndian( p_tmd->num_contents ) ) if( !p_tmd || i > qFromBigEndian( p_tmd->num_contents ) )

View File

@ -186,7 +186,8 @@ public:
//returned in host endian //returned in host endian
quint64 Size( quint16 i ); quint64 Size( quint16 i );
quint16 Type( quint16 i ); quint16 Type( quint16 i );
quint16 BootIndex( quint16 i ); quint16 BootIndex();
quint16 Index( quint16 i );
quint64 Tid(); quint64 Tid();
quint64 IOS(); quint64 IOS();
quint16 Gid(); quint16 Gid();

View File

@ -22,6 +22,8 @@
#define NAND_ATTR_OTHER( attr ) ( ( attr >> 2 ) & 3 ) #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 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_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 }; #define SD_IV { 0x21, 0x67, 0x12, 0xe6, 0xaa, 0x1f, 0x68, 0x9f, 0x95, 0xc5, 0xa2, 0x23, 0x24, 0xdc, 0x6a, 0x98 };

View File

@ -121,7 +121,7 @@ Wad::Wad( const QByteArray &stuff )
//is using the AES that would change the key on us //is using the AES that would change the key on us
AesSetKey( ticket.DecryptedKey() ); AesSetKey( ticket.DecryptedKey() );
QByteArray decData = AesDecrypt( t.BootIndex( i ), encData ); QByteArray decData = AesDecrypt( t.Index( i ), encData );
decData.resize( t.Size( i ) ); decData.resize( t.Size( i ) );
QByteArray realHash = GetSha1( decData ); QByteArray realHash = GetSha1( decData );
if( realHash != t.Hash( i ) ) 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 ); 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 //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() ); AesSetKey( ticket.DecryptedKey() );
encData = AesEncrypt( t.BootIndex( i ), decDataPadded ); encData = AesEncrypt( t.Index( i ), decDataPadded );
} }
partsEnc << encData; partsEnc << encData;
} }
@ -233,7 +233,7 @@ Wad::Wad( QDir dir )
} }
AesSetKey( ticket.DecryptedKey() ); AesSetKey( ticket.DecryptedKey() );
appD = PaddedByteArray( appD, 0x40 ); appD = PaddedByteArray( appD, 0x40 );
QByteArray encData = AesEncrypt( t.BootIndex( i ), appD ); QByteArray encData = AesEncrypt( t.Index( i ), appD );
partsEnc << encData; partsEnc << encData;
} }
//if something in the tmd changed, fakesign it //if something in the tmd changed, fakesign it
@ -311,7 +311,7 @@ const QByteArray Wad::Content( quint16 i )
AesSetKey( ticket.DecryptedKey() ); AesSetKey( ticket.DecryptedKey() );
QByteArray decData = AesDecrypt( t.BootIndex( i ), encData ); QByteArray decData = AesDecrypt( t.Index( i ), encData );
decData.resize( t.Size( i ) ); decData.resize( t.Size( i ) );
QByteArray realHash = GetSha1( decData ); QByteArray realHash = GetSha1( decData );
if( realHash != t.Hash( i ) ) if( realHash != t.Hash( i ) )
@ -809,7 +809,7 @@ bool Wad::ReplaceContent( quint16 idx, const QByteArray &ba )
AesSetKey( ti.DecryptedKey() ); AesSetKey( ti.DecryptedKey() );
QByteArray decDataPadded = PaddedByteArray( ba, 0x40 ); QByteArray decDataPadded = PaddedByteArray( ba, 0x40 );
QByteArray encData = AesEncrypt( t.BootIndex( idx ), decDataPadded ); QByteArray encData = AesEncrypt( t.Index( idx ), decDataPadded );
partsEnc.replace( idx, encData ); partsEnc.replace( idx, encData );
return true; return true;

View File

@ -6,7 +6,7 @@
#include "../WiiQt/tiktmd.h" #include "../WiiQt/tiktmd.h"
#include "../WiiQt/settingtxtdialog.h" #include "../WiiQt/settingtxtdialog.h"
#include "../WiiQt/u8.h" #include "../WiiQt/u8.h"
#include "../WiiQt/keysbin.h"
//yippie for global variables //yippie for global variables
QStringList args; QStringList args;
@ -20,10 +20,15 @@ QList<quint16> fats;
quint32 verbose = 0; quint32 verbose = 0;
bool tryToKeepGoing = false; bool tryToKeepGoing = false;
bool color = true; bool color = true;
bool calcRsa = false;
QByteArray sysMenuResource; QByteArray sysMenuResource;
QByteArray sysMenuExe;
quint64 sysMenuIos;
bool CheckTitleIntegrity( quint64 tid );
#ifdef Q_WS_WIN #ifdef Q_WS_WIN
#include <windows.h> // WinApi header #include <windows.h>
#define C_STICKY 31 #define C_STICKY 31
#define C_CAP 192 #define C_CAP 192
@ -34,10 +39,10 @@ int GetColor()
{ {
WORD wColor = 0; WORD wColor = 0;
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
CONSOLE_SCREEN_BUFFER_INFO csbi; CONSOLE_SCREEN_BUFFER_INFO csbi;
//We use csbi for the wAttributes word. //We use csbi for the wAttributes word.
if( GetConsoleScreenBufferInfo(hStdOut, &csbi ) ) if( GetConsoleScreenBufferInfo( hStdOut, &csbi ) )
{ {
wColor = csbi.wAttributes; wColor = csbi.wAttributes;
} }
@ -64,19 +69,19 @@ struct bin_str
static struct bin_str color_indicator[] = static struct bin_str color_indicator[] =
{ {
{ LEN_STR_PAIR ("\033[") }, /* lc: Left of color sequence */ { LEN_STR_PAIR ("\033[") }, /* lc: Left of color sequence */
{ LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */ { LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */
{ 0, NULL }, /* ec: End color (replaces lc+no+rc) */ { 0, NULL }, /* ec: End color (replaces lc+no+rc) */
{ LEN_STR_PAIR ("0") }, /* rs: Reset to ordinary colors */ { LEN_STR_PAIR ("0") }, /* rs: Reset to ordinary colors */
{ 0, NULL }, /* no: Normal */ { 0, NULL }, /* no: Normal */
{ 0, NULL }, /* fi: File: default */ { 0, NULL }, /* fi: File: default */
{ LEN_STR_PAIR ("01;34") }, /* di: Directory: bright blue */ { LEN_STR_PAIR ("01;34") }, /* di: Directory: bright blue */
{ LEN_STR_PAIR ("01;36") }, /* ln: Symlink: bright cyan */ { LEN_STR_PAIR ("01;36") }, /* ln: Symlink: bright cyan */
{ LEN_STR_PAIR ("33") }, /* pi: Pipe: yellow/brown */ { LEN_STR_PAIR ("33") }, /* pi: Pipe: yellow/brown */
{ LEN_STR_PAIR ("01;35") }, /* so: Socket: bright magenta */ { LEN_STR_PAIR ("01;35") }, /* so: Socket: bright magenta */
{ LEN_STR_PAIR ("01;33") }, /* bd: Block device: bright yellow */ { LEN_STR_PAIR ("01;33") }, /* bd: Block device: bright yellow */
{ LEN_STR_PAIR ("01;33") }, /* cd: Char device: bright yellow */ { LEN_STR_PAIR ("01;33") }, /* cd: Char device: bright yellow */
{ 0, NULL }, /* mi: Missing file: undefined */ { 0, NULL }, /* mi: Missing file: undefined */
{ 0, NULL }, /* or: Orphaned symlink: undefined */ { 0, NULL }, /* or: Orphaned symlink: undefined */
{ LEN_STR_PAIR ("01;32") }, /* ex: Executable: bright green */ { LEN_STR_PAIR ("01;32") }, /* ex: Executable: bright green */
{ LEN_STR_PAIR ("01;35") }, /* do: Door: bright magenta */ { LEN_STR_PAIR ("01;35") }, /* do: Door: bright magenta */
{ LEN_STR_PAIR ("37;41") }, /* su: setuid: white on red */ { 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 ("34;42") }, /* ow: other-writable: blue on green */
{ LEN_STR_PAIR ("30;42") }, /* tw: ow w/ sticky: black on green */ { LEN_STR_PAIR ("30;42") }, /* tw: ow w/ sticky: black on green */
{ LEN_STR_PAIR ("30;41") }, /* ca: black on red */ { 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 */ { LEN_STR_PAIR ("\033[K") }, /* cl: clear to end of line */
}; };
@ -102,26 +107,31 @@ void PrintColoredString( const char *msg, int highlite )
} }
else else
{ {
QString m( msg ); QString str( msg );
QString m2 = m.trimmed(); QStringList list = str.split( "\n", QString::SkipEmptyParts );
m.resize( m.indexOf( m2 ) ); foreach( QString s, list )
printf( "%s", m.toLatin1().data() ); //print all leading whitespace {
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 #ifdef Q_WS_WIN
SetConsoleTextAttribute( hConsole, highlite ); SetConsoleTextAttribute( hConsole, highlite );
#else #else
put_indicator( &color_indicator[ C_LEFT ] ); put_indicator( &color_indicator[ C_LEFT ] );
put_indicator( &color_indicator[ highlite ] ); //change color put_indicator( &color_indicator[ highlite ] ); //change color
put_indicator( &color_indicator[ C_RIGHT ] ); put_indicator( &color_indicator[ C_RIGHT ] );
#endif #endif
printf( "%s", m2.toLatin1().data() ); //print text printf( "%s", m2.toLatin1().data() ); //print text
#ifdef Q_WS_WIN #ifdef Q_WS_WIN
SetConsoleTextAttribute( hConsole, origColor ); SetConsoleTextAttribute( hConsole, origColor );
#else #else
put_indicator( &color_indicator[ C_LEFT ] ); put_indicator( &color_indicator[ C_LEFT ] );
put_indicator( &color_indicator[ C_NORM ] ); //reset color put_indicator( &color_indicator[ C_NORM ] ); //reset color
put_indicator( &color_indicator[ C_RIGHT ] ); put_indicator( &color_indicator[ C_RIGHT ] );
#endif #endif
printf( "\n" ); printf( "\n" );
}
} }
fflush( stdout ); fflush( stdout );
} }
@ -134,21 +144,19 @@ void DebugHandler( QtMsgType type, const char *msg )
case QtDebugMsg: case QtDebugMsg:
printf( "%s\n", msg ); printf( "%s\n", msg );
break; break;
case QtWarningMsg: case QtWarningMsg:
PrintColoredString( msg, C_STICKY ); PrintColoredString( msg, C_STICKY );
break; break;
case QtCriticalMsg: case QtCriticalMsg:
PrintColoredString( msg, C_CAP ); PrintColoredString( msg, C_CAP );
break; break;
case QtFatalMsg: case QtFatalMsg:
fprintf(stderr, "Fatal Error: %s\n", msg); fprintf( stderr, "Fatal Error: %s\n", msg );
abort(); abort();
break; break;
} }
} }
bool CheckTitleIntegrity( quint64 tid );
void Usage() void Usage()
{ {
qWarning() << "usage:" << QCoreApplication::arguments().at( 0 ) << "nand.bin" << "<other options>"; qWarning() << "usage:" << QCoreApplication::arguments().at( 0 ) << "nand.bin" << "<other options>";
@ -157,12 +165,14 @@ void Usage()
qDebug() << ""; qDebug() << "";
qDebug() << " -fs verify the filesystem is in tact"; qDebug() << " -fs verify the filesystem is in tact";
qDebug() << " verifies presence of uid & content.map & checks the hashes in the content.map"; 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() << " check all titles with a ticket titles for required IOS, proper uid & gid";
qDebug() << ""; qDebug() << "";
qDebug() << " -settingtxt check setting.txt itself and against system menu resources. 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() << "";
qDebug() << " -uid Look any titles in the uid.sys, check signatures and whatnot. this must be combined with \"-fs\""; 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() << "";
qDebug() << " -clInfo shows free, used, and lost ( marked used, but dont belong to any file ) clusters"; qDebug() << " -clInfo shows free, used, and lost ( marked used, but dont belong to any file ) clusters";
qDebug() << ""; qDebug() << "";
@ -173,12 +183,26 @@ void Usage()
qDebug() << ""; qDebug() << "";
qDebug() << " -v increase verbosity"; qDebug() << " -v increase verbosity";
qDebug() << ""; qDebug() << "";
qDebug() << " -continue try to keep going as fas as possible on errors that should be fatal"; qDebug() << " -continue try to keep going as fas as possible on errors that should be fatal";
qDebug() << ""; qDebug() << "";
qDebug() << " -nocolor don\'t use terminal color trickery"; qDebug() << " -nocolor don\'t use terminal color trickery";
qDebug() << "";
qDebug() << " -about info about this program";
exit( 1 ); 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 ) void Fail( const QString& str )
{ {
qCritical() << str; qCritical() << str;
@ -217,7 +241,7 @@ void ShowBootInfo( quint8 boot1, QList<Boot2Info> boot2stuff )
qDebug() << "Boot1 D (fixed)"; qDebug() << "Boot1 D (fixed)";
break; break;
default: default:
qDebug() << "unrecognized boot1 version"; qWarning() << "unrecognized boot1 version";
break; break;
} }
quint16 cnt = boot2stuff.size(); quint16 cnt = boot2stuff.size();
@ -321,8 +345,8 @@ QTreeWidgetItem *ItemFromPath( const QString &path )
item = FindItem( lookingFor, item ); item = FindItem( lookingFor, item );
if( !item ) if( !item )
{ {
// if( verbose ) //if( verbose )
// qWarning() << "ItemFromPath ->item not found" << path; // qWarning() << "ItemFromPath ->item not found" << path;
return NULL; return NULL;
} }
slash = nextSlash + 1; slash = nextSlash + 1;
@ -366,32 +390,27 @@ QList< quint64 > InstalledTitles()
for( quint16 j = 0; j < subfc2; j++ ) for( quint16 j = 0; j < subfc2; j++ )
{ {
QTreeWidgetItem *tikI = subF->child( j ); QTreeWidgetItem *tikI = subF->child( j );
QString name = tikI->text( 0 ); QString name = tikI->text( 0 );
//qDebug() << "checking item" << subF->text( 0 ) + "/" + name;
if( !name.endsWith( ".tik" ) ) if( !name.endsWith( ".tik" ) )
{ {
//qDebug() << "!tik";
continue; continue;
} }
name.resize( 8 ); name.resize( 8 );
quint32 lower = name.toUInt( &ok, 16 ); quint32 lower = name.toUInt( &ok, 16 );
if( !ok ) if( !ok )
{ {
//qDebug() << "!ok";
continue; continue;
} }
//now see if there is a tmd //now see if there is a tmd
QTreeWidgetItem *tmdI = ItemFromPath( "/title/" + subF->text( 0 ) + "/" + name + "/content/title.tmd" ); QTreeWidgetItem *tmdI = ItemFromPath( "/title/" + subF->text( 0 ) + "/" + name + "/content/title.tmd" );
if( !tmdI ) if( !tmdI )
{ {
//qDebug() << "no tmd";
continue; continue;
} }
quint64 tid = (( (quint64)upper << 32) | lower ); quint64 tid = ( ( (quint64)upper << 32) | lower );
//qDebug() << "adding item to list" << TidTxt( tid );
ret << tid; ret << tid;
} }
} }
@ -442,9 +461,9 @@ void BuildGoodIosList()
if( ba.isEmpty() ) if( ba.isEmpty() )
continue; continue;
Tmd t( ba ); //skip stubbzzzzz Tmd t( ba ); //skip stubbzzzzz
if( !( t.Version() % 0x100 ) && //version is a nice pretty round number if( !( t.Version() % 0x100 ) && //version is a nice pretty round number
t.Count() == 3 && //3 contents, 1 private and 2 shared t.Count() == 3 && //3 contents, 1 private and 2 shared
t.Type( 0 ) == 1 && t.Type( 0 ) == 1 &&
t.Type( 1 ) == 0x8001 && t.Type( 1 ) == 0x8001 &&
t.Type( 2 ) == 0x8001 ) t.Type( 2 ) == 0x8001 )
@ -454,7 +473,7 @@ void BuildGoodIosList()
if( !CheckTitleIntegrity( tid ) ) if( !CheckTitleIntegrity( tid ) )
continue; 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; 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 ) bool CheckTitleIntegrity( quint64 tid )
{ {
if( validIoses.contains( tid ) )//this one has already been checked if( validIoses.contains( tid ) )//this one has already been checked
@ -541,24 +669,27 @@ bool CheckTitleIntegrity( quint64 tid )
qDebug() << "error getting" << it << "data"; qDebug() << "error getting" << it << "data";
return false; return false;
} }
qint32 ch = check_cert_chain( ba ); if( calcRsa )
switch( ch ) {
{ qint32 ch = check_cert_chain( ba );
case ERROR_SIG_TYPE: switch( ch )
case ERROR_SUB_TYPE: {
case ERROR_RSA_HASH: case ERROR_SIG_TYPE:
case ERROR_RSA_TYPE_UNKNOWN: case ERROR_SUB_TYPE:
case ERROR_RSA_TYPE_MISMATCH: case ERROR_RSA_HASH:
case ERROR_CERT_NOT_FOUND: case ERROR_RSA_TYPE_UNKNOWN:
qWarning().nospace() << "\t" << qPrintable( it ) << " RSA signature isn't even close ( " << ch << " )"; case ERROR_RSA_TYPE_MISMATCH:
//return false; //maye in the future this will be true, but for now, this doesnt mean it wont boot case ERROR_CERT_NOT_FOUND:
break; qWarning().nospace() << "\t" << qPrintable( it ) << " RSA signature isn't even close ( " << ch << " )";
case ERROR_RSA_FAKESIGNED: //return false; //maye in the future this will be true, but for now, this doesnt mean it wont boot
qWarning().nospace() << "\t" << qPrintable( it ) << " fakesigned"; break;
break; case ERROR_RSA_FAKESIGNED:
default: qWarning().nospace() << "\t" << qPrintable( it ) << " fakesigned";
break; break;
} default:
break;
}
}
if( i ) if( i )
{ {
t = Tmd( ba ); t = Tmd( ba );
@ -591,7 +722,7 @@ bool CheckTitleIntegrity( quint64 tid )
{ {
qWarning() << "\tone of the shared contents is missing"; qWarning() << "\tone of the shared contents is missing";
return false; return false;
} }
} }
else//private 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 ) //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 //so far, i think this file is always boot index 1, type 1
if( tid == 0x100000002ull && t.BootIndex( i ) == 1 && if( tid == 0x100000002ull )
( args.contains( "-settingtxt", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) ) {
{ if( t.Index( i ) == 1 &&
sysMenuResource = ba; ( 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 //print a description of this title
if( verbose > 1 && t.BootIndex( i ) == 0 ) if( verbose > 1 && t.Index( i ) == 0 )
{ {
PrintName( ba ); PrintName( ba );
} }
} }
} }
//print version //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, "-" ); qWarning() << "\tthe IOS for this title is not bootable\n\t" << TidTxt( ios ).insert( 8, "-" );
return false; return false;
} }
if( tid == 0x100000002ull )
sysMenuIos = ios;
if( verbose > 1 && upper != 1 ) if( verbose > 1 && ( upper != 1 || tid == 0x100000002ull ) )
qDebug() << "\trequires IOS" << ((quint32)( ios & 0xffffffff ));// << TidTxt( ios ).insert( 8, "-" ); qDebug() << "\trequires IOS" << ((quint32)( ios & 0xffffffff ));
quint32 uid = uidM.GetUid( tid, false ); quint32 uid = uidM.GetUid( tid, false );
if( !uid ) 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 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"; qWarning() << "\tincorrect uid/gid for data folder";
RecurseCheckGidUid( dataI, uidS, gidS, "data/" ); 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 ) );
}*/
} }
dataP.resize( 25 ); dataP.resize( 25 );
dataP += "content"; dataP += "content";
@ -762,7 +891,7 @@ void ListDeletedTitles()
qWarning() << "\tError reading TMD for" << qPrintable( TidTxt( tid ).insert( 8, "-" ) + ( upper != 1 ? " (" + AsciiTxt( lower ) + ")" : "" ) ); qWarning() << "\tError reading TMD for" << qPrintable( TidTxt( tid ).insert( 8, "-" ) + ( upper != 1 ? " (" + AsciiTxt( lower ) + ")" : "" ) );
deleted = true; deleted = true;
} }
else else if( calcRsa )
{ {
qint32 ch = check_cert_chain( ba ); qint32 ch = check_cert_chain( ba );
switch( ch ) switch( ch )
@ -803,7 +932,7 @@ void ListDeletedTitles()
qWarning() << "\tError reading ticket for" << qPrintable( TidTxt( tid ).insert( 8, "-" ) + ( upper != 1 ? " (" + AsciiTxt( lower ) + ")" : "" ) ); qWarning() << "\tError reading ticket for" << qPrintable( TidTxt( tid ).insert( 8, "-" ) + ( upper != 1 ? " (" + AsciiTxt( lower ) + ")" : "" ) );
deleted = true; deleted = true;
} }
else else if( calcRsa )
{ {
qint32 ch = check_cert_chain( ba ); qint32 ch = check_cert_chain( ba );
switch( ch ) switch( ch )
@ -834,7 +963,8 @@ void ListDeletedTitles()
void CheckLostClusters() void CheckLostClusters()
{ {
QList<quint16> u = nand.GetFatsForEntry( 0 );//all clusters actually used for a file QList<quint16> 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; quint16 lost = 0;
QList<quint16> ffs; QList<quint16> ffs;
QList<quint16> frs; QList<quint16> frs;
@ -875,8 +1005,7 @@ void CheckEcc()
for( quint16 i = 0; i < 0x8000; i++ ) for( quint16 i = 0; i < 0x8000; i++ )
{ {
if( fats.at( i ) == 0xfffd || fats.at( i ) == 0xfffe ) if( fats.at( i ) == 0xfffd || fats.at( i ) == 0xfffe )
continue; continue;
//qDebug() << hex << i;
for( quint8 j = 0; j < 8; j++, checked += 8 ) for( quint8 j = 0; j < 8; j++, checked += 8 )
{ {
@ -896,24 +1025,17 @@ void CheckEcc()
{ {
quint16 p = clustersCpy.takeFirst(); quint16 p = clustersCpy.takeFirst();
if( fats.at( p ) < 0xfff0 ) if( fats.at( p ) < 0xfff0 )
badClustersNotSpecial ++; badClustersNotSpecial++;
//qDebug() << p << hex << fats.at( p );
quint16 block = p/8; quint16 block = p/8;
if( !blocks.contains( block ) ) if( !blocks.contains( block ) )
blocks << 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" qDebug() << bad.size() << "out of" << checked << "pages had incorrect ecc.\nthey were spread through"
<< clusters.size() << "clusters in" << blocks.size() << "blocks:\n" << blocks; << clusters.size() << "clusters in" << blocks.size() << "blocks:\n" << blocks;
qDebug() << badClustersNotSpecial << "of those clusters are non-special (they belong to the fs)"; qDebug() << badClustersNotSpecial << "of those clusters are non-special (they belong to the fs)";
//qDebug() << bad;
} }
void SetUpTree() void SetUpTree()
@ -1119,7 +1241,7 @@ void CheckSettingTxt()
qDebug() << qPrintable( str ); qDebug() << qPrintable( str );
} }
return; return;
error: error:
qCritical() << "Something is wrong with this setting.txt"; qCritical() << "Something is wrong with this setting.txt";
if( !shownSetting ) if( !shownSetting )
{ {
@ -1135,12 +1257,18 @@ int main( int argc, char *argv[] )
origColor = GetColor(); origColor = GetColor();
hConsole = GetStdHandle( STD_OUTPUT_HANDLE ); hConsole = GetStdHandle( STD_OUTPUT_HANDLE );
#endif #endif
qInstallMsgHandler( DebugHandler ); qInstallMsgHandler( DebugHandler );
qCritical() << "** nandBinCheck : Wii nand info tool **";
qCritical() << " from giantpune";
qCritical() << " built:" << __DATE__ << __TIME__;
args = QCoreApplication::arguments(); args = QCoreApplication::arguments();
if( args.contains( "-nocolor", Qt::CaseInsensitive ) ) if( args.contains( "-nocolor", Qt::CaseInsensitive ) )
color = false; color = false;
if( args.contains( "-about", Qt::CaseInsensitive ) )
About();
if( args.size() < 3 ) if( args.size() < 3 )
Usage(); Usage();
@ -1152,10 +1280,13 @@ int main( int argc, char *argv[] )
root = NULL; root = NULL;
verbose = args.count( "-v" ); verbose = args.count( "-v" );
if( args.contains( "-continue", Qt::CaseInsensitive ) ) if( args.contains( "-continue", Qt::CaseInsensitive ) )
tryToKeepGoing = true; 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 //these only serve to show info. no action is taken
if( args.contains( "-boot", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) ) 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 //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. //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 ) ) if( args.contains( "-settingtxt", Qt::CaseInsensitive ) || args.contains( "-all", Qt::CaseInsensitive ) )
{ {
CheckSettingTxt(); CheckSettingTxt();

View File

@ -28,7 +28,7 @@ SOURCES += main.cpp \
../WiiQt/settingtxtdialog.cpp \ ../WiiQt/settingtxtdialog.cpp \
../WiiQt/u8.cpp \ ../WiiQt/u8.cpp \
../WiiQt/lz77.cpp \ ../WiiQt/lz77.cpp \
../WiiQt/ash.cpp ../WiiQt/ash.cpp
HEADERS += ../WiiQt/tiktmd.h \ HEADERS += ../WiiQt/tiktmd.h \
../WiiQt/nandbin.h \ ../WiiQt/nandbin.h \
@ -40,7 +40,7 @@ HEADERS += ../WiiQt/tiktmd.h \
../WiiQt/settingtxtdialog.h \ ../WiiQt/settingtxtdialog.h \
../WiiQt/u8.h \ ../WiiQt/u8.h \
../WiiQt/lz77.h \ ../WiiQt/lz77.h \
../WiiQt/ash.h ../WiiQt/ash.h
FORMS += \ FORMS += \
../WiiQt/settingtxtdialog.ui ../WiiQt/settingtxtdialog.ui

View File

@ -971,13 +971,13 @@ void MainWindow::on_actionFormat_triggered()
shared = SharedContentMap(); shared = SharedContentMap();
if( !nand.CreateEntry( "/sys/uid.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) ) if( !nand.CreateEntry( "/sys/uid.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) )
{ {
ShowMessage( "<b>Error! Can't /sys/uid.sys</b>" ); ShowMessage( "<b>Error! Can't create /sys/uid.sys</b>" );
return; return;
} }
//clear content.map //clear content.map
if( !nand.CreateEntry( "/shared1/content.map", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) ) if( !nand.CreateEntry( "/shared1/content.map", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) )
{ {
ShowMessage( "<b>Error! Can't /shared1/content.map</b>" ); ShowMessage( "<b>Error! Can't create /shared1/content.map</b>" );
return; return;
} }