mirror of
https://github.com/martravi/wiiqt6.git
synced 2024-11-22 05:29:14 +01:00
* add spare.cpp/.h for calculating ecc & hmac used in the nand
git-svn-id: http://wiiqt.googlecode.com/svn/trunk@20 389f4c8b-5dfe-645f-db0e-df882bc27289
This commit is contained in:
parent
729f215d4e
commit
86c9d73b1e
@ -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;
|
||||||
}
|
}
|
||||||
f.seek( 0x158 );
|
if( type == 0 )
|
||||||
retval = f.read( 16 );
|
{
|
||||||
|
f.seek( 0x158 );
|
||||||
|
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
|
||||||
|
@ -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
215
WiiQt/nandspare.cpp
Normal 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
206
WiiQt/nandspare.h
Normal 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 ................
|
||||||
|
|
||||||
|
*/
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user