[nstool] Refactored creation and sharing of fnd::IFile ptrs.

This commit is contained in:
jakcron 2018-06-03 16:48:12 +08:00
parent 97cdaf36ac
commit 08f7f36e68
23 changed files with 282 additions and 310 deletions

View file

@ -1,10 +1,5 @@
#include "AesCtrWrappedIFile.h" #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) : AesCtrWrappedIFile::AesCtrWrappedIFile(fnd::IFile* file, bool ownIfile, const crypto::aes::sAes128Key& key, const crypto::aes::sAesIvCtr& ctr) :
mOwnIFile(ownIfile), mOwnIFile(ownIfile),
mFile(file), mFile(file),

View file

@ -5,7 +5,6 @@
class AesCtrWrappedIFile : public fnd::IFile class AesCtrWrappedIFile : public fnd::IFile
{ {
public: 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(fnd::IFile* file, bool ownIfile, const crypto::aes::sAes128Key& key, const crypto::aes::sAesIvCtr& ctr);
~AesCtrWrappedIFile(); ~AesCtrWrappedIFile();

View file

@ -143,7 +143,8 @@ void CnmtProcess::displayCmnt()
} }
CnmtProcess::CnmtProcess() : CnmtProcess::CnmtProcess() :
mReader(nullptr), mFile(nullptr),
mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL), mCliOutputType(OUTPUT_NORMAL),
mVerify(false) mVerify(false)
{ {
@ -151,9 +152,9 @@ CnmtProcess::CnmtProcess() :
CnmtProcess::~CnmtProcess() CnmtProcess::~CnmtProcess()
{ {
if (mReader != nullptr) if (mOwnIFile)
{ {
delete mReader; delete mFile;
} }
} }
@ -161,13 +162,13 @@ void CnmtProcess::process()
{ {
fnd::MemoryBlob scratch; fnd::MemoryBlob scratch;
if (mReader == nullptr) if (mFile == nullptr)
{ {
throw fnd::Exception(kModuleName, "No file reader set."); throw fnd::Exception(kModuleName, "No file reader set.");
} }
scratch.alloc(mReader->size()); scratch.alloc(mFile->size());
mReader->read(scratch.getBytes(), 0, scratch.getSize()); mFile->read(scratch.getBytes(), 0, scratch.getSize());
mCnmt.importBinary(scratch.getBytes(), 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) void CnmtProcess::setCliOutputMode(CliOutputType type)

View file

@ -14,7 +14,7 @@ public:
void process(); 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 setCliOutputMode(CliOutputType type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -23,7 +23,8 @@ public:
private: private:
const std::string kModuleName = "CnmtProcess"; const std::string kModuleName = "CnmtProcess";
fnd::IFile* mReader; fnd::IFile* mFile;
bool mOwnIFile;
CliOutputType mCliOutputType; CliOutputType mCliOutputType;
bool mVerify; bool mVerify;

View file

@ -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;
};

View file

@ -1,18 +1,7 @@
#include "nstool.h"
#include "HashTreeWrappedIFile.h" #include "HashTreeWrappedIFile.h"
#include "CopiedIFile.h"
#include "OffsetAdjustedIFile.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) : HashTreeWrappedIFile::HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, const HashTreeMeta& hdr) :
mOwnIFile(ownIFile), mOwnIFile(ownIFile),
mFile(file), mFile(file),
@ -156,7 +145,7 @@ void HashTreeWrappedIFile::initialiseDataLayer(const HashTreeMeta& hdr)
} }
// generate reader for data layer // 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; mDataOffset = 0;
mDataBlockSize = hdr.getDataLayer().block_size; mDataBlockSize = hdr.getDataLayer().block_size;

View file

@ -9,7 +9,6 @@
class HashTreeWrappedIFile : public fnd::IFile class HashTreeWrappedIFile : public fnd::IFile
{ {
public: public:
HashTreeWrappedIFile(fnd::IFile* file, const HashTreeMeta& hdr);
HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, const HashTreeMeta& hdr); HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, const HashTreeMeta& hdr);
~HashTreeWrappedIFile(); ~HashTreeWrappedIFile();

View file

@ -9,7 +9,6 @@
#include "NpdmProcess.h" #include "NpdmProcess.h"
#include "OffsetAdjustedIFile.h" #include "OffsetAdjustedIFile.h"
#include "AesCtrWrappedIFile.h" #include "AesCtrWrappedIFile.h"
#include "CopiedIFile.h"
#include "HashTreeWrappedIFile.h" #include "HashTreeWrappedIFile.h"
const char* getFormatVersionStr(nx::NcaHeader::FormatVersion format_ver) const char* getFormatVersionStr(nx::NcaHeader::FormatVersion format_ver)
@ -222,7 +221,8 @@ const char* getProgramPartitionNameStr(size_t i)
NcaProcess::NcaProcess() : NcaProcess::NcaProcess() :
mReader(nullptr), mFile(nullptr),
mOwnIFile(false),
mKeyset(nullptr), mKeyset(nullptr),
mCliOutputType(OUTPUT_NORMAL), mCliOutputType(OUTPUT_NORMAL),
mVerify(false), mVerify(false),
@ -237,9 +237,9 @@ NcaProcess::NcaProcess() :
NcaProcess::~NcaProcess() NcaProcess::~NcaProcess()
{ {
if (mReader != nullptr) if (mOwnIFile)
{ {
delete mReader; delete mFile;
} }
for (size_t i = 0; i < nx::nca::kPartitionNum; i++) for (size_t i = 0; i < nx::nca::kPartitionNum; i++)
@ -255,13 +255,13 @@ void NcaProcess::process()
{ {
fnd::MemoryBlob scratch; fnd::MemoryBlob scratch;
if (mReader == nullptr) if (mFile == nullptr)
{ {
throw fnd::Exception(kModuleName, "No file reader set."); throw fnd::Exception(kModuleName, "No file reader set.");
} }
// read header block // read header block
mReader->read((byte_t*)&mHdrBlock, 0, sizeof(nx::sNcaHeaderBlock)); mFile->read((byte_t*)&mHdrBlock, 0, sizeof(nx::sNcaHeaderBlock));
// decrypt header block // decrypt header block
nx::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyset->nca.header_key); 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) void NcaProcess::setKeyset(const sKeyset* keyset)
@ -539,13 +540,13 @@ void NcaProcess::generatePartitionConfiguration()
// create reader based on encryption type0 // create reader based on encryption type0
if (info.enc_type == nx::nca::CRYPT_NONE) 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) else if (info.enc_type == nx::nca::CRYPT_AESCTR)
{ {
if (mBodyKeys.aes_ctr.isSet == false) if (mBodyKeys.aes_ctr.isSet == false)
throw fnd::Exception(kModuleName, "AES-CTR Key was not determined"); 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) 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; fnd::IFile* tmp = info.reader;
info.reader = nullptr; 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) else if (info.hash_type != nx::nca::HASH_NONE)
{ {
@ -602,7 +603,7 @@ void NcaProcess::validateNcaSignatures()
if (mPartitions[nx::nca::PARTITION_CODE].reader != nullptr) if (mPartitions[nx::nca::PARTITION_CODE].reader != nullptr)
{ {
PfsProcess exefs; 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.setCliOutputMode(OUTPUT_MINIMAL);
exefs.process(); exefs.process();
@ -612,7 +613,7 @@ void NcaProcess::validateNcaSignatures()
const nx::PfsHeader::sFile& file = exefs.getPfsHeader().getFileList()[exefs.getPfsHeader().getFileList().getIndexOf(kNpdmExefsPath)]; const nx::PfsHeader::sFile& file = exefs.getPfsHeader().getFileList()[exefs.getPfsHeader().getFileList().getIndexOf(kNpdmExefsPath)];
NpdmProcess npdm; 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.setCliOutputMode(OUTPUT_MINIMAL);
npdm.process(); npdm.process();
@ -789,7 +790,7 @@ void NcaProcess::processPartitions()
if (partition.format_type == nx::nca::FORMAT_PFS0) if (partition.format_type == nx::nca::FORMAT_PFS0)
{ {
PfsProcess pfs; PfsProcess pfs;
pfs.setInputFile(partition.reader, 0, partition.reader->size()); pfs.setInputFile(partition.reader, SHARED_IFILE);
pfs.setCliOutputMode(mCliOutputType); pfs.setCliOutputMode(mCliOutputType);
pfs.setListFs(mListFs); pfs.setListFs(mListFs);
if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM) if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM)
@ -810,7 +811,7 @@ void NcaProcess::processPartitions()
else if (partition.format_type == nx::nca::FORMAT_ROMFS) else if (partition.format_type == nx::nca::FORMAT_ROMFS)
{ {
RomfsProcess romfs; RomfsProcess romfs;
romfs.setInputFile(partition.reader, 0, partition.reader->size()); romfs.setInputFile(partition.reader, SHARED_IFILE);
romfs.setCliOutputMode(mCliOutputType); romfs.setCliOutputMode(mCliOutputType);
romfs.setListFs(mListFs); romfs.setListFs(mListFs);
if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM) if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM)

View file

@ -17,7 +17,7 @@ public:
void process(); void process();
// generic // 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 setKeyset(const sKeyset* keyset);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputType type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -34,7 +34,8 @@ private:
const std::string kNpdmExefsPath = "main.npdm"; const std::string kNpdmExefsPath = "main.npdm";
// user options // user options
fnd::IFile* mReader; fnd::IFile* mFile;
bool mOwnIFile;
const sKeyset* mKeyset; const sKeyset* mKeyset;
CliOutputType mCliOutputType; CliOutputType mCliOutputType;
bool mVerify; bool mVerify;

View file

@ -1,6 +1,87 @@
#include "OffsetAdjustedIFile.h"
#include "NpdmProcess.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 kInstructionType[2] = { "32Bit", "64Bit" };
const std::string kProcAddrSpace[4] = { "Unknown", "64Bit", "32Bit", "32Bit no reserved" }; const std::string kProcAddrSpace[4] = { "Unknown", "64Bit", "32Bit", "32Bit no reserved" };
const std::string kAciType[2] = { "ACI0", "ACID" }; 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;
}

View file

@ -14,7 +14,7 @@ public:
void process(); 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 setKeyset(const sKeyset* keyset);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputType type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -24,7 +24,8 @@ public:
private: private:
const std::string kModuleName = "NpdmProcess"; const std::string kModuleName = "NpdmProcess";
fnd::IFile* mReader; fnd::IFile* mFile;
bool mOwnIFile;
const sKeyset* mKeyset; const sKeyset* mKeyset;
CliOutputType mCliOutputType; CliOutputType mCliOutputType;
bool mVerify; bool mVerify;

View file

@ -6,7 +6,8 @@
#include "NsoProcess.h" #include "NsoProcess.h"
NsoProcess::NsoProcess(): NsoProcess::NsoProcess():
mReader(nullptr), mFile(nullptr),
mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL), mCliOutputType(OUTPUT_NORMAL),
mVerify(false) mVerify(false)
{ {
@ -15,15 +16,15 @@ NsoProcess::NsoProcess():
NsoProcess::~NsoProcess() NsoProcess::~NsoProcess()
{ {
if (mReader != nullptr) if (mOwnIFile)
{ {
delete mReader; delete mFile;
} }
} }
void NsoProcess::process() void NsoProcess::process()
{ {
if (mReader == nullptr) if (mFile == nullptr)
{ {
throw fnd::Exception(kModuleName, "No file reader set."); 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) void NsoProcess::setCliOutputMode(CliOutputType type)
@ -84,17 +86,16 @@ const std::vector<std::string>& NsoProcess::getApiList() const
return mApiList; return mApiList;
} }
void NsoProcess::importHeader() void NsoProcess::importHeader()
{ {
fnd::MemoryBlob scratch; fnd::MemoryBlob scratch;
if (mReader->size() < sizeof(nx::sNsoHeader)) if (mFile->size() < sizeof(nx::sNsoHeader))
{ {
throw fnd::Exception(kModuleName, "Corrupt NSO file too small"); throw fnd::Exception(kModuleName, "Corrupt NSO file too small");
} }
scratch.alloc(sizeof(nx::sNsoHeader)); 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()); mHdr.importBinary(scratch.getBytes(), scratch.getSize());
} }
@ -109,7 +110,7 @@ void NsoProcess::importCodeSegments()
if (mHdr.getTextSegmentInfo().is_compressed) if (mHdr.getTextSegmentInfo().is_compressed)
{ {
scratch.alloc(mHdr.getTextSegmentInfo().file_layout.size); 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); mTextBlob.alloc(mHdr.getTextSegmentInfo().memory_layout.size);
compress::lz4::decompressData(scratch.getBytes(), scratch.getSize(), mTextBlob.getBytes(), mTextBlob.getSize(), decompressed_len); compress::lz4::decompressData(scratch.getBytes(), scratch.getSize(), mTextBlob.getBytes(), mTextBlob.getSize(), decompressed_len);
if (decompressed_len != mTextBlob.getSize()) if (decompressed_len != mTextBlob.getSize())
@ -120,7 +121,7 @@ void NsoProcess::importCodeSegments()
else else
{ {
mTextBlob.alloc(mHdr.getTextSegmentInfo().file_layout.size); 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) if (mHdr.getTextSegmentInfo().is_hashed)
{ {
@ -135,7 +136,7 @@ void NsoProcess::importCodeSegments()
if (mHdr.getRoSegmentInfo().is_compressed) if (mHdr.getRoSegmentInfo().is_compressed)
{ {
scratch.alloc(mHdr.getRoSegmentInfo().file_layout.size); 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); mRoBlob.alloc(mHdr.getRoSegmentInfo().memory_layout.size);
compress::lz4::decompressData(scratch.getBytes(), scratch.getSize(), mRoBlob.getBytes(), mRoBlob.getSize(), decompressed_len); compress::lz4::decompressData(scratch.getBytes(), scratch.getSize(), mRoBlob.getBytes(), mRoBlob.getSize(), decompressed_len);
if (decompressed_len != mRoBlob.getSize()) if (decompressed_len != mRoBlob.getSize())
@ -146,7 +147,7 @@ void NsoProcess::importCodeSegments()
else else
{ {
mRoBlob.alloc(mHdr.getRoSegmentInfo().file_layout.size); 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) if (mHdr.getRoSegmentInfo().is_hashed)
{ {
@ -161,7 +162,7 @@ void NsoProcess::importCodeSegments()
if (mHdr.getDataSegmentInfo().is_compressed) if (mHdr.getDataSegmentInfo().is_compressed)
{ {
scratch.alloc(mHdr.getDataSegmentInfo().file_layout.size); 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); mDataBlob.alloc(mHdr.getDataSegmentInfo().memory_layout.size);
compress::lz4::decompressData(scratch.getBytes(), scratch.getSize(), mDataBlob.getBytes(), mDataBlob.getSize(), decompressed_len); compress::lz4::decompressData(scratch.getBytes(), scratch.getSize(), mDataBlob.getBytes(), mDataBlob.getSize(), decompressed_len);
if (decompressed_len != mDataBlob.getSize()) if (decompressed_len != mDataBlob.getSize())
@ -172,7 +173,7 @@ void NsoProcess::importCodeSegments()
else else
{ {
mDataBlob.alloc(mHdr.getDataSegmentInfo().file_layout.size); 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) if (mHdr.getDataSegmentInfo().is_hashed)
{ {

View file

@ -17,7 +17,7 @@ public:
void process(); 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 setCliOutputMode(CliOutputType type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -33,7 +33,9 @@ public:
private: private:
const std::string kModuleName = "NsoProcess"; const std::string kModuleName = "NsoProcess";
fnd::IFile* mReader; fnd::IFile* mFile;
bool mOwnIFile;
CliOutputType mCliOutputType; CliOutputType mCliOutputType;
bool mVerify; bool mVerify;
sOptional<nx::npdm::InstructionType> mArchType; sOptional<nx::npdm::InstructionType> mArchType;

View file

@ -1,15 +1,5 @@
#include "OffsetAdjustedIFile.h" #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) : OffsetAdjustedIFile::OffsetAdjustedIFile(fnd::IFile* file, bool ownIFile, size_t offset, size_t size) :
mOwnIFile(ownIFile), mOwnIFile(ownIFile),
mFile(file), mFile(file),

View file

@ -3,7 +3,6 @@
class OffsetAdjustedIFile : public fnd::IFile class OffsetAdjustedIFile : public fnd::IFile
{ {
public: public:
OffsetAdjustedIFile(fnd::IFile* file, size_t offset, size_t size);
OffsetAdjustedIFile(fnd::IFile* file, bool ownIFile, size_t offset, size_t size); OffsetAdjustedIFile(fnd::IFile* file, bool ownIFile, size_t offset, size_t size);
~OffsetAdjustedIFile(); ~OffsetAdjustedIFile();

View file

@ -1,10 +1,10 @@
#include <fnd/SimpleFile.h> #include <fnd/SimpleFile.h>
#include <fnd/io.h> #include <fnd/io.h>
#include "OffsetAdjustedIFile.h"
#include "PfsProcess.h" #include "PfsProcess.h"
PfsProcess::PfsProcess() : PfsProcess::PfsProcess() :
mReader(nullptr), mFile(nullptr),
mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL), mCliOutputType(OUTPUT_NORMAL),
mVerify(false), mVerify(false),
mExtractPath(), mExtractPath(),
@ -17,9 +17,9 @@ PfsProcess::PfsProcess() :
PfsProcess::~PfsProcess() PfsProcess::~PfsProcess()
{ {
if (mReader != nullptr) if (mOwnIFile)
{ {
delete mReader; delete mFile;
} }
} }
@ -27,14 +27,14 @@ void PfsProcess::process()
{ {
fnd::MemoryBlob scratch; fnd::MemoryBlob scratch;
if (mReader == nullptr) if (mFile == nullptr)
{ {
throw fnd::Exception(kModuleName, "No file reader set."); throw fnd::Exception(kModuleName, "No file reader set.");
} }
// open minimum header to get full header size // open minimum header to get full header size
scratch.alloc(sizeof(nx::sPfsHeader)); 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) if (validateHeaderMagic(((nx::sPfsHeader*)scratch.getBytes())) == false)
{ {
throw fnd::Exception(kModuleName, "Corrupt Header"); throw fnd::Exception(kModuleName, "Corrupt Header");
@ -43,7 +43,7 @@ void PfsProcess::process()
// open minimum header to get full header size // open minimum header to get full header size
scratch.alloc(pfsHeaderSize); scratch.alloc(pfsHeaderSize);
mReader->read(scratch.getBytes(), 0, scratch.getSize()); mFile->read(scratch.getBytes(), 0, scratch.getSize());
mPfs.importBinary(scratch.getBytes(), scratch.getSize()); mPfs.importBinary(scratch.getBytes(), scratch.getSize());
if (mCliOutputType >= OUTPUT_NORMAL) if (mCliOutputType >= OUTPUT_NORMAL)
@ -56,9 +56,10 @@ void PfsProcess::process()
extractFs(); 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) void PfsProcess::setCliOutputMode(CliOutputType type)
@ -144,7 +145,7 @@ void PfsProcess::validateHfs()
for (size_t i = 0; i < file.getSize(); i++) for (size_t i = 0; i < file.getSize(); i++)
{ {
mCache.alloc(file[i].hash_protected_size); 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); crypto::sha::Sha256(mCache.getBytes(), mCache.getSize(), hash.bytes);
if (hash != file[i].hash) if (hash != file[i].hash)
{ {
@ -177,10 +178,10 @@ void PfsProcess::extractFs()
printf("extract=[%s]\n", file_path.c_str()); printf("extract=[%s]\n", file_path.c_str());
outFile.open(file_path, outFile.Create); 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++) 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.write(mCache.getBytes(), MIN(file[i].size - (kCacheSize * j),kCacheSize));
} }
outFile.close(); outFile.close();

View file

@ -15,7 +15,7 @@ public:
void process(); void process();
// generic // generic
void setInputFile(fnd::IFile* file, size_t offset, size_t size); void setInputFile(fnd::IFile* file, bool ownIFile);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputType type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -30,7 +30,8 @@ private:
const std::string kModuleName = "PfsProcess"; const std::string kModuleName = "PfsProcess";
static const size_t kCacheSize = 0x10000; static const size_t kCacheSize = 0x10000;
fnd::IFile* mReader; fnd::IFile* mFile;
bool mOwnIFile;
CliOutputType mCliOutputType; CliOutputType mCliOutputType;
bool mVerify; bool mVerify;

View file

@ -1,11 +1,11 @@
#include <fnd/SimpleTextOutput.h> #include <fnd/SimpleTextOutput.h>
#include <fnd/SimpleFile.h> #include <fnd/SimpleFile.h>
#include <fnd/io.h> #include <fnd/io.h>
#include "OffsetAdjustedIFile.h"
#include "RomfsProcess.h" #include "RomfsProcess.h"
RomfsProcess::RomfsProcess() : RomfsProcess::RomfsProcess() :
mReader(nullptr), mFile(nullptr),
mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL), mCliOutputType(OUTPUT_NORMAL),
mVerify(false), mVerify(false),
mExtractPath(), mExtractPath(),
@ -22,15 +22,15 @@ RomfsProcess::RomfsProcess() :
RomfsProcess::~RomfsProcess() RomfsProcess::~RomfsProcess()
{ {
if (mReader != nullptr) if (mOwnIFile)
{ {
delete mReader; delete mFile;
} }
} }
void RomfsProcess::process() void RomfsProcess::process()
{ {
if (mReader == nullptr) if (mFile == nullptr)
{ {
throw fnd::Exception(kModuleName, "No file reader set."); throw fnd::Exception(kModuleName, "No file reader set.");
} }
@ -45,9 +45,10 @@ void RomfsProcess::process()
extractFs(); 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) 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); 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++) 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.write(mCache.getBytes(), MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize));
} }
outFile.close(); outFile.close();
@ -254,7 +255,7 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir)
void RomfsProcess::resolveRomfs() void RomfsProcess::resolveRomfs()
{ {
// read header // 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 // logic check on the header layout
if (validateHeaderLayout(&mHdr) == false) if (validateHeaderLayout(&mHdr) == false)
@ -264,13 +265,13 @@ void RomfsProcess::resolveRomfs()
// read directory nodes // read directory nodes
mDirNodes.alloc(mHdr.sections[nx::romfs::DIR_NODE_TABLE].size.get()); 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"); //printf("[RAW DIR NODES]\n");
//fnd::SimpleTextOutput::hxdStyleDump(mDirNodes.getBytes(), mDirNodes.getSize()); //fnd::SimpleTextOutput::hxdStyleDump(mDirNodes.getBytes(), mDirNodes.getSize());
// read file nodes // read file nodes
mFileNodes.alloc(mHdr.sections[nx::romfs::FILE_NODE_TABLE].size.get()); 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"); //printf("[RAW FILE NODES]\n");
//fnd::SimpleTextOutput::hxdStyleDump(mFileNodes.getBytes(), mFileNodes.getSize()); //fnd::SimpleTextOutput::hxdStyleDump(mFileNodes.getBytes(), mFileNodes.getSize());

View file

@ -94,7 +94,7 @@ public:
void process(); void process();
// generic // generic
void setInputFile(fnd::IFile* file, size_t offset, size_t size); void setInputFile(fnd::IFile* file, bool ownIFile);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputType type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -108,7 +108,8 @@ private:
const std::string kModuleName = "RomfsProcess"; const std::string kModuleName = "RomfsProcess";
static const size_t kCacheSize = 0x10000; static const size_t kCacheSize = 0x10000;
fnd::IFile* mReader; fnd::IFile* mFile;
bool mOwnIFile;
CliOutputType mCliOutputType; CliOutputType mCliOutputType;
bool mVerify; bool mVerify;

View file

@ -3,6 +3,95 @@
#include "OffsetAdjustedIFile.h" #include "OffsetAdjustedIFile.h"
#include "XciProcess.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) inline const char* getBoolStr(bool isTrue)
{ {
return isTrue? "TRUE" : "FALSE"; return isTrue? "TRUE" : "FALSE";
@ -51,17 +140,16 @@ inline const char* getCardClockRate(uint32_t acc_ctrl_1)
return str; return str;
} }
void XciProcess::displayHeader() void XciProcess::displayHeader()
{ {
printf("[XCI HEADER]\n"); printf("[XCI HEADER]\n");
printf(" Magic: HEAD\n"); printf(" Magic: HEAD\n");
printf(" RomAreaStartPage: 0x%0x", mHdr.getRomAreaStartPage()); 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(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getRomAreaStartPage()));
printf("\n"); printf("\n");
printf(" BackupAreaStartPage: 0x%0x", mHdr.getBackupAreaStartPage()); 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(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage()));
printf("\n"); printf("\n");
printf(" KekIndex: %d\n", mHdr.getKekIndex()); 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(" RepairTool: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_REPAIR_TOOL)));
printf(" PackageId: 0x%" PRIx64 "\n", mHdr.getPackageId()); printf(" PackageId: 0x%" PRIx64 "\n", mHdr.getPackageId());
printf(" ValidDataEndPage: 0x%x", mHdr.getValidDataEndPage()); 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(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getValidDataEndPage()));
printf("\n"); printf("\n");
printf(" AesIv: "); printf(" AesIv: ");
@ -118,7 +206,7 @@ bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* t
fnd::MemoryBlob scratch; fnd::MemoryBlob scratch;
crypto::sha::sSha256Hash calc_hash; crypto::sha::sSha256Hash calc_hash;
scratch.alloc(len); 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); crypto::sha::Sha256(scratch.getBytes(), scratch.getSize(), calc_hash.bytes);
return calc_hash.compare(test_hash); return calc_hash.compare(test_hash);
} }
@ -144,7 +232,7 @@ void XciProcess::processRootPfs()
printf("[WARNING] XCI Root HFS0: FAIL (bad hash)\n"); 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.setListFs(mListFs);
mRootPfs.setVerifyMode(mVerify); mRootPfs.setVerifyMode(mVerify);
mRootPfs.setCliOutputMode(mCliOutputType); mRootPfs.setCliOutputMode(mCliOutputType);
@ -158,7 +246,7 @@ void XciProcess::processPartitionPfs()
for (size_t i = 0; i < rootPartitions.getSize(); i++) for (size_t i = 0; i < rootPartitions.getSize(); i++)
{ {
PfsProcess tmp; 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.setListFs(mListFs);
tmp.setVerifyMode(mVerify); tmp.setVerifyMode(mVerify);
tmp.setCliOutputMode(mCliOutputType); tmp.setCliOutputMode(mCliOutputType);
@ -173,90 +261,3 @@ void XciProcess::processPartitionPfs()
tmp.process(); 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;
}

View file

@ -18,7 +18,7 @@ public:
void process(); void process();
// generic // 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 setKeyset(const sKeyset* keyset);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputType type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -32,7 +32,8 @@ private:
const std::string kXciMountPointName = "gamecard:/"; const std::string kXciMountPointName = "gamecard:/";
static const size_t kFileExportBlockSize = 0x1000000; static const size_t kFileExportBlockSize = 0x1000000;
fnd::IFile* mReader; fnd::IFile* mFile;
bool mOwnIFile;
const sKeyset* mKeyset; const sKeyset* mKeyset;
CliOutputType mCliOutputType; CliOutputType mCliOutputType;
bool mVerify; bool mVerify;

View file

@ -15,14 +15,11 @@ int main(int argc, char** argv)
try { try {
user_set.parseCmdArgs(argc, argv); user_set.parseCmdArgs(argc, argv);
fnd::SimpleFile inputFile;
inputFile.open(user_set.getInputPath(), inputFile.Read);
if (user_set.getFileType() == FILE_XCI) if (user_set.getFileType() == FILE_XCI)
{ {
XciProcess 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.setKeyset(&user_set.getKeyset());
xci.setCliOutputMode(user_set.getCliOutputType()); xci.setCliOutputMode(user_set.getCliOutputType());
@ -44,7 +41,7 @@ int main(int argc, char** argv)
{ {
PfsProcess pfs; 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.setCliOutputMode(user_set.getCliOutputType());
pfs.setVerifyMode(user_set.isVerifyFile()); pfs.setVerifyMode(user_set.isVerifyFile());
@ -58,7 +55,7 @@ int main(int argc, char** argv)
{ {
RomfsProcess romfs; 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.setCliOutputMode(user_set.getCliOutputType());
romfs.setVerifyMode(user_set.isVerifyFile()); romfs.setVerifyMode(user_set.isVerifyFile());
@ -72,7 +69,7 @@ int main(int argc, char** argv)
{ {
NcaProcess nca; 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.setKeyset(&user_set.getKeyset());
nca.setCliOutputMode(user_set.getCliOutputType()); nca.setCliOutputMode(user_set.getCliOutputType());
nca.setVerifyMode(user_set.isVerifyFile()); nca.setVerifyMode(user_set.isVerifyFile());
@ -94,7 +91,7 @@ int main(int argc, char** argv)
{ {
NpdmProcess npdm; 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.setKeyset(&user_set.getKeyset());
npdm.setCliOutputMode(user_set.getCliOutputType()); npdm.setCliOutputMode(user_set.getCliOutputType());
npdm.setVerifyMode(user_set.isVerifyFile()); npdm.setVerifyMode(user_set.isVerifyFile());
@ -105,7 +102,7 @@ int main(int argc, char** argv)
{ {
CnmtProcess cnmt; 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.setCliOutputMode(user_set.getCliOutputType());
cnmt.setVerifyMode(user_set.isVerifyFile()); cnmt.setVerifyMode(user_set.isVerifyFile());
@ -115,7 +112,7 @@ int main(int argc, char** argv)
{ {
NsoProcess nso; 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.setCliOutputMode(user_set.getCliOutputType());
nso.setVerifyMode(user_set.isVerifyFile()); nso.setVerifyMode(user_set.isVerifyFile());

View file

@ -9,6 +9,11 @@
static const size_t kMasterKeyNum = 0x20; static const size_t kMasterKeyNum = 0x20;
static const size_t kNcaKeakNum = nx::nca::kKeyAreaEncryptionKeyNum; static const size_t kNcaKeakNum = nx::nca::kKeyAreaEncryptionKeyNum;
enum IFileOwnershipMode
{
SHARED_IFILE = false,
OWN_IFILE = true
};
enum FileType enum FileType
{ {