* fix bug in NUS downloader that added some titles to the list and then used another list, forgetting about the first 2 titles

* fix bug in nandBin class when the current superblock was the last one

git-svn-id: http://wiiqt.googlecode.com/svn/trunk@52 389f4c8b-5dfe-645f-db0e-df882bc27289
This commit is contained in:
giantpune@gmail.com 2011-01-15 22:21:43 +00:00
parent da0f3cc79e
commit dfd31fe4ed
6 changed files with 336 additions and 139 deletions

View File

@ -48,7 +48,7 @@ bool NandBin::SetPath( const QString &path )
return ret; return ret;
} }
#if 0 // apparently you dont need any extra reserved blocks for the thing to boot?
bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList<quint16> &badBlocks ) bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList<quint16> &badBlocks )
{ {
#ifndef NAND_BIN_CAN_WRITE #ifndef NAND_BIN_CAN_WRITE
@ -84,6 +84,132 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt
return false; return false;
} }
//setup variables
nandPath = path;
currentSuperCluster = 0x7f00;
superClusterVersion = 0xf0000000;
type = 2;
fats.clear();
memset( &fsts, 0, sizeof( fst_t ) * 0x17ff );
for( quint16 i = 0; i < 0x17ff; i++ )
fsts[ i ].fst_pos = i;
//reserve blocks 0 - 7
for( quint16 i = 0; i < 0x40; i++ )
{
fats << 0xfffc;
}
//find 90 blocks to reserve. they always appear to be close to the end of the nand
//TODO - this isnt always 90, all my nands have a different number, and 90 is right in the middle
//quint16 bCnt = badBlocks.size();
/*quint16 offset = 0;
for( quint16 i = 0; i < bCnt; i++ )
{
if( i >= 3998 )
offset++;
}*/
//mark all the "normal" blocks - free, or bad
for( quint16 i = 0x40; i < 0x7f00; i++ )
{
if( badBlocks.contains( i / 8 ) )
fats << 0xfffd;
else
fats << 0xfffe;
}
//mark the 90 reserved ones from above and reserve the superclusters
for( quint16 i = 0x7f00; i < 0x8000; i++ )
{
fats << 0xfffc;
}
//make the root item
fsts[ 0 ].filename[ 0 ] = '/';
fsts[ 0 ].attr = 0x16;
fsts[ 0 ].sib = 0xffff;
fsts[ 0 ].sub = 0xffff;
fstInited = true;
//set keys
QByteArray hmacKey = keys.mid( 0x144, 0x14 );
spare.SetHMacKey( hmacKey );//set the hmac key for calculating spare data
key = keys.mid( 0x158, 0x10 );
//write the metada to each of the superblocks
for( quint8 i = 0; i < 0x10; i++ )
{
if( !WriteMetaData() )
{
qWarning() << "NandBin::CreateNew -> error writing superblock" << i;
return false;
}
}
//build the tree
if( root )
delete root;
root = new QTreeWidgetItem( QStringList() << nandPath );
AddChildren( root, 0 );
return true;
}
#endif
//#if 0 // this boots ok on real HW
bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList<quint16> &badBlocks )
{
#ifndef NAND_BIN_CAN_WRITE
qWarning() << __FILE__ << "was built without write support";
return false;
#endif
if( keys.size() != 0x400 || first8.size() != 0x108000 )
{
qWarning() << "NandBin::CreateNew -> bad sizes" << hex << keys.size() << first8.size();
return false;
}
for( quint16 i = 0; i < 0x40; i++ )
{
if( badBlocks.contains( i / 8 ) )
{
qWarning() << "NandBin::CreateNew -> creating a nand with bad blocks in the first 8 is not supported";
return false;
}
}
for( quint16 i = 0x7f00; i < 0x8000; i++ )
{
if( badBlocks.contains( i / 8 ) )
{
qWarning() << "NandBin::CreateNew -> creating a nand with bad blocks in the superclusters not supported";
return false;
}
}
if( f.isOpen() )
f.close();
//create the new file, write the first 8 blocks, fill it with 0xff, and write the keys.bin at the end
f.setFileName( path );
if( !f.open( QIODevice::ReadWrite | QIODevice::Truncate ) )
{
qWarning() << "NandBin::CreateNew -> can't create file" << path;
return false;
}
f.write( first8 );
QByteArray block( 0x4200, 0xff );//generic empty block
for( quint16 i = 0; i < 0x7fc0; i++ )
f.write( block );
f.write( keys );
if( f.pos() != 0x21000400 )//no room left on the drive?
{
qWarning() << "NandBin::CreateNew -> dump size is wrong" << (quint32)f.pos();
return false;
}
//setup variables //setup variables
nandPath = path; nandPath = path;
currentSuperCluster = 0x7f00; currentSuperCluster = 0x7f00;
@ -111,7 +237,7 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt
} }
//mark all the "normal" blocks - free, or bad //mark all the "normal" blocks - free, or bad
for( quint16 i = 0x40; i < 0x7cf0 - bCnt; i++ ) for( quint16 i = 0x40; i < 0x7cf0 - offset; i++ )
{ {
if( badBlocks.contains( i / 8 ) ) if( badBlocks.contains( i / 8 ) )
fats << 0xfffd; fats << 0xfffd;
@ -120,7 +246,7 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt
} }
//mark the 90 reserved ones from above and reserve the superclusters //mark the 90 reserved ones from above and reserve the superclusters
for( quint16 i = 0x7cf0 - bCnt; i < 0x8000; i++ ) for( quint16 i = 0x7cf0 - offset; i < 0x8000; i++ )
{ {
fats << 0xfffc; fats << 0xfffc;
} }
@ -156,7 +282,7 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt
return true; return true;
} }
//#endif
QTreeWidgetItem *NandBin::GetTree() QTreeWidgetItem *NandBin::GetTree()
{ {
//qDebug() << "NandBin::GetTree()"; //qDebug() << "NandBin::GetTree()";
@ -335,6 +461,7 @@ bool NandBin::ExtractFile( fst_t fst, const QString &parent )
QByteArray data = GetFile( fst ); QByteArray data = GetFile( fst );
if( fst.size && !data.size() )//dont worry if files dont have anything in them anyways if( fst.size && !data.size() )//dont worry if files dont have anything in them anyways
//return true;
return false; return false;
if( !WriteFile( fi.absoluteFilePath(), data ) ) if( !WriteFile( fi.absoluteFilePath(), data ) )
@ -595,14 +722,22 @@ qint32 NandBin::FindSuperblock()
else else
{ {
//qDebug() << "using superblock" << hex << superClusterVersion << currentSuperCluster - 0x10 << f.pos() - n_len[ type ]; //qDebug() << "using superblock" << hex << superClusterVersion << currentSuperCluster - 0x10 << f.pos() - n_len[ type ];
currentSuperCluster -= ( 0x10 * rewind ); //currentSuperCluster -= ( 0x10 * rewind );
loc -= ( n_len[ type ] * rewind ); //loc -= ( n_len[ type ] * rewind );
rewind = 1;
break; break;
} }
if( loc == n_end[ type ] )
{
rewind = 1;
}
} }
if( !superClusterVersion ) if( !superClusterVersion )
return -1; return -1;
currentSuperCluster -= ( 0x10 * rewind );
loc -= ( n_len[ type ] * rewind );
//qDebug() << "using superblock" << hex << superClusterVersion << currentSuperCluster << "page:" << ( loc / 0x840 ); //qDebug() << "using superblock" << hex << superClusterVersion << currentSuperCluster << "page:" << ( loc / 0x840 );
return loc; return loc;
} }
@ -627,6 +762,7 @@ fst_t NandBin::GetFST( quint16 entry )
int loc_entry = ( ( ( entry / 0x40 ) * n_fst[ type ] ) + entry ) * 0x20; int loc_entry = ( ( ( entry / 0x40 ) * n_fst[ type ] ) + entry ) * 0x20;
if( (quint32)f.size() < loc_fst + loc_entry + sizeof( fst_t ) ) if( (quint32)f.size() < loc_fst + loc_entry + sizeof( fst_t ) )
{ {
qDebug() << hex << (quint32)f.size() << loc_fst << loc_entry << type << n_fst[ type ];
emit SendError( tr( "Tried to read fst_t beyond size of nand.bin" ) ); emit SendError( tr( "Tried to read fst_t beyond size of nand.bin" ) );
fst.filename[ 0 ] = '\0'; fst.filename[ 0 ] = '\0';
return fst; return fst;

View File

@ -531,10 +531,6 @@ bool NusDownloader::GetUpdate( const QString & upd, bool decrypt )
QString s = upd.toLower(); QString s = upd.toLower();
QMap< quint64, quint16 > titles; QMap< quint64, quint16 > titles;
//hell, give everybody these.
titles.insert( 0x1000248414741ull, 0x3 );//news channel HAGA
titles.insert( 0x1000248414641ull, 0x3 );//Weather Channel HAFA
if( s == "2.1e" ) titles = List21e(); if( s == "2.1e" ) titles = List21e();
else if( s == "3.0e" ) titles = List30e(); else if( s == "3.0e" ) titles = List30e();
else if( s == "3.1e" ) titles = List31e(); else if( s == "3.1e" ) titles = List31e();
@ -572,6 +568,10 @@ bool NusDownloader::GetUpdate( const QString & upd, bool decrypt )
else return false;//unknown update else return false;//unknown update
//hell, give everybody these.
titles.insert( 0x1000248414741ull, 0x3 );//news channel HAGA
titles.insert( 0x1000248414641ull, 0x3 );//Weather Channel HAFA
QMap< quint64, quint16 >::ConstIterator i = titles.begin(); QMap< quint64, quint16 >::ConstIterator i = titles.begin();
while( i != titles.end() ) while( i != titles.end() )
{ {
@ -855,8 +855,8 @@ QMap< quint64, quint16 > NusDownloader::List30e()
titles.insert( 0x1000248414341ull, 4 );//nigaoeNRv4 - MII titles.insert( 0x1000248414341ull, 4 );//nigaoeNRv4 - MII
titles.insert( 0x1000248414141ull, 0x1 );//photov1 titles.insert( 0x1000248414141ull, 0x1 );//photov1
titles.insert( 0x1000248414241ull, 7 );//shoppingv7 titles.insert( 0x1000248414241ull, 7 );//shoppingv7
titles.insert( 0x1000248414741ull, 0x3 );//news channel HAGA // titles.insert( 0x1000248414741ull, 0x3 );//news channel HAGA
titles.insert( 0x1000248414641ull, 0x3 );//Weather Channel HAFA // titles.insert( 0x1000248414641ull, 0x3 );//Weather Channel HAFA
return titles; return titles;
} }

View File

@ -14,6 +14,7 @@ QList< quint64 > tids;
QList< quint64 > validIoses;//dont put stubs in this list. QList< quint64 > validIoses;//dont put stubs in this list.
QTreeWidgetItem *root; QTreeWidgetItem *root;
QList<quint16> fats; QList<quint16> fats;
quint32 verbose = 0;
bool CheckTitleIntegrity( quint64 tid ); bool CheckTitleIntegrity( quint64 tid );
@ -31,6 +32,7 @@ void Usage()
qDebug() << " -spare calculate & compare ecc for all pages in the nand"; qDebug() << " -spare calculate & compare ecc for all pages in the nand";
qDebug() << " calculate & compare hmac signatures for all files and superblocks"; qDebug() << " calculate & compare hmac signatures for all files and superblocks";
qDebug() << " -all does all of the above"; qDebug() << " -all does all of the above";
qDebug() << " -v increase verbosity";
exit( 1 ); exit( 1 );
} }
@ -370,16 +372,21 @@ bool CheckTitleIntegrity( quint64 tid )
t = Tmd( ba ); t = Tmd( ba );
if( t.Tid() != tid ) if( t.Tid() != tid )
{ {
qDebug() << "the TMD contains the wrong TID"; qDebug() << "\tthe TMD contains the wrong TID";
return false; return false;
} }
if( verbose )
{
qDebug() << "\tversion:" << t.Version() << hex << t.Version();
qDebug() << "\taccess :" << hex << t.AccessFlags();
}
} }
else else
{ {
Ticket ticket( ba, false ); Ticket ticket( ba, false );
if( ticket.Tid() != tid ) if( ticket.Tid() != tid )
{ {
qDebug() << "the ticket contains the wrong TID"; qDebug() << "\tthe ticket contains the wrong TID";
return false; return false;
} }
} }
@ -650,6 +657,8 @@ int main( int argc, char *argv[] )
root = NULL; root = NULL;
verbose = args.count( "-v" );
//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 ) )
{ {

View File

@ -146,7 +146,7 @@ void MainWindow::NusIsDone()
//make sure there is a setting.txt //make sure there is a setting.txt
QTreeWidgetItem *item = ItemFromPath( "/title/00000001/00000002/data/setting.txt" ); QTreeWidgetItem *item = ItemFromPath( "/title/00000001/00000002/data/setting.txt" );
if( !item ) if( !item && ItemFromPath( "/title/00000001/00000002/data" ) )//only try to make setting.txt if it is missing and there is a folder to hold it
{ {
quint8 reg = SETTING_TXT_UNK; quint8 reg = SETTING_TXT_UNK;
if( ui->lineEdit_tid->text().endsWith( "e", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 ) if( ui->lineEdit_tid->text().endsWith( "e", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
@ -311,11 +311,13 @@ void MainWindow::on_actionImportWad_triggered()
ShowMessage( tr( "<b>Error setting the basepath of the nand to %1</b>" ).arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) ); ShowMessage( tr( "<b>Error setting the basepath of the nand to %1</b>" ).arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) );
return; return;
} }
QString fn = QFileDialog::getOpenFileName( this, tr("Wad files(*.wad)"), QCoreApplication::applicationDirPath(), tr("WadFiles (*.wad)") ); //QString fn = QFileDialog::getOpenFileName( this, tr("Wad files(*.wad)"), QCoreApplication::applicationDirPath(), tr("WadFiles (*.wad)") );
QStringList fns = QFileDialog::getOpenFileNames( this, tr("Wad files(*.wad)"), QCoreApplication::applicationDirPath(), tr("WadFiles (*.wad)") );
if( fn.isEmpty() ) if( fns.isEmpty() )
return; return;
foreach( QString fn, fns )
{
QByteArray data = ReadFile( fn ); QByteArray data = ReadFile( fn );
if( data.isEmpty() ) if( data.isEmpty() )
return; return;
@ -344,6 +346,7 @@ void MainWindow::on_actionImportWad_triggered()
job.decrypt = true; job.decrypt = true;
ShowMessage( tr( "Installing %1 to nand" ).arg( fn ) ); ShowMessage( tr( "Installing %1 to nand" ).arg( fn ) );
InstallNUSItem( job ); InstallNUSItem( job );
}
} }
@ -756,3 +759,29 @@ void MainWindow::on_actionAbout_triggered()
"<br>giantpune" ); "<br>giantpune" );
QMessageBox::critical( this, tr( "About" ), txt ); QMessageBox::critical( this, tr( "About" ), txt );
} }
#if 0
//add a default settings file if there is one laying around
void MainWindow::TryToAddDefaultSettings()
{
if( ItemFromPath( "/shared2/sys/SYSCONF" ) )
return;
QByteArray stuff = ReadFile( "./default_SYSCONF" );
if( stuff.isEmpty() )
return;
quint32 uiD = uid.GetUid( NAND_TEST_OWNER );
if( !CreateIfNeeded( "/shared2/sys", uiD, NAND_TEST_GROUP, NAND_DIR, NAND_RW, NAND_RW, NAND_RW ) )
return;
quint16 handle = nand.CreateEntry( "/shared2/sys/SYSCONF", uiD, NAND_TEST_GROUP, NAND_FILE, NAND_RW, NAND_RW, NAND_RW );
if( !handle || !nand.SetData( handle, stuff ) || !nand.WriteMetaData() )
{
ShowMessage( "<b>Error adding the default settings</b>" );
return;
}
UpdateTree();
ShowMessage( "Wrote /shared2/sys/SYSCONF" );
}
#endif

View File

@ -48,6 +48,9 @@ private:
void SaveSettings(); void SaveSettings();
void LoadSettings(); void LoadSettings();
#if 0
void TryToAddDefaultSettings();
#endif
public slots: public slots:
//slots for getting info from the NUS downloader //slots for getting info from the NUS downloader

View File

@ -145,7 +145,27 @@ void NgDialog::on_pushButton_keys_clicked()
if( fn.isEmpty() ) if( fn.isEmpty() )
return; return;
QByteArray ba = ReadFile( fn ); QFile file( fn );
QByteArray ba;
switch( file.size() )
{
case 0x400:
if( !file.open( QIODevice::ReadOnly ) )
break;
ba = file.readAll();
file.close();
break;
case 0x21000400:
if( !file.open( QIODevice::ReadOnly ) )
break;
file.seek( 0x21000000 );
ba = file.read( 0x400 );
file.close();
break;
default:
break;
}
if( ba.size() != 0x400 ) if( ba.size() != 0x400 )
{ {
ui->label_message->setText( tr( "keys.bin should be 0x400 bytes" ) ); ui->label_message->setText( tr( "keys.bin should be 0x400 bytes" ) );