[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() :
mFile(nullptr),
mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false)
{
@ -29,7 +29,8 @@ void AssetProcess::process()
}
importHeader();
displayHeader();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
displayHeader();
processSections();
}
@ -39,9 +40,9 @@ void AssetProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile;
}
void AssetProcess::setCliOutputMode(CliOutputType type)
void AssetProcess::setCliOutputMode(CliOutputMode type)
{
mCliOutputType = type;
mCliOutputMode = type;
}
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.setCliOutputMode(mCliOutputType);
mNacp.setCliOutputMode(mCliOutputMode);
mNacp.setVerifyMode(mVerify);
mNacp.process();
@ -129,7 +130,7 @@ void AssetProcess::processSections()
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.setCliOutputMode(mCliOutputType);
mRomfs.setCliOutputMode(mCliOutputMode);
mRomfs.setVerifyMode(mVerify);
mRomfs.process();
@ -138,7 +139,7 @@ void AssetProcess::processSections()
void AssetProcess::displayHeader()
{
if (mCliOutputType >= OUTPUT_NORMAL)
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
{
printf("[ASET Header]\n");
printf(" Icon:\n");

View file

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

View file

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

View file

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

View file

@ -426,7 +426,7 @@ std::string getSaveDataSizeStr(int64_t size)
NacpProcess::NacpProcess() :
mFile(nullptr),
mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false)
{
}
@ -453,10 +453,8 @@ void NacpProcess::process()
mNacp.importBinary(scratch.getBytes(), scratch.getSize());
if (mCliOutputType >= OUTPUT_NORMAL)
{
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
displayNacp();
}
}
void NacpProcess::setInputFile(fnd::IFile* file, bool ownIFile)
@ -465,9 +463,9 @@ void NacpProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile;
}
void NacpProcess::setCliOutputMode(CliOutputType type)
void NacpProcess::setCliOutputMode(CliOutputMode type)
{
mCliOutputType = type;
mCliOutputMode = type;
}
void NacpProcess::setVerifyMode(bool verify)
@ -485,7 +483,7 @@ void NacpProcess::displayNacp()
printf("[ApplicationControlProperty]\n");
printf(" Menu Description:\n");
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());
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);
}
if (mNacp.getBcatPassphase().empty() == false)
if (mNacp.getBcatPassphase().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
printf(" BCAT:\n");
printf(" BcatPassphase: %s\n", mNacp.getBcatPassphase().c_str());
@ -537,35 +535,35 @@ void NacpProcess::displayNacp()
}
printf(" SaveData:\n");
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(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().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(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().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(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().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(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().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());
}
if (mNacp.getCacheStorageSize().journal_size > 0)
if (mNacp.getCacheStorageSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
printf(" CacheStorage:\n");
printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageSize().size).c_str());
@ -575,7 +573,10 @@ void NacpProcess::displayNacp()
}
printf(" Other Flags:\n");
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(" CrashReportMode: %s\n", getCrashReportModeStr(mNacp.getCrashReportMode()));
printf(" HDCP: %s\n", getHdcpStr(mNacp.getHdcp()));
@ -584,16 +585,16 @@ void NacpProcess::displayNacp()
printf(" DataLossConfirmation: %s\n", getDataLossConfirmationStr(mNacp.getDataLossConfirmation()));
printf(" RepairFlag: %s\n", getRepairFlagStr(mNacp.getRepairFlag()));
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());
}
if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0)
if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
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());
if (mNacp.getPresenceGroupId() > 0)
if (mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
printf(" PresenceGroupId: 0x%016" PRIx64 "\n", mNacp.getPresenceGroupId());
}
}

View file

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

View file

@ -224,7 +224,7 @@ NcaProcess::NcaProcess() :
mFile(nullptr),
mOwnIFile(false),
mKeyset(nullptr),
mCliOutputType(OUTPUT_NORMAL),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false),
mListFs(false)
{
@ -283,7 +283,7 @@ void NcaProcess::process()
validateNcaSignatures();
// display header
if (mCliOutputType >= OUTPUT_NORMAL)
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
displayHeader();
// process partition
@ -322,9 +322,9 @@ void NcaProcess::setKeyset(const sKeyset* keyset)
mKeyset = keyset;
}
void NcaProcess::setCliOutputMode(CliOutputType type)
void NcaProcess::setCliOutputMode(CliOutputMode type)
{
mCliOutputType = type;
mCliOutputMode = type;
}
void NcaProcess::setVerifyMode(bool verify)
@ -458,21 +458,27 @@ void NcaProcess::generateNcaBodyEncryptionKeys()
{
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: ");
fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var));
if (mBodyKeys.aes_ctr.isSet)
{
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()
@ -590,9 +596,7 @@ void NcaProcess::validateNcaSignatures()
// validate signature[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
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] NCA Header Main Signature: FAIL \n");
printf("[WARNING] NCA Header Main Signature: FAIL \n");
}
// validate signature[1]
@ -604,7 +608,7 @@ void NcaProcess::validateNcaSignatures()
{
PfsProcess exefs;
exefs.setInputFile(mPartitions[nx::nca::PARTITION_CODE].reader, SHARED_IFILE);
exefs.setCliOutputMode(OUTPUT_MINIMAL);
exefs.setCliOutputMode(0);
exefs.process();
// open main.npdm
@ -614,38 +618,30 @@ void NcaProcess::validateNcaSignatures()
NpdmProcess npdm;
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();
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
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] NCA Header ACID Signature: FAIL \n");
printf("[WARNING] NCA Header ACID Signature: FAIL \n");
}
}
else
{
// this is minimal even though it's a warning because it's a validation method
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] NCA Header ACID Signature: FAIL (\"%s\" not present in ExeFs)\n", kNpdmExefsPath.c_str());
printf("[WARNING] NCA Header ACID Signature: FAIL (\"%s\" not present in ExeFs)\n", kNpdmExefsPath.c_str());
}
}
else
{
// this is minimal even though it's a warning because it's a validation method
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)\n");
printf("[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)\n");
}
}
else
{
// this is minimal even though it's a warning because it's a validation method
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] NCA Header ACID Signature: FAIL (No ExeFs partition)\n");
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(" <--------------------------------------------------------------------------->\n");
@ -699,70 +695,74 @@ void NcaProcess::displayHeader()
printf(" <--------------------------------------------------------------------------->\n");
}
printf(" Partitions:\n");
for (size_t i = 0; i < mHdr.getPartitions().getSize(); i++)
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
{
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(" Offset: 0x%" PRIx64 "\n", (uint64_t)info.offset);
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size);
printf(" Format Type: %s\n", getFormatTypeStr(info.format_type));
printf(" Hash Type: %s\n", getHashTypeStr(info.hash_type));
printf(" Enc. Type: %s\n", getEncryptionTypeStr(info.enc_type));
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(" %d:\n", (int)i);
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)info.offset);
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size);
printf(" Format Type: %s\n", getFormatTypeStr(info.format_type));
printf(" Hash Type: %s\n", getHashTypeStr(info.hash_type));
printf(" Enc. Type: %s\n", getEncryptionTypeStr(info.enc_type));
if (info.enc_type == nx::nca::CRYPT_AESCTR)
{
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(" 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(" 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(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset);
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size);
printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size);
for (size_t j = 0; j < hash_hdr.getMasterHashList().getSize(); j++)
{
printf(" Master Hash %d: ", (int)j);
fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[j].bytes, sizeof(crypto::sha::sSha256Hash));
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);
printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size);
for (size_t j = 0; j < hash_hdr.getMasterHashList().getSize(); j++)
{
printf(" Master Hash %d: ", (int)j);
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_L
}
@ -791,7 +791,7 @@ void NcaProcess::processPartitions()
{
PfsProcess pfs;
pfs.setInputFile(partition.reader, SHARED_IFILE);
pfs.setCliOutputMode(mCliOutputType);
pfs.setCliOutputMode(mCliOutputMode);
pfs.setListFs(mListFs);
if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM)
{
@ -812,7 +812,7 @@ void NcaProcess::processPartitions()
{
RomfsProcess romfs;
romfs.setInputFile(partition.reader, SHARED_IFILE);
romfs.setCliOutputMode(mCliOutputType);
romfs.setCliOutputMode(mCliOutputMode);
romfs.setListFs(mListFs);
if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM)
{

View file

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

View file

@ -4,7 +4,7 @@ NpdmProcess::NpdmProcess() :
mFile(nullptr),
mOwnIFile(false),
mKeyset(nullptr),
mCliOutputType(OUTPUT_NORMAL),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false)
{
}
@ -37,7 +37,7 @@ void NpdmProcess::process()
validateAciFromAcid(mNpdm.getAci(), mNpdm.getAcid());
}
if (mCliOutputType >= OUTPUT_NORMAL)
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{
// npdm binary
displayNpdmHeader(mNpdm);
@ -67,9 +67,9 @@ void NpdmProcess::setKeyset(const sKeyset* keyset)
mKeyset = keyset;
}
void NpdmProcess::setCliOutputMode(CliOutputType type)
void NpdmProcess::setCliOutputMode(CliOutputMode type)
{
mCliOutputType = type;
mCliOutputMode = type;
}
void NpdmProcess::setVerifyMode(bool verify)
@ -296,9 +296,7 @@ void NpdmProcess::validateAcidSignature(const nx::AcidBinary& acid)
acid.verifyBinary(mKeyset->acid_sign_key);
}
catch (...) {
// this is minimal even though it's a warning because it's a validation method
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] ACID Signature: FAIL\n");
printf("[WARNING] ACID Signature: FAIL\n");
}
}
@ -308,20 +306,17 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
// check Program ID
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())
{
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n");
printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n");
}
// Check FAC
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++)
@ -335,8 +330,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
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 (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 (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 (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
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 (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 (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 (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
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 (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
@ -440,8 +431,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
if (rightFound == false)
{
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++)
@ -456,8 +447,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
if (rightFound == false)
{
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
@ -472,29 +463,25 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi
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
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
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();
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
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
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 (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 setKeyset(const sKeyset* keyset);
void setCliOutputMode(CliOutputType type);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
const nx::NpdmBinary& getNpdmBinary() const;
@ -27,7 +27,7 @@ private:
fnd::IFile* mFile;
bool mOwnIFile;
const sKeyset* mKeyset;
CliOutputType mCliOutputType;
CliOutputMode mCliOutputMode;
bool mVerify;
nx::NpdmBinary mNpdm;

View file

@ -9,7 +9,7 @@
NroProcess::NroProcess():
mFile(nullptr),
mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false),
mInstructionType(nx::npdm::INSTR_64BIT),
mListApi(false),
@ -35,8 +35,11 @@ void NroProcess::process()
importHeader();
importCodeSegments();
importApiList();
displayHeader();
displayRoMetaData();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{
displayHeader();
displayRoMetaData();
}
if (mIsHomebrewNro)
mAssetProc.process();
}
@ -47,9 +50,9 @@ void NroProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile;
}
void NroProcess::setCliOutputMode(CliOutputType type)
void NroProcess::setCliOutputMode(CliOutputMode type)
{
mCliOutputType = type;
mCliOutputMode = type;
}
void NroProcess::setVerifyMode(bool verify)
@ -111,7 +114,7 @@ void NroProcess::importHeader()
{
mIsHomebrewNro = true;
mAssetProc.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNroSize(), mFile->size() - mHdr.getNroSize()), true);
mAssetProc.setCliOutputMode(mCliOutputType);
mAssetProc.setCliOutputMode(mCliOutputMode);
mAssetProc.setVerifyMode(mVerify);
}
else
@ -164,48 +167,45 @@ void NroProcess::importApiList()
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)
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(" 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 (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(" .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());
#undef _HEXDUMP_L
}
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");
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());
}
}
if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || mCliOutputType > OUTPUT_NORMAL))
if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
{
printf("[Symbol List]\n");
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));
}
}
}
const char* NroProcess::getApiTypeStr(SdkApiString::ApiType type) const

View file

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

View file

@ -8,7 +8,7 @@
NsoProcess::NsoProcess():
mFile(nullptr),
mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false),
mInstructionType(nx::npdm::INSTR_64BIT),
mListApi(false),
@ -34,8 +34,11 @@ void NsoProcess::process()
importHeader();
importCodeSegments();
importApiList();
displayNsoHeader();
displayRoMetaData();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{
displayNsoHeader();
displayRoMetaData();
}
}
void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile)
@ -44,9 +47,9 @@ void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile;
}
void NsoProcess::setCliOutputMode(CliOutputType type)
void NsoProcess::setCliOutputMode(CliOutputMode type)
{
mCliOutputType = type;
mCliOutputMode = type;
}
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)
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(" ModuleId: ");
_HEXDUMP_L(mNsoHdr.getModuleId().data, nx::nso::kModuleIdSize);
printf(" Hash: ");
_HEXDUMP_L(mNsoHdr.getTextSegmentInfo().hash.bytes, 32);
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
}
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");
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());
}
}
if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || mCliOutputType > OUTPUT_NORMAL))
if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
{
printf("[Symbol List]\n");
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));
}
}
}
const char* NsoProcess::getApiTypeStr(SdkApiString::ApiType type) const
{
const char* str;

View file

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

View file

@ -5,7 +5,7 @@
PfsProcess::PfsProcess() :
mFile(nullptr),
mOwnIFile(false),
mCliOutputType(OUTPUT_NORMAL),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false),
mExtractPath(),
mExtract(false),
@ -46,10 +46,12 @@ void PfsProcess::process()
mFile->read(scratch.getBytes(), 0, scratch.getSize());
mPfs.importBinary(scratch.getBytes(), scratch.getSize());
if (mCliOutputType >= OUTPUT_NORMAL)
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{
displayHeader();
if (mListFs || mCliOutputType >= OUTPUT_VERBOSE)
displayFs();
if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
displayFs();
}
if (mPfs.getFsType() == mPfs.TYPE_HFS0 && mVerify)
validateHfs();
if (mExtract)
@ -62,9 +64,9 @@ void PfsProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile;
}
void PfsProcess::setCliOutputMode(CliOutputType type)
void PfsProcess::setCliOutputMode(CliOutputMode type)
{
mCliOutputType = type;
mCliOutputMode = type;
}
void PfsProcess::setVerifyMode(bool verify)
@ -107,7 +109,7 @@ void PfsProcess::displayFs()
for (size_t i = 0; i < mPfs.getFileList().getSize(); i++)
{
printf(" %s", mPfs.getFileList()[i].name.c_str());
if (mCliOutputType >= OUTPUT_VERBOSE)
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
{
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);
@ -149,9 +151,7 @@ void PfsProcess::validateHfs()
crypto::sha::Sha256(mCache.getBytes(), file[i].hash_protected_size, hash.bytes);
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, file[i].name);
if (mCliOutputType >= OUTPUT_VERBOSE)
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
printf("extract=[%s]\n", file_path.c_str());
outFile.open(file_path, outFile.Create);

View file

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

View file

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

View file

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

View file

@ -45,8 +45,10 @@ void UserSettings::showHelp()
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(" -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(" -q, --quiet Minimal output\n");
printf("\n XCI (GameCard Image)\n");
printf(" nstool [--listfs] [--update <dir> --logo <dir> --normal <dir> --secure <dir>] <.xci file>\n");
printf(" --listfs Print file system in embedded partitions\n");
@ -101,9 +103,9 @@ bool UserSettings::isVerifyFile() const
return mVerifyFile;
}
CliOutputType UserSettings::getCliOutputType() const
CliOutputMode UserSettings::getCliOutputMode() const
{
return mOutputType;
return mOutputMode;
}
bool UserSettings::isListFs() const
@ -223,18 +225,24 @@ void UserSettings::populateCmdArgs(int argc, char** argv, sCmdArgs& cmd_args)
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")
{
if (hasParamter) throw fnd::Exception(kModuleName, args[i] + " does not take a parameter.");
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")
{
if (!hasParamter) throw fnd::Exception(kModuleName, args[i] + " requries a parameter.");
@ -588,8 +596,6 @@ void UserSettings::populateUserSettings(sCmdArgs& args)
// check invalid input
if (args.input_path.isSet == false)
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
mInputPath = *args.input_path;
@ -618,13 +624,22 @@ void UserSettings::populateUserSettings(sCmdArgs& args)
mAssetIconPath = args.asset_icon_path;
mAssetNacpPath = args.asset_nacp_path;
// determine output path
// determine output mode
mOutputMode = _BIT(OUTPUT_BASIC);
if (args.verbose_output.isSet)
mOutputType = OUTPUT_VERBOSE;
else if (args.minimal_output.isSet)
mOutputType = OUTPUT_MINIMAL;
else
mOutputType = OUTPUT_NORMAL;
{
mOutputMode |= _BIT(OUTPUT_KEY_DATA);
mOutputMode |= _BIT(OUTPUT_LAYOUT);
mOutputMode |= _BIT(OUTPUT_EXTENDED);
}
if (args.show_keys.isSet)
{
mOutputMode |= _BIT(OUTPUT_KEY_DATA);
}
if (args.show_layout.isSet)
{
mOutputMode |= _BIT(OUTPUT_LAYOUT);
}
// determine input file type
if (args.file_type.isSet)

View file

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

View file

@ -7,7 +7,7 @@ XciProcess::XciProcess() :
mFile(nullptr),
mOwnIFile(false),
mKeyset(nullptr),
mCliOutputType(OUTPUT_NORMAL),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false),
mListFs(false),
mRootPfs(),
@ -49,10 +49,8 @@ void XciProcess::process()
mHdr.importBinary(scratch.getBytes(), scratch.getSize());
// display header
if (mCliOutputType >= OUTPUT_NORMAL)
{
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
displayHeader();
}
// process root partition
processRootPfs();
@ -72,9 +70,9 @@ void XciProcess::setKeyset(const sKeyset* keyset)
mKeyset = keyset;
}
void XciProcess::setCliOutputMode(CliOutputType type)
void XciProcess::setCliOutputMode(CliOutputMode type)
{
mCliOutputType = type;
mCliOutputMode = type;
}
void XciProcess::setVerifyMode(bool verify)
@ -142,62 +140,80 @@ inline const char* getCardClockRate(uint32_t acc_ctrl_1)
void XciProcess::displayHeader()
{
printf("[XCI HEADER]\n");
printf(" Magic: HEAD\n");
printf(" RomAreaStartPage: 0x%0x", mHdr.getRomAreaStartPage());
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() != (uint32_t)(-1))
printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage()));
printf("\n");
printf(" KekIndex: %d\n", mHdr.getKekIndex());
printf(" TitleKeyDecIndex: %d\n", mHdr.getTitleKeyDecIndex());
printf(" RomSize: 0x%x (%s)\n", mHdr.getRomSizeType(), getRomSizeStr(mHdr.getRomSizeType()));
printf(" CardHeaderVersion: %d\n", mHdr.getCardHeaderVersion());
printf(" Flags: 0x%x\n", mHdr.getFlags());
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)));
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() != (uint32_t)(-1))
printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getValidDataEndPage()));
printf("\n");
printf(" AesIv: ");
fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv));
printf(" PartitionFs:\n");
printf(" Offset: 0x%" PRIx64 "\n", mHdr.getPartitionFsAddress());
printf(" Size: 0x%" PRIx64 "\n", mHdr.getPartitionFsSize());
printf(" Hash: ");
fnd::SimpleTextOutput::hexDump(mHdr.getPartitionFsHash().bytes, sizeof(mHdr.getPartitionFsHash().bytes));
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("[XCI Header]\n");
printf(" Magic: HEAD\n");
printf(" KekIndex: %d\n", mHdr.getKekIndex());
printf(" TitleKeyDecIndex: %d\n", mHdr.getTitleKeyDecIndex());
printf(" RomSize: 0x%x (%s)\n", mHdr.getRomSizeType(), getRomSizeStr(mHdr.getRomSizeType()));
printf(" CardHeaderVersion: %d\n", mHdr.getCardHeaderVersion());
printf(" Flags: 0x%x\n", mHdr.getFlags());
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)));
printf(" RepairTool: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_REPAIR_TOOL)));
printf(" PackageId: 0x%" PRIx64 "\n", mHdr.getPackageId());
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
printf(" InitialDataHash: \n");
fnd::SimpleTextOutput::hexDump(mHdr.getInitialDataHash().bytes, sizeof(mHdr.getInitialDataHash().bytes));
}
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
printf(" Enc Header AES-IV: ");
fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv));
}
printf(" SelSec: 0x%x\n", mHdr.getSelSec());
printf(" SelT1Key: 0x%x\n", mHdr.getSelT1Key());
printf(" SelKey: 0x%x\n", mHdr.getSelKey());
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
{
printf(" RomAreaStartPage: 0x%0x", mHdr.getRomAreaStartPage());
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() != (uint32_t)(-1))
printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage()));
printf("\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(" ValidDataEndPage: 0x%x", mHdr.getValidDataEndPage());
if (mHdr.getValidDataEndPage() != (uint32_t)(-1))
printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getValidDataEndPage()));
printf("\n");
printf(" LimArea: 0x%x", mHdr.getLimAreaPage());
if (mHdr.getLimAreaPage() != (uint32_t)(-1))
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)
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
printf(" UppHash: ");
printf(" CUP TitleId: %016" PRIx64 "\n", mHdr.getUppId());
printf(" Partition Hash: ");
fnd::SimpleTextOutput::hexDump(mHdr.getUppHash(), 8);
printf(" UppId: %016" PRIx64 "\n", mHdr.getUppId());
}
@ -217,9 +233,7 @@ void XciProcess::validateXciSignature()
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)
{
// this is minimal even though it's a warning because it's a validation method
if (mCliOutputType >= OUTPUT_MINIMAL)
printf("[WARNING] XCI Header Signature: FAIL \n");
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.setListFs(mListFs);
mRootPfs.setVerifyMode(false);
mRootPfs.setCliOutputMode(mCliOutputType);
mRootPfs.setCliOutputMode(mCliOutputMode);
mRootPfs.setMountPointName(kXciMountPointName);
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.setListFs(mListFs);
tmp.setVerifyMode(mVerify);
tmp.setCliOutputMode(mCliOutputType);
tmp.setCliOutputMode(mCliOutputMode);
tmp.setMountPointName(kXciMountPointName + rootPartitions[i].name);
for (size_t j = 0; j < mExtractInfo.size(); j++)
{

View file

@ -20,7 +20,7 @@ public:
// generic
void setInputFile(fnd::IFile* file, bool ownIFile);
void setKeyset(const sKeyset* keyset);
void setCliOutputMode(CliOutputType type);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
// xci specific
@ -34,7 +34,7 @@ private:
fnd::IFile* mFile;
bool mOwnIFile;
const sKeyset* mKeyset;
CliOutputType mCliOutputType;
CliOutputMode mCliOutputMode;
bool mVerify;
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.setKeyset(&user_set.getKeyset());
xci.setCliOutputMode(user_set.getCliOutputType());
xci.setCliOutputMode(user_set.getCliOutputMode());
xci.setVerifyMode(user_set.isVerifyFile());
if (user_set.getXciUpdatePath().isSet)
@ -45,7 +45,7 @@ int main(int argc, char** argv)
PfsProcess pfs;
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());
if (user_set.getFsPath().isSet)
@ -59,7 +59,7 @@ int main(int argc, char** argv)
RomfsProcess romfs;
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());
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.setKeyset(&user_set.getKeyset());
nca.setCliOutputMode(user_set.getCliOutputType());
nca.setCliOutputMode(user_set.getCliOutputMode());
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.setKeyset(&user_set.getKeyset());
npdm.setCliOutputMode(user_set.getCliOutputType());
npdm.setCliOutputMode(user_set.getCliOutputMode());
npdm.setVerifyMode(user_set.isVerifyFile());
npdm.process();
@ -106,7 +106,7 @@ int main(int argc, char** argv)
CnmtProcess cnmt;
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.process();
@ -116,7 +116,7 @@ int main(int argc, char** argv)
NsoProcess obj;
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.setInstructionType(user_set.getInstType());
@ -130,7 +130,7 @@ int main(int argc, char** argv)
NroProcess obj;
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.setInstructionType(user_set.getInstType());
@ -153,7 +153,7 @@ int main(int argc, char** argv)
NacpProcess nacp;
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.process();
@ -163,7 +163,7 @@ int main(int argc, char** argv)
AssetProcess obj;
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());
if (user_set.getAssetIconPath().isSet)

View file

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