[nstool] Refactor logic for managing output mode.

This commit is contained in:
jakcron 2018-06-18 23:30:19 +08:00
parent 17cc0d9c47
commit 2f5a4d9c23
24 changed files with 436 additions and 416 deletions

View file

@ -7,7 +7,7 @@
AssetProcess::AssetProcess() : AssetProcess::AssetProcess() :
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false) mVerify(false)
{ {
@ -29,7 +29,8 @@ void AssetProcess::process()
} }
importHeader(); importHeader();
displayHeader(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
displayHeader();
processSections(); processSections();
} }
@ -39,9 +40,9 @@ void AssetProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile; mOwnIFile = ownIFile;
} }
void AssetProcess::setCliOutputMode(CliOutputType type) void AssetProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputType = type; mCliOutputMode = type;
} }
void AssetProcess::setVerifyMode(bool verify) void AssetProcess::setVerifyMode(bool verify)
@ -117,7 +118,7 @@ void AssetProcess::processSections()
} }
mNacp.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNacpInfo().offset, mHdr.getNacpInfo().size), true); mNacp.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNacpInfo().offset, mHdr.getNacpInfo().size), true);
mNacp.setCliOutputMode(mCliOutputType); mNacp.setCliOutputMode(mCliOutputMode);
mNacp.setVerifyMode(mVerify); mNacp.setVerifyMode(mVerify);
mNacp.process(); mNacp.process();
@ -129,7 +130,7 @@ void AssetProcess::processSections()
throw fnd::Exception(kModuleName, "ASET geometry for romfs beyond file size"); throw fnd::Exception(kModuleName, "ASET geometry for romfs beyond file size");
mRomfs.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getRomfsInfo().offset, mHdr.getRomfsInfo().size), true); mRomfs.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getRomfsInfo().offset, mHdr.getRomfsInfo().size), true);
mRomfs.setCliOutputMode(mCliOutputType); mRomfs.setCliOutputMode(mCliOutputMode);
mRomfs.setVerifyMode(mVerify); mRomfs.setVerifyMode(mVerify);
mRomfs.process(); mRomfs.process();
@ -138,7 +139,7 @@ void AssetProcess::processSections()
void AssetProcess::displayHeader() void AssetProcess::displayHeader()
{ {
if (mCliOutputType >= OUTPUT_NORMAL) if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
{ {
printf("[ASET Header]\n"); printf("[ASET Header]\n");
printf(" Icon:\n"); printf(" Icon:\n");

View file

@ -17,7 +17,7 @@ public:
void process(); void process();
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
void setListFs(bool list); void setListFs(bool list);
@ -32,7 +32,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
CliOutputType mCliOutputType; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
sOptional<std::string> mIconExtractPath; sOptional<std::string> mIconExtractPath;

View file

@ -145,7 +145,7 @@ void CnmtProcess::displayCmnt()
CnmtProcess::CnmtProcess() : CnmtProcess::CnmtProcess() :
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false) mVerify(false)
{ {
} }
@ -172,10 +172,8 @@ void CnmtProcess::process()
mCnmt.importBinary(scratch.getBytes(), scratch.getSize()); mCnmt.importBinary(scratch.getBytes(), scratch.getSize());
if (mCliOutputType >= OUTPUT_NORMAL) if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{
displayCmnt(); displayCmnt();
}
} }
void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile) void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile)
@ -184,9 +182,9 @@ void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile; mOwnIFile = ownIFile;
} }
void CnmtProcess::setCliOutputMode(CliOutputType type) void CnmtProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputType = type; mCliOutputMode = type;
} }
void CnmtProcess::setVerifyMode(bool verify) void CnmtProcess::setVerifyMode(bool verify)

View file

@ -15,7 +15,7 @@ public:
void process(); void process();
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
const nx::ContentMetaBinary& getContentMetaBinary() const; const nx::ContentMetaBinary& getContentMetaBinary() const;
@ -25,7 +25,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
CliOutputType mCliOutputType; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
nx::ContentMetaBinary mCnmt; nx::ContentMetaBinary mCnmt;

View file

@ -426,7 +426,7 @@ std::string getSaveDataSizeStr(int64_t size)
NacpProcess::NacpProcess() : NacpProcess::NacpProcess() :
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false) mVerify(false)
{ {
} }
@ -453,10 +453,8 @@ void NacpProcess::process()
mNacp.importBinary(scratch.getBytes(), scratch.getSize()); mNacp.importBinary(scratch.getBytes(), scratch.getSize());
if (mCliOutputType >= OUTPUT_NORMAL) if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{
displayNacp(); displayNacp();
}
} }
void NacpProcess::setInputFile(fnd::IFile* file, bool ownIFile) void NacpProcess::setInputFile(fnd::IFile* file, bool ownIFile)
@ -465,9 +463,9 @@ void NacpProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile; mOwnIFile = ownIFile;
} }
void NacpProcess::setCliOutputMode(CliOutputType type) void NacpProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputType = type; mCliOutputMode = type;
} }
void NacpProcess::setVerifyMode(bool verify) void NacpProcess::setVerifyMode(bool verify)
@ -485,7 +483,7 @@ void NacpProcess::displayNacp()
printf("[ApplicationControlProperty]\n"); printf("[ApplicationControlProperty]\n");
printf(" Menu Description:\n"); printf(" Menu Description:\n");
printf(" DisplayVersion: %s\n", mNacp.getDisplayVersion().c_str()); printf(" DisplayVersion: %s\n", mNacp.getDisplayVersion().c_str());
if (mNacp.getIsbn().empty() == false) if (mNacp.getIsbn().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
printf(" ISBN: %s\n", mNacp.getIsbn().c_str()); printf(" ISBN: %s\n", mNacp.getIsbn().c_str());
for (size_t i = 0; i < mNacp.getTitle().getSize(); i++) for (size_t i = 0; i < mNacp.getTitle().getSize(); i++)
{ {
@ -520,7 +518,7 @@ void NacpProcess::displayNacp()
printf(" Age: %d\n", mNacp.getRatingAge()[i].age); printf(" Age: %d\n", mNacp.getRatingAge()[i].age);
} }
if (mNacp.getBcatPassphase().empty() == false) if (mNacp.getBcatPassphase().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" BCAT:\n"); printf(" BCAT:\n");
printf(" BcatPassphase: %s\n", mNacp.getBcatPassphase().c_str()); printf(" BcatPassphase: %s\n", mNacp.getBcatPassphase().c_str());
@ -537,35 +535,35 @@ void NacpProcess::displayNacp()
} }
printf(" SaveData:\n"); printf(" SaveData:\n");
printf(" SaveDatawOwnerId: 0x%016" PRIx64 "\n", mNacp.getSaveDatawOwnerId()); printf(" SaveDatawOwnerId: 0x%016" PRIx64 "\n", mNacp.getSaveDatawOwnerId());
if (mNacp.getUserAccountSaveDataSize().journal_size > 0) if (mNacp.getUserAccountSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" UserAccountSaveData:\n"); printf(" UserAccountSaveData:\n");
printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().size).c_str()); printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().size).c_str());
printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().journal_size).c_str()); printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().journal_size).c_str());
} }
if (mNacp.getDeviceSaveDataSize().journal_size > 0) if (mNacp.getDeviceSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" DeviceSaveData:\n"); printf(" DeviceSaveData:\n");
printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().size).c_str()); printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().size).c_str());
printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().journal_size).c_str()); printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().journal_size).c_str());
} }
if (mNacp.getUserAccountSaveDataMax().journal_size > 0) if (mNacp.getUserAccountSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" UserAccountSaveDataMax:\n"); printf(" UserAccountSaveDataMax:\n");
printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().size).c_str()); printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().size).c_str());
printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().journal_size).c_str()); printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().journal_size).c_str());
} }
if (mNacp.getDeviceSaveDataMax().journal_size > 0) if (mNacp.getDeviceSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" DeviceSaveDataMax:\n"); printf(" DeviceSaveDataMax:\n");
printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().size).c_str()); printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().size).c_str());
printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().journal_size).c_str()); printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().journal_size).c_str());
} }
if (mNacp.getTemporaryStorageSize() > 0) if (mNacp.getTemporaryStorageSize() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" TemporaryStorageSize: %s\n", getSaveDataSizeStr(mNacp.getTemporaryStorageSize()).c_str()); printf(" TemporaryStorageSize: %s\n", getSaveDataSizeStr(mNacp.getTemporaryStorageSize()).c_str());
} }
if (mNacp.getCacheStorageSize().journal_size > 0) if (mNacp.getCacheStorageSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" CacheStorage:\n"); printf(" CacheStorage:\n");
printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageSize().size).c_str()); printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageSize().size).c_str());
@ -575,7 +573,10 @@ void NacpProcess::displayNacp()
} }
printf(" Other Flags:\n"); printf(" Other Flags:\n");
printf(" StartupUserAccount: %s\n", getStartupUserAccountStr(mNacp.getStartupUserAccount())); printf(" StartupUserAccount: %s\n", getStartupUserAccountStr(mNacp.getStartupUserAccount()));
//printf(" TouchScreenUsageMode: %s\n", getTouchScreenUsageModeStr(mNacp.getTouchScreenUsageMode())); if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
printf(" TouchScreenUsageMode: %s\n", getTouchScreenUsageModeStr(mNacp.getTouchScreenUsageMode()));
}
printf(" AttributeFlag: %s\n", getAttributeFlagStr(mNacp.getAttributeFlag())); printf(" AttributeFlag: %s\n", getAttributeFlagStr(mNacp.getAttributeFlag()));
printf(" CrashReportMode: %s\n", getCrashReportModeStr(mNacp.getCrashReportMode())); printf(" CrashReportMode: %s\n", getCrashReportModeStr(mNacp.getCrashReportMode()));
printf(" HDCP: %s\n", getHdcpStr(mNacp.getHdcp())); printf(" HDCP: %s\n", getHdcpStr(mNacp.getHdcp()));
@ -584,16 +585,16 @@ void NacpProcess::displayNacp()
printf(" DataLossConfirmation: %s\n", getDataLossConfirmationStr(mNacp.getDataLossConfirmation())); printf(" DataLossConfirmation: %s\n", getDataLossConfirmationStr(mNacp.getDataLossConfirmation()));
printf(" RepairFlag: %s\n", getRepairFlagStr(mNacp.getRepairFlag())); printf(" RepairFlag: %s\n", getRepairFlagStr(mNacp.getRepairFlag()));
printf(" ProgramIndex: 0x%02x\n", mNacp.getProgramIndex()); printf(" ProgramIndex: 0x%02x\n", mNacp.getProgramIndex());
if (mNacp.getApplicationErrorCodeCategory().empty() == false) if (mNacp.getApplicationErrorCodeCategory().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" ApplicationErrorCodeCategory: %s\n", mNacp.getApplicationErrorCodeCategory().c_str()); printf(" ApplicationErrorCodeCategory: %s\n", mNacp.getApplicationErrorCodeCategory().c_str());
} }
if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0) if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" Other Ids:\n"); printf(" Other Ids:\n");
if (mNacp.getSeedForPsuedoDeviceId() > 0) if (mNacp.getSeedForPsuedoDeviceId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
printf(" SeedForPsuedoDeviceId: 0x%016" PRIx64 "\n", mNacp.getSeedForPsuedoDeviceId()); printf(" SeedForPsuedoDeviceId: 0x%016" PRIx64 "\n", mNacp.getSeedForPsuedoDeviceId());
if (mNacp.getPresenceGroupId() > 0) if (mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
printf(" PresenceGroupId: 0x%016" PRIx64 "\n", mNacp.getPresenceGroupId()); printf(" PresenceGroupId: 0x%016" PRIx64 "\n", mNacp.getPresenceGroupId());
} }
} }

View file

@ -15,7 +15,7 @@ public:
void process(); void process();
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
const nx::ApplicationControlPropertyBinary& getApplicationControlPropertyBinary() const; const nx::ApplicationControlPropertyBinary& getApplicationControlPropertyBinary() const;
@ -25,7 +25,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
CliOutputType mCliOutputType; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
nx::ApplicationControlPropertyBinary mNacp; nx::ApplicationControlPropertyBinary mNacp;

View file

@ -224,7 +224,7 @@ NcaProcess::NcaProcess() :
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mKeyset(nullptr), mKeyset(nullptr),
mCliOutputType(OUTPUT_NORMAL), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false), mVerify(false),
mListFs(false) mListFs(false)
{ {
@ -283,7 +283,7 @@ void NcaProcess::process()
validateNcaSignatures(); validateNcaSignatures();
// display header // display header
if (mCliOutputType >= OUTPUT_NORMAL) if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
displayHeader(); displayHeader();
// process partition // process partition
@ -322,9 +322,9 @@ void NcaProcess::setKeyset(const sKeyset* keyset)
mKeyset = keyset; mKeyset = keyset;
} }
void NcaProcess::setCliOutputMode(CliOutputType type) void NcaProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputType = type; mCliOutputMode = type;
} }
void NcaProcess::setVerifyMode(bool verify) void NcaProcess::setVerifyMode(bool verify)
@ -458,21 +458,27 @@ void NcaProcess::generateNcaBodyEncryptionKeys()
{ {
mBodyKeys.aes_xts = mKeyset->nca.manual_body_key_aesxts; mBodyKeys.aes_xts = mKeyset->nca.manual_body_key_aesxts;
} }
/*
if (mBodyKeys.aes_ctr.isSet) if (_HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA))
{ {
printf("AES-CTR Key: "); if (mBodyKeys.aes_ctr.isSet)
fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var)); {
printf("[NCA Body Key]\n");
printf(" AES-CTR Key: ");
fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var));
}
if (mBodyKeys.aes_xts.isSet)
{
printf("[NCA Body Key]\n");
printf(" AES-XTS Key0: ");
fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var));
printf(" AES-XTS Key1: ");
fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var));
}
} }
if (mBodyKeys.aes_xts.isSet)
{
printf("AES-XTS Key0: ");
fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var));
printf("AES-XTS Key1: ");
fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var));
}
*/
} }
void NcaProcess::generatePartitionConfiguration() void NcaProcess::generatePartitionConfiguration()
@ -590,9 +596,7 @@ void NcaProcess::validateNcaSignatures()
// validate signature[0] // validate signature[0]
if (crypto::rsa::pss::rsaVerify(mKeyset->nca.header_sign_key, crypto::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_main) != 0) if (crypto::rsa::pss::rsaVerify(mKeyset->nca.header_sign_key, crypto::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_main) != 0)
{ {
// this is minimal even though it's a warning because it's a validation method printf("[WARNING] NCA Header Main Signature: FAIL \n");
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] NCA Header Main Signature: FAIL \n");
} }
// validate signature[1] // validate signature[1]
@ -604,7 +608,7 @@ void NcaProcess::validateNcaSignatures()
{ {
PfsProcess exefs; PfsProcess exefs;
exefs.setInputFile(mPartitions[nx::nca::PARTITION_CODE].reader, SHARED_IFILE); exefs.setInputFile(mPartitions[nx::nca::PARTITION_CODE].reader, SHARED_IFILE);
exefs.setCliOutputMode(OUTPUT_MINIMAL); exefs.setCliOutputMode(0);
exefs.process(); exefs.process();
// open main.npdm // open main.npdm
@ -614,38 +618,30 @@ void NcaProcess::validateNcaSignatures()
NpdmProcess npdm; NpdmProcess npdm;
npdm.setInputFile(new OffsetAdjustedIFile(mPartitions[nx::nca::PARTITION_CODE].reader, SHARED_IFILE, file.offset, file.size), OWN_IFILE); npdm.setInputFile(new OffsetAdjustedIFile(mPartitions[nx::nca::PARTITION_CODE].reader, SHARED_IFILE, file.offset, file.size), OWN_IFILE);
npdm.setCliOutputMode(OUTPUT_MINIMAL); npdm.setCliOutputMode(0);
npdm.process(); npdm.process();
if (crypto::rsa::pss::rsaVerify(npdm.getNpdmBinary().getAcid().getNcaHeader2RsaKey(), crypto::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_acid) != 0) if (crypto::rsa::pss::rsaVerify(npdm.getNpdmBinary().getAcid().getNcaHeader2RsaKey(), crypto::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_acid) != 0)
{ {
// this is minimal even though it's a warning because it's a validation method printf("[WARNING] NCA Header ACID Signature: FAIL \n");
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] NCA Header ACID Signature: FAIL \n");
} }
} }
else else
{ {
// this is minimal even though it's a warning because it's a validation method printf("[WARNING] NCA Header ACID Signature: FAIL (\"%s\" not present in ExeFs)\n", kNpdmExefsPath.c_str());
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] NCA Header ACID Signature: FAIL (\"%s\" not present in ExeFs)\n", kNpdmExefsPath.c_str());
} }
} }
else else
{ {
// this is minimal even though it's a warning because it's a validation method printf("[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)\n");
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)\n");
} }
} }
else else
{ {
// this is minimal even though it's a warning because it's a validation method printf("[WARNING] NCA Header ACID Signature: FAIL (No ExeFs partition)\n");
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] NCA Header ACID Signature: FAIL (No ExeFs partition)\n");
} }
} }
} }
@ -674,7 +670,7 @@ void NcaProcess::displayHeader()
} }
if (mBodyKeys.keak_list.getSize() > 0) if (mBodyKeys.keak_list.getSize() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA))
{ {
printf(" Key Area: \n"); printf(" Key Area: \n");
printf(" <--------------------------------------------------------------------------->\n"); printf(" <--------------------------------------------------------------------------->\n");
@ -699,70 +695,74 @@ void NcaProcess::displayHeader()
printf(" <--------------------------------------------------------------------------->\n"); printf(" <--------------------------------------------------------------------------->\n");
} }
printf(" Partitions:\n"); if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
for (size_t i = 0; i < mHdr.getPartitions().getSize(); i++)
{ {
sPartitionInfo& info = mPartitions[i]; printf(" Partitions:\n");
for (size_t i = 0; i < mHdr.getPartitions().getSize(); i++)
{
sPartitionInfo& info = mPartitions[i];
printf(" %d:\n", (int)i); printf(" %d:\n", (int)i);
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)info.offset); printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)info.offset);
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size); printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size);
printf(" Format Type: %s\n", getFormatTypeStr(info.format_type)); printf(" Format Type: %s\n", getFormatTypeStr(info.format_type));
printf(" Hash Type: %s\n", getHashTypeStr(info.hash_type)); printf(" Hash Type: %s\n", getHashTypeStr(info.hash_type));
printf(" Enc. Type: %s\n", getEncryptionTypeStr(info.enc_type)); printf(" Enc. Type: %s\n", getEncryptionTypeStr(info.enc_type));
if (info.enc_type == nx::nca::CRYPT_AESCTR) if (info.enc_type == nx::nca::CRYPT_AESCTR)
{
printf(" AES-CTR: ");
crypto::aes::sAesIvCtr ctr;
crypto::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv);
fnd::SimpleTextOutput::hexDump(ctr.iv, sizeof(crypto::aes::sAesIvCtr));
}
if (info.hash_type == nx::nca::HASH_HIERARCHICAL_INTERGRITY)
{
HashTreeMeta& hash_hdr = info.hash_tree_meta;
printf(" HierarchicalIntegrity Header:\n");
//printf(" TypeId: 0x%x\n", hash_hdr.type_id.get());
//printf(" MasterHashSize: 0x%x\n", hash_hdr.master_hash_size.get());
//printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().getSize());
for (size_t j = 0; j < hash_hdr.getHashLayerInfo().getSize(); j++)
{ {
printf(" Hash Layer %d:\n", (int)j); printf(" AES-CTR: ");
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].offset); crypto::aes::sAesIvCtr ctr;
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].size); crypto::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv);
printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getHashLayerInfo()[j].block_size); fnd::SimpleTextOutput::hexDump(ctr.iv, sizeof(crypto::aes::sAesIvCtr));
} }
if (info.hash_type == nx::nca::HASH_HIERARCHICAL_INTERGRITY)
{
HashTreeMeta& hash_hdr = info.hash_tree_meta;
printf(" HierarchicalIntegrity Header:\n");
//printf(" TypeId: 0x%x\n", hash_hdr.type_id.get());
//printf(" MasterHashSize: 0x%x\n", hash_hdr.master_hash_size.get());
//printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().getSize());
for (size_t j = 0; j < hash_hdr.getHashLayerInfo().getSize(); j++)
{
printf(" Hash Layer %d:\n", (int)j);
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].offset);
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].size);
printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getHashLayerInfo()[j].block_size);
}
printf(" Data Layer:\n"); printf(" Data Layer:\n");
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset); printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset);
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size); printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size);
printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size); printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size);
for (size_t j = 0; j < hash_hdr.getMasterHashList().getSize(); j++) for (size_t j = 0; j < hash_hdr.getMasterHashList().getSize(); j++)
{ {
printf(" Master Hash %d: ", (int)j); printf(" Master Hash %d: ", (int)j);
fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[j].bytes, sizeof(crypto::sha::sSha256Hash)); fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[j].bytes, sizeof(crypto::sha::sSha256Hash));
}
} }
else if (info.hash_type == nx::nca::HASH_HIERARCHICAL_SHA256)
{
HashTreeMeta& hash_hdr = info.hash_tree_meta;
printf(" HierarchicalSha256 Header:\n");
printf(" Master Hash: ");
fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[0].bytes, sizeof(crypto::sha::sSha256Hash));
printf(" HashBlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size);
//printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().getSize());
printf(" Hash Layer:\n");
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].offset);
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].size);
printf(" Data Layer:\n");
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset);
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size);
}
//else
//{
// printf(" Hash Superblock:\n");
// fnd::SimpleTextOutput::hxdStyleDump(fs_header.hash_superblock, nx::nca::kFsHeaderHashSuperblockLen);
//}
} }
else if (info.hash_type == nx::nca::HASH_HIERARCHICAL_SHA256)
{
HashTreeMeta& hash_hdr = info.hash_tree_meta;
printf(" HierarchicalSha256 Header:\n");
printf(" Master Hash: ");
fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[0].bytes, sizeof(crypto::sha::sSha256Hash));
printf(" HashBlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size);
//printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().getSize());
printf(" Hash Layer:\n");
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].offset);
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].size);
printf(" Data Layer:\n");
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset);
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size);
}
//else
//{
// printf(" Hash Superblock:\n");
// fnd::SimpleTextOutput::hxdStyleDump(fs_header.hash_superblock, nx::nca::kFsHeaderHashSuperblockLen);
//}
} }
#undef _HEXDUMP_U #undef _HEXDUMP_U
#undef _HEXDUMP_L #undef _HEXDUMP_L
} }
@ -791,7 +791,7 @@ void NcaProcess::processPartitions()
{ {
PfsProcess pfs; PfsProcess pfs;
pfs.setInputFile(partition.reader, SHARED_IFILE); pfs.setInputFile(partition.reader, SHARED_IFILE);
pfs.setCliOutputMode(mCliOutputType); pfs.setCliOutputMode(mCliOutputMode);
pfs.setListFs(mListFs); pfs.setListFs(mListFs);
if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM) if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM)
{ {
@ -812,7 +812,7 @@ void NcaProcess::processPartitions()
{ {
RomfsProcess romfs; RomfsProcess romfs;
romfs.setInputFile(partition.reader, SHARED_IFILE); romfs.setInputFile(partition.reader, SHARED_IFILE);
romfs.setCliOutputMode(mCliOutputType); romfs.setCliOutputMode(mCliOutputMode);
romfs.setListFs(mListFs); romfs.setListFs(mListFs);
if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM) if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM)
{ {

View file

@ -19,7 +19,7 @@ public:
// generic // generic
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setKeyset(const sKeyset* keyset); void setKeyset(const sKeyset* keyset);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
// nca specfic // nca specfic
@ -37,7 +37,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
const sKeyset* mKeyset; const sKeyset* mKeyset;
CliOutputType mCliOutputType; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
struct sExtract struct sExtract

View file

@ -4,7 +4,7 @@ NpdmProcess::NpdmProcess() :
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mKeyset(nullptr), mKeyset(nullptr),
mCliOutputType(OUTPUT_NORMAL), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false) mVerify(false)
{ {
} }
@ -37,7 +37,7 @@ void NpdmProcess::process()
validateAciFromAcid(mNpdm.getAci(), mNpdm.getAcid()); validateAciFromAcid(mNpdm.getAci(), mNpdm.getAcid());
} }
if (mCliOutputType >= OUTPUT_NORMAL) if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{ {
// npdm binary // npdm binary
displayNpdmHeader(mNpdm); displayNpdmHeader(mNpdm);
@ -67,9 +67,9 @@ void NpdmProcess::setKeyset(const sKeyset* keyset)
mKeyset = keyset; mKeyset = keyset;
} }
void NpdmProcess::setCliOutputMode(CliOutputType type) void NpdmProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputType = type; mCliOutputMode = type;
} }
void NpdmProcess::setVerifyMode(bool verify) void NpdmProcess::setVerifyMode(bool verify)
@ -296,9 +296,7 @@ void NpdmProcess::validateAcidSignature(const nx::AcidBinary& acid)
acid.verifyBinary(mKeyset->acid_sign_key); acid.verifyBinary(mKeyset->acid_sign_key);
} }
catch (...) { catch (...) {
// this is minimal even though it's a warning because it's a validation method printf("[WARNING] ACID Signature: FAIL\n");
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] ACID Signature: FAIL\n");
} }
} }
@ -308,20 +306,17 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
// check Program ID // check Program ID
if (acid.getProgramIdMin() > 0 && aci.getProgramId() < acid.getProgramIdMin()) if (acid.getProgramIdMin() > 0 && aci.getProgramId() < acid.getProgramIdMin())
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n");
printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n");
} }
else if (acid.getProgramIdMax() > 0 && aci.getProgramId() > acid.getProgramIdMax()) else if (acid.getProgramIdMax() > 0 && aci.getProgramId() > acid.getProgramIdMax())
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n");
printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n");
} }
// Check FAC // Check FAC
if (aci.getFac().getFormatVersion() != acid.getFac().getFormatVersion()) if (aci.getFac().getFormatVersion() != acid.getFac().getFormatVersion())
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] ACI/FAC FormatVersion: FAIL (%d != %d (expected))\n", aci.getFac().getFormatVersion(),acid.getFac().getFormatVersion());
printf("[WARNING] ACI/FAC FormatVersion: FAIL (%d != %d (expected))\n", aci.getFac().getFormatVersion(),acid.getFac().getFormatVersion());
} }
for (size_t i = 0; i < aci.getFac().getFsaRightsList().getSize(); i++) for (size_t i = 0; i < aci.getFac().getFsaRightsList().getSize(); i++)
@ -335,8 +330,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
if (fsaRightFound == false) if (fsaRightFound == false)
{ {
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] ACI/FAC FsaRights: FAIL (%s not permitted)\n", kFsaFlag[aci.getFac().getFsaRightsList()[i]].c_str()); printf("[WARNING] ACI/FAC FsaRights: FAIL (%s not permitted)\n", kFsaFlag[aci.getFac().getFsaRightsList()[i]].c_str());
} }
} }
@ -351,8 +346,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
if (rightFound == false) if (rightFound == false)
{ {
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%08x not permitted)\n", aci.getFac().getContentOwnerIdList()[i]); printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%08x not permitted)\n", aci.getFac().getContentOwnerIdList()[i]);
} }
} }
@ -367,8 +362,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
if (rightFound == false) if (rightFound == false)
{ {
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%08x not permitted)\n", aci.getFac().getSaveDataOwnerIdList()[i]); printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%08x not permitted)\n", aci.getFac().getSaveDataOwnerIdList()[i]);
} }
} }
@ -384,8 +379,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
if (rightFound == false) if (rightFound == false)
{ {
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] ACI/SAC ServiceList: FAIL (%s%s not permitted)\n", aci.getSac().getServiceList()[i].getName().c_str(), aci.getSac().getServiceList()[i].isServer()? " (Server)" : ""); printf("[WARNING] ACI/SAC ServiceList: FAIL (%s%s not permitted)\n", aci.getSac().getServiceList()[i].getName().c_str(), aci.getSac().getServiceList()[i].isServer()? " (Server)" : "");
} }
} }
@ -393,23 +388,19 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
// check thread info // check thread info
if (aci.getKc().getThreadInfo().getMaxCpuId() != acid.getKc().getThreadInfo().getMaxCpuId()) if (aci.getKc().getThreadInfo().getMaxCpuId() != acid.getKc().getThreadInfo().getMaxCpuId())
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMaxCpuId());
printf("[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMaxCpuId());
} }
if (aci.getKc().getThreadInfo().getMinCpuId() != acid.getKc().getThreadInfo().getMinCpuId()) if (aci.getKc().getThreadInfo().getMinCpuId() != acid.getKc().getThreadInfo().getMinCpuId())
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMinCpuId());
printf("[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMinCpuId());
} }
if (aci.getKc().getThreadInfo().getMaxPriority() != acid.getKc().getThreadInfo().getMaxPriority()) if (aci.getKc().getThreadInfo().getMaxPriority() != acid.getKc().getThreadInfo().getMaxPriority())
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMaxPriority());
printf("[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMaxPriority());
} }
if (aci.getKc().getThreadInfo().getMinPriority() != acid.getKc().getThreadInfo().getMinPriority()) if (aci.getKc().getThreadInfo().getMinPriority() != acid.getKc().getThreadInfo().getMinPriority())
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMinPriority());
printf("[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMinPriority());
} }
// check system calls // check system calls
for (size_t i = 0; i < aci.getKc().getSystemCalls().getSystemCalls().getSize(); i++) for (size_t i = 0; i < aci.getKc().getSystemCalls().getSystemCalls().getSize(); i++)
@ -423,8 +414,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
if (rightFound == false) if (rightFound == false)
{ {
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] ACI/KC SystemCallList: FAIL (%s not permitted)\n", kSysCall[aci.getKc().getSystemCalls().getSystemCalls()[i]].c_str()); printf("[WARNING] ACI/KC SystemCallList: FAIL (%s not permitted)\n", kSysCall[aci.getKc().getSystemCalls().getSystemCalls()[i]].c_str());
} }
} }
// check memory maps // check memory maps
@ -440,8 +431,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
if (rightFound == false) if (rightFound == false)
{ {
const nx::MemoryMappingHandler::sMemoryMapping& map = aci.getKc().getMemoryMaps().getMemoryMaps()[i]; const nx::MemoryMappingHandler::sMemoryMapping& map = aci.getKc().getMemoryMaps().getMemoryMaps()[i];
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] ACI/KC MemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str()); printf("[WARNING] ACI/KC MemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str());
} }
} }
for (size_t i = 0; i < aci.getKc().getMemoryMaps().getIoMemoryMaps().getSize(); i++) for (size_t i = 0; i < aci.getKc().getMemoryMaps().getIoMemoryMaps().getSize(); i++)
@ -456,8 +447,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
if (rightFound == false) if (rightFound == false)
{ {
const nx::MemoryMappingHandler::sMemoryMapping& map = aci.getKc().getMemoryMaps().getIoMemoryMaps()[i]; const nx::MemoryMappingHandler::sMemoryMapping& map = aci.getKc().getMemoryMaps().getIoMemoryMaps()[i];
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] ACI/KC IoMemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str()); printf("[WARNING] ACI/KC IoMemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str());
} }
} }
// check interupts // check interupts
@ -472,29 +463,25 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
if (rightFound == false) if (rightFound == false)
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] ACI/KC InteruptsList: FAIL (0x%0x not permitted)\n", aci.getKc().getInterupts().getInteruptList()[i]);
printf("[WARNING] ACI/KC InteruptsList: FAIL (0x%0x not permitted)\n", aci.getKc().getInterupts().getInteruptList()[i]);
} }
} }
// check misc params // check misc params
if (aci.getKc().getMiscParams().getProgramType() != acid.getKc().getMiscParams().getProgramType()) if (aci.getKc().getMiscParams().getProgramType() != acid.getKc().getMiscParams().getProgramType())
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] ACI/KC ProgramType: FAIL (%d not permitted)\n", aci.getKc().getMiscParams().getProgramType());
printf("[WARNING] ACI/KC ProgramType: FAIL (%d not permitted)\n", aci.getKc().getMiscParams().getProgramType());
} }
// check kernel version // check kernel version
uint32_t aciKernelVersion = (uint32_t)aci.getKc().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKc().getKernelVersion().getVerMinor(); uint32_t aciKernelVersion = (uint32_t)aci.getKc().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKc().getKernelVersion().getVerMinor();
uint32_t acidKernelVersion = (uint32_t)acid.getKc().getKernelVersion().getVerMajor() << 16 | (uint32_t)acid.getKc().getKernelVersion().getVerMinor(); uint32_t acidKernelVersion = (uint32_t)acid.getKc().getKernelVersion().getVerMajor() << 16 | (uint32_t)acid.getKc().getKernelVersion().getVerMinor();
if (aciKernelVersion < acidKernelVersion) if (aciKernelVersion < acidKernelVersion)
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] ACI/KC RequiredKernelVersion: FAIL (%d.%d not permitted)\n", aci.getKc().getKernelVersion().getVerMajor(), aci.getKc().getKernelVersion().getVerMinor());
printf("[WARNING] ACI/KC RequiredKernelVersion: FAIL (%d.%d not permitted)\n", aci.getKc().getKernelVersion().getVerMajor(), aci.getKc().getKernelVersion().getVerMinor());
} }
// check handle table size // check handle table size
if (aci.getKc().getHandleTableSize().getHandleTableSize() > acid.getKc().getHandleTableSize().getHandleTableSize()) if (aci.getKc().getHandleTableSize().getHandleTableSize() > acid.getKc().getHandleTableSize().getHandleTableSize())
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] ACI/KC HandleTableSize: FAIL (0x%x too large)\n", aci.getKc().getHandleTableSize().getHandleTableSize());
printf("[WARNING] ACI/KC HandleTableSize: FAIL (0x%x too large)\n", aci.getKc().getHandleTableSize().getHandleTableSize());
} }
// check misc flags // check misc flags
for (size_t i = 0; i < aci.getKc().getMiscFlags().getFlagList().getSize(); i++) for (size_t i = 0; i < aci.getKc().getMiscFlags().getFlagList().getSize(); i++)
@ -508,8 +495,7 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
if (rightFound == false) if (rightFound == false)
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] ACI/KC MiscFlag: FAIL (%s not permitted)\n", kMiscFlag[aci.getKc().getMiscFlags().getFlagList()[i]].c_str());
printf("[WARNING] ACI/KC MiscFlag: FAIL (%s not permitted)\n", kMiscFlag[aci.getKc().getMiscFlags().getFlagList()[i]].c_str());
} }
} }
} }

View file

@ -16,7 +16,7 @@ public:
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setKeyset(const sKeyset* keyset); void setKeyset(const sKeyset* keyset);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
const nx::NpdmBinary& getNpdmBinary() const; const nx::NpdmBinary& getNpdmBinary() const;
@ -27,7 +27,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
const sKeyset* mKeyset; const sKeyset* mKeyset;
CliOutputType mCliOutputType; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
nx::NpdmBinary mNpdm; nx::NpdmBinary mNpdm;

View file

@ -9,7 +9,7 @@
NroProcess::NroProcess(): NroProcess::NroProcess():
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false), mVerify(false),
mInstructionType(nx::npdm::INSTR_64BIT), mInstructionType(nx::npdm::INSTR_64BIT),
mListApi(false), mListApi(false),
@ -35,8 +35,11 @@ void NroProcess::process()
importHeader(); importHeader();
importCodeSegments(); importCodeSegments();
importApiList(); importApiList();
displayHeader(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
displayRoMetaData(); {
displayHeader();
displayRoMetaData();
}
if (mIsHomebrewNro) if (mIsHomebrewNro)
mAssetProc.process(); mAssetProc.process();
} }
@ -47,9 +50,9 @@ void NroProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile; mOwnIFile = ownIFile;
} }
void NroProcess::setCliOutputMode(CliOutputType type) void NroProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputType = type; mCliOutputMode = type;
} }
void NroProcess::setVerifyMode(bool verify) void NroProcess::setVerifyMode(bool verify)
@ -111,7 +114,7 @@ void NroProcess::importHeader()
{ {
mIsHomebrewNro = true; mIsHomebrewNro = true;
mAssetProc.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNroSize(), mFile->size() - mHdr.getNroSize()), true); mAssetProc.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNroSize(), mFile->size() - mHdr.getNroSize()), true);
mAssetProc.setCliOutputMode(mCliOutputType); mAssetProc.setCliOutputMode(mCliOutputMode);
mAssetProc.setVerifyMode(mVerify); mAssetProc.setVerifyMode(mVerify);
} }
else else
@ -164,48 +167,45 @@ void NroProcess::importApiList()
void NroProcess::displayHeader() void NroProcess::displayHeader()
{ {
#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
if (mCliOutputType >= OUTPUT_NORMAL) printf("[NRO Header]\n");
printf(" RoCrt: ");
_HEXDUMP_L(mHdr.getRoCrt().data, nx::nro::kRoCrtSize);
printf("\n");
printf(" ModuleId: ");
_HEXDUMP_L(mHdr.getModuleId().data, nx::nro::kModuleIdSize);
printf("\n");
printf(" NroSize: 0x%" PRIx32 "\n", mHdr.getNroSize());
printf(" Program Sections:\n");
printf(" .text:\n");
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getTextInfo().memory_offset);
printf(" Size: 0x%" PRIx32 "\n", mHdr.getTextInfo().size);
printf(" .ro:\n");
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoInfo().memory_offset);
printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoInfo().size);
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf("[NRO Header]\n"); printf(" .api_info:\n");
printf(" RoCrt: "); printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().memory_offset);
_HEXDUMP_L(mHdr.getRoCrt().data, nx::nro::kRoCrtSize); printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size);
printf("\n"); printf(" .dynstr:\n");
printf(" ModuleId: "); printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().memory_offset);
_HEXDUMP_L(mHdr.getModuleId().data, nx::nro::kModuleIdSize); printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size);
printf("\n"); printf(" .dynsym:\n");
printf(" NroSize: 0x%" PRIx32 "\n", mHdr.getNroSize()); printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().memory_offset);
printf(" Program Sections:\n"); printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size);
printf(" .text:\n");
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getTextInfo().memory_offset);
printf(" Size: 0x%" PRIx32 "\n", mHdr.getTextInfo().size);
printf(" .ro:\n");
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoInfo().memory_offset);
printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoInfo().size);
if (mCliOutputType >= OUTPUT_VERBOSE)
{
printf(" .api_info:\n");
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().memory_offset);
printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size);
printf(" .dynstr:\n");
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().memory_offset);
printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size);
printf(" .dynsym:\n");
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().memory_offset);
printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size);
}
printf(" .data:\n");
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getDataInfo().memory_offset);
printf(" Size: 0x%" PRIx32 "\n", mHdr.getDataInfo().size);
printf(" .bss:\n");
printf(" Size: 0x%" PRIx32 "\n", mHdr.getBssSize());
} }
printf(" .data:\n");
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getDataInfo().memory_offset);
printf(" Size: 0x%" PRIx32 "\n", mHdr.getDataInfo().size);
printf(" .bss:\n");
printf(" Size: 0x%" PRIx32 "\n", mHdr.getBssSize());
#undef _HEXDUMP_L #undef _HEXDUMP_L
} }
void NroProcess::displayRoMetaData() void NroProcess::displayRoMetaData()
{ {
if (mApiList.size() > 0 && (mListApi || mCliOutputType > OUTPUT_NORMAL)) if (mApiList.size() > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
{ {
printf("[SDK API List]\n"); printf("[SDK API List]\n");
for (size_t i = 0; i < mApiList.size(); i++) for (size_t i = 0; i < mApiList.size(); i++)
@ -216,7 +216,7 @@ void NroProcess::displayRoMetaData()
printf(" Module: %s\n", mApiList[i].getModuleName().c_str()); printf(" Module: %s\n", mApiList[i].getModuleName().c_str());
} }
} }
if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || mCliOutputType > OUTPUT_NORMAL)) if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
{ {
printf("[Symbol List]\n"); printf("[Symbol List]\n");
for (size_t i = 0; i < mDynSymbolList.getDynamicSymbolList().getSize(); i++) for (size_t i = 0; i < mDynSymbolList.getDynamicSymbolList().getSize(); i++)
@ -225,7 +225,6 @@ void NroProcess::displayRoMetaData()
printf(" %s [SHN=%s (%04x)][STT=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type)); printf(" %s [SHN=%s (%04x)][STT=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type));
} }
} }
} }
const char* NroProcess::getApiTypeStr(SdkApiString::ApiType type) const const char* NroProcess::getApiTypeStr(SdkApiString::ApiType type) const

View file

@ -20,7 +20,7 @@ public:
void process(); void process();
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
void setInstructionType(nx::npdm::InstructionType type); void setInstructionType(nx::npdm::InstructionType type);
@ -38,7 +38,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
CliOutputType mCliOutputType; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
nx::npdm::InstructionType mInstructionType; nx::npdm::InstructionType mInstructionType;
bool mListApi; bool mListApi;

View file

@ -8,7 +8,7 @@
NsoProcess::NsoProcess(): NsoProcess::NsoProcess():
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false), mVerify(false),
mInstructionType(nx::npdm::INSTR_64BIT), mInstructionType(nx::npdm::INSTR_64BIT),
mListApi(false), mListApi(false),
@ -34,8 +34,11 @@ void NsoProcess::process()
importHeader(); importHeader();
importCodeSegments(); importCodeSegments();
importApiList(); importApiList();
displayNsoHeader(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
displayRoMetaData(); {
displayNsoHeader();
displayRoMetaData();
}
} }
void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile) void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile)
@ -44,9 +47,9 @@ void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile; mOwnIFile = ownIFile;
} }
void NsoProcess::setCliOutputMode(CliOutputType type) void NsoProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputType = type; mCliOutputMode = type;
} }
void NsoProcess::setVerifyMode(bool verify) void NsoProcess::setVerifyMode(bool verify)
@ -204,75 +207,73 @@ void NsoProcess::displayNsoHeader()
{ {
#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
if (mCliOutputType >= OUTPUT_NORMAL) printf("[NSO Header]\n");
printf(" ModuleId: ");
_HEXDUMP_L(mNsoHdr.getModuleId().data, nx::nso::kModuleIdSize);
printf("\n");
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
printf(" Program Segments:\n");
printf(" .module_name:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getModuleNameInfo().offset);
printf(" FileSize: 0x%" PRIx32 "\n", mNsoHdr.getModuleNameInfo().size);
printf(" .text:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().file_layout.offset);
printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getTextSegmentInfo().file_layout.size, mNsoHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : "");
printf(" .ro:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().file_layout.offset);
printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getRoSegmentInfo().file_layout.size, mNsoHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : "");
printf(" .data:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().file_layout.offset);
printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getDataSegmentInfo().file_layout.size, mNsoHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : "");
printf(" Program Sections:\n");
printf(" .text:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().memory_layout.offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().memory_layout.size);
if (mNsoHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf("[NSO Header]\n"); printf(" Hash: ");
printf(" ModuleId: "); _HEXDUMP_L(mNsoHdr.getTextSegmentInfo().hash.bytes, 32);
_HEXDUMP_L(mNsoHdr.getModuleId().data, nx::nso::kModuleIdSize);
printf("\n"); printf("\n");
printf(" Program Segments:\n");
printf(" .module_name:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getModuleNameInfo().offset);
printf(" FileSize: 0x%" PRIx32 "\n", mNsoHdr.getModuleNameInfo().size);
printf(" .text:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().file_layout.offset);
printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getTextSegmentInfo().file_layout.size, mNsoHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : "");
printf(" .ro:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().file_layout.offset);
printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getRoSegmentInfo().file_layout.size, mNsoHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : "");
printf(" .data:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().file_layout.offset);
printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getDataSegmentInfo().file_layout.size, mNsoHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : "");
printf(" Program Sections:\n");
printf(" .text:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().memory_layout.offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().memory_layout.size);
if (mNsoHdr.getTextSegmentInfo().is_hashed && mCliOutputType >= OUTPUT_VERBOSE)
{
printf(" Hash: ");
_HEXDUMP_L(mNsoHdr.getTextSegmentInfo().hash.bytes, 32);
printf("\n");
}
printf(" .ro:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().memory_layout.offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().memory_layout.size);
if (mNsoHdr.getRoSegmentInfo().is_hashed && mCliOutputType >= OUTPUT_VERBOSE)
{
printf(" Hash: ");
_HEXDUMP_L(mNsoHdr.getRoSegmentInfo().hash.bytes, 32);
printf("\n");
}
if (mCliOutputType >= OUTPUT_VERBOSE)
{
printf(" .api_info:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoEmbeddedInfo().offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoEmbeddedInfo().size);
printf(" .dynstr:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoDynStrInfo().offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoDynStrInfo().size);
printf(" .dynsym:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoDynSymInfo().offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoDynSymInfo().size);
}
printf(" .data:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().memory_layout.offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().memory_layout.size);
if (mNsoHdr.getDataSegmentInfo().is_hashed && mCliOutputType >= OUTPUT_VERBOSE)
{
printf(" Hash: ");
_HEXDUMP_L(mNsoHdr.getDataSegmentInfo().hash.bytes, 32);
printf("\n");
}
printf(" .bss:\n");
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getBssSize());
} }
printf(" .ro:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().memory_layout.offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().memory_layout.size);
if (mNsoHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
printf(" Hash: ");
_HEXDUMP_L(mNsoHdr.getRoSegmentInfo().hash.bytes, 32);
printf("\n");
}
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
printf(" .api_info:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoEmbeddedInfo().offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoEmbeddedInfo().size);
printf(" .dynstr:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoDynStrInfo().offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoDynStrInfo().size);
printf(" .dynsym:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoDynSymInfo().offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoDynSymInfo().size);
}
printf(" .data:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().memory_layout.offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().memory_layout.size);
if (mNsoHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
printf(" Hash: ");
_HEXDUMP_L(mNsoHdr.getDataSegmentInfo().hash.bytes, 32);
printf("\n");
}
printf(" .bss:\n");
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getBssSize());
#undef _HEXDUMP_L #undef _HEXDUMP_L
} }
void NsoProcess::displayRoMetaData() void NsoProcess::displayRoMetaData()
{ {
if (mApiList.size() > 0 && (mListApi || mCliOutputType > OUTPUT_NORMAL)) if (mApiList.size() > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
{ {
printf("[SDK API List]\n"); printf("[SDK API List]\n");
for (size_t i = 0; i < mApiList.size(); i++) for (size_t i = 0; i < mApiList.size(); i++)
@ -283,7 +284,7 @@ void NsoProcess::displayRoMetaData()
printf(" Module: %s\n", mApiList[i].getModuleName().c_str()); printf(" Module: %s\n", mApiList[i].getModuleName().c_str());
} }
} }
if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || mCliOutputType > OUTPUT_NORMAL)) if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
{ {
printf("[Symbol List]\n"); printf("[Symbol List]\n");
for (size_t i = 0; i < mDynSymbolList.getDynamicSymbolList().getSize(); i++) for (size_t i = 0; i < mDynSymbolList.getDynamicSymbolList().getSize(); i++)
@ -292,9 +293,9 @@ void NsoProcess::displayRoMetaData()
printf(" %s [SHN=%s (%04x)][STT=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type)); printf(" %s [SHN=%s (%04x)][STT=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type));
} }
} }
} }
const char* NsoProcess::getApiTypeStr(SdkApiString::ApiType type) const const char* NsoProcess::getApiTypeStr(SdkApiString::ApiType type) const
{ {
const char* str; const char* str;

View file

@ -19,7 +19,7 @@ public:
void process(); void process();
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
void setInstructionType(nx::npdm::InstructionType type); void setInstructionType(nx::npdm::InstructionType type);
@ -31,7 +31,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
CliOutputType mCliOutputType; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
nx::npdm::InstructionType mInstructionType; nx::npdm::InstructionType mInstructionType;
bool mListApi; bool mListApi;

View file

@ -5,7 +5,7 @@
PfsProcess::PfsProcess() : PfsProcess::PfsProcess() :
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false), mVerify(false),
mExtractPath(), mExtractPath(),
mExtract(false), mExtract(false),
@ -46,10 +46,12 @@ void PfsProcess::process()
mFile->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 (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{
displayHeader(); displayHeader();
if (mListFs || mCliOutputType >= OUTPUT_VERBOSE) if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
displayFs(); displayFs();
}
if (mPfs.getFsType() == mPfs.TYPE_HFS0 && mVerify) if (mPfs.getFsType() == mPfs.TYPE_HFS0 && mVerify)
validateHfs(); validateHfs();
if (mExtract) if (mExtract)
@ -62,9 +64,9 @@ void PfsProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile; mOwnIFile = ownIFile;
} }
void PfsProcess::setCliOutputMode(CliOutputType type) void PfsProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputType = type; mCliOutputMode = type;
} }
void PfsProcess::setVerifyMode(bool verify) void PfsProcess::setVerifyMode(bool verify)
@ -107,7 +109,7 @@ void PfsProcess::displayFs()
for (size_t i = 0; i < mPfs.getFileList().getSize(); i++) for (size_t i = 0; i < mPfs.getFileList().getSize(); i++)
{ {
printf(" %s", mPfs.getFileList()[i].name.c_str()); printf(" %s", mPfs.getFileList()[i].name.c_str());
if (mCliOutputType >= OUTPUT_VERBOSE) if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
{ {
if (mPfs.getFsType() == mPfs.TYPE_PFS0) if (mPfs.getFsType() == mPfs.TYPE_PFS0)
printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")\n", (uint64_t)mPfs.getFileList()[i].offset, (uint64_t)mPfs.getFileList()[i].size); printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")\n", (uint64_t)mPfs.getFileList()[i].offset, (uint64_t)mPfs.getFileList()[i].size);
@ -149,9 +151,7 @@ void PfsProcess::validateHfs()
crypto::sha::Sha256(mCache.getBytes(), file[i].hash_protected_size, hash.bytes); crypto::sha::Sha256(mCache.getBytes(), file[i].hash_protected_size, hash.bytes);
if (hash != file[i].hash) if (hash != file[i].hash)
{ {
if (mCliOutputType >= OUTPUT_MINIMAL) printf("[WARNING] HFS0 %s%s%s: FAIL (bad hash)\n", !mMountName.empty()? mMountName.c_str() : "", (!mMountName.empty() && mMountName.at(mMountName.length()-1) != '/' )? "/" : "", file[i].name.c_str());
printf("[WARNING] HFS0 %s%s%s: FAIL (bad hash)\n", !mMountName.empty()? mMountName.c_str() : "", (!mMountName.empty() && mMountName.at(mMountName.length()-1) != '/' )? "/" : "", file[i].name.c_str());
} }
} }
} }
@ -174,7 +174,7 @@ void PfsProcess::extractFs()
fnd::io::appendToPath(file_path, mExtractPath); fnd::io::appendToPath(file_path, mExtractPath);
fnd::io::appendToPath(file_path, file[i].name); fnd::io::appendToPath(file_path, file[i].name);
if (mCliOutputType >= OUTPUT_VERBOSE) if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
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);

View file

@ -16,7 +16,7 @@ public:
// generic // generic
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
// pfs specific // pfs specific
@ -32,7 +32,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
CliOutputType mCliOutputType; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
std::string mExtractPath; std::string mExtractPath;

View file

@ -6,7 +6,7 @@
RomfsProcess::RomfsProcess() : RomfsProcess::RomfsProcess() :
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false), mVerify(false),
mExtractPath(), mExtractPath(),
mExtract(false), mExtract(false),
@ -37,10 +37,12 @@ void RomfsProcess::process()
resolveRomfs(); resolveRomfs();
if (mCliOutputType >= OUTPUT_NORMAL) if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{
displayHeader(); displayHeader();
if (mListFs || mCliOutputType >= OUTPUT_VERBOSE) if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
displayFs(); displayFs();
}
if (mExtract) if (mExtract)
extractFs(); extractFs();
} }
@ -51,9 +53,9 @@ void RomfsProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile; mOwnIFile = ownIFile;
} }
void RomfsProcess::setCliOutputMode(CliOutputType type) void RomfsProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputType = type; mCliOutputMode = type;
} }
void RomfsProcess::setVerifyMode(bool verify) void RomfsProcess::setVerifyMode(bool verify)
@ -94,7 +96,7 @@ void RomfsProcess::displayFile(const sFile& file, size_t tab) const
{ {
printTab(tab); printTab(tab);
printf("%s", file.name.c_str()); printf("%s", file.name.c_str());
if (mCliOutputType >= OUTPUT_VERBOSE) if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
{ {
printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")", file.offset, file.size); printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")", file.offset, file.size);
} }
@ -154,9 +156,8 @@ void RomfsProcess::extractDir(const std::string& path, const sDirectory& dir)
fnd::io::appendToPath(file_path, dir_path); fnd::io::appendToPath(file_path, dir_path);
fnd::io::appendToPath(file_path, dir.file_list[i].name); fnd::io::appendToPath(file_path, dir.file_list[i].name);
if (mCliOutputType >= OUTPUT_VERBOSE) if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
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);
mFile->seek(dir.file_list[i].offset); mFile->seek(dir.file_list[i].offset);

View file

@ -95,7 +95,7 @@ public:
// generic // generic
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
// romfs specific // romfs specific
@ -110,7 +110,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
CliOutputType mCliOutputType; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
std::string mExtractPath; std::string mExtractPath;

View file

@ -45,8 +45,10 @@ void UserSettings::showHelp()
printf(" -k, --keyset Specify keyset file\n"); printf(" -k, --keyset Specify keyset file\n");
printf(" -t, --type Specify input file type [xci, pfs, romfs, nca, npdm, cnmt, nso, nro, nacp, aset]\n"); printf(" -t, --type Specify input file type [xci, pfs, romfs, nca, npdm, cnmt, nso, nro, nacp, aset]\n");
printf(" -y, --verify Verify file\n"); printf(" -y, --verify Verify file\n");
printf("\n Output Options:\n");
printf(" --showkeys Show keys generated\n");
printf(" --showlayout Show layout metadata\n");
printf(" -v, --verbose Verbose output\n"); printf(" -v, --verbose Verbose output\n");
printf(" -q, --quiet Minimal output\n");
printf("\n XCI (GameCard Image)\n"); printf("\n XCI (GameCard Image)\n");
printf(" nstool [--listfs] [--update <dir> --logo <dir> --normal <dir> --secure <dir>] <.xci file>\n"); printf(" nstool [--listfs] [--update <dir> --logo <dir> --normal <dir> --secure <dir>] <.xci file>\n");
printf(" --listfs Print file system in embedded partitions\n"); printf(" --listfs Print file system in embedded partitions\n");
@ -101,9 +103,9 @@ bool UserSettings::isVerifyFile() const
return mVerifyFile; return mVerifyFile;
} }
CliOutputType UserSettings::getCliOutputType() const CliOutputMode UserSettings::getCliOutputMode() const
{ {
return mOutputType; return mOutputMode;
} }
bool UserSettings::isListFs() const bool UserSettings::isListFs() const
@ -223,18 +225,24 @@ void UserSettings::populateCmdArgs(int argc, char** argv, sCmdArgs& cmd_args)
cmd_args.verify_file = true; cmd_args.verify_file = true;
} }
else if (args[i] == "--showkeys")
{
if (hasParamter) throw fnd::Exception(kModuleName, args[i] + " does not take a parameter.");
cmd_args.show_keys = true;
}
else if (args[i] == "--showlayout")
{
if (hasParamter) throw fnd::Exception(kModuleName, args[i] + " does not take a parameter.");
cmd_args.show_layout = true;
}
else if (args[i] == "-v" || args[i] == "--verbose") else if (args[i] == "-v" || args[i] == "--verbose")
{ {
if (hasParamter) throw fnd::Exception(kModuleName, args[i] + " does not take a parameter."); if (hasParamter) throw fnd::Exception(kModuleName, args[i] + " does not take a parameter.");
cmd_args.verbose_output = true; cmd_args.verbose_output = true;
} }
else if (args[i] == "-q" || args[i] == "--quiet")
{
if (hasParamter) throw fnd::Exception(kModuleName, args[i] + " does not take a parameter.");
cmd_args.minimal_output = true;
}
else if (args[i] == "-k" || args[i] == "--keyset") else if (args[i] == "-k" || args[i] == "--keyset")
{ {
if (!hasParamter) throw fnd::Exception(kModuleName, args[i] + " requries a parameter."); if (!hasParamter) throw fnd::Exception(kModuleName, args[i] + " requries a parameter.");
@ -588,8 +596,6 @@ void UserSettings::populateUserSettings(sCmdArgs& args)
// check invalid input // check invalid input
if (args.input_path.isSet == false) if (args.input_path.isSet == false)
throw fnd::Exception(kModuleName, "No input file specified"); throw fnd::Exception(kModuleName, "No input file specified");
if (args.verbose_output.isSet && args.minimal_output.isSet)
throw fnd::Exception(kModuleName, "Options --verbose and --quiet cannot be used together.");
// save arguments // save arguments
mInputPath = *args.input_path; mInputPath = *args.input_path;
@ -618,13 +624,22 @@ void UserSettings::populateUserSettings(sCmdArgs& args)
mAssetIconPath = args.asset_icon_path; mAssetIconPath = args.asset_icon_path;
mAssetNacpPath = args.asset_nacp_path; mAssetNacpPath = args.asset_nacp_path;
// determine output path // determine output mode
mOutputMode = _BIT(OUTPUT_BASIC);
if (args.verbose_output.isSet) if (args.verbose_output.isSet)
mOutputType = OUTPUT_VERBOSE; {
else if (args.minimal_output.isSet) mOutputMode |= _BIT(OUTPUT_KEY_DATA);
mOutputType = OUTPUT_MINIMAL; mOutputMode |= _BIT(OUTPUT_LAYOUT);
else mOutputMode |= _BIT(OUTPUT_EXTENDED);
mOutputType = OUTPUT_NORMAL; }
if (args.show_keys.isSet)
{
mOutputMode |= _BIT(OUTPUT_KEY_DATA);
}
if (args.show_layout.isSet)
{
mOutputMode |= _BIT(OUTPUT_LAYOUT);
}
// determine input file type // determine input file type
if (args.file_type.isSet) if (args.file_type.isSet)

View file

@ -18,7 +18,7 @@ public:
const sKeyset& getKeyset() const; const sKeyset& getKeyset() const;
FileType getFileType() const; FileType getFileType() const;
bool isVerifyFile() const; bool isVerifyFile() const;
CliOutputType getCliOutputType() const; CliOutputMode getCliOutputMode() const;
// specialised toggles // specialised toggles
bool isListFs() const; bool isListFs() const;
@ -50,8 +50,9 @@ private:
sOptional<std::string> keyset_path; sOptional<std::string> keyset_path;
sOptional<std::string> file_type; sOptional<std::string> file_type;
sOptional<bool> verify_file; sOptional<bool> verify_file;
sOptional<bool> show_keys;
sOptional<bool> show_layout;
sOptional<bool> verbose_output; sOptional<bool> verbose_output;
sOptional<bool> minimal_output;
sOptional<bool> list_fs; sOptional<bool> list_fs;
sOptional<std::string> update_path; sOptional<std::string> update_path;
sOptional<std::string> logo_path; sOptional<std::string> logo_path;
@ -75,7 +76,7 @@ private:
FileType mFileType; FileType mFileType;
sKeyset mKeyset; sKeyset mKeyset;
bool mVerifyFile; bool mVerifyFile;
CliOutputType mOutputType; CliOutputMode mOutputMode;
bool mListFs; bool mListFs;
sOptional<std::string> mXciUpdatePath; sOptional<std::string> mXciUpdatePath;

View file

@ -7,7 +7,7 @@ XciProcess::XciProcess() :
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mKeyset(nullptr), mKeyset(nullptr),
mCliOutputType(OUTPUT_NORMAL), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false), mVerify(false),
mListFs(false), mListFs(false),
mRootPfs(), mRootPfs(),
@ -49,10 +49,8 @@ void XciProcess::process()
mHdr.importBinary(scratch.getBytes(), scratch.getSize()); mHdr.importBinary(scratch.getBytes(), scratch.getSize());
// display header // display header
if (mCliOutputType >= OUTPUT_NORMAL) if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{
displayHeader(); displayHeader();
}
// process root partition // process root partition
processRootPfs(); processRootPfs();
@ -72,9 +70,9 @@ void XciProcess::setKeyset(const sKeyset* keyset)
mKeyset = keyset; mKeyset = keyset;
} }
void XciProcess::setCliOutputMode(CliOutputType type) void XciProcess::setCliOutputMode(CliOutputMode type)
{ {
mCliOutputType = type; mCliOutputMode = type;
} }
void XciProcess::setVerifyMode(bool verify) void XciProcess::setVerifyMode(bool verify)
@ -142,63 +140,81 @@ inline const char* getCardClockRate(uint32_t acc_ctrl_1)
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(" KekIndex: %d\n", mHdr.getKekIndex());
if (mHdr.getRomAreaStartPage() != (uint32_t)(-1)) printf(" TitleKeyDecIndex: %d\n", mHdr.getTitleKeyDecIndex());
printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getRomAreaStartPage())); printf(" RomSize: 0x%x (%s)\n", mHdr.getRomSizeType(), getRomSizeStr(mHdr.getRomSizeType()));
printf("\n"); printf(" CardHeaderVersion: %d\n", mHdr.getCardHeaderVersion());
printf(" BackupAreaStartPage: 0x%0x", mHdr.getBackupAreaStartPage()); printf(" Flags: 0x%x\n", mHdr.getFlags());
if (mHdr.getBackupAreaStartPage() != (uint32_t)(-1)) printf(" AutoBoot: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_AUTOBOOT)));
printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage())); printf(" HistoryErase: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_HISTORY_ERASE)));
printf("\n"); printf(" RepairTool: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_REPAIR_TOOL)));
printf(" KekIndex: %d\n", mHdr.getKekIndex()); printf(" PackageId: 0x%" PRIx64 "\n", mHdr.getPackageId());
printf(" TitleKeyDecIndex: %d\n", mHdr.getTitleKeyDecIndex()); if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
printf(" RomSize: 0x%x (%s)\n", mHdr.getRomSizeType(), getRomSizeStr(mHdr.getRomSizeType())); {
printf(" CardHeaderVersion: %d\n", mHdr.getCardHeaderVersion()); printf(" InitialDataHash: \n");
printf(" Flags: 0x%x\n", mHdr.getFlags()); fnd::SimpleTextOutput::hexDump(mHdr.getInitialDataHash().bytes, sizeof(mHdr.getInitialDataHash().bytes));
printf(" AutoBoot: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_AUTOBOOT))); }
printf(" HistoryErase: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_HISTORY_ERASE))); if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
printf(" RepairTool: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_REPAIR_TOOL))); {
printf(" PackageId: 0x%" PRIx64 "\n", mHdr.getPackageId()); printf(" Enc Header AES-IV: ");
printf(" ValidDataEndPage: 0x%x", mHdr.getValidDataEndPage()); fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv));
if (mHdr.getValidDataEndPage() != (uint32_t)(-1)) }
printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getValidDataEndPage())); printf(" SelSec: 0x%x\n", mHdr.getSelSec());
printf("\n"); printf(" SelT1Key: 0x%x\n", mHdr.getSelT1Key());
printf(" AesIv: "); printf(" SelKey: 0x%x\n", mHdr.getSelKey());
fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv)); if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
printf(" PartitionFs:\n"); {
printf(" Offset: 0x%" PRIx64 "\n", mHdr.getPartitionFsAddress()); printf(" RomAreaStartPage: 0x%0x", mHdr.getRomAreaStartPage());
printf(" Size: 0x%" PRIx64 "\n", mHdr.getPartitionFsSize()); if (mHdr.getRomAreaStartPage() != (uint32_t)(-1))
printf(" Hash: "); printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getRomAreaStartPage()));
fnd::SimpleTextOutput::hexDump(mHdr.getPartitionFsHash().bytes, sizeof(mHdr.getPartitionFsHash().bytes)); printf("\n");
printf(" InitialData:\n");
printf(" Hash: ");
fnd::SimpleTextOutput::hexDump(mHdr.getInitialDataHash().bytes, sizeof(mHdr.getInitialDataHash().bytes));
printf(" SelSec: 0x%x\n", mHdr.getSelSec());
printf(" SelT1Key: 0x%x\n", mHdr.getSelT1Key());
printf(" SelKey: 0x%x\n", mHdr.getSelKey());
printf(" LimArea: 0x%x", mHdr.getLimAreaPage());
if (mHdr.getLimAreaPage() != (uint32_t)(-1))
printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getLimAreaPage()));
printf("\n");
printf(" BackupAreaStartPage: 0x%0x", mHdr.getBackupAreaStartPage());
if (mHdr.getBackupAreaStartPage() != (uint32_t)(-1))
printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage()));
printf("\n");
printf(" FwVersion: v%d.%d\n", mHdr.getFwVerMajor(), mHdr.getFwVerMinor()); printf(" ValidDataEndPage: 0x%x", mHdr.getValidDataEndPage());
printf(" AccCtrl1: 0x%x\n", mHdr.getAccCtrl1()); if (mHdr.getValidDataEndPage() != (uint32_t)(-1))
printf(" CardClockRate: %s\n", getCardClockRate(mHdr.getAccCtrl1())); printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getValidDataEndPage()));
printf(" Wait1TimeRead: 0x%x\n", mHdr.getWait1TimeRead()); printf("\n");
printf(" Wait2TimeRead: 0x%x\n", mHdr.getWait2TimeRead());
printf(" Wait1TimeWrite: 0x%x\n", mHdr.getWait1TimeWrite()); printf(" LimArea: 0x%x", mHdr.getLimAreaPage());
printf(" Wait2TimeWrite: 0x%x\n", mHdr.getWait2TimeWrite()); if (mHdr.getLimAreaPage() != (uint32_t)(-1))
printf(" FwMode: 0x%x\n", mHdr.getFwMode()); printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getLimAreaPage()));
printf("\n");
printf(" PartitionFs Header:\n");
printf(" Offset: 0x%" PRIx64 "\n", mHdr.getPartitionFsAddress());
printf(" Size: 0x%" PRIx64 "\n", mHdr.getPartitionFsSize());
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
printf(" Hash: ");
fnd::SimpleTextOutput::hexDump(mHdr.getPartitionFsHash().bytes, sizeof(mHdr.getPartitionFsHash().bytes));
}
}
printf("[XCI Extended Header]\n");
printf(" FwVersion: v%d.%d\n", mHdr.getFwVerMajor(), mHdr.getFwVerMinor());
printf(" AccCtrl1: 0x%x\n", mHdr.getAccCtrl1());
printf(" CardClockRate: %s\n", getCardClockRate(mHdr.getAccCtrl1()));
printf(" Wait1TimeRead: 0x%x\n", mHdr.getWait1TimeRead());
printf(" Wait2TimeRead: 0x%x\n", mHdr.getWait2TimeRead());
printf(" Wait1TimeWrite: 0x%x\n", mHdr.getWait1TimeWrite());
printf(" Wait2TimeWrite: 0x%x\n", mHdr.getWait2TimeWrite());
printf(" FwMode: 0x%x\n", mHdr.getFwMode());
printf(" Update Partition Info:\n");
#define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff) #define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff)
printf(" UppVersion: v%" PRId32 " (%d.%d.%d.%d)\n", mHdr.getUppVersion(), _SPLIT_VER(mHdr.getUppVersion())); printf(" CUP Version: v%" PRId32 " (%d.%d.%d.%d)\n", mHdr.getUppVersion(), _SPLIT_VER(mHdr.getUppVersion()));
#undef _SPLIT_VER #undef _SPLIT_VER
printf(" UppHash: "); printf(" CUP TitleId: %016" PRIx64 "\n", mHdr.getUppId());
printf(" Partition Hash: ");
fnd::SimpleTextOutput::hexDump(mHdr.getUppHash(), 8); fnd::SimpleTextOutput::hexDump(mHdr.getUppHash(), 8);
printf(" UppId: %016" PRIx64 "\n", mHdr.getUppId());
} }
bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash) bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash)
@ -217,9 +233,7 @@ void XciProcess::validateXciSignature()
crypto::sha::Sha256((byte_t*)&mHdrPage.header, sizeof(nx::sXciHeader), calc_hash.bytes); crypto::sha::Sha256((byte_t*)&mHdrPage.header, sizeof(nx::sXciHeader), calc_hash.bytes);
if (crypto::rsa::pkcs::rsaVerify(mKeyset->xci.header_sign_key, crypto::sha::HASH_SHA256, calc_hash.bytes, mHdrPage.signature) != 0) if (crypto::rsa::pkcs::rsaVerify(mKeyset->xci.header_sign_key, crypto::sha::HASH_SHA256, calc_hash.bytes, mHdrPage.signature) != 0)
{ {
// this is minimal even though it's a warning because it's a validation method printf("[WARNING] XCI Header Signature: FAIL \n");
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] XCI Header Signature: FAIL \n");
} }
} }
@ -232,7 +246,7 @@ void XciProcess::processRootPfs()
mRootPfs.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()), OWN_IFILE); mRootPfs.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()), OWN_IFILE);
mRootPfs.setListFs(mListFs); mRootPfs.setListFs(mListFs);
mRootPfs.setVerifyMode(false); mRootPfs.setVerifyMode(false);
mRootPfs.setCliOutputMode(mCliOutputType); mRootPfs.setCliOutputMode(mCliOutputMode);
mRootPfs.setMountPointName(kXciMountPointName); mRootPfs.setMountPointName(kXciMountPointName);
mRootPfs.process(); mRootPfs.process();
} }
@ -252,7 +266,7 @@ void XciProcess::processPartitionPfs()
tmp.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].size), OWN_IFILE); 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(mCliOutputMode);
tmp.setMountPointName(kXciMountPointName + rootPartitions[i].name); tmp.setMountPointName(kXciMountPointName + rootPartitions[i].name);
for (size_t j = 0; j < mExtractInfo.size(); j++) for (size_t j = 0; j < mExtractInfo.size(); j++)
{ {

View file

@ -20,7 +20,7 @@ public:
// generic // generic
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setKeyset(const sKeyset* keyset); void setKeyset(const sKeyset* keyset);
void setCliOutputMode(CliOutputType type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
// xci specific // xci specific
@ -34,7 +34,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
const sKeyset* mKeyset; const sKeyset* mKeyset;
CliOutputType mCliOutputType; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
struct sExtractInfo struct sExtractInfo

View file

@ -25,7 +25,7 @@ int main(int argc, char** argv)
xci.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); 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.getCliOutputMode());
xci.setVerifyMode(user_set.isVerifyFile()); xci.setVerifyMode(user_set.isVerifyFile());
if (user_set.getXciUpdatePath().isSet) if (user_set.getXciUpdatePath().isSet)
@ -45,7 +45,7 @@ int main(int argc, char** argv)
PfsProcess pfs; PfsProcess pfs;
pfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); pfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
pfs.setCliOutputMode(user_set.getCliOutputType()); pfs.setCliOutputMode(user_set.getCliOutputMode());
pfs.setVerifyMode(user_set.isVerifyFile()); pfs.setVerifyMode(user_set.isVerifyFile());
if (user_set.getFsPath().isSet) if (user_set.getFsPath().isSet)
@ -59,7 +59,7 @@ int main(int argc, char** argv)
RomfsProcess romfs; RomfsProcess romfs;
romfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); romfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
romfs.setCliOutputMode(user_set.getCliOutputType()); romfs.setCliOutputMode(user_set.getCliOutputMode());
romfs.setVerifyMode(user_set.isVerifyFile()); romfs.setVerifyMode(user_set.isVerifyFile());
if (user_set.getFsPath().isSet) if (user_set.getFsPath().isSet)
@ -74,7 +74,7 @@ int main(int argc, char** argv)
nca.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); 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.getCliOutputMode());
nca.setVerifyMode(user_set.isVerifyFile()); nca.setVerifyMode(user_set.isVerifyFile());
@ -96,7 +96,7 @@ int main(int argc, char** argv)
npdm.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); 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.getCliOutputMode());
npdm.setVerifyMode(user_set.isVerifyFile()); npdm.setVerifyMode(user_set.isVerifyFile());
npdm.process(); npdm.process();
@ -106,7 +106,7 @@ int main(int argc, char** argv)
CnmtProcess cnmt; CnmtProcess cnmt;
cnmt.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); cnmt.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
cnmt.setCliOutputMode(user_set.getCliOutputType()); cnmt.setCliOutputMode(user_set.getCliOutputMode());
cnmt.setVerifyMode(user_set.isVerifyFile()); cnmt.setVerifyMode(user_set.isVerifyFile());
cnmt.process(); cnmt.process();
@ -116,7 +116,7 @@ int main(int argc, char** argv)
NsoProcess obj; NsoProcess obj;
obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
obj.setCliOutputMode(user_set.getCliOutputType()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(user_set.isVerifyFile());
obj.setInstructionType(user_set.getInstType()); obj.setInstructionType(user_set.getInstType());
@ -130,7 +130,7 @@ int main(int argc, char** argv)
NroProcess obj; NroProcess obj;
obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
obj.setCliOutputMode(user_set.getCliOutputType()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(user_set.isVerifyFile());
obj.setInstructionType(user_set.getInstType()); obj.setInstructionType(user_set.getInstType());
@ -153,7 +153,7 @@ int main(int argc, char** argv)
NacpProcess nacp; NacpProcess nacp;
nacp.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); nacp.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
nacp.setCliOutputMode(user_set.getCliOutputType()); nacp.setCliOutputMode(user_set.getCliOutputMode());
nacp.setVerifyMode(user_set.isVerifyFile()); nacp.setVerifyMode(user_set.isVerifyFile());
nacp.process(); nacp.process();
@ -163,7 +163,7 @@ int main(int argc, char** argv)
AssetProcess obj; AssetProcess obj;
obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
obj.setCliOutputMode(user_set.getCliOutputType()); obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(user_set.isVerifyFile());
if (user_set.getAssetIconPath().isSet) if (user_set.getAssetIconPath().isSet)

View file

@ -31,13 +31,16 @@ enum FileType
FILE_INVALID = -1, FILE_INVALID = -1,
}; };
enum CliOutputType enum CliOutputModeFlag
{ {
OUTPUT_MINIMAL, OUTPUT_BASIC,
OUTPUT_NORMAL, OUTPUT_LAYOUT,
OUTPUT_VERBOSE OUTPUT_KEY_DATA,
OUTPUT_EXTENDED
}; };
typedef byte_t CliOutputMode;
template <typename T> template <typename T>
struct sOptional struct sOptional
{ {