* add spare.cpp/.h for calculating ecc & hmac used in the nand

This commit is contained in:
giantpune@gmail.com 2010-12-15 08:11:56 +00:00
parent 63f58938fe
commit 0ddcbca710
6 changed files with 616 additions and 17 deletions

2
.gitattributes vendored
View File

@ -14,6 +14,8 @@ WiiQt/nandbin.cpp -text
WiiQt/nandbin.h -text WiiQt/nandbin.h -text
WiiQt/nanddump.cpp -text WiiQt/nanddump.cpp -text
WiiQt/nanddump.h -text WiiQt/nanddump.h -text
WiiQt/nandspare.cpp -text
WiiQt/nandspare.h -text
WiiQt/nusdownloader.cpp -text WiiQt/nusdownloader.cpp -text
WiiQt/nusdownloader.h -text WiiQt/nusdownloader.h -text
WiiQt/savebanner.cpp -text WiiQt/savebanner.cpp -text

View File

@ -254,6 +254,56 @@ bool NandBin::InitNand( QIcon dirs, QIcon files )
blocks << block; blocks << block;
} }
//debug shitzz
//ecc
/*int blNo = 7;
for( int b = 0; b < 8; b++ )
{
qDebug() << "cluster" << b << "of block" << hex << blNo;
int clNo = ( blNo * 8 ) + b;
for( int i = 0; i < 8; i++ )
{
qDebug() << "page" << i << "of cluster" << hex << ( clNo - ( blNo * 8 ) ) << "(" << clNo << ")";
QByteArray whole = GetPage( ( clNo * 8 ) + i, true );
if( whole.size() != 0x840 )
{
qDebug() << "wrong size" << hex << whole.size();
continue;
}
QByteArray eccR = whole.mid( 0x800, 0x40 );
QByteArray eccC = NandSpare::CalcEcc( whole.left( 0x800 ) );
hexdump( eccR );
hexdump( eccC );
}
}*/
//this makes correct hmac data for the superblocks
/*int blNo = 0xff0;//first superblock
//int blNo = 0xffe;//last superblock
for( int b = blNo; b < 16 + blNo; b += 2 )
{
//if( !( b % 2 ) )
//continue;
QByteArray clData;
for( int c = 0; c < 16; c++ )
{
for( int p = 0; p < 8; p++ )
{
QByteArray whole = GetPage( ( ( b * 64 ) + ( c * 8 ) + p ), true );
clData += whole.left( 0x800 );
}
}
qDebug() << "hmac:";
QByteArray hmR = spare.Get_hmac_meta( clData, ( b * 8 ) );
hexdump( hmR );
}*/
//GetFile( 369 );
if( !bootBlocks.SetBlocks( blocks ) ) if( !bootBlocks.SetBlocks( blocks ) )
return false; return false;
@ -292,6 +342,7 @@ quint8 NandBin::Boot1Version()
bool NandBin::GetKey( int type ) bool NandBin::GetKey( int type )
{ {
QByteArray hmacKey;
switch( type ) switch( type )
{ {
case 0: case 0:
@ -307,9 +358,12 @@ bool NandBin::GetKey( int type )
keyPath.resize( sl + 1 ); keyPath.resize( sl + 1 );
keyPath += "keys.bin"; keyPath += "keys.bin";
key = ReadKeyfile( keyPath ); key = ReadKeyfile( keyPath, 0 );
if( key.isEmpty() ) if( key.isEmpty() )
return false; return false;
hmacKey = ReadKeyfile( keyPath, 1 );
if( hmacKey.isEmpty() )
return false;
} }
break; break;
case 2: case 2:
@ -319,6 +373,9 @@ bool NandBin::GetKey( int type )
emit SendError( tr( "Tried to read keys from unopened file" ) ); emit SendError( tr( "Tried to read keys from unopened file" ) );
return false; return false;
} }
f.seek( 0x21000144 );
hmacKey = f.read( 20 );
f.seek( 0x21000158 ); f.seek( 0x21000158 );
key = f.read( 16 ); key = f.read( 16 );
} }
@ -328,10 +385,12 @@ bool NandBin::GetKey( int type )
return false; return false;
break; break;
} }
spare.SetHMacKey( hmacKey );//set the hmac key for calculating spare data
//hexdump( hmacKey );
return true; return true;
} }
QByteArray NandBin::ReadKeyfile( QString path ) QByteArray NandBin::ReadKeyfile( QString path, quint8 type )
{ {
QByteArray retval; QByteArray retval;
QFile f( path ); QFile f( path );
@ -340,14 +399,22 @@ QByteArray NandBin::ReadKeyfile( QString path )
emit SendError( tr( "Can't open %1!" ).arg( path ) ); emit SendError( tr( "Can't open %1!" ).arg( path ) );
return retval; return retval;
} }
if( f.size() < 0x16e ) if( f.size() < 0x400 )
{ {
f.close(); f.close();
emit SendError( tr( "keys.bin is too small!" ) ); emit SendError( tr( "keys.bin is too small!" ) );
return retval; return retval;
} }
if( type == 0 )
{
f.seek( 0x158 ); f.seek( 0x158 );
retval = f.read( 16 ); retval = f.read( 16 );
}
else if( type == 1 )
{
f.seek( 0x144 );
retval = f.read( 20 );
}
f.close(); f.close();
return retval; return retval;
@ -388,7 +455,7 @@ qint32 NandBin::FindSuperblock()
f.seek( n_len[ type ] - 4 ); f.seek( n_len[ type ] - 4 );
} }
return -1; return -1;//hmmmm what happens if the last supercluster is the latest one? seems like a bug to fix at a later date...
} }
fst_t NandBin::GetFST( quint16 entry ) fst_t NandBin::GetFST( quint16 entry )
@ -422,7 +489,7 @@ fst_t NandBin::GetFST( quint16 entry )
f.read( (char*)&fst.attr, 1 ); f.read( (char*)&fst.attr, 1 );
f.read( (char*)&fst.sub, 2 ); f.read( (char*)&fst.sub, 2 );
f.read( (char*)&fst.sib, 2 ); f.read( (char*)&fst.sib, 2 );
if( type && ( entry + 1 ) % 64 == 0 )//bug in other nand.bin extracterizers. the entry for every 64th fst item is inturrupeted by some ecc shit if( type && ( entry + 1 ) % 64 == 0 )//bug in other nand.bin extracterizers. the entry for every 64th fst item is inturrupeted by some spare shit
{ {
f.read( (char*)&fst.size, 2 ); f.read( (char*)&fst.size, 2 );
f.seek( f.pos() + 0x40 ); f.seek( f.pos() + 0x40 );
@ -440,6 +507,7 @@ fst_t NandBin::GetFST( quint16 entry )
fst.uid = qFromBigEndian( fst.uid ); fst.uid = qFromBigEndian( fst.uid );
fst.gid = qFromBigEndian( fst.gid ); fst.gid = qFromBigEndian( fst.gid );
fst.x3 = qFromBigEndian( fst.x3 ); fst.x3 = qFromBigEndian( fst.x3 );
fst.fst_pos = entry;
fst.mode &= 1; fst.mode &= 1;
return fst; return fst;
@ -473,6 +541,21 @@ quint16 NandBin::GetFAT( quint16 fat_entry )
return ret; return ret;
} }
QByteArray NandBin::GetPage( quint32 pageNo, bool withEcc )
{
//qDebug() << "NandBin::GetPage( " << hex << pageNo << ", " << withEcc << " )";
quint32 n_pagelen[] = { 0x800, 0x840, 0x840 };
if( f.size() < ( pageNo + 1 ) * n_pagelen[ type ] )
{
emit SendError( tr( "Tried to read page past size of nand.bin" ) );
return QByteArray();
}
f.seek( pageNo * n_pagelen[ type ] ); //seek to the beginning of the page to read
QByteArray page = f.read( ( type && withEcc ) ? n_pagelen[ type ] : 0x800 );
return page;
}
QByteArray NandBin::GetCluster( quint16 cluster_entry, bool decrypt ) QByteArray NandBin::GetCluster( quint16 cluster_entry, bool decrypt )
{ {
//qDebug() << "NandBin::GetCluster" << hex << cluster_entry; //qDebug() << "NandBin::GetCluster" << hex << cluster_entry;
@ -492,7 +575,9 @@ QByteArray NandBin::GetCluster( quint16 cluster_entry, bool decrypt )
f.seek( ( cluster_entry * n_clusterlen[ type ] ) + ( i * n_pagelen[ type ] ) ); //seek to the beginning of the page to read f.seek( ( cluster_entry * n_clusterlen[ type ] ) + ( i * n_pagelen[ type ] ) ); //seek to the beginning of the page to read
//QByteArray page = f.read( n_pagelen[ type ] ); //read the page, with ecc //QByteArray page = f.read( n_pagelen[ type ] ); //read the page, with ecc
QByteArray page = f.read( 0x800 ); //read the page, skip the ecc QByteArray page = f.read( 0x800 ); //read the page, skip the ecc
//hexdump( page.mid( 0x800, 0x40 ) );//just here for debugging purposes
//cluster += page.left( 0x800 );
cluster += page; cluster += page;
} }
if( cluster.size() != 0x4000 ) if( cluster.size() != 0x4000 )
@ -520,25 +605,31 @@ QByteArray NandBin::GetFile( quint16 entry )
return GetFile( fst ); return GetFile( fst );
} }
QByteArray NandBin::GetFile( fst_t fst ) QByteArray NandBin::GetFile( fst_t fst_ )
{ {
if( !fst.size ) qDebug() << "NandBin::GetFile" << (const char*)fst_.filename;
if( !fst_.size )
return QByteArray(); return QByteArray();
quint16 fat = fst.sub; quint16 fat = fst_.sub;
//int cluster_span = (int)( fst.size / 0x4000) + 1; //int cluster_span = (int)( fst.size / 0x4000) + 1;
QByteArray data; QByteArray data;
//int idx = 0;
for (int i = 0; fat < 0xFFF0; i++) for (int i = 0; fat < 0xFFF0; i++)
{ {
QByteArray cluster = GetCluster( fat ); QByteArray cluster = GetCluster( fat );
if( cluster.size() != 0x4000 ) if( cluster.size() != 0x4000 )
return QByteArray(); return QByteArray();
//debug shit... am i creating correct hmac data?
//WriteDecryptedCluster( 0, cluster, fst_, idx++ );
data += cluster; data += cluster;
fat = GetFAT( fat ); fat = GetFAT( fat );
} }
//this check doesnt really seem to matter, it always appears to be 1 extra cluster added to the end //this check doesnt really seem to matter, it always appears to be 1 extra cluster added to the end
//of the file and that extra bit is dropped in this function before the data is returned. //of the file and that extra bit is dropped in this function before the data is returned.
/*if( data.size() != cluster_span * 0x4000 ) /*if( data.size() != cluster_span * 0x4000 )
@ -551,18 +642,18 @@ QByteArray NandBin::GetFile( fst_t fst )
emit SendError( tr( "Error reading file [ block size is not a as expected ] %1" ).arg( FstName( fst ) ) ); emit SendError( tr( "Error reading file [ block size is not a as expected ] %1" ).arg( FstName( fst ) ) );
}*/ }*/
if( (quint32)data.size() < fst.size ) if( (quint32)data.size() < fst_.size )
{ {
qDebug() << "(quint32)data.size() < fst.size :: " qDebug() << "(quint32)data.size() < fst.size :: "
<< hex << data.size() << hex << data.size()
<< "expected size:" << hex << fst.size; << "expected size:" << hex << fst_.size;
emit SendError( tr( "Error reading file [ returned data size is less that the size in the fst ]" ) ); emit SendError( tr( "Error reading file [ returned data size is less that the size in the fst ]" ) );
return QByteArray(); return QByteArray();
} }
if( (quint32)data.size() > fst.size ) if( (quint32)data.size() > fst_.size )
data.resize( fst.size );//dont need to give back all the data, only up to the expected size data.resize( fst_.size );//dont need to give back all the data, only up to the expected size
return data; return data;
} }
@ -694,6 +785,79 @@ void NandBin::ShowInfo()
<< "\nreserved:" << hex << reserved; << "\nreserved:" << hex << reserved;
} }
bool NandBin::WriteCluster( quint32 pageNo, const QByteArray data, const QByteArray hmac )
{
if( data.size() != 0x4000 )
{
qWarning() << "NandBin::WriteCluster -> size:" << hex << data.size();
return false;
}
for( int i = 0; i < 8; i++ )
{
QByteArray spareData( 0x40, '\0' );
quint8* sp = (quint8*)spareData.data();
QByteArray ecc = spare.CalcEcc( data.mid( i * 0x800, 0x800 ) );
memcpy( sp + 0x30, ecc.data(), 0x14 );
sp[ 0 ] = 0xff; // good block
if( !hmac.isEmpty() )
{
if( i == 6 )
{
memcpy( (char*)sp + 1, hmac.data(), 20 );
memcpy( (char*)sp + 21, hmac.data(), 12 );
}
else if( i == 7 )
{
memcpy( (char*)sp + 1, hmac.data() + 12, 8 );
}
}
if( !WritePage( pageNo + i, data.mid( i * 0x800, 0x800 ) + spareData ) )
return false;
}
return true;
}
bool NandBin::WriteDecryptedCluster( quint32 pageNo, const QByteArray data, fst_t fst, quint16 idx )
{
qDebug() << "NandBin::WriteDecryptedCluster";
QByteArray hmac = spare.Get_hmac_data( data, fst.uid, (const unsigned char *)&fst.filename, fst.fst_pos, fst.x3, idx );
hexdump( hmac );
return true;
/*fs_hmac_data(
buffer,
fp->node->uid,
(const unsigned char *)fp->node->name,
fp->idx,
fp->node->dummy,
fp->cluster_idx,
hmac
);*/
AesSetKey( key );
QByteArray encData = AesEncrypt( 0, data );
return WriteCluster( pageNo, encData, hmac );
}
bool NandBin::WritePage( quint32 pageNo, const QByteArray data )
{
//qDebug() << "NandBin::WritePage(" << hex << pageNo << ")";
return true;
quint32 n_pagelen[] = { 0x800, 0x840, 0x840 };
if( (quint32)data.size() != n_pagelen[ type ] )
{
qWarning() << "data is wrong size" << hex << data.size();
return false;
}
if( f.size() < ( pageNo + 1 ) * n_pagelen[ type ] )
{
emit SendError( tr( "Tried to write page past size of nand.bin" ) );
return false;
}
f.seek( pageNo * n_pagelen[ type ] ); //seek to the beginning of the page to write
return f.write( data );
}
/* /*
structure of blocks 0 - 7 structure of blocks 0 - 7

View File

@ -3,6 +3,7 @@
#include "includes.h" #include "includes.h"
#include "blocks0to7.h" #include "blocks0to7.h"
#include "nandspare.h"
struct fst_t struct fst_t
{ {
quint8 filename[ 0xc ]; quint8 filename[ 0xc ];
@ -14,6 +15,7 @@ struct fst_t
quint32 uid; quint32 uid;
quint16 gid; quint16 gid;
quint32 x3; quint32 x3;
quint16 fst_pos;//not really part of the nand structure, but needed when calculating hmac data
}; };
// class to deal with an encrypted wii nand dump // class to deal with an encrypted wii nand dump
// basic usage... create an object, set a path, call InitNand. then you can get the detailed list of entries with GetTree() // basic usage... create an object, set a path, call InitNand. then you can get the detailed list of entries with GetTree()
@ -89,6 +91,8 @@ public:
const QList<Boot2Info> Boot2Infos(); const QList<Boot2Info> Boot2Infos();
quint8 Boot1Version(); quint8 Boot1Version();
QByteArray GetPage( quint32 pageNo, bool withEcc = false );
private: private:
QByteArray key; QByteArray key;
@ -104,6 +108,8 @@ private:
QIcon groupIcon; QIcon groupIcon;
QIcon keyIcon; QIcon keyIcon;
NandSpare spare;//used to handle the hmac mumbojumbo
//read all the fst and remember them rather than seeking back and forth in the file all the time //read all the fst and remember them rather than seeking back and forth in the file all the time
// uses ~120KiB RAM // uses ~120KiB RAM
bool fstInited; bool fstInited;
@ -115,7 +121,7 @@ private:
int GetDumpType( quint64 fileSize ); int GetDumpType( quint64 fileSize );
bool GetKey( int type ); bool GetKey( int type );
QByteArray ReadKeyfile( QString path ); QByteArray ReadKeyfile( QString path, quint8 type );//type 0 for nand key, type 1 for hmac
qint32 FindSuperblock(); qint32 FindSuperblock();
quint16 GetFAT( quint16 fat_entry ); quint16 GetFAT( quint16 fat_entry );
fst_t GetFST( quint16 entry ); fst_t GetFST( quint16 entry );
@ -137,6 +143,10 @@ private:
//holds info about boot1 & 2 //holds info about boot1 & 2
Blocks0to7 bootBlocks; Blocks0to7 bootBlocks;
bool WriteCluster( quint32 pageNo, const QByteArray data, const QByteArray hmac );
bool WriteDecryptedCluster( quint32 pageNo, const QByteArray data, fst_t fst, quint16 idx );
bool WritePage( quint32 pageNo, const QByteArray data );
signals: signals:
//connect to these to receive messages from this object //connect to these to receive messages from this object
void SendError( QString ); void SendError( QString );

215
WiiQt/nandspare.cpp Normal file
View File

@ -0,0 +1,215 @@
#include "nandspare.h"
#include "tools.h"
NandSpare::NandSpare()
{
}
void NandSpare::SetHMacKey( const QByteArray key )
{
hmacKey = key;
}
quint8 NandSpare::Parity( quint8 x )
{
quint8 y = 0;
while( x )
{
y ^= ( x & 1 );
x >>= 1;
}
return y;
}
QByteArray NandSpare::CalcEcc( QByteArray in )
{
if( in.size() != 0x800 )
return QByteArray();
quint8 a[ 12 ][ 2 ];
quint32 a0, a1;
quint8 x;
QByteArray ret( 16, '\0' );
char* ecc = ret.data();
char* data = in.data();
for( int k = 0; k < 4; k++ )
{
memset( a, 0, sizeof a );
for( int i = 0; i < 512; i++ )
{
x = data[ i ];
for( int j = 0; j < 9; j++ )
a[ 3 + j ][ ( i >> j ) & 1 ] ^= x;
}
x = a[ 3 ][ 0 ] ^ a[ 3 ][ 1 ];
a[ 0 ][ 0 ] = x & 0x55;
a[ 0 ][ 1 ] = x & 0xaa;
a[ 1 ][ 0 ] = x & 0x33;
a[ 1 ][ 1 ] = x & 0xcc;
a[ 2 ][ 0 ] = x & 0x0f;
a[ 2 ][ 1 ] = x & 0xf0;
for( int j = 0; j < 12; j++ )
{
a[ j ][ 0 ] = Parity( a[ j ][ 0 ]);
a[ j ][ 1 ] = Parity( a[ j ][ 1 ]);
}
a0 = a1 = 0;
for( int j = 0; j < 12; j++ )
{
a0 |= a[ j ][ 0 ] << j;
a1 |= a[ j ][ 1 ] << j;
}
ecc[ 0 ] = a0;
ecc[ 1 ] = a0 >> 8;
ecc[ 2 ] = a1;
ecc[ 3 ] = a1 >> 8;
data += 512;
ecc += 4;
}
return ret;
}
typedef struct{
unsigned char key[ 0x40 ];
SHA1Context hash_ctx;
} hmac_ctx;
void wbe32(void *ptr, quint32 val) { *(quint32*)ptr = qFromBigEndian( (quint32)val ); }
void wbe16(void *ptr, quint16 val) { *(quint16*)ptr = qFromBigEndian( val ); }
// reversing done by gray
static unsigned char hmac_key[ 20 ];
void hmac_init(hmac_ctx *ctx, const char *key, int key_size)
{
key_size = key_size<0x40 ? key_size: 0x40;
memset( ctx->key,0,0x40 );
memcpy( ctx->key,key,key_size );
for( int i = 0; i < 0x40; ++i )
ctx->key[ i ] ^= 0x36; // ipad
SHA1Reset( &ctx->hash_ctx );
SHA1Input( &ctx->hash_ctx, ctx->key, 0x40 );
}
void hmac_update( hmac_ctx *ctx, const quint8 *data, int size )
{
SHA1Input( &ctx->hash_ctx,data,size );
}
void hmac_final( hmac_ctx *ctx, unsigned char *hmac )
{
//int i;
unsigned char hash[ 0x14 ];
memset( hash, 0, 0x14 );
SHA1Result(&ctx->hash_ctx);
// this sha1 implementation is buggy, needs to switch endian
for( int i = 0;i < 5;++i )
{
wbe32( hash + 4 * i, ctx->hash_ctx.Message_Digest[ i ] );
}
for( int i = 0; i < 0x40; ++i )
ctx->key[i] ^= 0x36^0x5c; // opad
SHA1Reset(&ctx->hash_ctx);
SHA1Input(&ctx->hash_ctx,ctx->key,0x40);
SHA1Input(&ctx->hash_ctx,hash,0x14);
SHA1Result(&ctx->hash_ctx);
//hexdump(ctx->hash_ctx.Message_Digest, 0x14);
for( int i = 0; i < 5; ++i )
{
wbe32( hash + 4 * i, ctx->hash_ctx.Message_Digest[ i ] );
}
memcpy( hmac, hash, 0x14 );
}
void fs_hmac_set_key(const char *key, int key_size)
{
memset( hmac_key, 0, 0x14 );
memcpy( hmac_key, key, key_size < 0x14 ? key_size : 0x14 );
}
void fs_hmac_generic( const unsigned char *data, int size, const unsigned char *extra, int extra_size, unsigned char *hmac )
{
hmac_ctx ctx;
hmac_init( &ctx,(const char *)hmac_key,0x14 );
hmac_update( &ctx,extra, extra_size );
hmac_update( &ctx,data, size );
hmac_final( &ctx, hmac );
}
void fs_hmac_meta( const unsigned char *super_data, short super_blk, unsigned char *hmac )
{
unsigned char extra[ 0x40 ];
memset( extra,0,0x40 );
wbe16( extra + 0x12, super_blk );
fs_hmac_generic( super_data, 0x40000, extra, 0x40, hmac );
}
void fs_hmac_data( const unsigned char *data, quint32 uid, const unsigned char *name, quint32 entry_n, quint32 x3, quint16 blk, unsigned char *hmac )
{
//int i,j;
unsigned char extra[ 0x40 ];
memset( extra, 0, 0x40 );
wbe32( extra, uid );
memcpy( extra + 4, name, 12 );
wbe16( extra + 0x12, blk );
wbe32( extra + 0x14, entry_n );
wbe32( extra + 0x18, x3 );
// fprintf(stderr,"extra (%s): \nX ",name);
// for(i=0;i<0x20;++i){
// fprintf(stderr,"%02X ",extra[i]);
// if(!((i+1)&0xf)) fprintf(stderr,"\nX ");
// }
fs_hmac_generic( data, 0x4000, extra, 0x40, hmac );
}
QByteArray NandSpare::Get_hmac_data( const QByteArray cluster, quint32 uid, const unsigned char *name, quint32 entry_n, quint32 x3, quint16 blk )
{
qDebug() << "NandSpare::Get_hmac_data" << hex << cluster.size() << uid << QString( (const char*)name, 12 ) << entry_n << x3 << blk;
if( hmacKey.size() != 0x14 || cluster.size() != 0x4000 )
return QByteArray();
fs_hmac_set_key( hmacKey.data(), 0x14 );
QByteArray ret( 0x14, '\xba' );
fs_hmac_data( (const unsigned char *)cluster.data(), uid, name, entry_n, x3, blk, (unsigned char *)ret.data() );
return ret;
}
QByteArray NandSpare::Get_hmac_meta( const QByteArray cluster, quint16 super_blk )
{
//qDebug() << "NandSpare::Get_hmac_meta" << hex << super_blk;
if( hmacKey.size() != 0x14 || cluster.size() != 0x40000 )
{
//qDebug() << "NandSpare::Get_hmac_meta" << hex << hmacKey.size() << cluster.size();
return QByteArray();
}
fs_hmac_set_key( hmacKey.data(), 0x14 );
QByteArray ret( 0x14, '\0' );
fs_hmac_meta( (const unsigned char *)cluster.data(), super_blk, (unsigned char *)ret.data() );
return ret;
}

206
WiiQt/nandspare.h Normal file
View File

@ -0,0 +1,206 @@
#ifndef NANDSPARE_H
#define NANDSPARE_H
//some class to handle the ecc & hmac data in the nandBin
#include "includes.h"
#include "sha1.h"
class NandSpare
{
public:
NandSpare();
void SetHMacKey( const QByteArray key );
QByteArray Get_hmac_data( const QByteArray cluster, quint32 uid, const unsigned char *name, quint32 entry_n, quint32 x3, quint16 blk );
QByteArray Get_hmac_meta( const QByteArray cluster, quint16 super_blk );
static QByteArray CalcEcc( QByteArray in );
static quint8 Parity( quint8 x );
private:
QByteArray hmacKey;
};
#endif // NANDSPARE_H
/*
spare data...
0x40 bytes
0x30 = hmac
0x10 = ecc
block 0 ( boot1 )
all hmac is 0xffs
all ecc is calc'd. after the first 9 pages, it works out to all 0s
block 1 ( boot2v2 )
all hmac is 0xff and then 0s
block 2
same as above until page 2
starting at page 2, no ecc or hmac is written. its all 0xff
spare data is only written for pages used, not on a cluster basis
block 3 ( bootmii )
same as block 1
block 4
same as above( hmac starts with 0xff then all 0s. after page2 cluster 2 all ecc works at to 0s as well )
spare data is written for clusters used, not on a page basis
block 5 ( never been used )
all spare data is 0xffs, nothing is calculated
block 6 ( boot2 copy )
same as block 2
block 7
same as block 1
super blocks
hmac data is only on
block ff1 cluster 7 page: 6 ( 3fc7e )
block ff1 cluster 7 page: 7 ( 3fc7f )
block ff3 cluster 7 page: 6 ( 3fcfe )
block ff3 cluster 7 page: 7 ( 3fcff )
block ff5 cluster 7 page: 6 ( 3fd7e )
block ff5 cluster 7 page: 7 ( 3fd7f )
block ff7 cluster 7 page: 6 ( 3fdfe )
block ff7 cluster 7 page: 7 ( 3fdff )
block ff9 cluster 7 page: 6 ( 3fe7e )
block ff9 cluster 7 page: 7 ( 3fe7f )
block ffb cluster 7 page: 6 ( 3fefe )
block ffb cluster 7 page: 7 ( 3feff )
block ffd cluster 7 page: 6 ( 3ff7e )
block ffd cluster 7 page: 7 ( 3ff7f )
block fff cluster 7 page: 6 ( 3fffe )
block fff cluster 7 page: 7 ( 3ffff )
*/
/*
block ff1 cluster 7 page: 6 ( 3fc7e )
NandBin::GetPage( 3fc7e , true )
00000000 ff1646bd cef67127 e662a4dc 5154ec52 ..F...q'.b..QT.R
00000010 c844ebb9 fb1646bd cef67127 e662a4dc .D....F...q'.b..
00000020 51000000 00000000 00000000 00000000 Q...............
00000030 00000000 00000000 00000000 00000000 ................
block ff1 cluster 7 page: 7 ( 3fc7f )
NandBin::GetPage( 3fc7f , true )
00000000 ff54ec52 c844ebb9 fb000000 0020049e .T.R.D....... ..
00000010 00000000 40000000 002004f1 a8000000 ....@.... ......
00000020 00000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
block ff3 cluster 7 page: 6 ( 3fcfe )
NandBin::GetPage( 3fcfe , true )
00000000 ff199405 907b607c 4cd691d2 825f2de9 .....{`|L...._-.
00000010 18185217 38199405 907b607c 4cd691d2 ..R.8....{`|L...
00000020 82000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
block ff3 cluster 7 page: 7 ( 3fcff )
NandBin::GetPage( 3fcff , true )
00000000 ff5f2de9 18185217 38600000 000043dd ._-...R.8`....C.
00000010 05cf0bd7 38c882b2 24b67f57 6087c41f ....8...$..W`...
00000020 4d000000 00000000 00000000 00000000 M...............
00000030 00000000 00000000 00000000 00000000 ................
block ff5 cluster 7 page: 6 ( 3fd7e )
NandBin::GetPage( 3fd7e , true )
00000000 ff1c1964 3e97b995 b864f566 b9fa025d ...d>....d.f...]
00000010 4f708e95 cc1c1964 3e97b995 b864f566 Op.....d>....d.f
00000020 b9000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
block ff5 cluster 7 page: 7 ( 3fd7f )
NandBin::GetPage( 3fd7f , true )
00000000 fffa025d 4f708e95 cc2004f8 80b8f3d4 ...]Op... ......
00000010 b94820bc f631c4c2 40c8e1da 12a29ba9 .H ..1..@.......
00000020 df000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
*//*
block ff7 cluster 7 page: 6 ( 3fdfe )
NandBin::GetPage( 3fdfe , true )
00000000 ffff8ca6 8f936ad2 d4fb8424 16cd48ef ......j....$..H.
00000010 1ee1003f edff8ca6 8f936ad2 d4fb8424 ...?......j....$
00000020 16000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
block ff7 cluster 7 page: 7 ( 3fdff )
NandBin::GetPage( 3fdff , true )
00000000 ffcd48ef 1ee1003f ed000000 1020000d ..H....?..... ..
00000010 eb000000 01000000 03000000 022004f7 ............. ..
00000020 f4000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
block ff9 cluster 7 page: 6 ( 3fe7e )
NandBin::GetPage( 3fe7e , true )
00000000 ffada309 ba23b5e5 fa37a52d 10d13f10 .....#...7.-..?.
00000010 72265162 43ada309 ba23b5e5 fa37a52d r&QbC....#...7.-
00000020 10000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
block ff9 cluster 7 page: 7 ( 3fe7f )
NandBin::GetPage( 3fe7f , true )
00000000 ffd13f10 72265162 432000ae 00000000 ..?.r&QbC ......
00000010 002004ae 00000000 102004f1 e02000ad . ....... ... ..
00000020 c4000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
block ffb cluster 7 page: 6 ( 3fefe )
NandBin::GetPage( 3fefe , true )
00000000 ff40a82f f3e32161 5f9e91e7 841daf5e .@./..!a_......^
00000010 c74678b2 b540a82f f3e32161 5f9e91e7 .Fx..@./..!a_...
00000020 84000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
block ffb cluster 7 page: 7 ( 3feff )
NandBin::GetPage( 3feff , true )
00000000 ff1daf5e c74678b2 b52000ae 0000ed15 ...^.Fx.. ......
00000010 e892928e 766d0000 00000000 00022001 ....vm........ .
00000020 da000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
block ffd cluster 7 page: 6 ( 3ff7e )
NandBin::GetPage( 3ff7e , true )
00000000 ff80ded9 67d7c195 ffd65a8b 907ea776 ....g.....Z..~.v
00000010 8c56dc33 8280ded9 67d7c195 ffd65a8b .V.3....g.....Z.
00000020 90000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
block ffd cluster 7 page: 7 ( 3ff7f )
NandBin::GetPage( 3ff7f , true )
00000000 ff7ea776 8c56dc33 82000000 00200091 .~.v.V.3..... ..
00000010 c0000000 40000000 002004f1 80000000 ....@.... ......
00000020 00000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
block fff cluster 7 page: 6 ( 3fffe )
NandBin::GetPage( 3fffe , true )
00000000 ff9570f7 915460fe 3f32d363 9a1ebfa9 ..p..T`.?2.c....
00000010 74d3e0a4 969570f7 915460fe 3f32d363 t.....p..T`.?2.c
00000020 9a000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
block fff cluster 7 page: 7 ( 3ffff )
NandBin::GetPage( 3ffff , true )
00000000 ff1ebfa9 74d3e0a4 962004f8 80b8f3d4 ....t.... ......
00000010 b94820bc f631c4c2 40c8e1da 12a29ba9 .H ..1..@.......
00000020 df000000 00000000 00000000 00000000 ................
00000030 00000000 00000000 00000000 00000000 ................
*/

View File

@ -13,14 +13,16 @@ SOURCES += main.cpp \
../WiiQt/aes.c \ ../WiiQt/aes.c \
../WiiQt/sha1.c \ ../WiiQt/sha1.c \
nandthread.cpp \ nandthread.cpp \
boot2infodialog.cpp boot2infodialog.cpp \
../WiiQt/nandspare.cpp
HEADERS += nandwindow.h \ HEADERS += nandwindow.h \
../WiiQt/tiktmd.h \ ../WiiQt/tiktmd.h \
../WiiQt/nandbin.h \ ../WiiQt/nandbin.h \
../WiiQt/tools.h \ ../WiiQt/tools.h \
nandthread.h \ nandthread.h \
boot2infodialog.h boot2infodialog.h \
../WiiQt/nandspare.h
FORMS += nandwindow.ui \ FORMS += nandwindow.ui \
boot2infodialog.ui boot2infodialog.ui