[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"
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),

View 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();

View file

@ -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)

View file

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

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 "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;

View file

@ -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();

View file

@ -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)

View file

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

View file

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

View file

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

View file

@ -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)
{

View file

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

View file

@ -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),

View 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();

View file

@ -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();

View file

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

View file

@ -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());

View file

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

View file

@ -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);
@ -172,91 +260,4 @@ 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;
}
}

View file

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

View file

@ -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());

View file

@ -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
{