mirror of
https://github.com/jakcron/nstool.git
synced 2024-12-22 18:55:29 +00:00
Merge pull request #16 from jakcron/IFile-ptr-ownership-refactor
I file ptr ownership refactor
This commit is contained in:
commit
20f75bc1ba
|
@ -20,6 +20,7 @@ namespace fnd
|
|||
};
|
||||
|
||||
SimpleFile();
|
||||
SimpleFile(const std::string& path, OpenMode mode);
|
||||
~SimpleFile();
|
||||
|
||||
void open(const std::string& path, OpenMode mode);
|
||||
|
|
|
@ -14,6 +14,12 @@ SimpleFile::SimpleFile() :
|
|||
{
|
||||
}
|
||||
|
||||
SimpleFile::SimpleFile(const std::string& path, OpenMode mode) :
|
||||
SimpleFile()
|
||||
{
|
||||
open(path, mode);
|
||||
}
|
||||
|
||||
SimpleFile::~SimpleFile()
|
||||
{
|
||||
close();
|
||||
|
|
|
@ -167,7 +167,6 @@
|
|||
<ItemGroup>
|
||||
<ClInclude Include="source\AesCtrWrappedIFile.h" />
|
||||
<ClInclude Include="source\CnmtProcess.h" />
|
||||
<ClInclude Include="source\CopiedIFile.h" />
|
||||
<ClInclude Include="source\DynamicSymbolParser.h" />
|
||||
<ClInclude Include="source\HashTreeMeta.h" />
|
||||
<ClInclude Include="source\HashTreeWrappedIFile.h" />
|
||||
|
|
|
@ -42,9 +42,6 @@
|
|||
<ClInclude Include="source\AesCtrWrappedIFile.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="source\CopiedIFile.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="source\OffsetAdjustedIFile.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
#include "AesCtrWrappedIFile.h"
|
||||
|
||||
AesCtrWrappedIFile::AesCtrWrappedIFile(fnd::IFile* file, const crypto::aes::sAes128Key& key, const crypto::aes::sAesIvCtr& ctr) :
|
||||
AesCtrWrappedIFile(file, false, key, ctr)
|
||||
{
|
||||
}
|
||||
|
||||
AesCtrWrappedIFile::AesCtrWrappedIFile(fnd::IFile* file, bool ownIfile, const crypto::aes::sAes128Key& key, const crypto::aes::sAesIvCtr& ctr) :
|
||||
mOwnIFile(ownIfile),
|
||||
mFile(file),
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
class AesCtrWrappedIFile : public fnd::IFile
|
||||
{
|
||||
public:
|
||||
AesCtrWrappedIFile(fnd::IFile* file, const crypto::aes::sAes128Key& key, const crypto::aes::sAesIvCtr& ctr);
|
||||
AesCtrWrappedIFile(fnd::IFile* file, bool ownIfile, const crypto::aes::sAes128Key& key, const crypto::aes::sAesIvCtr& ctr);
|
||||
~AesCtrWrappedIFile();
|
||||
|
||||
|
|
|
@ -143,7 +143,8 @@ void CnmtProcess::displayCmnt()
|
|||
}
|
||||
|
||||
CnmtProcess::CnmtProcess() :
|
||||
mReader(nullptr),
|
||||
mFile(nullptr),
|
||||
mOwnIFile(false),
|
||||
mCliOutputType(OUTPUT_NORMAL),
|
||||
mVerify(false)
|
||||
{
|
||||
|
@ -151,9 +152,9 @@ CnmtProcess::CnmtProcess() :
|
|||
|
||||
CnmtProcess::~CnmtProcess()
|
||||
{
|
||||
if (mReader != nullptr)
|
||||
if (mOwnIFile)
|
||||
{
|
||||
delete mReader;
|
||||
delete mFile;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,13 +162,13 @@ void CnmtProcess::process()
|
|||
{
|
||||
fnd::MemoryBlob scratch;
|
||||
|
||||
if (mReader == nullptr)
|
||||
if (mFile == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
scratch.alloc(mReader->size());
|
||||
mReader->read(scratch.getBytes(), 0, scratch.getSize());
|
||||
scratch.alloc(mFile->size());
|
||||
mFile->read(scratch.getBytes(), 0, scratch.getSize());
|
||||
|
||||
mCnmt.importBinary(scratch.getBytes(), scratch.getSize());
|
||||
|
||||
|
@ -177,9 +178,10 @@ void CnmtProcess::process()
|
|||
}
|
||||
}
|
||||
|
||||
void CnmtProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size)
|
||||
void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||
{
|
||||
mReader = new OffsetAdjustedIFile(file, offset, size);
|
||||
mFile = file;
|
||||
mOwnIFile = ownIFile;
|
||||
}
|
||||
|
||||
void CnmtProcess::setCliOutputMode(CliOutputType type)
|
||||
|
|
|
@ -14,7 +14,7 @@ public:
|
|||
|
||||
void process();
|
||||
|
||||
void setInputFile(fnd::IFile* file, size_t offset, size_t size);
|
||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
||||
void setCliOutputMode(CliOutputType type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
||||
|
@ -23,7 +23,8 @@ public:
|
|||
private:
|
||||
const std::string kModuleName = "CnmtProcess";
|
||||
|
||||
fnd::IFile* mReader;
|
||||
fnd::IFile* mFile;
|
||||
bool mOwnIFile;
|
||||
CliOutputType mCliOutputType;
|
||||
bool mVerify;
|
||||
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
#pragma once
|
||||
#include <fnd/IFile.h>
|
||||
|
||||
class CopiedIFile : public fnd::IFile
|
||||
{
|
||||
public:
|
||||
inline CopiedIFile(fnd::IFile* file) : mFile(file) {}
|
||||
|
||||
inline size_t size() { return mFile->size(); }
|
||||
inline void seek(size_t offset) { mFile->seek(offset); }
|
||||
inline void read(byte_t* out, size_t len) { mFile->read(out, len); }
|
||||
inline void read(byte_t* out, size_t offset, size_t len) { mFile->read(out, offset, len); }
|
||||
inline void write(const byte_t* out, size_t len) { mFile->write(out, len); }
|
||||
inline void write(const byte_t* out, size_t offset, size_t len) { mFile->write(out, offset, len); }
|
||||
private:
|
||||
fnd::IFile* mFile;
|
||||
};
|
|
@ -1,18 +1,7 @@
|
|||
#include "nstool.h"
|
||||
#include "HashTreeWrappedIFile.h"
|
||||
#include "CopiedIFile.h"
|
||||
#include "OffsetAdjustedIFile.h"
|
||||
|
||||
|
||||
HashTreeWrappedIFile::HashTreeWrappedIFile(fnd::IFile* file, const HashTreeMeta& hdr) :
|
||||
mOwnIFile(true),
|
||||
mFile(file),
|
||||
mData(nullptr),
|
||||
mDataHashLayer(),
|
||||
mAlignHashCalcToBlock(false)
|
||||
{
|
||||
initialiseDataLayer(hdr);
|
||||
}
|
||||
|
||||
HashTreeWrappedIFile::HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, const HashTreeMeta& hdr) :
|
||||
mOwnIFile(ownIFile),
|
||||
mFile(file),
|
||||
|
@ -156,7 +145,7 @@ void HashTreeWrappedIFile::initialiseDataLayer(const HashTreeMeta& hdr)
|
|||
}
|
||||
|
||||
// generate reader for data layer
|
||||
mData = new OffsetAdjustedIFile(mFile, false, hdr.getDataLayer().offset, hdr.getDataLayer().size);
|
||||
mData = new OffsetAdjustedIFile(mFile, SHARED_IFILE, hdr.getDataLayer().offset, hdr.getDataLayer().size);
|
||||
mDataOffset = 0;
|
||||
mDataBlockSize = hdr.getDataLayer().block_size;
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
class HashTreeWrappedIFile : public fnd::IFile
|
||||
{
|
||||
public:
|
||||
HashTreeWrappedIFile(fnd::IFile* file, const HashTreeMeta& hdr);
|
||||
HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, const HashTreeMeta& hdr);
|
||||
~HashTreeWrappedIFile();
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "NpdmProcess.h"
|
||||
#include "OffsetAdjustedIFile.h"
|
||||
#include "AesCtrWrappedIFile.h"
|
||||
#include "CopiedIFile.h"
|
||||
#include "HashTreeWrappedIFile.h"
|
||||
|
||||
const char* getFormatVersionStr(nx::NcaHeader::FormatVersion format_ver)
|
||||
|
@ -222,7 +221,8 @@ const char* getProgramPartitionNameStr(size_t i)
|
|||
|
||||
|
||||
NcaProcess::NcaProcess() :
|
||||
mReader(nullptr),
|
||||
mFile(nullptr),
|
||||
mOwnIFile(false),
|
||||
mKeyset(nullptr),
|
||||
mCliOutputType(OUTPUT_NORMAL),
|
||||
mVerify(false),
|
||||
|
@ -237,9 +237,9 @@ NcaProcess::NcaProcess() :
|
|||
|
||||
NcaProcess::~NcaProcess()
|
||||
{
|
||||
if (mReader != nullptr)
|
||||
if (mOwnIFile)
|
||||
{
|
||||
delete mReader;
|
||||
delete mFile;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nx::nca::kPartitionNum; i++)
|
||||
|
@ -255,13 +255,13 @@ void NcaProcess::process()
|
|||
{
|
||||
fnd::MemoryBlob scratch;
|
||||
|
||||
if (mReader == nullptr)
|
||||
if (mFile == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
// read header block
|
||||
mReader->read((byte_t*)&mHdrBlock, 0, sizeof(nx::sNcaHeaderBlock));
|
||||
mFile->read((byte_t*)&mHdrBlock, 0, sizeof(nx::sNcaHeaderBlock));
|
||||
|
||||
// decrypt header block
|
||||
nx::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyset->nca.header_key);
|
||||
|
@ -311,9 +311,10 @@ void NcaProcess::process()
|
|||
*/
|
||||
}
|
||||
|
||||
void NcaProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size)
|
||||
void NcaProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||
{
|
||||
mReader = new OffsetAdjustedIFile(file, offset, size);
|
||||
mFile = file;
|
||||
mOwnIFile = ownIFile;
|
||||
}
|
||||
|
||||
void NcaProcess::setKeyset(const sKeyset* keyset)
|
||||
|
@ -539,13 +540,13 @@ void NcaProcess::generatePartitionConfiguration()
|
|||
// create reader based on encryption type0
|
||||
if (info.enc_type == nx::nca::CRYPT_NONE)
|
||||
{
|
||||
info.reader = new OffsetAdjustedIFile(mReader, info.offset, info.size);
|
||||
info.reader = new OffsetAdjustedIFile(mFile, SHARED_IFILE, info.offset, info.size);
|
||||
}
|
||||
else if (info.enc_type == nx::nca::CRYPT_AESCTR)
|
||||
{
|
||||
if (mBodyKeys.aes_ctr.isSet == false)
|
||||
throw fnd::Exception(kModuleName, "AES-CTR Key was not determined");
|
||||
info.reader = new OffsetAdjustedIFile(new AesCtrWrappedIFile(mReader, mBodyKeys.aes_ctr.var, info.aes_ctr), true, info.offset, info.size);
|
||||
info.reader = new OffsetAdjustedIFile(new AesCtrWrappedIFile(mFile, SHARED_IFILE, mBodyKeys.aes_ctr.var, info.aes_ctr), OWN_IFILE, info.offset, info.size);
|
||||
}
|
||||
else if (info.enc_type == nx::nca::CRYPT_AESXTS || info.enc_type == nx::nca::CRYPT_AESCTREX)
|
||||
{
|
||||
|
@ -565,7 +566,7 @@ void NcaProcess::generatePartitionConfiguration()
|
|||
{
|
||||
fnd::IFile* tmp = info.reader;
|
||||
info.reader = nullptr;
|
||||
info.reader = new HashTreeWrappedIFile(tmp, true, info.hash_tree_meta);
|
||||
info.reader = new HashTreeWrappedIFile(tmp, OWN_IFILE, info.hash_tree_meta);
|
||||
}
|
||||
else if (info.hash_type != nx::nca::HASH_NONE)
|
||||
{
|
||||
|
@ -602,7 +603,7 @@ void NcaProcess::validateNcaSignatures()
|
|||
if (mPartitions[nx::nca::PARTITION_CODE].reader != nullptr)
|
||||
{
|
||||
PfsProcess exefs;
|
||||
exefs.setInputFile(mPartitions[nx::nca::PARTITION_CODE].reader, 0, mPartitions[nx::nca::PARTITION_CODE].reader->size());
|
||||
exefs.setInputFile(mPartitions[nx::nca::PARTITION_CODE].reader, SHARED_IFILE);
|
||||
exefs.setCliOutputMode(OUTPUT_MINIMAL);
|
||||
exefs.process();
|
||||
|
||||
|
@ -612,7 +613,7 @@ void NcaProcess::validateNcaSignatures()
|
|||
const nx::PfsHeader::sFile& file = exefs.getPfsHeader().getFileList()[exefs.getPfsHeader().getFileList().getIndexOf(kNpdmExefsPath)];
|
||||
|
||||
NpdmProcess npdm;
|
||||
npdm.setInputFile(mPartitions[nx::nca::PARTITION_CODE].reader, file.offset, file.size);
|
||||
npdm.setInputFile(new OffsetAdjustedIFile(mPartitions[nx::nca::PARTITION_CODE].reader, SHARED_IFILE, file.offset, file.size), OWN_IFILE);
|
||||
npdm.setCliOutputMode(OUTPUT_MINIMAL);
|
||||
npdm.process();
|
||||
|
||||
|
@ -789,7 +790,7 @@ void NcaProcess::processPartitions()
|
|||
if (partition.format_type == nx::nca::FORMAT_PFS0)
|
||||
{
|
||||
PfsProcess pfs;
|
||||
pfs.setInputFile(partition.reader, 0, partition.reader->size());
|
||||
pfs.setInputFile(partition.reader, SHARED_IFILE);
|
||||
pfs.setCliOutputMode(mCliOutputType);
|
||||
pfs.setListFs(mListFs);
|
||||
if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM)
|
||||
|
@ -810,7 +811,7 @@ void NcaProcess::processPartitions()
|
|||
else if (partition.format_type == nx::nca::FORMAT_ROMFS)
|
||||
{
|
||||
RomfsProcess romfs;
|
||||
romfs.setInputFile(partition.reader, 0, partition.reader->size());
|
||||
romfs.setInputFile(partition.reader, SHARED_IFILE);
|
||||
romfs.setCliOutputMode(mCliOutputType);
|
||||
romfs.setListFs(mListFs);
|
||||
if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM)
|
||||
|
|
|
@ -17,7 +17,7 @@ public:
|
|||
void process();
|
||||
|
||||
// generic
|
||||
void setInputFile(fnd::IFile* file, size_t offset, size_t size);
|
||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
||||
void setKeyset(const sKeyset* keyset);
|
||||
void setCliOutputMode(CliOutputType type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
@ -34,7 +34,8 @@ private:
|
|||
const std::string kNpdmExefsPath = "main.npdm";
|
||||
|
||||
// user options
|
||||
fnd::IFile* mReader;
|
||||
fnd::IFile* mFile;
|
||||
bool mOwnIFile;
|
||||
const sKeyset* mKeyset;
|
||||
CliOutputType mCliOutputType;
|
||||
bool mVerify;
|
||||
|
|
|
@ -1,6 +1,87 @@
|
|||
#include "OffsetAdjustedIFile.h"
|
||||
#include "NpdmProcess.h"
|
||||
|
||||
NpdmProcess::NpdmProcess() :
|
||||
mFile(nullptr),
|
||||
mOwnIFile(false),
|
||||
mKeyset(nullptr),
|
||||
mCliOutputType(OUTPUT_NORMAL),
|
||||
mVerify(false)
|
||||
{
|
||||
}
|
||||
|
||||
NpdmProcess::~NpdmProcess()
|
||||
{
|
||||
if (mOwnIFile)
|
||||
{
|
||||
delete mFile;
|
||||
}
|
||||
}
|
||||
|
||||
void NpdmProcess::process()
|
||||
{
|
||||
fnd::MemoryBlob scratch;
|
||||
|
||||
if (mFile == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
scratch.alloc(mFile->size());
|
||||
mFile->read(scratch.getBytes(), 0, scratch.getSize());
|
||||
|
||||
mNpdm.importBinary(scratch.getBytes(), scratch.getSize());
|
||||
|
||||
if (mVerify)
|
||||
{
|
||||
validateAcidSignature(mNpdm.getAcid());
|
||||
validateAciFromAcid(mNpdm.getAci(), mNpdm.getAcid());
|
||||
}
|
||||
|
||||
if (mCliOutputType >= OUTPUT_NORMAL)
|
||||
{
|
||||
// npdm binary
|
||||
displayNpdmHeader(mNpdm);
|
||||
|
||||
// aci binary
|
||||
displayAciHdr(mNpdm.getAci());
|
||||
displayFac(mNpdm.getAci().getFac());
|
||||
displaySac(mNpdm.getAci().getSac());
|
||||
displayKernelCap(mNpdm.getAci().getKc());
|
||||
|
||||
// acid binary
|
||||
displayAciHdr(mNpdm.getAcid());
|
||||
displayFac(mNpdm.getAcid().getFac());
|
||||
displaySac(mNpdm.getAcid().getSac());
|
||||
displayKernelCap(mNpdm.getAcid().getKc());
|
||||
}
|
||||
}
|
||||
|
||||
void NpdmProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||
{
|
||||
mFile = file;
|
||||
mOwnIFile = ownIFile;
|
||||
}
|
||||
|
||||
void NpdmProcess::setKeyset(const sKeyset* keyset)
|
||||
{
|
||||
mKeyset = keyset;
|
||||
}
|
||||
|
||||
void NpdmProcess::setCliOutputMode(CliOutputType type)
|
||||
{
|
||||
mCliOutputType = type;
|
||||
}
|
||||
|
||||
void NpdmProcess::setVerifyMode(bool verify)
|
||||
{
|
||||
mVerify = verify;
|
||||
}
|
||||
|
||||
const nx::NpdmBinary& NpdmProcess::getNpdmBinary() const
|
||||
{
|
||||
return mNpdm;
|
||||
}
|
||||
|
||||
const std::string kInstructionType[2] = { "32Bit", "64Bit" };
|
||||
const std::string kProcAddrSpace[4] = { "Unknown", "64Bit", "32Bit", "32Bit no reserved" };
|
||||
const std::string kAciType[2] = { "ACI0", "ACID" };
|
||||
|
@ -615,83 +696,3 @@ void NpdmProcess::displayKernelCap(const nx::KcBinary& kern)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
NpdmProcess::NpdmProcess() :
|
||||
mReader(nullptr),
|
||||
mKeyset(nullptr),
|
||||
mCliOutputType(OUTPUT_NORMAL),
|
||||
mVerify(false)
|
||||
{
|
||||
}
|
||||
|
||||
NpdmProcess::~NpdmProcess()
|
||||
{
|
||||
if (mReader != nullptr)
|
||||
{
|
||||
delete mReader;
|
||||
}
|
||||
}
|
||||
|
||||
void NpdmProcess::process()
|
||||
{
|
||||
fnd::MemoryBlob scratch;
|
||||
|
||||
if (mReader == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
scratch.alloc(mReader->size());
|
||||
mReader->read(scratch.getBytes(), 0, scratch.getSize());
|
||||
|
||||
mNpdm.importBinary(scratch.getBytes(), scratch.getSize());
|
||||
|
||||
if (mVerify)
|
||||
{
|
||||
validateAcidSignature(mNpdm.getAcid());
|
||||
validateAciFromAcid(mNpdm.getAci(), mNpdm.getAcid());
|
||||
}
|
||||
|
||||
if (mCliOutputType >= OUTPUT_NORMAL)
|
||||
{
|
||||
// npdm binary
|
||||
displayNpdmHeader(mNpdm);
|
||||
|
||||
// aci binary
|
||||
displayAciHdr(mNpdm.getAci());
|
||||
displayFac(mNpdm.getAci().getFac());
|
||||
displaySac(mNpdm.getAci().getSac());
|
||||
displayKernelCap(mNpdm.getAci().getKc());
|
||||
|
||||
// acid binary
|
||||
displayAciHdr(mNpdm.getAcid());
|
||||
displayFac(mNpdm.getAcid().getFac());
|
||||
displaySac(mNpdm.getAcid().getSac());
|
||||
displayKernelCap(mNpdm.getAcid().getKc());
|
||||
}
|
||||
}
|
||||
|
||||
void NpdmProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size)
|
||||
{
|
||||
mReader = new OffsetAdjustedIFile(file, offset, size);
|
||||
}
|
||||
|
||||
void NpdmProcess::setKeyset(const sKeyset* keyset)
|
||||
{
|
||||
mKeyset = keyset;
|
||||
}
|
||||
|
||||
void NpdmProcess::setCliOutputMode(CliOutputType type)
|
||||
{
|
||||
mCliOutputType = type;
|
||||
}
|
||||
|
||||
void NpdmProcess::setVerifyMode(bool verify)
|
||||
{
|
||||
mVerify = verify;
|
||||
}
|
||||
|
||||
const nx::NpdmBinary& NpdmProcess::getNpdmBinary() const
|
||||
{
|
||||
return mNpdm;
|
||||
}
|
|
@ -14,7 +14,7 @@ public:
|
|||
|
||||
void process();
|
||||
|
||||
void setInputFile(fnd::IFile* file, size_t offset, size_t size);
|
||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
||||
void setKeyset(const sKeyset* keyset);
|
||||
void setCliOutputMode(CliOutputType type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
@ -24,7 +24,8 @@ public:
|
|||
private:
|
||||
const std::string kModuleName = "NpdmProcess";
|
||||
|
||||
fnd::IFile* mReader;
|
||||
fnd::IFile* mFile;
|
||||
bool mOwnIFile;
|
||||
const sKeyset* mKeyset;
|
||||
CliOutputType mCliOutputType;
|
||||
bool mVerify;
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
#include "NsoProcess.h"
|
||||
|
||||
NsoProcess::NsoProcess():
|
||||
mReader(nullptr),
|
||||
mFile(nullptr),
|
||||
mOwnIFile(false),
|
||||
mCliOutputType(OUTPUT_NORMAL),
|
||||
mVerify(false)
|
||||
{
|
||||
|
@ -15,15 +16,15 @@ NsoProcess::NsoProcess():
|
|||
|
||||
NsoProcess::~NsoProcess()
|
||||
{
|
||||
if (mReader != nullptr)
|
||||
if (mOwnIFile)
|
||||
{
|
||||
delete mReader;
|
||||
delete mFile;
|
||||
}
|
||||
}
|
||||
|
||||
void NsoProcess::process()
|
||||
{
|
||||
if (mReader == nullptr)
|
||||
if (mFile == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
@ -39,9 +40,10 @@ void NsoProcess::process()
|
|||
}
|
||||
}
|
||||
|
||||
void NsoProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size)
|
||||
void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||
{
|
||||
mReader = new OffsetAdjustedIFile(file, offset, size);
|
||||
mFile = file;
|
||||
mOwnIFile = ownIFile;
|
||||
}
|
||||
|
||||
void NsoProcess::setCliOutputMode(CliOutputType type)
|
||||
|
@ -84,17 +86,16 @@ const std::vector<std::string>& NsoProcess::getApiList() const
|
|||
return mApiList;
|
||||
}
|
||||
|
||||
|
||||
void NsoProcess::importHeader()
|
||||
{
|
||||
fnd::MemoryBlob scratch;
|
||||
if (mReader->size() < sizeof(nx::sNsoHeader))
|
||||
if (mFile->size() < sizeof(nx::sNsoHeader))
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Corrupt NSO file too small");
|
||||
}
|
||||
|
||||
scratch.alloc(sizeof(nx::sNsoHeader));
|
||||
mReader->read(scratch.getBytes(), 0, scratch.getSize());
|
||||
mFile->read(scratch.getBytes(), 0, scratch.getSize());
|
||||
|
||||
mHdr.importBinary(scratch.getBytes(), scratch.getSize());
|
||||
}
|
||||
|
@ -109,7 +110,7 @@ void NsoProcess::importCodeSegments()
|
|||
if (mHdr.getTextSegmentInfo().is_compressed)
|
||||
{
|
||||
scratch.alloc(mHdr.getTextSegmentInfo().file_layout.size);
|
||||
mReader->read(scratch.getBytes(), mHdr.getTextSegmentInfo().file_layout.offset, scratch.getSize());
|
||||
mFile->read(scratch.getBytes(), mHdr.getTextSegmentInfo().file_layout.offset, scratch.getSize());
|
||||
mTextBlob.alloc(mHdr.getTextSegmentInfo().memory_layout.size);
|
||||
compress::lz4::decompressData(scratch.getBytes(), scratch.getSize(), mTextBlob.getBytes(), mTextBlob.getSize(), decompressed_len);
|
||||
if (decompressed_len != mTextBlob.getSize())
|
||||
|
@ -120,7 +121,7 @@ void NsoProcess::importCodeSegments()
|
|||
else
|
||||
{
|
||||
mTextBlob.alloc(mHdr.getTextSegmentInfo().file_layout.size);
|
||||
mReader->read(mTextBlob.getBytes(), mHdr.getTextSegmentInfo().file_layout.offset, mTextBlob.getSize());
|
||||
mFile->read(mTextBlob.getBytes(), mHdr.getTextSegmentInfo().file_layout.offset, mTextBlob.getSize());
|
||||
}
|
||||
if (mHdr.getTextSegmentInfo().is_hashed)
|
||||
{
|
||||
|
@ -135,7 +136,7 @@ void NsoProcess::importCodeSegments()
|
|||
if (mHdr.getRoSegmentInfo().is_compressed)
|
||||
{
|
||||
scratch.alloc(mHdr.getRoSegmentInfo().file_layout.size);
|
||||
mReader->read(scratch.getBytes(), mHdr.getRoSegmentInfo().file_layout.offset, scratch.getSize());
|
||||
mFile->read(scratch.getBytes(), mHdr.getRoSegmentInfo().file_layout.offset, scratch.getSize());
|
||||
mRoBlob.alloc(mHdr.getRoSegmentInfo().memory_layout.size);
|
||||
compress::lz4::decompressData(scratch.getBytes(), scratch.getSize(), mRoBlob.getBytes(), mRoBlob.getSize(), decompressed_len);
|
||||
if (decompressed_len != mRoBlob.getSize())
|
||||
|
@ -146,7 +147,7 @@ void NsoProcess::importCodeSegments()
|
|||
else
|
||||
{
|
||||
mRoBlob.alloc(mHdr.getRoSegmentInfo().file_layout.size);
|
||||
mReader->read(mRoBlob.getBytes(), mHdr.getRoSegmentInfo().file_layout.offset, mRoBlob.getSize());
|
||||
mFile->read(mRoBlob.getBytes(), mHdr.getRoSegmentInfo().file_layout.offset, mRoBlob.getSize());
|
||||
}
|
||||
if (mHdr.getRoSegmentInfo().is_hashed)
|
||||
{
|
||||
|
@ -161,7 +162,7 @@ void NsoProcess::importCodeSegments()
|
|||
if (mHdr.getDataSegmentInfo().is_compressed)
|
||||
{
|
||||
scratch.alloc(mHdr.getDataSegmentInfo().file_layout.size);
|
||||
mReader->read(scratch.getBytes(), mHdr.getDataSegmentInfo().file_layout.offset, scratch.getSize());
|
||||
mFile->read(scratch.getBytes(), mHdr.getDataSegmentInfo().file_layout.offset, scratch.getSize());
|
||||
mDataBlob.alloc(mHdr.getDataSegmentInfo().memory_layout.size);
|
||||
compress::lz4::decompressData(scratch.getBytes(), scratch.getSize(), mDataBlob.getBytes(), mDataBlob.getSize(), decompressed_len);
|
||||
if (decompressed_len != mDataBlob.getSize())
|
||||
|
@ -172,7 +173,7 @@ void NsoProcess::importCodeSegments()
|
|||
else
|
||||
{
|
||||
mDataBlob.alloc(mHdr.getDataSegmentInfo().file_layout.size);
|
||||
mReader->read(mDataBlob.getBytes(), mHdr.getDataSegmentInfo().file_layout.offset, mDataBlob.getSize());
|
||||
mFile->read(mDataBlob.getBytes(), mHdr.getDataSegmentInfo().file_layout.offset, mDataBlob.getSize());
|
||||
}
|
||||
if (mHdr.getDataSegmentInfo().is_hashed)
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@ public:
|
|||
|
||||
void process();
|
||||
|
||||
void setInputFile(fnd::IFile* file, size_t offset, size_t size);
|
||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
||||
void setCliOutputMode(CliOutputType type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
||||
|
@ -33,7 +33,9 @@ public:
|
|||
private:
|
||||
const std::string kModuleName = "NsoProcess";
|
||||
|
||||
fnd::IFile* mReader;
|
||||
fnd::IFile* mFile;
|
||||
bool mOwnIFile;
|
||||
|
||||
CliOutputType mCliOutputType;
|
||||
bool mVerify;
|
||||
sOptional<nx::npdm::InstructionType> mArchType;
|
||||
|
|
|
@ -1,15 +1,5 @@
|
|||
#include "OffsetAdjustedIFile.h"
|
||||
|
||||
OffsetAdjustedIFile::OffsetAdjustedIFile(fnd::IFile* file, size_t offset, size_t size) :
|
||||
mOwnIFile(false),
|
||||
mFile(file),
|
||||
mBaseOffset(offset),
|
||||
mCurrentOffset(0),
|
||||
mSize(size)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
OffsetAdjustedIFile::OffsetAdjustedIFile(fnd::IFile* file, bool ownIFile, size_t offset, size_t size) :
|
||||
mOwnIFile(ownIFile),
|
||||
mFile(file),
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
class OffsetAdjustedIFile : public fnd::IFile
|
||||
{
|
||||
public:
|
||||
OffsetAdjustedIFile(fnd::IFile* file, size_t offset, size_t size);
|
||||
OffsetAdjustedIFile(fnd::IFile* file, bool ownIFile, size_t offset, size_t size);
|
||||
~OffsetAdjustedIFile();
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include <fnd/SimpleFile.h>
|
||||
#include <fnd/io.h>
|
||||
#include "OffsetAdjustedIFile.h"
|
||||
#include "PfsProcess.h"
|
||||
|
||||
PfsProcess::PfsProcess() :
|
||||
mReader(nullptr),
|
||||
mFile(nullptr),
|
||||
mOwnIFile(false),
|
||||
mCliOutputType(OUTPUT_NORMAL),
|
||||
mVerify(false),
|
||||
mExtractPath(),
|
||||
|
@ -17,9 +17,9 @@ PfsProcess::PfsProcess() :
|
|||
|
||||
PfsProcess::~PfsProcess()
|
||||
{
|
||||
if (mReader != nullptr)
|
||||
if (mOwnIFile)
|
||||
{
|
||||
delete mReader;
|
||||
delete mFile;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,14 +27,14 @@ void PfsProcess::process()
|
|||
{
|
||||
fnd::MemoryBlob scratch;
|
||||
|
||||
if (mReader == nullptr)
|
||||
if (mFile == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
// open minimum header to get full header size
|
||||
scratch.alloc(sizeof(nx::sPfsHeader));
|
||||
mReader->read(scratch.getBytes(), 0, scratch.getSize());
|
||||
mFile->read(scratch.getBytes(), 0, scratch.getSize());
|
||||
if (validateHeaderMagic(((nx::sPfsHeader*)scratch.getBytes())) == false)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Corrupt Header");
|
||||
|
@ -43,7 +43,7 @@ void PfsProcess::process()
|
|||
|
||||
// open minimum header to get full header size
|
||||
scratch.alloc(pfsHeaderSize);
|
||||
mReader->read(scratch.getBytes(), 0, scratch.getSize());
|
||||
mFile->read(scratch.getBytes(), 0, scratch.getSize());
|
||||
mPfs.importBinary(scratch.getBytes(), scratch.getSize());
|
||||
|
||||
if (mCliOutputType >= OUTPUT_NORMAL)
|
||||
|
@ -56,9 +56,10 @@ void PfsProcess::process()
|
|||
extractFs();
|
||||
}
|
||||
|
||||
void PfsProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size)
|
||||
void PfsProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||
{
|
||||
mReader = new OffsetAdjustedIFile(file, offset, size);
|
||||
mFile = file;
|
||||
mOwnIFile = ownIFile;
|
||||
}
|
||||
|
||||
void PfsProcess::setCliOutputMode(CliOutputType type)
|
||||
|
@ -144,7 +145,7 @@ void PfsProcess::validateHfs()
|
|||
for (size_t i = 0; i < file.getSize(); i++)
|
||||
{
|
||||
mCache.alloc(file[i].hash_protected_size);
|
||||
mReader->read(mCache.getBytes(), file[i].offset, file[i].hash_protected_size);
|
||||
mFile->read(mCache.getBytes(), file[i].offset, file[i].hash_protected_size);
|
||||
crypto::sha::Sha256(mCache.getBytes(), mCache.getSize(), hash.bytes);
|
||||
if (hash != file[i].hash)
|
||||
{
|
||||
|
@ -177,10 +178,10 @@ void PfsProcess::extractFs()
|
|||
printf("extract=[%s]\n", file_path.c_str());
|
||||
|
||||
outFile.open(file_path, outFile.Create);
|
||||
mReader->seek(file[i].offset);
|
||||
mFile->seek(file[i].offset);
|
||||
for (size_t j = 0; j < ((file[i].size / kCacheSize) + ((file[i].size % kCacheSize) != 0)); j++)
|
||||
{
|
||||
mReader->read(mCache.getBytes(), MIN(file[i].size - (kCacheSize * j),kCacheSize));
|
||||
mFile->read(mCache.getBytes(), MIN(file[i].size - (kCacheSize * j),kCacheSize));
|
||||
outFile.write(mCache.getBytes(), MIN(file[i].size - (kCacheSize * j),kCacheSize));
|
||||
}
|
||||
outFile.close();
|
||||
|
|
|
@ -15,7 +15,7 @@ public:
|
|||
void process();
|
||||
|
||||
// generic
|
||||
void setInputFile(fnd::IFile* file, size_t offset, size_t size);
|
||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
||||
void setCliOutputMode(CliOutputType type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
||||
|
@ -30,7 +30,8 @@ private:
|
|||
const std::string kModuleName = "PfsProcess";
|
||||
static const size_t kCacheSize = 0x10000;
|
||||
|
||||
fnd::IFile* mReader;
|
||||
fnd::IFile* mFile;
|
||||
bool mOwnIFile;
|
||||
CliOutputType mCliOutputType;
|
||||
bool mVerify;
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#include <fnd/SimpleTextOutput.h>
|
||||
#include <fnd/SimpleFile.h>
|
||||
#include <fnd/io.h>
|
||||
#include "OffsetAdjustedIFile.h"
|
||||
#include "RomfsProcess.h"
|
||||
|
||||
RomfsProcess::RomfsProcess() :
|
||||
mReader(nullptr),
|
||||
mFile(nullptr),
|
||||
mOwnIFile(false),
|
||||
mCliOutputType(OUTPUT_NORMAL),
|
||||
mVerify(false),
|
||||
mExtractPath(),
|
||||
|
@ -22,15 +22,15 @@ RomfsProcess::RomfsProcess() :
|
|||
|
||||
RomfsProcess::~RomfsProcess()
|
||||
{
|
||||
if (mReader != nullptr)
|
||||
if (mOwnIFile)
|
||||
{
|
||||
delete mReader;
|
||||
delete mFile;
|
||||
}
|
||||
}
|
||||
|
||||
void RomfsProcess::process()
|
||||
{
|
||||
if (mReader == nullptr)
|
||||
if (mFile == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
@ -45,9 +45,10 @@ void RomfsProcess::process()
|
|||
extractFs();
|
||||
}
|
||||
|
||||
void RomfsProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size)
|
||||
void RomfsProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||
{
|
||||
mReader = new OffsetAdjustedIFile(file, offset, size);
|
||||
mFile = file;
|
||||
mOwnIFile = ownIFile;
|
||||
}
|
||||
|
||||
void RomfsProcess::setCliOutputMode(CliOutputType type)
|
||||
|
@ -158,10 +159,10 @@ void RomfsProcess::extractDir(const std::string& path, const sDirectory& dir)
|
|||
|
||||
|
||||
outFile.open(file_path, outFile.Create);
|
||||
mReader->seek(dir.file_list[i].offset);
|
||||
mFile->seek(dir.file_list[i].offset);
|
||||
for (size_t j = 0; j < ((dir.file_list[i].size / kCacheSize) + ((dir.file_list[i].size % kCacheSize) != 0)); j++)
|
||||
{
|
||||
mReader->read(mCache.getBytes(), MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize));
|
||||
mFile->read(mCache.getBytes(), MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize));
|
||||
outFile.write(mCache.getBytes(), MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize));
|
||||
}
|
||||
outFile.close();
|
||||
|
@ -254,7 +255,7 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir)
|
|||
void RomfsProcess::resolveRomfs()
|
||||
{
|
||||
// read header
|
||||
mReader->read((byte_t*)&mHdr, 0, sizeof(nx::sRomfsHeader));
|
||||
mFile->read((byte_t*)&mHdr, 0, sizeof(nx::sRomfsHeader));
|
||||
|
||||
// logic check on the header layout
|
||||
if (validateHeaderLayout(&mHdr) == false)
|
||||
|
@ -264,13 +265,13 @@ void RomfsProcess::resolveRomfs()
|
|||
|
||||
// read directory nodes
|
||||
mDirNodes.alloc(mHdr.sections[nx::romfs::DIR_NODE_TABLE].size.get());
|
||||
mReader->read(mDirNodes.getBytes(), mHdr.sections[nx::romfs::DIR_NODE_TABLE].offset.get(), mDirNodes.getSize());
|
||||
mFile->read(mDirNodes.getBytes(), mHdr.sections[nx::romfs::DIR_NODE_TABLE].offset.get(), mDirNodes.getSize());
|
||||
//printf("[RAW DIR NODES]\n");
|
||||
//fnd::SimpleTextOutput::hxdStyleDump(mDirNodes.getBytes(), mDirNodes.getSize());
|
||||
|
||||
// read file nodes
|
||||
mFileNodes.alloc(mHdr.sections[nx::romfs::FILE_NODE_TABLE].size.get());
|
||||
mReader->read(mFileNodes.getBytes(), mHdr.sections[nx::romfs::FILE_NODE_TABLE].offset.get(), mFileNodes.getSize());
|
||||
mFile->read(mFileNodes.getBytes(), mHdr.sections[nx::romfs::FILE_NODE_TABLE].offset.get(), mFileNodes.getSize());
|
||||
//printf("[RAW FILE NODES]\n");
|
||||
//fnd::SimpleTextOutput::hxdStyleDump(mFileNodes.getBytes(), mFileNodes.getSize());
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ public:
|
|||
void process();
|
||||
|
||||
// generic
|
||||
void setInputFile(fnd::IFile* file, size_t offset, size_t size);
|
||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
||||
void setCliOutputMode(CliOutputType type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
||||
|
@ -108,7 +108,8 @@ private:
|
|||
const std::string kModuleName = "RomfsProcess";
|
||||
static const size_t kCacheSize = 0x10000;
|
||||
|
||||
fnd::IFile* mReader;
|
||||
fnd::IFile* mFile;
|
||||
bool mOwnIFile;
|
||||
CliOutputType mCliOutputType;
|
||||
bool mVerify;
|
||||
|
||||
|
|
|
@ -3,6 +3,95 @@
|
|||
#include "OffsetAdjustedIFile.h"
|
||||
#include "XciProcess.h"
|
||||
|
||||
XciProcess::XciProcess() :
|
||||
mFile(nullptr),
|
||||
mOwnIFile(false),
|
||||
mKeyset(nullptr),
|
||||
mCliOutputType(OUTPUT_NORMAL),
|
||||
mVerify(false),
|
||||
mListFs(false),
|
||||
mRootPfs(),
|
||||
mExtractInfo()
|
||||
{
|
||||
}
|
||||
|
||||
XciProcess::~XciProcess()
|
||||
{
|
||||
if (mOwnIFile)
|
||||
{
|
||||
delete mFile;
|
||||
}
|
||||
}
|
||||
|
||||
void XciProcess::process()
|
||||
{
|
||||
fnd::MemoryBlob scratch;
|
||||
|
||||
if (mFile == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
// read header page
|
||||
mFile->read((byte_t*)&mHdrPage, 0, sizeof(nx::sXciHeaderPage));
|
||||
|
||||
// allocate memory for and decrypt sXciHeader
|
||||
scratch.alloc(sizeof(nx::sXciHeader));
|
||||
nx::XciUtils::decryptXciHeader((const byte_t*)&mHdrPage.header, scratch.getBytes(), mKeyset->xci.header_key.key);
|
||||
|
||||
// validate header signature
|
||||
if (mVerify)
|
||||
{
|
||||
validateXciSignature();
|
||||
}
|
||||
|
||||
// deserialise header
|
||||
mHdr.importBinary(scratch.getBytes(), scratch.getSize());
|
||||
|
||||
// display header
|
||||
if (mCliOutputType >= OUTPUT_NORMAL)
|
||||
{
|
||||
displayHeader();
|
||||
}
|
||||
|
||||
// process root partition
|
||||
processRootPfs();
|
||||
|
||||
// process partitions
|
||||
processPartitionPfs();
|
||||
}
|
||||
|
||||
void XciProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||
{
|
||||
mFile = file;
|
||||
mOwnIFile = ownIFile;
|
||||
}
|
||||
|
||||
void XciProcess::setKeyset(const sKeyset* keyset)
|
||||
{
|
||||
mKeyset = keyset;
|
||||
}
|
||||
|
||||
void XciProcess::setCliOutputMode(CliOutputType type)
|
||||
{
|
||||
mCliOutputType = type;
|
||||
}
|
||||
|
||||
void XciProcess::setVerifyMode(bool verify)
|
||||
{
|
||||
mVerify = verify;
|
||||
}
|
||||
|
||||
void XciProcess::setPartitionForExtract(const std::string& partition_name, const std::string& extract_path)
|
||||
{
|
||||
mExtractInfo.push_back({partition_name, extract_path});
|
||||
}
|
||||
|
||||
void XciProcess::setListFs(bool list_fs)
|
||||
{
|
||||
mListFs = list_fs;
|
||||
}
|
||||
|
||||
inline const char* getBoolStr(bool isTrue)
|
||||
{
|
||||
return isTrue? "TRUE" : "FALSE";
|
||||
|
@ -51,17 +140,16 @@ inline const char* getCardClockRate(uint32_t acc_ctrl_1)
|
|||
return str;
|
||||
}
|
||||
|
||||
|
||||
void XciProcess::displayHeader()
|
||||
{
|
||||
printf("[XCI HEADER]\n");
|
||||
printf(" Magic: HEAD\n");
|
||||
printf(" RomAreaStartPage: 0x%0x", mHdr.getRomAreaStartPage());
|
||||
if (mHdr.getRomAreaStartPage() != -1)
|
||||
if (mHdr.getRomAreaStartPage() != (uint32_t)(-1))
|
||||
printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getRomAreaStartPage()));
|
||||
printf("\n");
|
||||
printf(" BackupAreaStartPage: 0x%0x", mHdr.getBackupAreaStartPage());
|
||||
if (mHdr.getBackupAreaStartPage() != -1)
|
||||
if (mHdr.getBackupAreaStartPage() != (uint32_t)(-1))
|
||||
printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage()));
|
||||
printf("\n");
|
||||
printf(" KekIndex: %d\n", mHdr.getKekIndex());
|
||||
|
@ -74,7 +162,7 @@ void XciProcess::displayHeader()
|
|||
printf(" RepairTool: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_REPAIR_TOOL)));
|
||||
printf(" PackageId: 0x%" PRIx64 "\n", mHdr.getPackageId());
|
||||
printf(" ValidDataEndPage: 0x%x", mHdr.getValidDataEndPage());
|
||||
if (mHdr.getValidDataEndPage() != -1)
|
||||
if (mHdr.getValidDataEndPage() != (uint32_t)(-1))
|
||||
printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getValidDataEndPage()));
|
||||
printf("\n");
|
||||
printf(" AesIv: ");
|
||||
|
@ -118,7 +206,7 @@ bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* t
|
|||
fnd::MemoryBlob scratch;
|
||||
crypto::sha::sSha256Hash calc_hash;
|
||||
scratch.alloc(len);
|
||||
mReader->read(scratch.getBytes(), offset, len);
|
||||
mFile->read(scratch.getBytes(), offset, len);
|
||||
crypto::sha::Sha256(scratch.getBytes(), scratch.getSize(), calc_hash.bytes);
|
||||
return calc_hash.compare(test_hash);
|
||||
}
|
||||
|
@ -144,7 +232,7 @@ void XciProcess::processRootPfs()
|
|||
printf("[WARNING] XCI Root HFS0: FAIL (bad hash)\n");
|
||||
}
|
||||
}
|
||||
mRootPfs.setInputFile(mReader, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize());
|
||||
mRootPfs.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()), OWN_IFILE);
|
||||
mRootPfs.setListFs(mListFs);
|
||||
mRootPfs.setVerifyMode(mVerify);
|
||||
mRootPfs.setCliOutputMode(mCliOutputType);
|
||||
|
@ -158,7 +246,7 @@ void XciProcess::processPartitionPfs()
|
|||
for (size_t i = 0; i < rootPartitions.getSize(); i++)
|
||||
{
|
||||
PfsProcess tmp;
|
||||
tmp.setInputFile(mReader, mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].size);
|
||||
tmp.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].size), OWN_IFILE);
|
||||
tmp.setListFs(mListFs);
|
||||
tmp.setVerifyMode(mVerify);
|
||||
tmp.setCliOutputMode(mCliOutputType);
|
||||
|
@ -173,90 +261,3 @@ void XciProcess::processPartitionPfs()
|
|||
tmp.process();
|
||||
}
|
||||
}
|
||||
|
||||
XciProcess::XciProcess() :
|
||||
mReader(nullptr),
|
||||
mKeyset(nullptr),
|
||||
mCliOutputType(OUTPUT_NORMAL),
|
||||
mVerify(false),
|
||||
mListFs(false),
|
||||
mRootPfs(),
|
||||
mExtractInfo()
|
||||
{
|
||||
}
|
||||
|
||||
XciProcess::~XciProcess()
|
||||
{
|
||||
if (mReader != nullptr)
|
||||
{
|
||||
delete mReader;
|
||||
}
|
||||
}
|
||||
|
||||
void XciProcess::process()
|
||||
{
|
||||
fnd::MemoryBlob scratch;
|
||||
|
||||
if (mReader == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
// read header page
|
||||
mReader->read((byte_t*)&mHdrPage, 0, sizeof(nx::sXciHeaderPage));
|
||||
|
||||
// allocate memory for and decrypt sXciHeader
|
||||
scratch.alloc(sizeof(nx::sXciHeader));
|
||||
nx::XciUtils::decryptXciHeader((const byte_t*)&mHdrPage.header, scratch.getBytes(), mKeyset->xci.header_key.key);
|
||||
|
||||
// validate header signature
|
||||
if (mVerify)
|
||||
{
|
||||
validateXciSignature();
|
||||
}
|
||||
|
||||
// deserialise header
|
||||
mHdr.importBinary(scratch.getBytes(), scratch.getSize());
|
||||
|
||||
// display header
|
||||
if (mCliOutputType >= OUTPUT_NORMAL)
|
||||
{
|
||||
displayHeader();
|
||||
}
|
||||
|
||||
// process root partition
|
||||
processRootPfs();
|
||||
|
||||
// process partitions
|
||||
processPartitionPfs();
|
||||
}
|
||||
|
||||
void XciProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size)
|
||||
{
|
||||
mReader = new OffsetAdjustedIFile(file, offset, size);
|
||||
}
|
||||
|
||||
void XciProcess::setKeyset(const sKeyset* keyset)
|
||||
{
|
||||
mKeyset = keyset;
|
||||
}
|
||||
|
||||
void XciProcess::setCliOutputMode(CliOutputType type)
|
||||
{
|
||||
mCliOutputType = type;
|
||||
}
|
||||
|
||||
void XciProcess::setVerifyMode(bool verify)
|
||||
{
|
||||
mVerify = verify;
|
||||
}
|
||||
|
||||
void XciProcess::setPartitionForExtract(const std::string& partition_name, const std::string& extract_path)
|
||||
{
|
||||
mExtractInfo.push_back({partition_name, extract_path});
|
||||
}
|
||||
|
||||
void XciProcess::setListFs(bool list_fs)
|
||||
{
|
||||
mListFs = list_fs;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public:
|
|||
void process();
|
||||
|
||||
// generic
|
||||
void setInputFile(fnd::IFile* file, size_t offset, size_t size);
|
||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
||||
void setKeyset(const sKeyset* keyset);
|
||||
void setCliOutputMode(CliOutputType type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
@ -32,7 +32,8 @@ private:
|
|||
const std::string kXciMountPointName = "gamecard:/";
|
||||
static const size_t kFileExportBlockSize = 0x1000000;
|
||||
|
||||
fnd::IFile* mReader;
|
||||
fnd::IFile* mFile;
|
||||
bool mOwnIFile;
|
||||
const sKeyset* mKeyset;
|
||||
CliOutputType mCliOutputType;
|
||||
bool mVerify;
|
||||
|
|
|
@ -15,14 +15,11 @@ int main(int argc, char** argv)
|
|||
try {
|
||||
user_set.parseCmdArgs(argc, argv);
|
||||
|
||||
fnd::SimpleFile inputFile;
|
||||
inputFile.open(user_set.getInputPath(), inputFile.Read);
|
||||
|
||||
if (user_set.getFileType() == FILE_XCI)
|
||||
{
|
||||
XciProcess xci;
|
||||
|
||||
xci.setInputFile(&inputFile, 0, inputFile.size());
|
||||
xci.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
|
||||
xci.setKeyset(&user_set.getKeyset());
|
||||
xci.setCliOutputMode(user_set.getCliOutputType());
|
||||
|
@ -44,7 +41,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
PfsProcess pfs;
|
||||
|
||||
pfs.setInputFile(&inputFile, 0, inputFile.size());
|
||||
pfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
pfs.setCliOutputMode(user_set.getCliOutputType());
|
||||
pfs.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -58,7 +55,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
RomfsProcess romfs;
|
||||
|
||||
romfs.setInputFile(&inputFile, 0, inputFile.size());
|
||||
romfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
romfs.setCliOutputMode(user_set.getCliOutputType());
|
||||
romfs.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -72,7 +69,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
NcaProcess nca;
|
||||
|
||||
nca.setInputFile(&inputFile, 0, inputFile.size());
|
||||
nca.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
nca.setKeyset(&user_set.getKeyset());
|
||||
nca.setCliOutputMode(user_set.getCliOutputType());
|
||||
nca.setVerifyMode(user_set.isVerifyFile());
|
||||
|
@ -94,7 +91,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
NpdmProcess npdm;
|
||||
|
||||
npdm.setInputFile(&inputFile, 0, inputFile.size());
|
||||
npdm.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
npdm.setKeyset(&user_set.getKeyset());
|
||||
npdm.setCliOutputMode(user_set.getCliOutputType());
|
||||
npdm.setVerifyMode(user_set.isVerifyFile());
|
||||
|
@ -105,7 +102,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
CnmtProcess cnmt;
|
||||
|
||||
cnmt.setInputFile(&inputFile, 0, inputFile.size());
|
||||
cnmt.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
cnmt.setCliOutputMode(user_set.getCliOutputType());
|
||||
cnmt.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -115,7 +112,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
NsoProcess nso;
|
||||
|
||||
nso.setInputFile(&inputFile, 0, inputFile.size());
|
||||
nso.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
nso.setCliOutputMode(user_set.getCliOutputType());
|
||||
nso.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
static const size_t kMasterKeyNum = 0x20;
|
||||
static const size_t kNcaKeakNum = nx::nca::kKeyAreaEncryptionKeyNum;
|
||||
|
||||
enum IFileOwnershipMode
|
||||
{
|
||||
SHARED_IFILE = false,
|
||||
OWN_IFILE = true
|
||||
};
|
||||
|
||||
enum FileType
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue