* moving the "library" files into a common folder 'WiiQt'

* adding in ASH0, LZ77 and  ( messy ) U8 classes
This commit is contained in:
giantpune@gmail.com 2010-12-10 03:50:08 +00:00
parent 4a3c8bb598
commit 085ce1d522
48 changed files with 3290 additions and 596 deletions

64
.gitattributes vendored
View File

@ -1,45 +1,53 @@
* text=auto !eol
nandExtract/aes.c -text
nandExtract/aes.h -text
WiiQt/aes.c -text
WiiQt/aes.h -text
WiiQt/ash.cpp -text
WiiQt/ash.h -text
WiiQt/includes.h -text
WiiQt/lz77.cpp -text
WiiQt/lz77.h -text
WiiQt/md5.cpp -text
WiiQt/md5.h -text
WiiQt/nandbin.cpp -text
WiiQt/nandbin.h -text
WiiQt/nanddump.cpp -text
WiiQt/nanddump.h -text
WiiQt/nusdownloader.cpp -text
WiiQt/nusdownloader.h -text
WiiQt/savebanner.cpp -text
WiiQt/savebanner.h -text
WiiQt/settingtxtdialog.cpp -text
WiiQt/settingtxtdialog.h -text
WiiQt/settingtxtdialog.ui -text
WiiQt/sha1.c -text
WiiQt/sha1.h -text
WiiQt/sharedcontentmap.cpp -text
WiiQt/sharedcontentmap.h -text
WiiQt/tiktmd.cpp -text
WiiQt/tiktmd.h -text
WiiQt/tools.cpp -text
WiiQt/tools.h -text
WiiQt/u8.cpp -text
WiiQt/u8.h -text
WiiQt/uidmap.cpp -text
WiiQt/uidmap.h -text
WiiQt/wad.cpp -text
WiiQt/wad.h -text
nandExtract/includes.h -text
nandExtract/main.cpp -text
nandExtract/nandExtract.pro -text
nandExtract/nandbin.cpp -text
nandExtract/nandbin.h -text
nandExtract/nandwindow.cpp -text
nandExtract/nandwindow.h -text
nandExtract/nandwindow.ui -text
nandExtract/readmii.txt -text
nandExtract/tools.cpp -text
nandExtract/tools.h -text
nand_dump/aes.c -text
nand_dump/aes.h -text
nand_dump/includes.h -text
nand_dump/main.cpp -text
nand_dump/mainwindow.cpp -text
nand_dump/mainwindow.h -text
nand_dump/mainwindow.ui -text
nand_dump/nand.pro -text
nand_dump/nanddump.cpp -text
nand_dump/nanddump.h -text
nand_dump/nusdownloader.cpp -text
nand_dump/nusdownloader.h -text
nand_dump/readmii.txt -text
nand_dump/settingtxtdialog.cpp -text
nand_dump/settingtxtdialog.h -text
nand_dump/settingtxtdialog.ui -text
nand_dump/sha1.c -text
nand_dump/sha1.h -text
nand_dump/sharedcontentmap.cpp -text
nand_dump/sharedcontentmap.h -text
nand_dump/tiktmd.cpp -text
nand_dump/tiktmd.h -text
nand_dump/tools.cpp -text
nand_dump/tools.h -text
nand_dump/uidmap.cpp -text
nand_dump/uidmap.h -text
nand_dump/wad.cpp -text
nand_dump/wad.h -text
saveToy/includes.h -text
saveToy/main.cpp -text
saveToy/mainwindow.cpp -text
@ -50,11 +58,7 @@ saveToy/noIcon.png -text
saveToy/rc.qrc -text
saveToy/readmii.txt -text
saveToy/saveToy.pro -text
saveToy/savebanner.cpp -text
saveToy/savebanner.h -text
saveToy/savelistitem.cpp -text
saveToy/savelistitem.h -text
saveToy/saveloadthread.cpp -text
saveToy/saveloadthread.h -text
saveToy/tools.cpp -text
saveToy/tools.h -text

429
WiiQt/ash.cpp Normal file
View File

@ -0,0 +1,429 @@
#include "ash.h"
bool IsAshCompressed( const QByteArray ba )
{
return ba.startsWith( "ASH" );
}
QByteArray DecryptAsh( const QByteArray ba )
{
if( !IsAshCompressed( ba ) )
{
qWarning() << "DecryptAsh -> wrong magic";
return QByteArray();
}
quint32 r[ 32 ];
quint32 count=0;
quint32 t;
quint64 memAddr = (quint64)( ba.data() );//in
r[4] = 0x80000000;
qint64 inDiff = memAddr - r[ 4 ];//difference in r[ 4 ] and the real address. hack to support higher memory addresses than crediar's version
r[5] = 0x415348;
r[6] = 0x415348;
//Rvl_decode_ash:
r[5] = qFromBigEndian(*(quint32 *)( r[4] + inDiff + 4 ) );
r[5] = r[5] & 0x00FFFFFF;
quint32 size = r[5];
//qDebug() << "Decompressed size:" << hex << size;
char crap2[ size ];
quint64 memAddr2 = (quint64)( crap2 );//outbuf
r[3] = 0x90000000;
qint64 outDiff = memAddr2 - r[ 3 ];//difference in r[ 3 ] and the real address
quint32 o = r[ 3 ];
memset( (void*)( r[ 3 ] + outDiff ), 0, size );
r[24] = 0x10;
r[28] = qFromBigEndian(*(quint32 *)(r[4]+8 + inDiff));
r[25] = 0;
r[29] = 0;
r[26] = qFromBigEndian(*(quint32 *)(r[4]+0xC + inDiff));
r[30] = qFromBigEndian(*(quint32 *)(r[4]+r[28] + inDiff));
r[28] = r[28] + 4;
//r[8] = 0x8108<<16;
//HACK, pointer to RAM
char crap3[ 0x100000 ];
quint64 memAddr3 = (quint64)( crap3 );//outbuf
r[8] = 0x84000000;
qint64 outDiff2 = memAddr3 - r[ 8 ];//difference in r[ 3 ] and the real address
memset( (void*)( r[8] + outDiff2 ), 0, 0x100000 );
r[8] = r[8];
r[9] = r[8] + 0x07FE;
r[10] = r[9] + 0x07FE;
r[11] = r[10] + 0x1FFE;
r[31] = r[11] + 0x1FFE;
r[23] = 0x200;
r[22] = 0x200;
r[27] = 0;
loc_81332124:
if( r[25] != 0x1F )
goto loc_81332140;
r[0] = r[26] >> 31;
r[26]= qFromBigEndian(*(quint32 *)(r[4] + r[24] + inDiff));
r[25]= 0;
r[24]= r[24] + 4;
goto loc_8133214C;
loc_81332140:
r[0] = r[26] >> 31;
r[25]= r[25] + 1;
r[26]= r[26] << 1;
loc_8133214C:
if( r[0] == 0 )
goto loc_81332174;
r[0] = r[23] | 0x8000;
*(quint16 *)(r[31] + outDiff2) = (quint16)qFromBigEndian((quint16)r[0]);
r[0] = r[23] | 0x4000;
*(quint16 *)(r[31]+2 + outDiff2) = (quint16)qFromBigEndian((quint16)r[0]);
r[31] = r[31] + 4;
r[27] = r[27] + 2;
r[23] = r[23] + 1;
r[22] = r[22] + 1;
goto loc_81332124;
loc_81332174:
r[12] = 9;
r[21] = r[25] + r[12];
t = r[21];
if( r[21] > 0x20 )
goto loc_813321AC;
r[21] = (~(r[12] - 0x20))+1;
r[6] = r[26] >> r[21];
if( t == 0x20 )
goto loc_8133219C;
r[26] = r[26] << r[12];
r[25] = r[25] + r[12];
goto loc_813321D0;
loc_8133219C:
r[26]= qFromBigEndian(*(quint32 *)(r[4] + r[24] + inDiff));
r[25]= 0;
r[24]= r[24] + 4;
goto loc_813321D0;
loc_813321AC:
r[0] = (~(r[12] - 0x20))+1;
r[6] = r[26] >> r[0];
r[26]= qFromBigEndian(*(quint32 *)(r[4] + r[24] + inDiff));
r[0] = (~(r[21] - 0x40))+1;
r[24]= r[24] + 4;
r[0] = r[26] >> r[0];
r[6] = r[6] | r[0];
r[25] = r[21] - 0x20;
r[26] = r[26] << r[25];
loc_813321D0:
r[12]= (quint16)qFromBigEndian((quint16)(*(quint16 *)(( r[31] + outDiff2 ) - 2)));
r[31] -= 2;
r[27]= r[27] - 1;
r[0] = r[12] & 0x8000;
r[12]= (r[12] & 0x1FFF) << 1;
if( r[0] == 0 )
goto loc_813321F8;
*(quint16 *)(r[9]+r[12] + outDiff2 ) = (quint16)qFromBigEndian((quint16)r[6]);//?????
r[6] = (r[12] & 0x3FFF)>>1;//extrwi %r6, %r12, 14,17
if( r[27] != 0 )
goto loc_813321D0;
goto loc_81332204;
loc_813321F8:
*(quint16 *)(r[8]+r[12] + outDiff2) = (quint16)qFromBigEndian((quint16)r[6]);
r[23] = r[22];
goto loc_81332124;
loc_81332204:
r[23] = 0x800;
r[22] = 0x800;
loc_8133220C:
if( r[29] != 0x1F )
goto loc_81332228;
r[0] = r[30] >> 31;
r[30]= qFromBigEndian(*(quint32 *)(r[4] + r[28] + inDiff));
r[29]= 0;
r[28]= r[28] + 4;
goto loc_81332234;
loc_81332228:
r[0] = r[30] >> 31;
r[29]= r[29] + 1;
r[30]= r[30] << 1;
loc_81332234:
if( r[0] == 0 )
goto loc_8133225C;
r[0] = r[23] | 0x8000;
*(quint16 *)(r[31] + outDiff2) = (quint16)qFromBigEndian((quint16)r[0]);
r[0] = r[23] | 0x4000;
*(quint16 *)(r[31]+2 + outDiff2) = (quint16)qFromBigEndian((quint16)r[0]);
r[31] = r[31] + 4;
r[27] = r[27] + 2;
r[23] = r[23] + 1;
r[22] = r[22] + 1;
goto loc_8133220C;
loc_8133225C:
r[12] = 0xB;
r[21] = r[29] + r[12];
t = r[21];
if( r[21] > 0x20 )
goto loc_81332294;
r[21] = (~(r[12] - 0x20))+1;
r[7] = r[30] >> r[21];
if( t == 0x20 )
goto loc_81332284;
r[30] = r[30] << r[12];
r[29] = r[29] + r[12];
goto loc_813322B8;
loc_81332284:
r[30]= qFromBigEndian(*(quint32 *)(r[4] + r[28] + inDiff));
r[29]= 0;
r[28]= r[28] + 4;
goto loc_813322B8;
loc_81332294:
r[0] = (~(r[12] - 0x20))+1;
r[7] = r[30] >> r[0];
r[30]= qFromBigEndian(*(quint32 *)(r[4] + r[28] + inDiff));
r[0] = (~(r[21] - 0x40))+1;
r[28]= r[28] + 4;
r[0] = r[30] >> r[0];
r[7] = r[7] | r[0];
r[29]= r[21] - 0x20;
r[30]= r[30] << r[29];
loc_813322B8:
r[12]= (quint16)qFromBigEndian((quint16)(*(quint16 *)((r[31] + outDiff2 ) - 2)));
r[31] -= 2;
r[27]= r[27] - 1;
r[0] = r[12] & 0x8000;
r[12]= (r[12] & 0x1FFF) << 1;
if( r[0] == 0 )
goto loc_813322E0;
*(quint16 *)(r[11]+r[12] + outDiff2 ) = (quint16)qFromBigEndian((quint16)r[7]);//????
r[7] = (r[12] & 0x3FFF)>>1;// extrwi %r7, %r12, 14,17
if( r[27] != 0 )
goto loc_813322B8;
goto loc_813322EC;
loc_813322E0:
*(quint16 *)(r[10]+r[12] + outDiff2 ) = (quint16)qFromBigEndian((quint16)r[7]);
r[23] = r[22];
goto loc_8133220C;
loc_813322EC:
r[0] = r[5];
loc_813322F0:
r[12]= r[6];
loc_813322F4:
if( r[12] < 0x200 )
goto loc_8133233C;
if( r[25] != 0x1F )
goto loc_81332318;
r[31] = r[26] >> 31;
r[26] = qFromBigEndian(*(quint32 *)(r[4] + r[24] + inDiff));
r[24] = r[24] + 4;
r[25] = 0;
goto loc_81332324;
loc_81332318:
r[31] = r[26] >> 31;
r[25] = r[25] + 1;
r[26] = r[26] << 1;
loc_81332324:
r[27] = r[12] << 1;
if( r[31] != 0 )
goto loc_81332334;
r[12] = (quint16)qFromBigEndian((quint16)(*(quint16 *)(r[8] + r[27] + outDiff2 )));
goto loc_813322F4;
loc_81332334:
r[12] = (quint16)qFromBigEndian((quint16)(*(quint16 *)(r[9] + r[27] + outDiff2 )));
goto loc_813322F4;
loc_8133233C:
if( r[12] >= 0x100 )
goto loc_8133235C;
*(quint8 *)(r[3] + outDiff) = r[12];
r[3] = r[3] + 1;
r[5] = r[5] - 1;
if( r[5] != 0 )
goto loc_813322F0;
goto loc_81332434;
loc_8133235C:
r[23] = r[7];
loc_81332360:
if( r[23] < 0x800 )
goto loc_813323A8;
if( r[29] != 0x1F )
goto loc_81332384;
r[31] = r[30] >> 31;
r[30] = qFromBigEndian(*(quint32 *)(r[4] + r[28] + inDiff));
r[28] = r[28] + 4;
r[29] = 0;
goto loc_81332390;
loc_81332384:
r[31] = r[30] >> 31;
r[29] = r[29] + 1;
r[30] = r[30] << 1;
loc_81332390:
r[27] = r[23] << 1;
if( r[31] != 0 )
goto loc_813323A0;
r[23] = (quint16)qFromBigEndian((quint16)(*(quint16 *)(r[10] + r[27] + outDiff2 )));
goto loc_81332360;
loc_813323A0:
r[23] = (quint16)qFromBigEndian((quint16)(*(quint16 *)(r[11] + r[27] + outDiff2 )));
goto loc_81332360;
loc_813323A8:
r[12] = r[12] - 0xFD;
r[23] = ~r[23] + r[3] + 1;
r[5] = ~r[12] + r[5] + 1;
r[31] = r[12] >> 3;
if( r[31] == 0 )
goto loc_81332414;
count = r[31];
loc_813323C0:
r[31] = *(quint8 *)(( r[23] + outDiff ) - 1);
*(quint8 *)(r[3] + outDiff) = r[31];
r[31] = *(quint8 *)( r[23] + outDiff );
*(quint8 *)(r[3]+1 + outDiff) = r[31];
r[31] = *(quint8 *)(( r[23] + outDiff ) + 1);
*(quint8 *)(r[3]+2 + outDiff) = r[31];
r[31] = *(quint8 *)(( r[23] + outDiff ) + 2);
*(quint8 *)(r[3]+3 + outDiff) = r[31];
r[31] = *(quint8 *)(( r[23] + outDiff ) + 3);
*(quint8 *)(r[3]+4 + outDiff) = r[31];
r[31] = *(quint8 *)(( r[23] + outDiff ) + 4);
*(quint8 *)(r[3]+5 + outDiff) = r[31];
r[31] = *(quint8 *)(( r[23] + outDiff ) + 5);
*(quint8 *)(r[3]+6 + outDiff) = r[31];
r[31] = *(quint8 *)(( r[23] + outDiff ) + 6);
*(quint8 *)(r[3]+7 + outDiff) = r[31];
r[23] = r[23] + 8;
r[3] = r[3] + 8;
if( --count )
goto loc_813323C0;
r[12] = r[12] & 7;
if( r[12] == 0 )
goto loc_8133242C;
loc_81332414:
count = r[12];
loc_81332418:
r[31] = *(quint8 *)(( r[23] + outDiff ) - 1);
r[23] = r[23] + 1;
*(quint8 *)(r[3] + outDiff ) = r[31];
r[3] = r[3] + 1;
if( --count )
goto loc_81332418;
loc_8133242C:
if( r[5] != 0 )
goto loc_813322F0;
loc_81332434:
r[3] = r[0];
QByteArray ret( r[ 3 ], '\0' );
QBuffer outBuf( &ret );
outBuf.open( QIODevice::WriteOnly );
outBuf.write( (const char*)( o + outDiff ), r[ 3 ] );
outBuf.close();
return ret;
}

13
WiiQt/ash.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef ASH_H
#define ASH_H
#include "includes.h"
//returns a byteArray of decompressed ASH data
//returns an empty array if the data doesnt have the ASH magic word
QByteArray DecryptAsh( const QByteArray ba );
//check if data starts with "ASH". no other check is done
bool IsAshCompressed( const QByteArray ba );
#endif // ASH_H

View File

@ -15,8 +15,8 @@
#include <QMainWindow>
#include <QMenu>
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkReply>
//#include <QNetworkAccessManager>
//#include <QNetworkReply>
#include <QObject>
#include <QProcess>
#include <QQueue>

393
WiiQt/lz77.cpp Normal file
View File

@ -0,0 +1,393 @@
#include "lz77.h"
//most functions here are taken from wii.cs by leathl
//they have just been tweeked slightly to work with Qt C++
LZ77::LZ77()
{
match_position = 0;
match_length = 0;
textsize = 0;
codesize = 0;
}
int LZ77::GetLz77Offset( const QByteArray &data )
{
QByteArray start = data.left( 5000 );
return start.indexOf( "LZ77" );
}
void LZ77::InitTree()
{
int i;
int N = 4096;
for( i = N + 1; i <= N + 256; i++ )
rson[ i ] = N;
for( i = 0; i < N; i++ )
dad[ i ] = N;
}
void LZ77::DeleteNode( int p )
{
int N = 4096;
int q;
if( dad[ p ] == N )
return; /* not in tree */
if( rson[ p ] == N )
q = lson[ p ];
else if( lson[ p ] == N )
q = rson[ p ];
else
{
q = lson[ p ];
if( rson[ q ] != N )
{
do
{
q = rson[ q ];
}
while( rson[ q ] != N );
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;
}
dad[ q ] = dad[ p ];
if( rson[ dad[ p ] ] == p )
rson[ dad[ p ] ] = q;
else
lson[ dad[ p ] ] = q;
dad[ p ] = N;
}
void LZ77::InsertNode( int r )
{
int i, p, cmp;
int N = 4096;
int F = 18;
cmp = 1;
p = N + 1 + ( text_buf[ r ] == ( quint16 )0xffff ? ( quint16 )0 : text_buf[ r ] );
rson[ r ] = lson[ r ] = N;
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 ];
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 ];
lson[ r ] = lson[ p ];
rson[ r ] = rson[ p ];
dad[ lson[ p ] ] = r;
dad[ rson[ p ] ] = r;
if( rson[ dad[ p ] ] == p )
rson[ dad[ p ] ] = r;
else
lson[ dad[ p ] ] = r;
dad[ p ] = N;
}
quint32 LZ77::GetDecompressedSize( const QByteArray &data )
{
int off = GetLz77Offset( data );
if( off == -1 )
{
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;
}
buf.seek( off + 4 );
quint32 gbaheader;
buf.seek( off + 4 );
buf.read( (char*)&gbaheader, 4 );
return ( gbaheader >> 8 );
}
QByteArray LZ77::Decompress( const QByteArray &compressed, int offset )
{
int N = 4096;
int F = 18;
int threshold = 2;
int k, r, z, flags;
quint16 i, j;
char ch;
quint32 decomp_size;
quint32 cur_size = 0;
QByteArray crap = compressed;
QBuffer infile( &crap );
if( !infile.open( QBuffer::ReadOnly ) )
{
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();
}
quint32 gbaheader;
infile.seek( offset + 4 );
infile.read( (char*)&gbaheader, 4 );
decomp_size = gbaheader >> 8;
quint8 text_buf[ N + 17 ];
for( i = 0; i < N - F; i++ )
text_buf[ i ] = 0xdf;
r = N - F;
flags = 7;
z = 7;
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;
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;
if( !infile.getChar( &ch ) )
break;
j = (quint8)ch;
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 );
text_buf[ r++ ] = ch;
r &= ( N - 1 );
cur_size++;
}
}
}
return ret;
}
QByteArray LZ77::Decompress( const QByteArray &compressed )
{
int off = GetLz77Offset( compressed );
if( off < 0 )
{
qWarning() << "LZ77::Decompress -> data is not compressed";
return compressed;
}
return Decompress( compressed, off );
}
QByteArray LZ77::Compress( const QByteArray &ba )
{
//testing 1, 2
//return ba;
LZ77 lz;
QByteArray ret = lz.Compr( ba );
return ret;
}
QByteArray LZ77::Compr( const QByteArray &ba )
{
int i, len, r, s, last_match_length, code_buf_ptr;
char ch;
int code_buf[ 17 ];
int mask;
int N = 4096;
int F = 18;
int threshold = 2;
quint32 filesize = (ba.size() << 8) + 0x10;
QByteArray crap = ba;
QBuffer infile( &crap );
if( !infile.open( QBuffer::ReadOnly ) )
{
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();
}
output.putChar( 'L' );
output.putChar( 'Z' );
output.putChar( '7' );
output.putChar( '7' );
output.write( (const char*)&filesize, 4 );
InitTree();
code_buf[ 0 ] = 0;
code_buf_ptr = 1;
mask = 0x80;
s = 0;
r = N - F;
for( i = s; i < r; i++ )
text_buf[ i ] = 0xffff;
for( len = 0; len < F && infile.getChar( &ch ); len++ )
text_buf[ r + len ] = (quint8)ch;
if( ( textsize = len ) == 0)
return ba;
for( i = 1; i <= F; i++ )
InsertNode( r - i );
InsertNode( r );
do
{
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;
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 ] );
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;
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( len > 0 );
if( code_buf_ptr > 1 )
{
for( i = 0; i < code_buf_ptr; i++ )
output.putChar( (quint8)code_buf[ i ] );
codesize += code_buf_ptr;
}
int padding = codesize % 4;
if( padding != 0 )
output.write( QByteArray( 4 - padding, '\0' ) );
infile.close();
return ret;
}

48
WiiQt/lz77.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef LZ77_H
#define LZ77_H
#include "includes.h"
//class for daling with LZ77 compression
//! in most cases, you just want to use the static functions
// QByteArray stuff = LZ77::Decompress( someCompressedData );
// QByteArray compressedData = LZ77::Compress( someData );
class LZ77
{
public:
LZ77();
void InsertNode( int r );
void DeleteNode( int p );
void InitTree();
//gets the offset in a bytearray if the lz77 magic word
static int GetLz77Offset( const QByteArray &data );
//gets the decompressed size of a lz77 compressed buffer
static quint32 GetDecompressedSize( const QByteArray &data );
//used internally by the static compression function
QByteArray Compr( const QByteArray &ba );
static QByteArray Decompress( const QByteArray &compressed, int offset );
//finds the lz77 magic word and decompressed the data after it
// returns only the decompressed data. anything before the lz77 magic word is not included
static QByteArray Decompress( const QByteArray &compressed );
//compressed a qbytearray with the lz77 argorythm
//returns a qbytearray ncluding the lz77 header
static QByteArray Compress( const QByteArray &ba );
private:
int lson[ 4097 ];
int rson[ 4353 ];
int dad[ 4097 ];
quint16 text_buf[ 4113 ];
int match_position;
int match_length;
int textsize;
int codesize;
};
#endif // LZ77_H

377
WiiQt/md5.cpp Normal file
View File

@ -0,0 +1,377 @@
/* MD5
converted to C++ class by Frank Thilo (thilo@unix-ag.org)
for bzflag (http://www.bzflag.org)
based on:
md5.h and md5.c
reference implemantion of RFC 1321
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/* interface header */
#include "md5.h"
/* system implementation headers */
#include <stdio.h>
#include <string.h>
// Constants for MD5Transform routine.
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
//char output[50];
///////////////////////////////////////////////
// F, G, H and I are basic MD5 functions.
inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) {
return (x&y) | (~x&z);
}
inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) {
return (x&z) | (y&~z);
}
inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) {
return x^y^z;
}
inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) {
return y ^ (x | ~z);
}
// rotate_left rotates x left n bits.
inline MD5::uint4 MD5::rotate_left(uint4 x, int n) {
return (x << n) | (x >> (32-n));
}
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
// Rotation is separate from addition to prevent recomputation.
inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
a = rotate_left(a+ F(b,c,d) + x + ac, s) + b;
}
inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
a = rotate_left(a + G(b,c,d) + x + ac, s) + b;
}
inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
a = rotate_left(a + H(b,c,d) + x + ac, s) + b;
}
inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
a = rotate_left(a + I(b,c,d) + x + ac, s) + b;
}
//////////////////////////////////////////////
// default ctor, just initailize
MD5::MD5()
{
init();
}
//////////////////////////////////////////////
// nifty shortcut ctor, compute MD5 for string and finalize it right away
MD5::MD5(const std::string &text)
{
init();
update(text.c_str(), text.length());
finalize();
}
//////////////////////////////
void MD5::init()
{
finalized=false;
count[0] = 0;
count[1] = 0;
// load magic initialization constants.
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
}
//////////////////////////////
// decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4.
void MD5::decode(uint4 output[], const uint1 input[], size_type len)
{
for (unsigned int i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
(((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
}
//////////////////////////////
// encodes input (uint4) into output (unsigned char). Assumes len is
// a multiple of 4.
void MD5::encode(uint1 output[], const uint4 input[], size_type len)
{
for (size_type i = 0, j = 0; j < len; i++, j += 4) {
output[j] = input[i] & 0xff;
output[j+1] = (input[i] >> 8) & 0xff;
output[j+2] = (input[i] >> 16) & 0xff;
output[j+3] = (input[i] >> 24) & 0xff;
}
}
//////////////////////////////
// apply MD5 algo on a block
void MD5::transform(const uint1 block[blocksize])
{
uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
decode (x, block, blocksize);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
// Zeroize sensitive information.
memset(x, 0, sizeof x);
}
//////////////////////////////
// MD5 block update operation. Continues an MD5 message-digest
// operation, processing another message block
void MD5::update(const unsigned char input[], size_type length)
{
// compute number of bytes mod 64
size_type index = count[0] / 8 % blocksize;
// Update number of bits
if ((count[0] += (length << 3)) < (length << 3))
count[1]++;
count[1] += (length >> 29);
// number of bytes we need to fill in buffer
size_type firstpart = 64 - index;
size_type i;
// transform as many times as possible.
if (length >= firstpart)
{
// fill buffer first, transform
memcpy(&buffer[index], input, firstpart);
transform(buffer);
// transform chunks of blocksize (64 bytes)
for (i = firstpart; i + blocksize <= length; i += blocksize)
transform(&input[i]);
index = 0;
}
else
i = 0;
// buffer remaining input
memcpy(&buffer[index], &input[i], length-i);
}
//////////////////////////////
// for convenience provide a verson with signed char
void MD5::update(const char input[], size_type length)
{
update((const unsigned char*)input, length);
}
//////////////////////////////
// MD5 finalization. Ends an MD5 message-digest operation, writing the
// the message digest and zeroizing the context.
MD5& MD5::finalize()
{
static unsigned char padding[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
if (!finalized) {
// Save number of bits
unsigned char bits[8];
encode(bits, count, 8);
// pad out to 56 mod 64.
size_type index = count[0] / 8 % 64;
size_type padLen = (index < 56) ? (56 - index) : (120 - index);
update(padding, padLen);
// Append length (before padding)
update(bits, 8);
// Store state in digest
encode(digest, state, 16);
// Zeroize sensitive information.
memset(buffer, 0, sizeof buffer);
memset(count, 0, sizeof count);
finalized=true;
}
//sprintf(output,"%s",this);
return *this;
}
//////////////////////////////
// return hex representation of digest as string
std::string MD5::hexdigest() const
{
if (!finalized)
return "";
char buf[33];
for (int i=0; i<16; i++)
sprintf(buf+i*2, "%02x", digest[i]);
buf[32]=0;
sprintf( (char*)outputBuf,"%s",buf);
return std::string(buf);
}
char* MD5::hexdigestChar() const
{
if (!finalized)
return NULL;
memset( (char*)&outputBuf, 0, 0x20 );
memcpy( (char*)&outputBuf, &digest, 16 );
return (char*)outputBuf;
}
//////////////////////////////
std::ostream& operator<<(std::ostream& out, MD5 md5)
{
return out << md5.hexdigest();
}
//////////////////////////////
std::string md5(const std::string str)
{
MD5 md5 = MD5(str);
return md5.hexdigest();
}

99
WiiQt/md5.h Normal file
View File

@ -0,0 +1,99 @@
/* MD5
converted to C++ class by Frank Thilo (thilo@unix-ag.org)
for bzflag (http://www.bzflag.org)
based on:
md5.h and md5.c
reference implementation of RFC 1321
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#ifndef BZF_MD5_H
#define BZF_MD5_H
#include <string>
#include <iostream>
// a small class for calculating MD5 hashes of strings or byte arrays
// it is not meant to be fast or secure
//
// usage: 1) feed it blocks of uchars with update()
// 2) finalize()
// 3) get hexdigest() string
// or
// MD5(std::string).hexdigest()
//
// assumes that char is 8 bit and int is 32 bit
class MD5
{
public:
typedef unsigned int size_type; // must be 32bit
MD5();
MD5(const std::string& text);
void update(const unsigned char *buf, size_type length);
void update(const char *buf, size_type length);
MD5& finalize();
std::string hexdigest() const;
char* hexdigestChar() const;
friend std::ostream& operator<<(std::ostream&, MD5 md5);
private:
void init();
typedef unsigned char uint1; // 8bit
typedef unsigned int uint4; // 32bit
enum {blocksize = 64}; // VC6 won't eat a const static int here
void transform(const uint1 block[blocksize]);
static void decode(uint4 output[], const uint1 input[], size_type len);
static void encode(uint1 output[], const uint4 input[], size_type len);
bool finalized;
uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk
uint4 count[2]; // 64bit counter for number of bits (lo, hi)
uint4 state[4]; // digest so far
uint1 digest[16]; // the result
// low level logic operations
static inline uint4 F(uint4 x, uint4 y, uint4 z);
static inline uint4 G(uint4 x, uint4 y, uint4 z);
static inline uint4 H(uint4 x, uint4 y, uint4 z);
static inline uint4 I(uint4 x, uint4 y, uint4 z);
static inline uint4 rotate_left(uint4 x, int n);
static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
//little buffer for giving the result
char outputBuf[ 0x20 ];
};
std::string md5(const std::string str);
#endif

View File

@ -22,8 +22,7 @@ NandBin::~NandBin()
bool NandBin::SetPath( const QString &path )
{
nandPath = path;//TODO: dont need both these variables. definitely dont need to set the global one here
nandFile = path;
//nandPath = path;
if( f.isOpen() )
f.close();
@ -246,7 +245,7 @@ bool NandBin::GetKey( int type )
case 0:
case 1:
{
QString keyPath = nandFile;
QString keyPath = nandPath;
int sl = keyPath.lastIndexOf( "/" );
if( sl == -1 )
{
@ -514,6 +513,72 @@ void NandBin::SetFixNamesForFAT( bool fix )
fatNames = fix;
}
const QByteArray NandBin::GetData( const QString &path )
{
QTreeWidgetItem *item = ItemFromPath( path );
if( !item )
return QByteArray();
if( !item->text( 6 ).contains( "1" ) )
{
qDebug() << "NandBin::GetData -> can't get data for a folder" << item->text( 0 );
return QByteArray();
}
bool ok = false;
quint16 entry = item->text( 1 ).toInt( &ok, 10 );
if( !ok )
return QByteArray();
return GetFile( entry );
}
QTreeWidgetItem *NandBin::ItemFromPath( const QString &path )
{
if( !root || !root->childCount() )
return NULL;
QTreeWidgetItem *item = root->child( 0 );
if( item->text( 0 ) != "/" )
{
qWarning() << "NandBin::ItemFromPath -> root is not \"/\"" << item->text( 0 );
return NULL;
}
if( !path.startsWith( "/" ) || path.contains( "//" ))
{
qWarning() << "NandBin::ItemFromPath -> invalid path";
return NULL;
}
int slash = 1;
while( slash )
{
int nextSlash = path.indexOf( "/", slash + 1 );
QString lookingFor = path.mid( slash, nextSlash - slash );
item = FindItem( lookingFor, item );
if( !item )
{
qWarning() << "NandBin::ItemFromPath ->item not found" << path;
return NULL;
}
slash = nextSlash + 1;
}
return item;
}
QTreeWidgetItem *NandBin::FindItem( const QString &s, QTreeWidgetItem *parent )
{
int cnt = parent->childCount();
for( int i = 0; i <cnt; i++ )
{
QTreeWidgetItem *r = parent->child( i );
if( r->text( 0 ) == s )
{
return r;
}
}
return NULL;
}
void NandBin::ShowInfo()
{
quint16 badBlocks = 0;

View File

@ -4,7 +4,7 @@
#include "includes.h"
struct fst_t
{
quint8 filename[ 0xc ];//showmii wads has size 0xb here but reads 0xc bytes into name??
quint8 filename[ 0xc ];
quint8 mode;
quint8 attr;
quint16 sub;
@ -17,25 +17,42 @@ struct fst_t
// 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()
// extract files with GetFile()
//once InitNand() is called, you can get the contents of the nand in a nice QTreeWidgetItem* with GetTree()
class NandBin : public QObject
{
Q_OBJECT
public:
//creates a NandBin object. if a path is given, it will call SetPath() on that path. though you cant check the return value
NandBin( QObject * parent = 0, const QString &path = QString() );
//destroys this object, and all its used resources ( closes the nand.bin file and deletes the filetree )
~NandBin();
//sets the path of this object to path. returns false if it cannot open an already existing file
//keys.bin should be in this same path if they are to be used
bool SetPath( const QString &path );
//try to read the filesystem and create a tree from its contents
//this takes care of the stuff like reading the keys, finding teh superblock, and creating the QTreeWidgetItem* tree
//icons given here will be the ones used when asking for that tree
bool InitNand( QIcon dirs = QIcon(), QIcon files = QIcon() );
//get a root item containing children that are actually entries in the nand dump
//the root itself is just a container to hold them all and can be deleted once its children are taken
//! all returned items are cloned and it is up to you to delete them !
//text is assigned to the items as follows...
// 0 name
// 1 entry #
// 2 size
// 3 uid
// 4 gid
// 5 x3
// 6 mode
// 7 attr
QTreeWidgetItem *GetTree();
//returns the data that makes up the file of a given entry#
QByteArray GetFile( quint16 entry );
//extracts an item( and all its children ) to a directory
//this function is BLOCKING and will block the current thread, so if done in the gui thread, it will freeze your GUI till it returns
@ -48,13 +65,27 @@ public:
//theres more illegal characters in FAT, but thes seems to be the only one that happens on the nand FS
void SetFixNamesForFAT( bool fix = true );
//returns the data that makes up the file of a given entry#
QByteArray GetFile( quint16 entry );
//get data for a given path
//! this function is slower than the above one, as it first iterates through the QTreeWidgetItems till it finds the right ono
//! and then end up calling the above one anyways.
//the path should be a file, not folder
//returns an empty array on failure
//path should start with "/" and items should be delimited by "/"
//ie... /title/00000001/00000002/data/setting.txt
const QByteArray GetData( const QString &path );
private:
QByteArray key;
qint32 loc_super;
qint32 loc_fat;
qint32 loc_fst;
QString extractPath;
QString nandFile;
QString nandPath;
QFile f;
int type;
@ -69,7 +100,6 @@ private:
quint16 GetFAT( quint16 fat_entry );
fst_t GetFST( quint16 entry );
QByteArray GetCluster( quint16 cluster_entry, bool decrypt = true );
//QByteArray ReadPage( quint32 i, bool withEcc = false );
QByteArray GetFile( fst_t fst );
QString FstName( fst_t fst );
@ -81,8 +111,11 @@ private:
QTreeWidgetItem *root;
bool AddChildren( QTreeWidgetItem *parent, quint16 entry );
QTreeWidgetItem *ItemFromPath( const QString &path );
QTreeWidgetItem *FindItem( const QString &s, QTreeWidgetItem *parent );
signals:
//connect to these to receive messages from this object
void SendError( QString );
void SendText( QString );
};

View File

@ -126,6 +126,8 @@ QByteArray NandDump::GetSettingTxt()
bool NandDump::SetSettingTxt( const QByteArray ba )
{
if( basePath.isEmpty() )
return false;
QString path = basePath + "/title/00000001/00000002/data";
if( !QFileInfo( path ).exists() && !QDir().mkpath( path ) )
return false;
@ -134,6 +136,8 @@ bool NandDump::SetSettingTxt( const QByteArray ba )
const QByteArray NandDump::GetFile( const QString &path )
{
if( basePath.isEmpty() )
return QByteArray();
QFile f( basePath + path );
if( !f.open( QIODevice::ReadOnly ) )
{
@ -148,6 +152,8 @@ const QByteArray NandDump::GetFile( const QString &path )
//write some file to the nand
bool NandDump::SaveData( const QByteArray ba, const QString& path )
{
if( basePath.isEmpty() )
return false;
qDebug() << "NandDump::SaveData" << path << hex << ba.size();
QFile f( basePath + path );
if( !f.open( QIODevice::WriteOnly ) )
@ -164,6 +170,8 @@ bool NandDump::SaveData( const QByteArray ba, const QString& path )
void NandDump::DeleteData( const QString & path )
{
qDebug() << "NandDump::DeleteData" << path;
if( basePath.isEmpty() )
return;
QFile::remove( basePath + path );
}

View File

@ -6,6 +6,10 @@
#include "sharedcontentmap.h"
#include "uidmap.h"
//class for handeling an extracted wii nand filesystem
//! nothing can be done unless basePath is set. do this either by setting it in the constructor, or by calling SetPath()
//! current reading and writing is limited to installing a title in the form of NusJob, reading/writing/deleting specific paths
//! for performance reasons, the uid and content map are cached and only written to the HDD when the destructor or Flush() is called
class NandDump
{
public:
@ -27,17 +31,27 @@ public:
bool DeleteTitle( quint64 tid, bool deleteData = false );
//check what version a given title is on this nand, returns 0 if it isnt installed
quint16 GetTitleVersion( quint64 tid );
//quint16 GetTitleVersion( quint64 tid );
//get a list of all titles for which there is a ticket & tmd
// returns a map of < tid, version >
//QMap< quint64, quint16 > GetInstalledTitles();
//write the current uid & content.map to the PC
//failure to make sure this is done can end up with a broken nand
bool Flush();
//overloads GetFile() with "/title/00000001/00000002/data/setting.txt"
QByteArray GetSettingTxt();
bool SetSettingTxt( const QByteArray ba );
//reads a file from the nand and returns it as a qbytearray
const QByteArray GetFile( const QString &path );
//tries to write the given bytearray to a file of the given path
bool SaveData( const QByteArray ba, const QString& path );
//expects a file, not directory
void DeleteData( const QString & path );

View File

@ -1,6 +1,9 @@
#ifndef NUSDOWNLOADER_H
#define NUSDOWNLOADER_H
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include "includes.h"
#include "tiktmd.h"

View File

@ -1,7 +1,7 @@
#include "savebanner.h"
#include "tools.h"
int TPL_ConvertRGB5A3ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height);
static int ConvertRGB5A3ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height);
SaveBanner::SaveBanner()
{
@ -201,7 +201,7 @@ QImage SaveBanner::ConvertTextureToImage( const QByteArray &ba, quint32 w, quint
{
//qDebug() << "SaveBanner::ConvertTextureToImage" << ba.size() << hex << w << h;
quint8* bitmapdata = NULL;//this will hold the converted image
int ret = TPL_ConvertRGB5A3ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h );
int ret = ConvertRGB5A3ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h );
if( !ret )
{
qWarning() << "SaveBanner::ConvertTextureToImage -> error converting image";
@ -211,10 +211,9 @@ QImage SaveBanner::ConvertTextureToImage( const QByteArray &ba, quint32 w, quint
QImage im2 = im.copy( im.rect() );//make a copy of the image so the "free" wont delete any data we still want
free( bitmapdata );
return im2;
}
int TPL_ConvertRGB5A3ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height)
static int ConvertRGB5A3ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height)
{
quint32 x, y;
quint32 x1, y1;

View File

@ -3,6 +3,8 @@
#include "includes.h"
//this class creates a dialog used to create & edit a setting.txt for a wii nand filesystem
// in most cases, the static function Edit() is what you want to use
namespace Ui {
class SettingTxtDialog;
}
@ -15,6 +17,10 @@ public:
explicit SettingTxtDialog( QWidget *parent = 0, const QByteArray &old = QByteArray() );
~SettingTxtDialog();
//displays a dialog window with teh given parent. if any data is ginev as old, it will try to populate the dialog with that
// otherwise it will use the defaulte values
// returns empty if the user clicked cancel, or a bytearray containing an encrypted setting.txt if they clicked ok
// the data is ready for writing to a wii nand
static QByteArray Edit( QWidget *parent = 0, const QByteArray &old = QByteArray() );
static QByteArray LolCrypt( QByteArray ba );

View File

@ -118,5 +118,5 @@ void SharedContentMap::AddEntry( const QString &app, const QByteArray &hash )
{
data += app.toAscii() + hash;
//qDebug() << "SharedContentMap::AddEntry -> added entry, rechecking this beast";
Check();
//Check();
}

View File

@ -3,6 +3,7 @@
#include "includes.h"
//class for handling a content.map from a wii nand
class SharedContentMap
{
public:
@ -13,11 +14,18 @@ public:
//if a path is given, it will check that the hashes in the map match up with the contents in the folder
bool Check( const QString &path = QString() );
//gets a string containing the 8 letter app that matches the given hash.
//returns an empty string if the hash is not found in the map
QString GetAppFromHash( QByteArray hash );
//gets the first available u32 that is not already in the map and returns it as a string
QString GetNextEmptyCid();
//adds an entry to the end of the map
//! this function doesnt check if the entry already exists
void AddEntry( const QString &app, const QByteArray &hash );
//get the entire data ready for writing to a wii nand
const QByteArray Data(){ return data; }
private:

View File

@ -135,9 +135,6 @@ typedef struct _cert_ecdsa {
#define COMMON_KEY {0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4, 0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7}
#define TITLE_IDH(x) ((u32)(((u64)(x))>>32))
#define TITLE_IDL(x) ((u32)(((u64)(x))))
//just a quick class to try to keep the rest of the code from getting full of the same shit over and over
class Ticket
{
@ -199,18 +196,19 @@ public:
quint16 Version();
//functions to edit the TMD
//you probably want to call FakeSign() after using these
bool SetTid( quint64 tid );
bool SetVersion( quint16 v );
bool SetType( quint16 cid, quint16 type );
bool SetSize( quint16 cid, quint32 size );
bool SetHash( quint16 cid, const QByteArray hash );
bool SetType( quint16 i, quint16 type );
bool SetSize( quint16 i, quint32 size );
bool SetHash( quint16 i, const QByteArray hash );
bool FakeSign();
//get the tmd data
//returns a qbytearray containing the tmd, from the rsa signature through the last content
const QByteArray Data(){ return data; }
//print the tmd info to qDebug()
//print some tmd info to qDebug()
void Dbg();
@ -225,7 +223,7 @@ private:
void SetPointer();
//this is just a pointer to the actual good stuff in "data".
//whenever data is changes, this pointer will become invalid and needs to be reset
//whenever data is changed, this pointer will become invalid and needs to be reset
tmd *p_tmd;
};

View File

@ -3,9 +3,9 @@
#include "aes.h"
#include "sha1.h"
QString currentDir;
QString cachePath = "./NUS_cache";
QString nandPath = "./dump";
//QString currentDir;
//QString cachePath = "./NUS_cache";
//QString nandPath = "./dump";
char ascii( char s ) {
if ( s < 0x20 ) return '.';

View File

@ -1,12 +1,14 @@
#ifndef TOOLS_H
#define TOOLS_H
#include "includes.h"
//#include "
#define RU(x,n) (-(-(x) & -(n))) //round up
#define MIN( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) )
#define MAX( x, y ) ( ( x ) > ( y ) ? ( x ) : ( y ) )
char ascii( char s );
void hexdump( const void *d, int len );
void hexdump( const QByteArray &d, int from = 0, int len = -1 );
@ -30,13 +32,13 @@ QByteArray ReadFile( const QString &path );
bool WriteFile( const QString &path, const QByteArray ba );
//keep track of the last folder browsed to when looking for files
extern QString currentDir;
//extern QString currentDir;
//folder used to cache stuff downloaded from NUS so duplicate titles dont need to be downloaded
extern QString cachePath;
//extern QString cachePath;
//folder to use as the base path for the nand
extern QString nandPath;
//extern QString nandPath;
#define CERTS_DAT_SIZE 2560
extern const quint8 certs_dat[ CERTS_DAT_SIZE ];

1415
WiiQt/u8.cpp Normal file

File diff suppressed because it is too large Load Diff

184
WiiQt/u8.h Normal file
View File

@ -0,0 +1,184 @@
#ifndef U8_H
#define U8_H
#include "includes.h"
/*order of the names in the imet header
japanese
english
german
french
spanish
italian
dutch
simp_chinese
trad_chinese
korean
*/
struct FEntry
{
union
{
struct
{
unsigned int Type :8;
unsigned int NameOffset :24;
};
unsigned int TypeName;
};
union
{
struct // File Entry
{
unsigned int FileOffset;
unsigned int FileLength;
};
struct // Dir Entry
{
unsigned int ParentOffset;
unsigned int NextOffset;
};
unsigned int entry[ 2 ];
};
};
enum
{
U8_Hdr_none = 0,
U8_Hdr_IMET_app,//basically the same except the app has 0x40 bytes of padding more than the bnr
U8_Hdr_IMET_bnr,
U8_Hdr_IMD5
};
//class to handle U8 archives found in wii games & system files
// handles different header types, lz77 & ash
//! basic usage is to read an existing U8 archive into a qbytearray and pass it to this class through the second constructor or Load()
//! you can also create a brand-spankin-new U8 archive by using the first constructor
//! check IsOk() to see if that it was loaded ok
//! then call Entries() to get a list of everything that is in the archive
//! access the data in that archive with AddEntry(), RemoveEntry(), ReplaceEntry(), RenameEntry(), and GetData()
class U8
{
public:
//creates a U8 object
//if initialize is true, it will call CreateEmptyData() in this U8
//you can also set the header type & imet names, though they dont affect the actual data in the archive
U8( bool initialize = false, int type = U8_Hdr_none, const QStringList &names = QStringList() );
U8( const QByteArray &ba );
//check if the u8 constructor finished successfully
bool IsOK();
void Load( const QByteArray &ba );
//set the variables and create an fst with only a root node
bool CreateEmptyData();
//adds an entry to this U8 with the given path, and type, and if it is a file entry, the given data
//returns the index of the created entry or -1 on error
int AddEntry( const QString &path, int type, const QByteArray &ba = QByteArray() );
//removes an entry, and all its children, from the archive
bool RemoveEntry( const QString &path );
//replace a file in the archive with different data ( only supports files, no directories )
//if autoCompress is true, it will check if the data to be replaced is ASH/LZ77 compressed and make sure the new data is LZ77'd
bool ReplaceEntry( const QString &path, const QByteArray &ba = QByteArray(), bool autoCompress = true );
//remane an entry. this expects a full path of the entry to be named, and newName is only the replacement name ( not the full path )
bool RenameEntry( const QString &path, const QString &newName );
//returns the index of an item in the archive FST, or -1 the item is not present
//it accepts names like "/arc/anim/". parent is the directory to start looking in
int FindEntry( const QString &str, int parent = 0 );
quint32 NextEntryInFolder( quint32 current, quint32 directory );
QString FstName( const FEntry *entry );
QString FstName( quint32 i );
//gets the data for a path inside the archive
//if no path is given, returns the data for the whole archive, starting at the U8 tag
//if onlyPayload is true, it will return the data unLZ77'd ( and without its IMET/IMD5 header for nested U8 archives )
const QByteArray GetData( const QString &str = QString(), bool onlyPayload = false );
//get the size of an entry in the archive
//if no path is given, returns the size for the whole archive, starting at the U8 tag
quint32 GetSize( const QString &str = QString() );
//returns a list of all the entries in the u8 archive
//directories end with "/"
const QStringList Entries();
//check the first 5000 bytes of a file for the u8 tag.
//if necessary, un-LZ77 the data before checking
//this doesnt check anything else in the archive
static bool IsU8( const QByteArray &ba );
//returns the location of the U8 tag in the first 5000 bytes of the given data
static int GetU8Offset( const QByteArray &ba );
//adds the IMD5 header to the given bytearray and returns it ( original data is modified )
static QByteArray AddIMD5( QByteArray ba );
//returns the U8 archive data with an IMD5 header added
//the actual data is not changed
const QByteArray AddIMD5();
//adds the IMET header to the given bytearray and returns it ( original data is modified )
static QByteArray AddIMET( QByteArray ba, const QStringList &names );
//get an IMET header using the given names and sizes
//padding type will add 0, 0x40, or 0x80 bytes of 0s to the beginning
static QByteArray GetIMET( const QStringList &names, int paddingType = U8_Hdr_IMET_app, quint32 iconSize = 0, quint32 bannerSize = 0, quint32 soundSize = 0 );
//returns the U8 archive data with an IMET header added
//the actual archive data is not changed
const QByteArray AddIMET( int paddingType = U8_Hdr_IMET_app );
//ruterns a list of the names as read from the imet header
const QStringList IMETNames();
//set the imet names
//the data in the archive is not changed, but calling AddIMET() on this banner will use the new names
void SetImetNames( const QStringList &names );
//void SetHeaderType( int type );
int GetHeaderType();
//reads from the fst and makes the list of paths
void CreateEntryList();
private:
QByteArray data;//data starting at the U8 tag
QStringList paths;
bool ok;
//if this archive as a whole is lz77 compressed
bool isLz77;
QStringList imetNames;
int headerType;
void ReadHeader( const QByteArray &ba );
//just a pointer to the fst data.
//this pointer needs to be updated any time data is changed
FEntry* fst;
//stored in host endian !
quint32 fstSize;
quint32 rootnode_offset;
quint32 data_offset;
quint32 NameOff;
//a list of the nested u8 archives
QMap<QString, U8>nestedU8s;
};
#endif // U8_H

View File

@ -3,6 +3,8 @@
#include "includes.h"
//class for handling the uid.sys in a virtual nand
//
class UIDmap
{
public:
@ -18,9 +20,11 @@ public:
quint32 GetUid( quint64 tid, bool autoCreate = true );
//creates a new uid.sys with the system menu entry.
//if addFactorySetupDiscs is true, it will add some entries for the setup discs used in the wii factory ( serve no purpose other than to just exist )
//if addFactorySetupDiscs is true, it will add some entries for the setup discs used in the wii factory
// ( serve no purpose other than to just exist )
void CreateNew( bool addFactorySetupDiscs = false );
//get th entire uid.sys data back in a state ready for writing to a nand
const QByteArray Data(){ return data; }
private:

View File

@ -472,14 +472,39 @@ QByteArray Wad::FromDirectory( QDir dir )
QList<QByteArray> datas = QList<QByteArray>()<< tmdP << tikP;
quint16 cnt = t.Count();
bool tmdChanged = false;
for( quint16 i = 0; i < cnt; i++ )
{
QByteArray appD = ReadFile( dir.absoluteFilePath( t.Cid( i ) + ".app" ) );
if( appD.isEmpty() )
return QByteArray();
if( (quint32)appD.size() != t.Size( i ) )
{
t.SetSize( i, appD.size() );
tmdChanged = true;
}
QByteArray realHash = GetSha1( appD );
if( t.Hash( i ) != realHash )
{
t.SetHash( i, realHash );
tmdChanged = true;
}
datas << appD;
}
//if something in the tmd changed, fakesign it and replace the data in our list with the new data
if( tmdChanged )
{
if( !t.FakeSign() )
{
qWarning() << "Error signing the wad";
}
else
{
datas.replace( 0, t.Data() );
}
}
Wad wad( datas, false );
if( !wad.IsOk() )
return QByteArray();

View File

@ -5,12 +5,15 @@ TARGET = nandExtract
TEMPLATE = app
SOURCES += main.cpp \
nandwindow.cpp \
nandbin.cpp \
tools.cpp \
aes.c
../WiiQt/nandbin.cpp \
../WiiQt/tools.cpp \
../WiiQt/savebanner.cpp \
../WiiQt/aes.c \
../WiiQt/sha1.c
HEADERS += nandwindow.h \
nandbin.h \
includes.h \
tools.h \
aes.h
../WiiQt/nandbin.h \
../WiiQt/tools.h \
../WiiQt/tools.h
FORMS += nandwindow.ui

View File

@ -1,6 +1,5 @@
#include "nandwindow.h"
#include "ui_nandwindow.h"
#include "tools.h"
NandWindow::NandWindow(QWidget *parent) :
QMainWindow(parent),
@ -13,9 +12,9 @@ NandWindow::NandWindow(QWidget *parent) :
ui->treeWidget->header()->resizeSection( 0, fm.width( QString( 22, 'W' ) ) );//name
ui->treeWidget->header()->resizeSection( 1, fm.width( "WWWWW" ) );//entry #
ui->treeWidget->header()->resizeSection( 2, fm.width( "WWWWW" ) );//size
ui->treeWidget->header()->resizeSection( 3, fm.width( "WWWWWWWWWW" ) );//uid
ui->treeWidget->header()->resizeSection( 4, fm.width( "WWWWWWWWWW" ) );//gid
ui->treeWidget->header()->resizeSection( 5, fm.width( "WWWWWWWWWW" ) );//x3
ui->treeWidget->header()->resizeSection( 3, fm.width( "WWWWWWWWW" ) );//uid
ui->treeWidget->header()->resizeSection( 4, fm.width( "WWWWWWWWW" ) );//gid
ui->treeWidget->header()->resizeSection( 5, fm.width( "WWWWWWWWW" ) );//x3
ui->treeWidget->header()->resizeSection( 6, fm.width( "WWWWW" ) );//mode
ui->treeWidget->header()->resizeSection( 7, fm.width( "WWWWW" ) );//attr
@ -131,4 +130,6 @@ void NandWindow::on_actionOpen_Nand_triggered()
//delete the made up root item
delete tree;
ui->statusBar->showMessage( "Loaded " + path, 5000 );
//nandBin.GetData( "/title/00000001/00000002/data/setting.txt" );//testing 1,2,1,2
}

View File

@ -2,7 +2,7 @@
#define NANDWINDOW_H
#include "includes.h"
#include "nandbin.h"
#include "../WiiQt/nandbin.h"
namespace Ui {
class NandWindow;

View File

@ -1,400 +0,0 @@
/* Rijndael Block Cipher - aes.c
Written by Mike Scott 21st April 1999
mike@compapp.dcu.ie
Permission for free direct or derivative use is granted subject
to compliance with any conditions that the originators of the
algorithm place on its exploitation.
*/
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>*/
#define u8 unsigned char /* 8 bits */
#define u32 unsigned long /* 32 bits */
#define u64 unsigned long long
/* rotates x one bit to the left */
#define ROTL(x) (((x)>>7)|((x)<<1))
/* Rotates 32-bit word left by 1, 2 or 3 byte */
#define ROTL8(x) (((x)<<8)|((x)>>24))
#define ROTL16(x) (((x)<<16)|((x)>>16))
#define ROTL24(x) (((x)<<24)|((x)>>8))
/* Fixed Data */
static u8 InCo[4]={0xB,0xD,0x9,0xE}; /* Inverse Coefficients */
static u8 fbsub[256];
static u8 rbsub[256];
static u8 ptab[256],ltab[256];
static u32 ftable[256];
static u32 rtable[256];
static u32 rco[30];
/* Parameter-dependent data */
int Nk,Nb,Nr;
u8 fi[24],ri[24];
u32 fkey[120];
u32 rkey[120];
static u32 pack(u8 *b)
{ /* pack bytes into a 32-bit Word */
return ((u32)b[3]<<24)|((u32)b[2]<<16)|((u32)b[1]<<8)|(u32)b[0];
}
static void unpack(u32 a,u8 *b)
{ /* unpack bytes from a word */
b[0]=(u8)a;
b[1]=(u8)(a>>8);
b[2]=(u8)(a>>16);
b[3]=(u8)(a>>24);
}
static u8 xtime(u8 a)
{
u8 b;
if (a&0x80) b=0x1B;
else b=0;
a<<=1;
a^=b;
return a;
}
static u8 bmul(u8 x,u8 y)
{ /* x.y= AntiLog(Log(x) + Log(y)) */
if (x && y) return ptab[(ltab[x]+ltab[y])%255];
else return 0;
}
static u32 SubByte(u32 a)
{
u8 b[4];
unpack(a,b);
b[0]=fbsub[b[0]];
b[1]=fbsub[b[1]];
b[2]=fbsub[b[2]];
b[3]=fbsub[b[3]];
return pack(b);
}
static u8 product(u32 x,u32 y)
{ /* dot product of two 4-byte arrays */
u8 xb[4],yb[4];
unpack(x,xb);
unpack(y,yb);
return bmul(xb[0],yb[0])^bmul(xb[1],yb[1])^bmul(xb[2],yb[2])^bmul(xb[3],yb[3]);
}
static u32 InvMixCol(u32 x)
{ /* matrix Multiplication */
u32 y,m;
u8 b[4];
m=pack(InCo);
b[3]=product(m,x);
m=ROTL24(m);
b[2]=product(m,x);
m=ROTL24(m);
b[1]=product(m,x);
m=ROTL24(m);
b[0]=product(m,x);
y=pack(b);
return y;
}
u8 ByteSub(u8 x)
{
u8 y=ptab[255-ltab[x]]; /* multiplicative inverse */
x=y; x=ROTL(x);
y^=x; x=ROTL(x);
y^=x; x=ROTL(x);
y^=x; x=ROTL(x);
y^=x; y^=0x63;
return y;
}
void gentables(void)
{ /* generate tables */
int i;
u8 y,b[4];
/* use 3 as primitive root to generate power and log tables */
ltab[0]=0;
ptab[0]=1; ltab[1]=0;
ptab[1]=3; ltab[3]=1;
for (i=2;i<256;i++)
{
ptab[i]=ptab[i-1]^xtime(ptab[i-1]);
ltab[ptab[i]]=i;
}
/* affine transformation:- each bit is xored with itself shifted one bit */
fbsub[0]=0x63;
rbsub[0x63]=0;
for (i=1;i<256;i++)
{
y=ByteSub((u8)i);
fbsub[i]=y; rbsub[y]=i;
}
for (i=0,y=1;i<30;i++)
{
rco[i]=y;
y=xtime(y);
}
/* calculate forward and reverse tables */
for (i=0;i<256;i++)
{
y=fbsub[i];
b[3]=y^xtime(y); b[2]=y;
b[1]=y; b[0]=xtime(y);
ftable[i]=pack(b);
y=rbsub[i];
b[3]=bmul(InCo[0],y); b[2]=bmul(InCo[1],y);
b[1]=bmul(InCo[2],y); b[0]=bmul(InCo[3],y);
rtable[i]=pack(b);
}
}
void gkey(int nb,int nk,u8 *key)
{ /* blocksize=32*nb bits. Key=32*nk bits */
/* currently nb,bk = 4, 6 or 8 */
/* key comes as 4*Nk bytes */
/* Key Scheduler. Create expanded encryption key */
int i,j,k,m,N;
int C1,C2,C3;
u32 CipherKey[8];
Nb=nb; Nk=nk;
/* Nr is number of rounds */
if (Nb>=Nk) Nr=6+Nb;
else Nr=6+Nk;
C1=1;
if (Nb<8) { C2=2; C3=3; }
else { C2=3; C3=4; }
/* pre-calculate forward and reverse increments */
for (m=j=0;j<nb;j++,m+=3)
{
fi[m]=(j+C1)%nb;
fi[m+1]=(j+C2)%nb;
fi[m+2]=(j+C3)%nb;
ri[m]=(nb+j-C1)%nb;
ri[m+1]=(nb+j-C2)%nb;
ri[m+2]=(nb+j-C3)%nb;
}
N=Nb*(Nr+1);
for (i=j=0;i<Nk;i++,j+=4)
{
CipherKey[i]=pack(key+j);
}
for (i=0;i<Nk;i++) fkey[i]=CipherKey[i];
for (j=Nk,k=0;j<N;j+=Nk,k++)
{
fkey[j]=fkey[j-Nk]^SubByte(ROTL24(fkey[j-1]))^rco[k];
if (Nk<=6)
{
for (i=1;i<Nk && (i+j)<N;i++)
fkey[i+j]=fkey[i+j-Nk]^fkey[i+j-1];
}
else
{
for (i=1;i<4 &&(i+j)<N;i++)
fkey[i+j]=fkey[i+j-Nk]^fkey[i+j-1];
if ((j+4)<N) fkey[j+4]=fkey[j+4-Nk]^SubByte(fkey[j+3]);
for (i=5;i<Nk && (i+j)<N;i++)
fkey[i+j]=fkey[i+j-Nk]^fkey[i+j-1];
}
}
/* now for the expanded decrypt key in reverse order */
for (j=0;j<Nb;j++) rkey[j+N-Nb]=fkey[j];
for (i=Nb;i<N-Nb;i+=Nb)
{
k=N-Nb-i;
for (j=0;j<Nb;j++) rkey[k+j]=InvMixCol(fkey[i+j]);
}
for (j=N-Nb;j<N;j++) rkey[j-N+Nb]=fkey[j];
}
/* There is an obvious time/space trade-off possible here. *
* Instead of just one ftable[], I could have 4, the other *
* 3 pre-rotated to save the ROTL8, ROTL16 and ROTL24 overhead */
void encrypt(u8 *buff)
{
int i,j,k,m;
u32 a[8],b[8],*x,*y,*t;
for (i=j=0;i<Nb;i++,j+=4)
{
a[i]=pack(buff+j);
a[i]^=fkey[i];
}
k=Nb;
x=a; y=b;
/* State alternates between a and b */
for (i=1;i<Nr;i++)
{ /* Nr is number of rounds. May be odd. */
/* if Nb is fixed - unroll this next
loop and hard-code in the values of fi[] */
for (m=j=0;j<Nb;j++,m+=3)
{ /* deal with each 32-bit element of the State */
/* This is the time-critical bit */
y[j]=fkey[k++]^ftable[(u8)x[j]]^
ROTL8(ftable[(u8)(x[fi[m]]>>8)])^
ROTL16(ftable[(u8)(x[fi[m+1]]>>16)])^
ROTL24(ftable[(u8)(x[fi[m+2]]>>24)]);
}
t=x; x=y; y=t; /* swap pointers */
}
/* Last Round - unroll if possible */
for (m=j=0;j<Nb;j++,m+=3)
{
y[j]=fkey[k++]^(u32)fbsub[(u8)x[j]]^
ROTL8((u32)fbsub[(u8)(x[fi[m]]>>8)])^
ROTL16((u32)fbsub[(u8)(x[fi[m+1]]>>16)])^
ROTL24((u32)fbsub[(u8)(x[fi[m+2]]>>24)]);
}
for (i=j=0;i<Nb;i++,j+=4)
{
unpack(y[i],(u8 *)&buff[j]);
x[i]=y[i]=0; /* clean up stack */
}
return;
}
void decrypt(u8 *buff)
{
int i,j,k,m;
u32 a[8],b[8],*x,*y,*t;
for (i=j=0;i<Nb;i++,j+=4)
{
a[i]=pack(buff+j);
a[i]^=rkey[i];
}
k=Nb;
x=a; y=b;
/* State alternates between a and b */
for (i=1;i<Nr;i++)
{ /* Nr is number of rounds. May be odd. */
/* if Nb is fixed - unroll this next
loop and hard-code in the values of ri[] */
for (m=j=0;j<Nb;j++,m+=3)
{ /* This is the time-critical bit */
y[j]=rkey[k++]^rtable[(u8)x[j]]^
ROTL8(rtable[(u8)(x[ri[m]]>>8)])^
ROTL16(rtable[(u8)(x[ri[m+1]]>>16)])^
ROTL24(rtable[(u8)(x[ri[m+2]]>>24)]);
}
t=x; x=y; y=t; /* swap pointers */
}
/* Last Round - unroll if possible */
for (m=j=0;j<Nb;j++,m+=3)
{
y[j]=rkey[k++]^(u32)rbsub[(u8)x[j]]^
ROTL8((u32)rbsub[(u8)(x[ri[m]]>>8)])^
ROTL16((u32)rbsub[(u8)(x[ri[m+1]]>>16)])^
ROTL24((u32)rbsub[(u8)(x[ri[m+2]]>>24)]);
}
for (i=j=0;i<Nb;i++,j+=4)
{
unpack(y[i],(u8 *)&buff[j]);
x[i]=y[i]=0; /* clean up stack */
}
return;
}
void aes_set_key(u8 *key) {
gentables();
gkey(4, 4, key);
}
// CBC mode decryption
void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len) {
u8 block[16];
unsigned int blockno = 0, i;
// debug_printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) {
unsigned int fraction;
if (blockno == (len / sizeof(block))) { // last block
fraction = len % sizeof(block);
if (fraction == 0) break;
memset(block, 0, sizeof(block));
} else fraction = 16;
// debug_printf("block %d: fraction = %d\n", blockno, fraction);
memcpy(block, inbuf + blockno * sizeof(block), fraction);
decrypt(block);
u8 *ctext_ptr;
if (blockno == 0) ctext_ptr = iv;
else ctext_ptr = inbuf + (blockno-1) * sizeof(block);
for(i=0; i < fraction; i++)
outbuf[blockno * sizeof(block) + i] =
ctext_ptr[i] ^ block[i];
// debug_printf("Block %d output: ", blockno);
// hexdump(outbuf + blockno*sizeof(block), 16);
}
}
// CBC mode encryption
void aes_encrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len) {
u8 block[16];
unsigned int blockno = 0, i;
// debug_printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) {
unsigned int fraction;
if (blockno == (len / sizeof(block))) { // last block
fraction = len % sizeof(block);
if (fraction == 0) break;
memset(block, 0, sizeof(block));
} else fraction = 16;
// debug_printf("block %d: fraction = %d\n", blockno, fraction);
memcpy(block, inbuf + blockno * sizeof(block), fraction);
for(i=0; i < fraction; i++)
block[i] = inbuf[blockno * sizeof(block) + i] ^ iv[i];
encrypt(block);
memcpy(iv, block, sizeof(block));
memcpy(outbuf + blockno * sizeof(block), block, sizeof(block));
// debug_printf("Block %d output: ", blockno);
// hexdump(outbuf + blockno*sizeof(block), 16);
}
}

View File

@ -1,18 +0,0 @@
#ifndef __AES_H_
#define __AES_H_
#include "includes.h"
#ifdef __cplusplus
extern "C" {
#endif
void aes_encrypt( quint8 *iv, const quint8 *inbuf, quint8 *outbuf, unsigned long long len );
void aes_decrypt( quint8 *iv, const quint8 *inbuf, quint8 *outbuf, unsigned long long len );
void aes_set_key( const quint8 *key );
#ifdef __cplusplus
}
#endif
#endif //__AES_H_

View File

@ -1,12 +1,10 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "settingtxtdialog.h"
#include "uidmap.h"
#include "sha1.h"
#include "tiktmd.h"
#include "tools.h"
#include "aes.h"
#include "wad.h"
#include "../WiiQt/settingtxtdialog.h"
#include "../WiiQt/tiktmd.h"
#include "../WiiQt/tools.h"
#include "../WiiQt/wad.h"
MainWindow::MainWindow( QWidget *parent ) : QMainWindow( parent ), ui( new Ui::MainWindow ), nus ( this )
{
@ -23,6 +21,11 @@ MainWindow::MainWindow( QWidget *parent ) : QMainWindow( parent ), ui( new Ui::M
connect( &nus, SIGNAL( SendData( NusJob ) ), this, SLOT( ReceiveTitleFromNus( NusJob) ) );
//TODO, really get these paths from settings
QString cachePath = "./NUS_cache";
QString nandPath = "./dump";
ui->lineEdit_cachePath->setText( cachePath );
ui->lineEdit_nandPath->setText( nandPath );
ui->lineEdit_extractPath->setText( "./downloaded" );

View File

@ -1,9 +1,9 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "includes.h"
#include "nusdownloader.h"
#include "nanddump.h"
#include "../WiiQt/includes.h"
#include "../WiiQt/nusdownloader.h"
#include "../WiiQt/nanddump.h"
namespace Ui {
class MainWindow;

View File

@ -13,29 +13,27 @@ TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
tools.cpp \
uidmap.cpp \
sharedcontentmap.cpp \
sha1.c \
tiktmd.cpp \
aes.c \
nusdownloader.cpp \
nanddump.cpp \
settingtxtdialog.cpp \
wad.cpp
../WiiQt/tools.cpp \
../WiiQt/sharedcontentmap.cpp \
../WiiQt/tiktmd.cpp \
../WiiQt/nusdownloader.cpp \
../WiiQt/uidmap.cpp \
../WiiQt/nanddump.cpp \
../WiiQt/settingtxtdialog.cpp \
../WiiQt/wad.cpp \
../WiiQt/aes.c \
../WiiQt/sha1.c
HEADERS += mainwindow.h \
tools.h \
includes.h \
uidmap.h \
sharedcontentmap.h \
sha1.h \
tiktmd.h \
aes.h \
nusdownloader.h \
nanddump.h \
settingtxtdialog.h \
wad.h
../WiiQt/tools.h \
../WiiQt/uidmap.h \
../WiiQt/sharedcontentmap.h \
../WiiQt/tiktmd.h \
../WiiQt/nusdownloader.h \
../WiiQt/uidmap.h \
../WiiQt/nanddump.h \
../WiiQt/settingtxtdialog.h \
../WiiQt/wad.h
FORMS += mainwindow.ui \
settingtxtdialog.ui
../WiiQt/settingtxtdialog.ui

View File

@ -1,6 +1,11 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "tools.h"
#include "savebanner.h"
//TODO... get these from settings and dont use global variables
static QString pcPath = "./saveBackups";
static QString sneekPath = "/media/SDHC_4GB";
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), bannerthread( this )
{
@ -108,6 +113,7 @@ void MainWindow::on_actionSet_Sneek_Path_triggered()
if( p.isEmpty() )
return;
ui->listWidget_sneekSaves->clear();
GetSavesFromSneek( p );
}

View File

@ -12,19 +12,21 @@ TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
savebanner.cpp \
savelistitem.cpp \
saveloadthread.cpp \
tools.cpp
../WiiQt/tools.cpp \
../WiiQt/savebanner.cpp \
../WiiQt/aes.c \
../WiiQt/sha1.c
HEADERS += mainwindow.h \
includes.h \
savebanner.h \
savelistitem.h \
saveloadthread.h \
tools.h
saveloadthread.h\
../WiiQt/tools.h
FORMS += mainwindow.ui
RESOURCES += \
rc.qrc
INCPATH += "../WiiQt"

View File

@ -70,6 +70,14 @@ void SaveLoadThread::run()
QFileInfoList fiL2 = subDir.entryInfoList();
cnt += fiL2.size();
subDir.setPath( basePath + "/title/00010002" );
QFileInfoList fiL3 = subDir.entryInfoList();
cnt += fiL3.size();
subDir.setPath( basePath + "/title/00010004" );
QFileInfoList fiL4 = subDir.entryInfoList();
cnt += fiL4.size();
foreach( QFileInfo f, fiL )
{
i++;
@ -97,9 +105,39 @@ void SaveLoadThread::run()
QByteArray stuff = ff.readAll();
ff.close();
quint32 size = GetFolderSize( f.absoluteFilePath() + "/data" );
emit SendItem( stuff, QString( "00010001" + f.fileName() ), type, size );
}
foreach( QFileInfo f, fiL3 )
{
i++;
emit SendProgress( (int)( ( (float)( i ) / (float)cnt ) * (float)100 ) );
QFile ff( f.absoluteFilePath() + "/data/banner.bin" );
if( !ff.exists() || !ff.open( QIODevice::ReadOnly ) )
continue;
QByteArray stuff = ff.readAll();
ff.close();
quint32 size = GetFolderSize( f.absoluteFilePath() + "/data" );
emit SendItem( stuff, QString( "00010002" + f.fileName() ), type, size );
}
foreach( QFileInfo f, fiL4 )
{
i++;
emit SendProgress( (int)( ( (float)( i ) / (float)cnt ) * (float)100 ) );
QFile ff( f.absoluteFilePath() + "/data/banner.bin" );
if( !ff.exists() || !ff.open( QIODevice::ReadOnly ) )
continue;
QByteArray stuff = ff.readAll();
ff.close();
quint32 size = GetFolderSize( f.absoluteFilePath() + "/data" );
emit SendItem( stuff, QString( "00010004" + f.fileName() ), type, size );
}
emit SendProgress( 100 );
emit SendDone( type );

View File

@ -1,46 +0,0 @@
#include "tools.h"
#include "includes.h"
QString currentDir;
QString pcPath = "./saveBackups";
QString sneekPath = "/media/SDHC_4GB";
char ascii( char s ) {
if ( s < 0x20 ) return '.';
if ( s > 0x7E ) return '.';
return s;
}
void hexdump( const void *d, int len ) {
unsigned char *data;
int i, off;
data = (unsigned char*)d;
fprintf( stderr, "\n");
for ( off = 0; off < len; off += 16 ) {
fprintf( stderr, "%08x ", off );
for ( i=0; i<16; i++ )
{
if( ( i + 1 ) % 4 )
{
if ( ( i + off ) >= len ) fprintf( stderr," ");
else fprintf( stderr,"%02x",data[ off + i ]);
}
else
{
if ( ( i + off ) >= len ) fprintf( stderr," ");
else fprintf( stderr,"%02x ",data[ off + i ]);
}
}
fprintf( stderr, " " );
for ( i = 0; i < 16; i++ )
if ( ( i + off) >= len ) fprintf( stderr," ");
else fprintf( stderr,"%c", ascii( data[ off + i ]));
fprintf( stderr,"\n");
}
fflush( stderr );
}
void hexdump( const QByteArray &d, int from, int len )
{
hexdump( d.data() + from, len == -1 ? d.size() : len );
}

View File

@ -1,20 +0,0 @@
#ifndef TOOLS_H
#define TOOLS_H
#include "includes.h"
#define RU(x,n) (-(-(x) & -(n))) //round up
#define MIN( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) )
#define MAX( x, y ) ( ( x ) > ( y ) ? ( x ) : ( y ) )
char ascii( char s );
void hexdump( const void *d, int len );
void hexdump( const QByteArray &d, int from = 0, int len = -1 );
//keep track of the last folder browsed to when looking for files
extern QString currentDir;
extern QString pcPath;
extern QString sneekPath;
#endif // TOOLS_H