From 15f5715c52529f3067fb8ad28e2aaf5af10be4f9 Mon Sep 17 00:00:00 2001 From: "giantpune@gmail.com" Date: Mon, 21 Feb 2011 15:51:14 +0000 Subject: [PATCH] * TMD:: use reserved2 for fakesigning. "zeros" is actually part of the region and breaks things * nandBin:: if SFFS generation rolls around to 0, write all 16 superclusters --- WiiQt/lz77.cpp | 318 +++++++++++++++++++++--------------------- WiiQt/nandbin.cpp | 166 ++++------------------ WiiQt/tiktmd.cpp | 17 ++- WiiQt/wad.cpp | 2 + nandBinCheck/main.cpp | 1 - 5 files changed, 198 insertions(+), 306 deletions(-) diff --git a/WiiQt/lz77.cpp b/WiiQt/lz77.cpp index 322ab21..bf90729 100644 --- a/WiiQt/lz77.cpp +++ b/WiiQt/lz77.cpp @@ -23,10 +23,10 @@ void LZ77::InitTree() int i; int N = 4096; for( i = N + 1; i <= N + 256; i++ ) - rson[ i ] = N; + rson[ i ] = N; for( i = 0; i < N; i++ ) - dad[ i ] = N; + dad[ i ] = N; } void LZ77::DeleteNode( int p ) @@ -35,41 +35,41 @@ void LZ77::DeleteNode( int p ) int q; if( dad[ p ] == N ) - return; /* not in tree */ + return; /* not in tree */ if( rson[ p ] == N ) - q = lson[ p ]; + q = lson[ p ]; else if( lson[ p ] == N ) - q = rson[ p ]; + q = rson[ p ]; else { - q = lson[ p ]; + q = lson[ p ]; - if( rson[ q ] != N ) - { - do - { - q = rson[ q ]; - } - while( rson[ q ] != N ); + if( rson[ q ] != N ) + { + do + { + q = rson[ q ]; + } + while( rson[ q ] != N ); - rson[ dad[ q ] ] = lson[ q ]; - dad[ lson[ q ] ] = dad[ q ]; + rson[ dad[ q ] ] = lson[ q ]; + dad[ lson[ q ] ] = dad[ q ]; - lson[ q ] = lson[ p ]; - dad[ lson[ p ] ] = q; - } - rson[ q ] = rson[ p ]; - dad[ rson[ p ] ] = q; + lson[ q ] = lson[ p ]; + dad[ lson[ p ] ] = q; + } + rson[ q ] = rson[ p ]; + dad[ rson[ p ] ] = q; } dad[ q ] = dad[ p ]; if( rson[ dad[ p ] ] == p ) - rson[ dad[ p ] ] = q; + rson[ dad[ p ] ] = q; else - lson[ dad[ p ] ] = q; + lson[ dad[ p ] ] = q; dad[ p ] = N; } @@ -85,38 +85,38 @@ void LZ77::InsertNode( int r ) match_length = 0; for( ; ; ) { - if( cmp >= 0 ) - { - if( rson[ p ] != N ) - p = rson[ p ]; - else - { - rson[ p ] = r; - dad[ r ] = p; - return; - } - } - else - { - if ( lson[ p ] != N ) - p = lson[ p ]; + if( cmp >= 0 ) + { + if( rson[ p ] != N ) + p = rson[ p ]; + else + { + rson[ p ] = r; + dad[ r ] = p; + return; + } + } + else + { + if ( lson[ p ] != N ) + p = lson[ p ]; - else - { - lson[ p ] = r; - dad[ r ] = p; - return; - } - } - for( i = 1; i < F; i++ ) - if( ( cmp = text_buf[ r + i ] - text_buf[ p + i ] ) != 0 ) - break; - if( i > match_length ) - { - match_position = p; - if( ( match_length = i ) >= F ) - break; - } + else + { + lson[ p ] = r; + dad[ r ] = p; + return; + } + } + for( i = 1; i < F; i++ ) + if( ( cmp = text_buf[ r + i ] - text_buf[ p + i ] ) != 0 ) + break; + if( i > match_length ) + { + match_position = p; + if( ( match_length = i ) >= F ) + break; + } } dad[ r ] = dad[ p ]; @@ -126,10 +126,10 @@ void LZ77::InsertNode( int r ) dad[ rson[ p ] ] = r; if( rson[ dad[ p ] ] == p ) - rson[ dad[ p ] ] = r; + rson[ dad[ p ] ] = r; else - lson[ dad[ p ] ] = r; + lson[ dad[ p ] ] = r; dad[ p ] = N; } @@ -139,15 +139,15 @@ quint32 LZ77::GetDecompressedSize( const QByteArray &data ) int off = GetLz77Offset( data ); if( off == -1 ) { - qWarning() << "LZ77::GetDecompressedSize -> no lz77 magic"; - return 0; + qWarning() << "LZ77::GetDecompressedSize -> no lz77 magic"; + return 0; } QByteArray ba = data; QBuffer buf( &ba ); if( !buf.open( QBuffer::ReadOnly ) ) { - qWarning() << "LZ77::GetDecompressedSize -> Can't create buffer"; - return 0; + qWarning() << "LZ77::GetDecompressedSize -> Can't create buffer"; + return 0; } buf.seek( off + 4 ); @@ -173,15 +173,15 @@ QByteArray LZ77::Decompress( const QByteArray &compressed, int offset ) QBuffer infile( &crap ); if( !infile.open( QBuffer::ReadOnly ) ) { - qWarning() << "Can't create buffer 1"; - return QByteArray(); + qWarning() << "Can't create buffer 1"; + return QByteArray(); } QByteArray ret; QBuffer outfile( &ret ); if( !outfile.open( QBuffer::ReadWrite ) ) { - qWarning() << "Can't create buffer 2"; - return QByteArray(); + qWarning() << "Can't create buffer 2"; + return QByteArray(); } quint32 gbaheader; @@ -192,7 +192,7 @@ QByteArray LZ77::Decompress( const QByteArray &compressed, int offset ) quint8 text_buf[ N + 17 ]; for( i = 0; i < N - F; i++ ) - text_buf[ i ] = 0xdf; + text_buf[ i ] = 0xdf; r = N - F; flags = 7; @@ -200,51 +200,51 @@ QByteArray LZ77::Decompress( const QByteArray &compressed, int offset ) while( true ) { - flags <<= 1; - z++; - if( z == 8 ) - { - if( !infile.getChar( &ch ) ) - break; - flags = (quint8) ch; - z = 0; - } - if( ( flags & 0x80 ) == 0 ) - { - if( !infile.getChar( &ch ) ) - break; + flags <<= 1; + z++; + if( z == 8 ) + { + if( !infile.getChar( &ch ) ) + break; + flags = (quint8) ch; + z = 0; + } + if( ( flags & 0x80 ) == 0 ) + { + if( !infile.getChar( &ch ) ) + break; - if( cur_size < decomp_size ) - outfile.putChar( ch ); + if( cur_size < decomp_size ) + outfile.putChar( ch ); - text_buf[ r++ ] = ch; - r &= ( N - 1 ); - cur_size++; - } - else - { - if( !infile.getChar( &ch ) ) - break; - i = (quint8)ch; + text_buf[ r++ ] = ch; + r &= ( N - 1 ); + cur_size++; + } + else + { + if( !infile.getChar( &ch ) ) + break; + i = (quint8)ch; - if( !infile.getChar( &ch ) ) - break; - j = (quint8)ch; + if( !infile.getChar( &ch ) ) + break; + j = (quint8)ch; - j = j | ( (i << 8) & 0xf00 ); - i = ( ( i >> 4 ) & 0x0f ) + threshold; + j = j | ( (i << 8) & 0xf00 ); + i = ( ( i >> 4 ) & 0x0f ) + threshold; - for( k = 0; k <= i; k++ ) - { - ch = text_buf[ ( r - j - 1 ) & ( N - 1 ) ]; - if( cur_size < decomp_size ) - outfile.putChar( ch ); + for( k = 0; k <= i; k++ ) + { + ch = text_buf[ ( r - j - 1 ) & ( N - 1 ) ]; + if( cur_size < decomp_size ) + outfile.putChar( ch ); - text_buf[ r++ ] = ch; - r &= ( N - 1 ); - cur_size++; - } - } + text_buf[ r++ ] = ch; + r &= ( N - 1 ); + cur_size++; + } + } } return ret; @@ -255,8 +255,8 @@ QByteArray LZ77::Decompress( const QByteArray &compressed ) int off = GetLz77Offset( compressed ); if( off < 0 ) { - qWarning() << "LZ77::Decompress -> data is not compressed"; - return compressed; + qWarning() << "LZ77::Decompress -> data is not compressed"; + return compressed; } return Decompress( compressed, off ); } @@ -285,15 +285,15 @@ QByteArray LZ77::Compr( const QByteArray &ba ) QBuffer infile( &crap ); if( !infile.open( QBuffer::ReadOnly ) ) { - qWarning() << "Can't create buffer 1"; - return QByteArray(); + qWarning() << "Can't create buffer 1"; + return QByteArray(); } QByteArray ret; QBuffer output( &ret ); if( !output.open( QBuffer::ReadWrite ) ) { - qWarning() << "Can't create buffer 2"; - return QByteArray(); + qWarning() << "Can't create buffer 2"; + return QByteArray(); } output.putChar( 'L' ); output.putChar( 'Z' ); @@ -310,83 +310,83 @@ QByteArray LZ77::Compr( const QByteArray &ba ) r = N - F; for( i = s; i < r; i++ ) - text_buf[ i ] = 0xffff; + text_buf[ i ] = 0xffff; for( len = 0; len < F && infile.getChar( &ch ); len++ ) - text_buf[ r + len ] = (quint8)ch; + text_buf[ r + len ] = (quint8)ch; if( ( textsize = len ) == 0) - return ba; + return ba; for( i = 1; i <= F; i++ ) - InsertNode( r - i ); + InsertNode( r - i ); InsertNode( r ); do { - if( match_length > len ) - match_length = len; + if( match_length > len ) + match_length = len; - if( match_length <= threshold ) - { - match_length = 1; - code_buf[ code_buf_ptr++ ] = text_buf[ r ]; - } - else - { - code_buf[ 0 ] |= mask; + if( match_length <= threshold ) + { + match_length = 1; + code_buf[ code_buf_ptr++ ] = text_buf[ r ]; + } + else + { + code_buf[ 0 ] |= mask; - code_buf[ code_buf_ptr++ ] = (quint8) - ( ( ( r - match_position - 1 ) >> 8) & 0x0f ) | - ( ( match_length - ( threshold + 1 ) ) << 4 ); + code_buf[ code_buf_ptr++ ] = (quint8) + ( ( ( r - match_position - 1 ) >> 8) & 0x0f ) | + ( ( match_length - ( threshold + 1 ) ) << 4 ); - code_buf[ code_buf_ptr++ ] = (quint8)( ( r - match_position - 1 ) & 0xff ); - } - if( ( mask >>= 1 ) == 0 ) - { - for( i = 0; i < code_buf_ptr; i++ ) - output.putChar( (quint8)code_buf[ i ] ); + code_buf[ code_buf_ptr++ ] = (quint8)( ( r - match_position - 1 ) & 0xff ); + } + if( ( mask >>= 1 ) == 0 ) + { + for( i = 0; i < code_buf_ptr; i++ ) + output.putChar( (quint8)code_buf[ i ] ); - codesize += code_buf_ptr; - code_buf[ 0 ] = 0; code_buf_ptr = 1; - mask = 0x80; - } + codesize += code_buf_ptr; + code_buf[ 0 ] = 0; code_buf_ptr = 1; + mask = 0x80; + } - last_match_length = match_length; - for( i = 0; i < last_match_length && infile.getChar( &ch ); i++ ) - { - DeleteNode( s ); - text_buf[ s ] = (quint8)ch; - if( s < F - 1 ) - text_buf[ s + N ] = (quint8)ch; + last_match_length = match_length; + for( i = 0; i < last_match_length && infile.getChar( &ch ); i++ ) + { + DeleteNode( s ); + text_buf[ s ] = (quint8)ch; + if( s < F - 1 ) + text_buf[ s + N ] = (quint8)ch; - s = ( s + 1 ) & ( N - 1 ); - r = ( r + 1 ) & ( N - 1 ); - InsertNode( r ); - } + s = ( s + 1 ) & ( N - 1 ); + r = ( r + 1 ) & ( N - 1 ); + InsertNode( r ); + } - while( i++ < last_match_length ) - { - DeleteNode( s ); - s = ( s + 1 ) & ( N - 1 ); - r = ( r + 1 ) & ( N - 1 ); - if( --len != 0 ) - InsertNode( r ); - } + while( i++ < last_match_length ) + { + DeleteNode( s ); + s = ( s + 1 ) & ( N - 1 ); + r = ( r + 1 ) & ( N - 1 ); + if( --len != 0 ) + InsertNode( r ); + } } while( len > 0 ); if( code_buf_ptr > 1 ) { - for( i = 0; i < code_buf_ptr; i++ ) - output.putChar( (quint8)code_buf[ i ] ); + for( i = 0; i < code_buf_ptr; i++ ) + output.putChar( (quint8)code_buf[ i ] ); - codesize += code_buf_ptr; + codesize += code_buf_ptr; } int padding = codesize % 4; if( padding != 0 ) - output.write( QByteArray( 4 - padding, '\0' ) ); + output.write( QByteArray( 4 - padding, '\0' ) ); infile.close(); return ret; diff --git a/WiiQt/nandbin.cpp b/WiiQt/nandbin.cpp index 94118dd..bccf2ea 100755 --- a/WiiQt/nandbin.cpp +++ b/WiiQt/nandbin.cpp @@ -219,133 +219,6 @@ bool NandBin::Format( bool secure ) #endif } -#if 0 // this boots ok on real HW. trap15 thinks these reserved blocks are IOS's way of marking ones it thinks are bad -bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList &badBlocks ) -{ -#ifndef NAND_BIN_CAN_WRITE - qWarning() << __FILE__ << "was built without write support"; - return false; -#endif - if( keys.size() != 0x400 || first8.size() != 0x108000 ) - { - qWarning() << "NandBin::CreateNew -> bad sizes" << hex << keys.size() << first8.size(); - return false; - } - for( quint16 i = 0; i < 0x40; i++ ) - { - if( badBlocks.contains( i / 8 ) ) - { - qWarning() << "NandBin::CreateNew -> creating a nand with bad blocks in the first 8 is not supported"; - return false; - } - } - - for( quint16 i = 0x7f00; i < 0x8000; i++ ) - { - if( badBlocks.contains( i / 8 ) ) - { - qWarning() << "NandBin::CreateNew -> creating a nand with bad blocks in the superclusters not supported"; - return false; - } - } - - if( f.isOpen() ) - f.close(); - - //create the new file, write the first 8 blocks, fill it with 0xff, and write the keys.bin at the end - f.setFileName( path ); - if( !f.open( QIODevice::ReadWrite | QIODevice::Truncate ) ) - { - qWarning() << "NandBin::CreateNew -> can't create file" << path; - return false; - } - - f.write( first8 ); - QByteArray block( 0x4200, 0xff );//generic empty block - for( quint16 i = 0; i < 0x7fc0; i++ ) - f.write( block ); - - f.write( keys ); - if( f.pos() != 0x21000400 )//no room left on the drive? - { - qWarning() << "NandBin::CreateNew -> dump size is wrong" << (quint32)f.pos(); - return false; - } - - //setup variables - nandPath = path; - currentSuperCluster = 0x7f00; - superClusterVersion = 1; - type = 2; - fats.clear(); - memset( &fsts, 0, sizeof( fst_t ) * 0x17ff ); - - for( quint16 i = 0; i < 0x17ff; i++ ) - fsts[ i ].fst_pos = i; - - //reserve blocks 0 - 7 - for( quint16 i = 0; i < 0x40; i++ ) - { - fats << 0xfffc; - } - //find 90 blocks to reserve. they always appear to be close to the end of the nand - //TODO - this isnt always 90, all my nands have a different number, and 90 is right in the middle - //sometimes IOS adds more - quint16 bCnt = badBlocks.size(); - quint16 offset = 0; - for( quint16 i = 0; i < bCnt; i++ ) - { - if( i >= 3998 ) - offset++; - } - - //mark all the "normal" blocks - free, or bad - for( quint16 i = 0x40; i < 0x7cf0 - offset; i++ ) - { - if( badBlocks.contains( i / 8 ) ) - fats << 0xfffd; - else - fats << 0xfffe; - - } - //mark the 90 reserved ones from above and reserve the superclusters - for( quint16 i = 0x7cf0 - offset; i < 0x8000; i++ ) - { - fats << 0xfffc; - } - - //make the root item - fsts[ 0 ].filename[ 0 ] = '/'; - fsts[ 0 ].attr = 0x16; - fsts[ 0 ].sib = 0xffff; - fsts[ 0 ].sub = 0xffff; - - fstInited = true; - - //set keys - QByteArray hmacKey = keys.mid( 0x144, 0x14 ); - spare.SetHMacKey( hmacKey );//set the hmac key for calculating spare data - key = keys.mid( 0x158, 0x10 ); - - //write the metada to each of the superblocks - for( quint8 i = 0; i < 0x10; i++ ) - { - if( !WriteMetaData() ) - { - qWarning() << "NandBin::CreateNew -> error writing superblock" << i; - return false; - } - } - - //build the tree - if( root ) - delete root; - root = new QTreeWidgetItem( QStringList() << nandPath ); - AddChildren( root, 0 ); - - return true; -} -#endif QTreeWidgetItem *NandBin::GetTree() { //qDebug() << "NandBin::GetTree()"; @@ -1344,10 +1217,10 @@ quint16 NandBin::CreateNode( const QString &name, quint32 uid, quint16 gid, quin return 0; } - QByteArray n = name.toLatin1().data(); + QByteArray n = name.toLatin1(); n.resize( 12 ); //qDebug() << "will add entry for" << n << "at" << hex << i; - memcpy( &fsts[ i ].filename, n, 12 ); + memcpy( &fsts[ i ].filename, n.data(), 12 ); fsts[ i ].attr = attr; fsts[ i ].wtf = 0; if( ( attr & 3 ) == 2 ) @@ -1552,14 +1425,14 @@ bool NandBin::DeleteItem( QTreeWidgetItem *item ) { fats.replace( cl, 0xfffe ); } - // qDebug() << "delete loop done. freed" << toFree.size() << "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 - // qDebug() << cnt << "childern"; + // qDebug() << cnt << "childern"; for( quint32 i = cnt; i > 0; i-- ) { if( !DeleteItem( item->child( i - 1 ) ) ) @@ -1575,7 +1448,7 @@ 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 ); + // qDebug() << "deleting tree item" << d->text( 0 ); delete d; return true; } @@ -1741,9 +1614,10 @@ bool NandBin::WriteMetaData() b.write( "SFFS" ); //magic word tmp = qFromBigEndian( nextClusterVersion ); - b.write( (const char*)&tmp, 4 ); //version - tmp = qFromBigEndian( (quint32)0x10 ); - b.write( (const char*)&tmp, 4 ); //wiibrew says its always 0x10. but mine is 0 + b.write( (const char*)&tmp, 4 ); //version + tmp = qFromBigEndian( (quint32)0 ); + //tmp = qFromBigEndian( (quint32)0x10 ); //wiibrew says its always 0x10. but mine is 0 + b.write( (const char*)&tmp, 4 ); //qDebug() << "writing the fats at" << hex << (quint32)b.pos(); //write all the fats @@ -1799,10 +1673,22 @@ bool NandBin::WriteMetaData() } } currentSuperCluster = nextSuperCluster; - superClusterVersion = nextClusterVersion; //probably need to put some magic here in case the version wraps around back to 0 + superClusterVersion = nextClusterVersion; - //make sure all the data is really written - f.flush(); + + //make sure all the data is really written + f.flush(); + + // in case the version wraps around back to 0 + if( !superClusterVersion ) + { + qDebug() << "NandBin::WriteMetaData -> SFFS generation rolled back to 0"; + for( quint16 i = 0; i < 15; i++ ) + { + if( !WriteMetaData() ) + return false; + } + } return true; } @@ -1908,7 +1794,7 @@ bool NandBin::CheckHmacData( quint16 entry ) } return true; -error: + error: qWarning() << FstName( fst ) << "is" << hex << fst.size << "bytes (" << clCnt << ") clusters"; hexdump( sp1 ); hexdump( sp2 ); @@ -1960,7 +1846,7 @@ bool NandBin::CheckHmacMeta( quint16 clNo ) } return true; -error: + error: qWarning() << "supercluster" << hex << clNo; hexdump( sp1 ); hexdump( sp2 ); diff --git a/WiiQt/tiktmd.cpp b/WiiQt/tiktmd.cpp index 37bcf4e..fb697f0 100644 --- a/WiiQt/tiktmd.cpp +++ b/WiiQt/tiktmd.cpp @@ -16,7 +16,7 @@ Tmd::Tmd( const QByteArray &stuff ) { data.resize( SignedSize() ); SetPointer(); - } + } //hexdump( stuff ); } @@ -230,7 +230,11 @@ void Tmd::Dbg() QString s = QString( "TMD Dbg:\ntid:: %1\ncnt:: %2\n" ) .arg( Tid(), 16, 16, QChar( '0' ) ) .arg( cnt ) + contents; - qDebug() << s; + qDebug() << s; + quint8 *p = (quint8*)data.data(); + qDebug() << "data" << p; + qDebug() << "pointer" << p_tmd; + qDebug() << "po" << payLoadOffset << SignedSize(); } bool Tmd::FakeSign() @@ -243,16 +247,17 @@ bool Tmd::FakeSign() quint16 i = 0; bool ret = false;//brute force the sha1 + quint16 *fs = (quint16*)&p_tmd->reserved2; do - { - p_tmd->zero = i;//no need to worry about endian here - if( GetSha1( data.mid( payLoadOffset, size ) ).startsWith( '\0' ) ) + { + *fs = i;//no need to worry about endian here + if( GetSha1( data.mid( payLoadOffset, size ) ).startsWith( '\0' ) ) { ret = true; break; } } - while( ++i ); + while( ++i ); return ret; } diff --git a/WiiQt/wad.cpp b/WiiQt/wad.cpp index dd8d883..d85dc7b 100644 --- a/WiiQt/wad.cpp +++ b/WiiQt/wad.cpp @@ -207,6 +207,8 @@ Wad::Wad( QDir dir ) //make sure to only add the tmd & ticket without all the cert mumbo jumbo tmdData = t.Data(); tikData = ticket.Data(); + t = Tmd( tmdData ); + ticket = Ticket( tikData ); quint16 cnt = t.Count(); diff --git a/nandBinCheck/main.cpp b/nandBinCheck/main.cpp index c84b336..204d5d2 100644 --- a/nandBinCheck/main.cpp +++ b/nandBinCheck/main.cpp @@ -548,7 +548,6 @@ bool CheckArm003( const QByteArray &stuff ) qDebug() << "\tSystem menu IOS does not appear to support the Korean-key check"; return false; - } void Check003()