mirror of
https://github.com/martravi/wiiqt.git
synced 2024-11-22 00:59:18 +01:00
* sort titles in nandBinChecker
* use unsigned int since HBC's TID wont fit in a signed 32 bit int * add key index fixing in the ticket class
This commit is contained in:
parent
00176fffdf
commit
0e671a6764
@ -13,7 +13,7 @@ NusDownloader::NusDownloader( QObject *parent, const QString &cPath ) : QObject(
|
|||||||
//change the cache path
|
//change the cache path
|
||||||
void NusDownloader::SetCachePath( const QString &cPath )
|
void NusDownloader::SetCachePath( const QString &cPath )
|
||||||
{
|
{
|
||||||
qDebug() << "NusDownloader::SetCachePath" << cPath;
|
//qDebug() << "NusDownloader::SetCachePath" << cPath;
|
||||||
cachePath = cPath;
|
cachePath = cPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +80,14 @@ bool Tmd::SetDiskAccess( bool allow )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quint32 Tmd::AccessFlags()
|
||||||
|
{
|
||||||
|
if( !p_tmd )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return qFromBigEndian( p_tmd->access_rights );
|
||||||
|
}
|
||||||
|
|
||||||
quint16 Tmd::Gid()
|
quint16 Tmd::Gid()
|
||||||
{
|
{
|
||||||
if( !p_tmd )
|
if( !p_tmd )
|
||||||
@ -154,6 +162,13 @@ bool Tmd::SetSize( quint16 cid, quint32 size )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quint16 Tmd::BootIndex( quint16 i )
|
||||||
|
{
|
||||||
|
if( !p_tmd || i > qFromBigEndian( p_tmd->num_contents ) )
|
||||||
|
return 0;
|
||||||
|
return qFromBigEndian( p_tmd->contents[ i ].index );
|
||||||
|
}
|
||||||
|
|
||||||
quint16 Tmd::Type( quint16 i )
|
quint16 Tmd::Type( quint16 i )
|
||||||
{
|
{
|
||||||
if( !p_tmd || i > qFromBigEndian( p_tmd->num_contents ) )
|
if( !p_tmd || i > qFromBigEndian( p_tmd->num_contents ) )
|
||||||
@ -234,7 +249,7 @@ bool Tmd::FakeSign()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ticket::Ticket( const QByteArray &stuff )
|
Ticket::Ticket( const QByteArray &stuff, bool fixKeyIndex )
|
||||||
{
|
{
|
||||||
data = stuff;
|
data = stuff;
|
||||||
p_tik = NULL;
|
p_tik = NULL;
|
||||||
@ -264,6 +279,20 @@ Ticket::Ticket( const QByteArray &stuff )
|
|||||||
data.resize( SignedSize() );
|
data.resize( SignedSize() );
|
||||||
SetPointer();
|
SetPointer();
|
||||||
}
|
}
|
||||||
|
quint8 *keyindex = ((quint8*)p_tik) + 0xb1;
|
||||||
|
if( fixKeyIndex && ( *keyindex > 0 ) )
|
||||||
|
{
|
||||||
|
if( *keyindex == 1 )//for now, just bail out for korean key
|
||||||
|
{
|
||||||
|
qWarning() << "Ticket::Ticket -> ticket uses the korean key. Only titles encrypted with the common key are supported";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qWarning() << "Ticket::Ticket -> key index is" << hex << *keyindex << ". Setting it to 0 and fakesigning";
|
||||||
|
|
||||||
|
*keyindex = 0;//anything other than 0 or 1 is probably an error. fix it
|
||||||
|
FakeSign();
|
||||||
|
//hexdump( data );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 Ticket::Tid()
|
quint64 Ticket::Tid()
|
||||||
|
@ -137,7 +137,7 @@ typedef struct _cert_ecdsa {
|
|||||||
class Ticket
|
class Ticket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Ticket( const QByteArray &stuff = QByteArray() );
|
Ticket( const QByteArray &stuff = QByteArray(), bool fixKeyIndex = true );
|
||||||
|
|
||||||
//expose the tik data to the rest of the code so it cas read directly from the p_tmd instead of having to add a function to access all the data
|
//expose the tik data to the rest of the code so it cas read directly from the p_tmd instead of having to add a function to access all the data
|
||||||
//the pointer should be good until "data" is changed
|
//the pointer should be good until "data" is changed
|
||||||
@ -184,11 +184,13 @@ public:
|
|||||||
QByteArray Hash( quint16 i );
|
QByteArray Hash( quint16 i );
|
||||||
|
|
||||||
//returned in host endian
|
//returned in host endian
|
||||||
quint64 Size( quint16 i );
|
quint64 Size( quint16 i );
|
||||||
quint16 Type( quint16 i );
|
quint16 Type( quint16 i );
|
||||||
|
quint16 BootIndex( quint16 i );
|
||||||
quint64 Tid();
|
quint64 Tid();
|
||||||
quint64 IOS();
|
quint64 IOS();
|
||||||
quint16 Gid();
|
quint16 Gid();
|
||||||
|
quint32 AccessFlags();
|
||||||
|
|
||||||
|
|
||||||
//gets the number of contents
|
//gets the number of contents
|
||||||
|
1056
WiiQt/u8.cpp
1056
WiiQt/u8.cpp
File diff suppressed because it is too large
Load Diff
162
WiiQt/wad.cpp
162
WiiQt/wad.cpp
@ -7,6 +7,8 @@ static QByteArray globalCert;
|
|||||||
Wad::Wad( const QByteArray &stuff )
|
Wad::Wad( const QByteArray &stuff )
|
||||||
{
|
{
|
||||||
ok = false;
|
ok = false;
|
||||||
|
if( !stuff.size() )//prevent error text when it isnt required
|
||||||
|
return;
|
||||||
if( stuff.size() < 0x80 )//less than this and there is definitely nothing there
|
if( stuff.size() < 0x80 )//less than this and there is definitely nothing there
|
||||||
{
|
{
|
||||||
Err( "Size is < 0x80" );
|
Err( "Size is < 0x80" );
|
||||||
@ -83,6 +85,9 @@ Wad::Wad( const QByteArray &stuff )
|
|||||||
Ticket ticket( tikData );
|
Ticket ticket( tikData );
|
||||||
Tmd t( tmdData );
|
Tmd t( tmdData );
|
||||||
|
|
||||||
|
//the constructor for Ticket may have fixed a bad key index. replace the data just incase it did
|
||||||
|
tikData = ticket.Data();
|
||||||
|
|
||||||
//hexdump( tikData );
|
//hexdump( tikData );
|
||||||
//hexdump( tmdData );
|
//hexdump( tmdData );
|
||||||
|
|
||||||
@ -107,8 +112,8 @@ Wad::Wad( const QByteArray &stuff )
|
|||||||
{
|
{
|
||||||
|
|
||||||
quint32 s = RU( t.Size( i ), 0x40 );
|
quint32 s = RU( t.Size( i ), 0x40 );
|
||||||
qDebug() << "content" << i << "is at" << hex << pos
|
//qDebug() << "content" << i << "is at" << hex << pos
|
||||||
<< "with size" << s;
|
// << "with size" << s;
|
||||||
QByteArray encData = stuff.mid( pos, s );
|
QByteArray encData = stuff.mid( pos, s );
|
||||||
pos += s;
|
pos += s;
|
||||||
|
|
||||||
@ -134,6 +139,7 @@ Wad::Wad( const QByteArray &stuff )
|
|||||||
|
|
||||||
Wad::Wad( const QList< QByteArray > &stuff, bool encrypted )
|
Wad::Wad( const QList< QByteArray > &stuff, bool encrypted )
|
||||||
{
|
{
|
||||||
|
ok = false;
|
||||||
if( stuff.size() < 3 )
|
if( stuff.size() < 3 )
|
||||||
{
|
{
|
||||||
Err( "Cant treate a wad with < 3 items" );
|
Err( "Cant treate a wad with < 3 items" );
|
||||||
@ -173,6 +179,84 @@ Wad::Wad( const QList< QByteArray > &stuff, bool encrypted )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Wad::Wad( QDir dir )
|
||||||
|
{
|
||||||
|
ok = false;
|
||||||
|
QFileInfoList tmds = dir.entryInfoList( QStringList() << "*.tmd" << "tmd.*", QDir::Files );
|
||||||
|
if( tmds.isEmpty() )
|
||||||
|
{
|
||||||
|
Err( "TMD not found" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tmdData = ReadFile( tmds.at( 0 ).absoluteFilePath() );
|
||||||
|
if( tmdData.isEmpty() )
|
||||||
|
return;
|
||||||
|
QFileInfoList tiks = dir.entryInfoList( QStringList() << "*.tik" << "cetk", QDir::Files );
|
||||||
|
if( tiks.isEmpty() )
|
||||||
|
{
|
||||||
|
Err( "Ticket not found" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tikData = ReadFile( tiks.at( 0 ).absoluteFilePath() );
|
||||||
|
if( tikData.isEmpty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
Tmd t( tmdData );
|
||||||
|
Ticket ticket( tikData );
|
||||||
|
|
||||||
|
//make sure to only add the tmd & ticket without all the cert mumbo jumbo
|
||||||
|
tmdData = t.Data();
|
||||||
|
tikData = ticket.Data();
|
||||||
|
|
||||||
|
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() )
|
||||||
|
{
|
||||||
|
Err( t.Cid( i ) + ".app not found" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
AesSetKey( ticket.DecryptedKey() );
|
||||||
|
appD = PaddedByteArray( appD, 0x40 );
|
||||||
|
QByteArray encData = AesEncrypt( i, appD );
|
||||||
|
partsEnc << encData;
|
||||||
|
}
|
||||||
|
//if something in the tmd changed, fakesign it
|
||||||
|
if( tmdChanged )
|
||||||
|
{
|
||||||
|
if( !t.FakeSign() )
|
||||||
|
{
|
||||||
|
Err( "Error signing the wad" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tmdData = t.Data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QFileInfoList certs = dir.entryInfoList( QStringList() << "*.cert", QDir::Files );
|
||||||
|
if( !certs.isEmpty() )
|
||||||
|
{
|
||||||
|
certData = ReadFile( certs.at( 0 ).absoluteFilePath() );
|
||||||
|
}
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
|
||||||
void Wad::SetCert( const QByteArray &stuff )
|
void Wad::SetCert( const QByteArray &stuff )
|
||||||
{
|
{
|
||||||
certData = stuff;
|
certData = stuff;
|
||||||
@ -204,6 +288,11 @@ const QByteArray Wad::getTik()
|
|||||||
return tikData;
|
return tikData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QByteArray Wad::GetCert()
|
||||||
|
{
|
||||||
|
return certData.isEmpty() ? globalCert : certData;
|
||||||
|
}
|
||||||
|
|
||||||
const QByteArray Wad::Content( quint16 i )
|
const QByteArray Wad::Content( quint16 i )
|
||||||
{
|
{
|
||||||
if( tmdData.isEmpty() || tikData.isEmpty() )
|
if( tmdData.isEmpty() || tikData.isEmpty() )
|
||||||
@ -547,7 +636,7 @@ QByteArray Wad::FromDirectory( QDir dir )
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wad::SetTid( quint64 tid )
|
bool Wad::SetTid( quint64 tid, bool fakeSign )
|
||||||
{
|
{
|
||||||
if( !tmdData.size() || !tikData.size() )
|
if( !tmdData.size() || !tikData.size() )
|
||||||
{
|
{
|
||||||
@ -560,12 +649,12 @@ bool Wad::SetTid( quint64 tid )
|
|||||||
t.SetTid( tid );
|
t.SetTid( tid );
|
||||||
ti.SetTid( tid );
|
ti.SetTid( tid );
|
||||||
|
|
||||||
if( !t.FakeSign() )
|
if( fakeSign && !t.FakeSign() )
|
||||||
{
|
{
|
||||||
Err( "Error signing TMD" );
|
Err( "Error signing TMD" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if( !ti.FakeSign() )
|
if( fakeSign && !ti.FakeSign() )
|
||||||
{
|
{
|
||||||
Err( "Error signing ticket" );
|
Err( "Error signing ticket" );
|
||||||
return false;
|
return false;
|
||||||
@ -575,7 +664,7 @@ bool Wad::SetTid( quint64 tid )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wad::SetIOS( quint32 ios )
|
bool Wad::SetIOS( quint32 ios, bool fakeSign )
|
||||||
{
|
{
|
||||||
if( !tmdData.size() || !tikData.size() )
|
if( !tmdData.size() || !tikData.size() )
|
||||||
{
|
{
|
||||||
@ -586,7 +675,7 @@ bool Wad::SetIOS( quint32 ios )
|
|||||||
|
|
||||||
t.SetIOS( ios );
|
t.SetIOS( ios );
|
||||||
|
|
||||||
if( !t.FakeSign() )
|
if( fakeSign && !t.FakeSign() )
|
||||||
{
|
{
|
||||||
Err( "Error signing TMD" );
|
Err( "Error signing TMD" );
|
||||||
return false;
|
return false;
|
||||||
@ -595,7 +684,27 @@ bool Wad::SetIOS( quint32 ios )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wad::SetAhb( bool remove )
|
bool Wad::SetVersion( quint16 ver, bool fakeSign )
|
||||||
|
{
|
||||||
|
if( !tmdData.size() || !tikData.size() )
|
||||||
|
{
|
||||||
|
Err( "Mising parts of the wad" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Tmd t( tmdData );
|
||||||
|
|
||||||
|
t.SetVersion( ver );
|
||||||
|
|
||||||
|
if( fakeSign && !t.FakeSign() )
|
||||||
|
{
|
||||||
|
Err( "Error signing TMD" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tmdData = t.Data();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Wad::SetAhb( bool remove, bool fakeSign )
|
||||||
{
|
{
|
||||||
if( !tmdData.size() || !tikData.size() )
|
if( !tmdData.size() || !tikData.size() )
|
||||||
{
|
{
|
||||||
@ -606,7 +715,7 @@ bool Wad::SetAhb( bool remove )
|
|||||||
|
|
||||||
t.SetAhb( remove );
|
t.SetAhb( remove );
|
||||||
|
|
||||||
if( !t.FakeSign() )
|
if( fakeSign && !t.FakeSign() )
|
||||||
{
|
{
|
||||||
Err( "Error signing TMD" );
|
Err( "Error signing TMD" );
|
||||||
return false;
|
return false;
|
||||||
@ -615,7 +724,7 @@ bool Wad::SetAhb( bool remove )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wad::SetDiskAccess( bool allow )
|
bool Wad::SetDiskAccess( bool allow, bool fakeSign )
|
||||||
{
|
{
|
||||||
if( !tmdData.size() || !tikData.size() )
|
if( !tmdData.size() || !tikData.size() )
|
||||||
{
|
{
|
||||||
@ -626,7 +735,7 @@ bool Wad::SetDiskAccess( bool allow )
|
|||||||
|
|
||||||
t.SetDiskAccess( allow );
|
t.SetDiskAccess( allow );
|
||||||
|
|
||||||
if( !t.FakeSign() )
|
if( fakeSign && !t.FakeSign() )
|
||||||
{
|
{
|
||||||
Err( "Error signing TMD" );
|
Err( "Error signing TMD" );
|
||||||
return false;
|
return false;
|
||||||
@ -635,6 +744,37 @@ bool Wad::SetDiskAccess( bool allow )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Wad::FakeSign( bool signTmd, bool signTicket )
|
||||||
|
{
|
||||||
|
if( !tmdData.size() || !tikData.size() )
|
||||||
|
{
|
||||||
|
Err( "Mising parts of the wad" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( signTicket )
|
||||||
|
{
|
||||||
|
Ticket ti( tikData );
|
||||||
|
if( !ti.FakeSign() )
|
||||||
|
{
|
||||||
|
Err( "Error signing ticket" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tikData = ti.Data();
|
||||||
|
}
|
||||||
|
if( signTmd )
|
||||||
|
{
|
||||||
|
Tmd t( tmdData );
|
||||||
|
if( !t.FakeSign() )
|
||||||
|
{
|
||||||
|
Err( "Error signing TMD" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tmdData = t.Data();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Wad::ReplaceContent( quint16 idx, const QByteArray &ba )
|
bool Wad::ReplaceContent( quint16 idx, const QByteArray &ba )
|
||||||
{
|
{
|
||||||
if( idx >= partsEnc.size() || !tmdData.size() || !tikData.size() )
|
if( idx >= partsEnc.size() || !tmdData.size() || !tikData.size() )
|
||||||
|
30
WiiQt/wad.h
30
WiiQt/wad.h
@ -13,6 +13,13 @@ public:
|
|||||||
//it will use the global cert unless one is given with SetCert
|
//it will use the global cert unless one is given with SetCert
|
||||||
Wad( const QList< QByteArray > &stuff, bool isEncrypted = true );
|
Wad( const QList< QByteArray > &stuff, bool isEncrypted = true );
|
||||||
|
|
||||||
|
//create a wad from the given directory
|
||||||
|
//! dir should be a directory containing a tmd ( "*.tmd" or "tmd.*" ), a ticket ( "*.tik" or "cetk" ),
|
||||||
|
//! all the contents ( <cid>.app :where cid is the correct cid from the tmd, not the "0, 1, 2, 3..." bullshit some broken wad-unpackers create )
|
||||||
|
//! if any of the .apps do not match in size or hash what is in the TMD, then the TMD will be updated and fakesigned
|
||||||
|
//! a cert ( "*.cert" ) is also supported, but not required
|
||||||
|
Wad( QDir dir );
|
||||||
|
|
||||||
//check if this wad is valid
|
//check if this wad is valid
|
||||||
bool IsOk(){ return ok; }
|
bool IsOk(){ return ok; }
|
||||||
|
|
||||||
@ -23,16 +30,21 @@ public:
|
|||||||
quint64 Tid();
|
quint64 Tid();
|
||||||
|
|
||||||
//set the tid in the ticket&tmd and fakesign the wad
|
//set the tid in the ticket&tmd and fakesign the wad
|
||||||
bool SetTid( quint64 tid );
|
bool SetTid( quint64 tid, bool fakeSign = true );
|
||||||
|
|
||||||
//set the ios in the ticket&tmd and fakesign the wad
|
//set the ios in the tmd and fakesign the wad
|
||||||
bool SetIOS( quint32 ios );
|
bool SetIOS( quint32 ios, bool fakeSign = true );
|
||||||
|
|
||||||
|
//set the version in the tmd and fakesign the wad
|
||||||
|
bool SetVersion( quint16 ver, bool fakeSign = true );
|
||||||
|
|
||||||
//set the tmd to allow AHBPROT removal
|
//set the tmd to allow AHBPROT removal
|
||||||
bool SetAhb( bool remove = true );
|
bool SetAhb( bool remove = true, bool fakeSign = true );
|
||||||
|
|
||||||
//set the tmd to allow direct disc access
|
//set the tmd to allow direct disc access
|
||||||
bool SetDiskAccess( bool allow = true );
|
bool SetDiskAccess( bool allow = true, bool fakeSign = true );
|
||||||
|
|
||||||
|
bool FakeSign( bool signTmd, bool signTicket );
|
||||||
|
|
||||||
//replace a content of this wad, update the size & hash in the tmd and sign it
|
//replace a content of this wad, update the size & hash in the tmd and sign it
|
||||||
//ba should be decrypted
|
//ba should be decrypted
|
||||||
@ -51,11 +63,7 @@ public:
|
|||||||
|
|
||||||
//pack a wad from the given directory
|
//pack a wad from the given directory
|
||||||
//returns a bytearray containing a wad reading for writing to a file
|
//returns a bytearray containing a wad reading for writing to a file
|
||||||
//or an empty bytearray on error
|
//or an empty bytearray on error
|
||||||
//! dir should be a directory containing a tmd ( "*.tmd" or "tmd.*" ), a ticket ( "*.tik" or "cetk" ),
|
|
||||||
//! all the contents ( <cid>.app :where cid is the correct cid from the tmd, not the "0, 1, 2, 3..." bullshit some broken wad-unpackers create )
|
|
||||||
//! if any of the .apps do not match in size or hash what is in the TMD, then the TMD will be updated and fakesigned
|
|
||||||
//! a cert ( "*.cert" ) is also supported, but not required
|
|
||||||
static QByteArray FromDirectory( QDir dir );
|
static QByteArray FromDirectory( QDir dir );
|
||||||
|
|
||||||
//get a assembled wad from the list of parts
|
//get a assembled wad from the list of parts
|
||||||
@ -72,6 +80,8 @@ public:
|
|||||||
//get the tik for the wad
|
//get the tik for the wad
|
||||||
const QByteArray getTik();
|
const QByteArray getTik();
|
||||||
|
|
||||||
|
const QByteArray GetCert();
|
||||||
|
|
||||||
//get the decrypted data from a content
|
//get the decrypted data from a content
|
||||||
const QByteArray Content( quint16 i );
|
const QByteArray Content( quint16 i );
|
||||||
|
|
||||||
|
@ -200,9 +200,9 @@ QList< quint64 > InstalledTitles()
|
|||||||
for( quint16 i = 0; i < subfc; i++ )//check all subfolders of "/ticket"
|
for( quint16 i = 0; i < subfc; i++ )//check all subfolders of "/ticket"
|
||||||
{
|
{
|
||||||
QTreeWidgetItem *subF = tikFolder->child( i );
|
QTreeWidgetItem *subF = tikFolder->child( i );
|
||||||
//qDebug() << "checking folder" << subF->text( 0 );
|
//qDebug() << "checking folder" << subF->text( 0 );
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
quint32 upper = subF->text( 0 ).toInt( &ok, 16 );//make sure it can be converted to int
|
quint32 upper = subF->text( 0 ).toUInt( &ok, 16 );//make sure it can be converted to int
|
||||||
if ( !ok )
|
if ( !ok )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -211,18 +211,18 @@ QList< quint64 > InstalledTitles()
|
|||||||
{
|
{
|
||||||
QTreeWidgetItem *tikI = subF->child( j );
|
QTreeWidgetItem *tikI = subF->child( j );
|
||||||
QString name = tikI->text( 0 );
|
QString name = tikI->text( 0 );
|
||||||
//qDebug() << "checking item" << subF->text( 0 ) + "/" + name;
|
//qDebug() << "checking item" << subF->text( 0 ) + "/" + name;
|
||||||
if( !name.endsWith( ".tik" ) )
|
if( !name.endsWith( ".tik" ) )
|
||||||
{
|
{
|
||||||
//qDebug() << "!tik";
|
//qDebug() << "!tik";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
name.resize( 8 );
|
name.resize( 8 );
|
||||||
quint32 lower = name.toInt( &ok, 16 );
|
quint32 lower = name.toUInt( &ok, 16 );
|
||||||
if( !ok )
|
if( !ok )
|
||||||
{
|
{
|
||||||
//qDebug() << "!ok";
|
//qDebug() << "!ok";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,15 +230,16 @@ QList< quint64 > InstalledTitles()
|
|||||||
QTreeWidgetItem *tmdI = ItemFromPath( "/title/" + subF->text( 0 ) + "/" + name + "/content/title.tmd" );
|
QTreeWidgetItem *tmdI = ItemFromPath( "/title/" + subF->text( 0 ) + "/" + name + "/content/title.tmd" );
|
||||||
if( !tmdI )
|
if( !tmdI )
|
||||||
{
|
{
|
||||||
//qDebug() << "no tmd";
|
//qDebug() << "no tmd";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 tid = (( (quint64)upper << 32) | lower );
|
quint64 tid = (( (quint64)upper << 32) | lower );
|
||||||
//qDebug() << "adding item to list" << TidTxt( tid );
|
//qDebug() << "adding item to list" << TidTxt( tid );
|
||||||
ret << tid;
|
ret << tid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
qSort( ret.begin(), ret.end() );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,6 +302,24 @@ void BuildGoodIosList()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RecurseCheckGidUid( QTreeWidgetItem *item, const QString &uidS, const QString &gidS, const QString &path )
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
quint16 cnt = item->childCount();
|
||||||
|
for( quint16 i = 0; i < cnt; i++ )
|
||||||
|
{
|
||||||
|
QTreeWidgetItem *child = item->child( i );
|
||||||
|
if( child->text( 3 ) != uidS || !child->text( 4 ).startsWith( gidS ) )
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
qDebug() << "\tincorrect uid/gid for" << QString( path + child->text( 0 ) );
|
||||||
|
}
|
||||||
|
if( !RecurseCheckGidUid( child, uidS, gidS, path + child->text( 0 ) + "/" ) )
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool CheckTitleIntegrity( quint64 tid )
|
bool CheckTitleIntegrity( quint64 tid )
|
||||||
{
|
{
|
||||||
if( validIoses.contains( tid ) )//this one has already been checked
|
if( validIoses.contains( tid ) )//this one has already been checked
|
||||||
@ -357,7 +376,7 @@ bool CheckTitleIntegrity( quint64 tid )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Ticket ticket( ba );
|
Ticket ticket( ba, false );
|
||||||
if( ticket.Tid() != tid )
|
if( ticket.Tid() != tid )
|
||||||
{
|
{
|
||||||
qDebug() << "the ticket contains the wrong TID";
|
qDebug() << "the ticket contains the wrong TID";
|
||||||
@ -378,7 +397,7 @@ bool CheckTitleIntegrity( quint64 tid )
|
|||||||
{
|
{
|
||||||
if( sharedM.GetAppFromHash( t.Hash( i ) ).isEmpty() )
|
if( sharedM.GetAppFromHash( t.Hash( i ) ).isEmpty() )
|
||||||
{
|
{
|
||||||
qDebug() << "one of the shared contents is missing";
|
qDebug() << "\tone of the shared contents is missing";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -391,7 +410,7 @@ bool CheckTitleIntegrity( quint64 tid )
|
|||||||
QByteArray ba = nand.GetData( pA );
|
QByteArray ba = nand.GetData( pA );
|
||||||
if( ba.isEmpty() )
|
if( ba.isEmpty() )
|
||||||
{
|
{
|
||||||
qDebug() << "one of the private contents is missing" << pA;
|
qDebug() << "\t error reading one of the private contents" << pA;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QByteArray realH = GetSha1( ba );
|
QByteArray realH = GetSha1( ba );
|
||||||
@ -432,13 +451,15 @@ bool CheckTitleIntegrity( quint64 tid )
|
|||||||
QString gidS = QString( "%1" ).arg( gid, 4, 16, QChar( '0' ) );
|
QString gidS = QString( "%1" ).arg( gid, 4, 16, QChar( '0' ) );
|
||||||
if( dataI->text( 3 ) != uidS || !dataI->text( 4 ).startsWith( gidS ) )//dont necessarily fail for this. the title will still be bootable without its data
|
if( dataI->text( 3 ) != uidS || !dataI->text( 4 ).startsWith( gidS ) )//dont necessarily fail for this. the title will still be bootable without its data
|
||||||
qDebug() << "\tincorrect uid/gid for data folder";
|
qDebug() << "\tincorrect uid/gid for data folder";
|
||||||
quint16 cnt = dataI->childCount();
|
|
||||||
|
RecurseCheckGidUid( dataI, uidS, gidS, "data/" );
|
||||||
|
/*quint16 cnt = dataI->childCount();
|
||||||
for( quint16 i = 0; i < cnt; i++ )
|
for( quint16 i = 0; i < cnt; i++ )
|
||||||
{
|
{
|
||||||
QTreeWidgetItem *item = dataI->child( i );
|
QTreeWidgetItem *item = dataI->child( i );
|
||||||
if( item->text( 3 ) != uidS || !item->text( 4 ).startsWith( gidS ) )
|
if( item->text( 3 ) != uidS || !item->text( 4 ).startsWith( gidS ) )
|
||||||
qDebug() << "\tincorrect uid/gid for" << QString( "data/" + item->text( 0 ) );
|
qDebug() << "\tincorrect uid/gid for" << QString( "data/" + item->text( 0 ) );
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
dataP.resize( 25 );
|
dataP.resize( 25 );
|
||||||
dataP += "content";
|
dataP += "content";
|
||||||
@ -617,8 +638,8 @@ void CheckHmac()
|
|||||||
int main( int argc, char *argv[] )
|
int main( int argc, char *argv[] )
|
||||||
{
|
{
|
||||||
QCoreApplication a( argc, argv );
|
QCoreApplication a( argc, argv );
|
||||||
QStringList args = QCoreApplication::arguments();
|
QStringList args = QCoreApplication::arguments();
|
||||||
if( args.size() < 2 )
|
if( args.size() < 2 )
|
||||||
Usage();
|
Usage();
|
||||||
|
|
||||||
if( !QFile( args.at( 1 ) ).exists() )
|
if( !QFile( args.at( 1 ) ).exists() )
|
||||||
@ -678,8 +699,6 @@ int main( int argc, char *argv[] )
|
|||||||
qDebug() << "verifying hmac...";
|
qDebug() << "verifying hmac...";
|
||||||
CheckHmac();
|
CheckHmac();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,24 +37,7 @@ MainWindow::MainWindow( QWidget *parent ) : QMainWindow( parent ), ui( new Ui::M
|
|||||||
connect( &nus, SIGNAL( SendDone() ), this, SLOT( NusIsDone() ) );
|
connect( &nus, SIGNAL( SendDone() ), this, SLOT( NusIsDone() ) );
|
||||||
connect( &nus, SIGNAL( SendData( NusJob ) ), this, SLOT( ReceiveTitleFromNus( NusJob) ) );
|
connect( &nus, SIGNAL( SendData( NusJob ) ), this, SLOT( ReceiveTitleFromNus( NusJob) ) );
|
||||||
|
|
||||||
//TODO, really get these paths from settings
|
|
||||||
|
|
||||||
/*#ifdef Q_WS_WIN
|
|
||||||
QString cachePath = "../../NUS_cache";
|
|
||||||
#else
|
|
||||||
QString cachePath = "../NUS_cache";
|
|
||||||
#endif
|
|
||||||
QString nandPath = "./dump";
|
|
||||||
|
|
||||||
ui->lineEdit_cachePath->setText( cachePath );
|
|
||||||
ui->lineEdit_nandPath->setText( nandPath );
|
|
||||||
ui->lineEdit_extractPath->setText( "./downloaded" );*/
|
|
||||||
|
|
||||||
LoadSettings();
|
LoadSettings();
|
||||||
|
|
||||||
|
|
||||||
//nand.SetPath( nandPath );
|
|
||||||
//nus.SetCachePath( cachePath );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
|
@ -39,7 +39,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
|||||||
}
|
}
|
||||||
else if( !pcPath.isEmpty() )
|
else if( !pcPath.isEmpty() )
|
||||||
GetSavesFromPC( pcPath );
|
GetSavesFromPC( pcPath );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
|
Loading…
Reference in New Issue
Block a user