Merge branch 'master' of github.com:jakcron/nstool

This commit is contained in:
Jack 2020-06-21 14:31:22 +08:00
commit 7962c8cb0b
28 changed files with 929 additions and 468 deletions

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
bin/*
data/*
*.o
*.a
*.so.*

View file

@ -45,20 +45,33 @@ pki_root_sign_key_private : RSA4096 Private Exponent (0x200 bytes)
; NCA Keys
nca_header_key : AES128-XTS Key (0x20 bytes)
nca_header_sign_key_modulus : RSA2048 Modulus (0x100 bytes)
nca_header_sign_key_private : RSA2048 Private Exponent (0x100 bytes)
nca_header_sign_key_##_modulus : RSA2048 Modulus (0x100 bytes)
nca_header_sign_key_##_private : RSA2048 Private Exponent (0x100 bytes)
nca_body_keak_application_## : AES128 Key (0x10 bytes)
nca_body_keak_ocean_## : AES128 Key (0x10 bytes)
nca_body_keak_system_## : AES128 Key (0x10 bytes)
; NRR Keys
nrr_certificate_sign_key_##_modulus : RSA2048 Modulus (0x100 bytes)
nrr_certificate_sign_key_##_private : RSA2048 Private Exponent (0x100 bytes)
; XCI Keys
xci_header_key : AES128 Key (0x10 bytes)
xci_header_sign_key_modulus : RSA2048 Modulus (0x100 bytes)
xci_header_sign_key_private : RSA2048 Private Exponent (0x100 bytes)
; ACID Keys
acid_sign_key_modulus : RSA2048 Modulus (0x100 bytes)
acid_sign_key_private : RSA2048 Private Exponent (0x100 bytes)
acid_sign_key_##_modulus : RSA2048 Modulus (0x100 bytes)
acid_sign_key_##_private : RSA2048 Private Exponent (0x100 bytes)
```
## Legacy Keynames
Since firmware `9.0.0+` support for signature key generations was retroactively added for RSA-PSS signatures in NRR, ACID and NCA. The old names for these keys are still valid:
```
nca_header_sign_key_modulus : alias for nca_header_sign_key_00_modulus
nca_header_sign_key_private : alias for nca_header_sign_key_00_private
acid_sign_key_modulus : alias for acid_sign_key_00_modulus
acid_sign_key_private : alias for acid_sign_key_00_private
```
## Compatibility with hactool keyset files

2
deps/libfnd vendored

@ -1 +1 @@
Subproject commit 98a6f623361781e5bf4efbec0477efa9729de2cd
Subproject commit 234c81d864e53cd208bb93bce69a1f5ff7e44161

@ -1 +1 @@
Subproject commit 112f9b59a3914dcc06a2713de8c7cd67112c57bb
Subproject commit 9372cb34d8ffdf4c84cc7a25ec9e675fdaff32c6

View file

@ -60,42 +60,59 @@ void CnmtProcess::importCnmt()
void CnmtProcess::displayCnmt()
{
#define _SPLIT_VER(ver) (uint32_t)((ver>>26) & 0x3f) << "." << (uint32_t)((ver>>20) & 0x3f) << "." << (uint32_t)((ver>>16) & 0xf) << "." << (uint32_t)(ver & 0xffff)
std::cout << "[ContentMeta]" << std::endl;
std::cout << " TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getTitleId() << std::endl;
std::cout << " Version: v" << std::dec << mCnmt.getTitleVersion() << " (" << _SPLIT_VER(mCnmt.getTitleVersion()) << ")"<< std::endl;
std::cout << " Type: " << nn::hac::ContentMetaUtil::getContentMetaTypeAsString(mCnmt.getContentMetaType()) << " (" << std::dec << mCnmt.getContentMetaType() << ")" << std::endl;
std::cout << " Attributes: 0x" << std::hex << (uint32_t)mCnmt.getAttributes() << std::endl;
if (mCnmt.getAttributes() != 0)
std::cout << " Version: " << nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getTitleVersion()) << " (v" << std::dec << mCnmt.getTitleVersion() << ")"<< std::endl;
std::cout << " Type: " << nn::hac::ContentMetaUtil::getContentMetaTypeAsString(mCnmt.getContentMetaType()) << " (" << std::dec << (uint32_t)mCnmt.getContentMetaType() << ")" << std::endl;
std::cout << " Attributes: 0x" << std::hex << mCnmt.getAttribute().to_ullong();
if (mCnmt.getAttribute().any())
{
for (size_t bit = 0; bit < (sizeof(byte_t)*8); bit++)
std::vector<std::string> attribute_list;
for (size_t flag = 0; flag < mCnmt.getAttribute().size(); flag++)
{
if (_HAS_BIT(mCnmt.getAttributes(), bit))
if (mCnmt.getAttribute().test(flag))
{
std::cout << " > " << nn::hac::ContentMetaUtil::getContentMetaAttributeAsString((nn::hac::cnmt::ContentMetaAttribute)bit) << std::endl;
attribute_list.push_back(nn::hac::ContentMetaUtil::getContentMetaAttributeFlagAsString(nn::hac::cnmt::ContentMetaAttributeFlag(flag)));
}
}
std::cout << " [";
for (auto itr = attribute_list.begin(); itr != attribute_list.end(); itr++)
{
std::cout << *itr;
if ((itr + 1) != attribute_list.end())
{
std::cout << ", ";
}
std::cout << " RequiredDownloadSystemVersion: v" << mCnmt.getRequiredDownloadSystemVersion() << " (" << _SPLIT_VER(mCnmt.getRequiredDownloadSystemVersion()) << ")"<< std::endl;
}
std::cout << "]";
}
std::cout << std::endl;
std::cout << " StorageId: " << nn::hac::ContentMetaUtil::getStorageIdAsString(mCnmt.getStorageId()) << " (" << std::dec << (uint32_t)mCnmt.getStorageId() << ")" << std::endl;
std::cout << " ContentInstallType: " << nn::hac::ContentMetaUtil::getContentInstallTypeAsString(mCnmt.getContentInstallType()) << " (" << std::dec << (uint32_t)mCnmt.getContentInstallType() << ")" << std::endl;
std::cout << " RequiredDownloadSystemVersion: " << nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getRequiredDownloadSystemVersion()) << " (v" << mCnmt.getRequiredDownloadSystemVersion() << ")"<< std::endl;
switch(mCnmt.getContentMetaType())
{
case (nn::hac::cnmt::METATYPE_APPLICATION):
case (nn::hac::cnmt::ContentMetaType::Application):
std::cout << " ApplicationExtendedHeader:" << std::endl;
std::cout << " RequiredSystemVersion: v" << std::dec << mCnmt.getApplicationMetaExtendedHeader().getRequiredSystemVersion() << " (" << _SPLIT_VER(mCnmt.getApplicationMetaExtendedHeader().getRequiredSystemVersion()) << ")"<< std::endl;
std::cout << " RequiredApplicationVersion: " << nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getApplicationMetaExtendedHeader().getRequiredApplicationVersion()) << " (v" << std::dec << mCnmt.getApplicationMetaExtendedHeader().getRequiredApplicationVersion() << ")"<< std::endl;
std::cout << " RequiredSystemVersion: " << nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getApplicationMetaExtendedHeader().getRequiredSystemVersion()) << " (v" << std::dec << mCnmt.getApplicationMetaExtendedHeader().getRequiredSystemVersion() << ")"<< std::endl;
std::cout << " PatchId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getApplicationMetaExtendedHeader().getPatchId() << std::endl;
break;
case (nn::hac::cnmt::METATYPE_PATCH):
case (nn::hac::cnmt::ContentMetaType::Patch):
std::cout << " PatchMetaExtendedHeader:" << std::endl;
std::cout << " RequiredSystemVersion: v" << std::dec << mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion() << " (" << _SPLIT_VER(mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion()) << ")"<< std::endl;
std::cout << " RequiredSystemVersion: " << nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion()) << " (v" << std::dec << mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion() << ")"<< std::endl;
std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getPatchMetaExtendedHeader().getApplicationId() << std::endl;
break;
case (nn::hac::cnmt::METATYPE_ADD_ON_CONTENT):
case (nn::hac::cnmt::ContentMetaType::AddOnContent):
std::cout << " AddOnContentMetaExtendedHeader:" << std::endl;
std::cout << " RequiredApplicationVersion: v" << std::dec << mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion() << " (" << _SPLIT_VER(mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion()) << ")" << std::endl;
std::cout << " RequiredApplicationVersion: " << nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion()) << " (v" << std::dec << mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion() << ")" << std::endl;
std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getAddOnContentMetaExtendedHeader().getApplicationId() << std::endl;
break;
case (nn::hac::cnmt::METATYPE_DELTA):
case (nn::hac::cnmt::ContentMetaType::Delta):
std::cout << " DeltaMetaExtendedHeader:" << std::endl;
std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getDeltaMetaExtendedHeader().getApplicationId() << std::endl;
break;
@ -109,8 +126,8 @@ void CnmtProcess::displayCnmt()
{
const nn::hac::ContentInfo& info = mCnmt.getContentInfo()[i];
std::cout << " " << std::dec << i << std::endl;
std::cout << " Type: " << nn::hac::ContentMetaUtil::getContentTypeAsString(info.getContentType()) << " (" << std::dec << info.getContentType() << ")" << std::endl;
std::cout << " Id: " << fnd::SimpleTextOutput::arrayToString(info.getContentId().data, nn::hac::cnmt::kContentIdLen, false, "") << std::endl;
std::cout << " Type: " << nn::hac::ContentMetaUtil::getContentTypeAsString(info.getContentType()) << " (" << std::dec << (uint32_t)info.getContentType() << ")" << std::endl;
std::cout << " Id: " << fnd::SimpleTextOutput::arrayToString(info.getContentId().data(), info.getContentId().size(), false, "") << std::endl;
std::cout << " Size: 0x" << std::hex << info.getContentSize() << std::endl;
std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(info.getContentHash().bytes, sizeof(info.getContentHash()), false, "") << std::endl;
}
@ -118,33 +135,88 @@ void CnmtProcess::displayCnmt()
if (mCnmt.getContentMetaInfo().size() > 0)
{
std::cout << " ContentMetaInfo:" << std::endl;
for (size_t i = 0; i < mCnmt.getContentMetaInfo().size(); i++)
displayContentMetaInfoList(mCnmt.getContentMetaInfo(), " ");
}
// print extended data
if (mCnmt.getContentMetaType() == nn::hac::cnmt::ContentMetaType::Patch && mCnmt.getPatchMetaExtendedHeader().getExtendedDataSize() != 0)
{
// this is stubbed as the raw output is for development purposes
//std::cout << " PatchMetaExtendedData:" << std::endl;
//fnd::SimpleTextOutput::hxdStyleDump(mCnmt.getPatchMetaExtendedData().data(), mCnmt.getPatchMetaExtendedData().size());
}
else if (mCnmt.getContentMetaType() == nn::hac::cnmt::ContentMetaType::Delta && mCnmt.getDeltaMetaExtendedHeader().getExtendedDataSize() != 0)
{
// this is stubbed as the raw output is for development purposes
//std::cout << " DeltaMetaExtendedData:" << std::endl;
//fnd::SimpleTextOutput::hxdStyleDump(mCnmt.getDeltaMetaExtendedData().data(), mCnmt.getDeltaMetaExtendedData().size());
}
else if (mCnmt.getContentMetaType() == nn::hac::cnmt::ContentMetaType::SystemUpdate && mCnmt.getSystemUpdateMetaExtendedHeader().getExtendedDataSize() != 0)
{
std::cout << " SystemUpdateMetaExtendedData:" << std::endl;
std::cout << " FormatVersion: " << std::dec << mCnmt.getSystemUpdateMetaExtendedData().getFormatVersion() << std::endl;
std::cout << " FirmwareVariation:" << std::endl;
auto variation_info = mCnmt.getSystemUpdateMetaExtendedData().getFirmwareVariationInfo();
for (size_t i = 0; i < mCnmt.getSystemUpdateMetaExtendedData().getFirmwareVariationInfo().size(); i++)
{
std::cout << " " << std::dec << i << std::endl;
std::cout << " FirmwareVariationId: 0x" << std::hex << variation_info[i].variation_id << std::endl;
if (mCnmt.getSystemUpdateMetaExtendedData().getFormatVersion() == 2)
{
std::cout << " ReferToBase: " << std::boolalpha << variation_info[i].meta.empty() << std::endl;
if (variation_info[i].meta.empty() == false)
{
std::cout << " ContentMeta:" << std::endl;
displayContentMetaInfoList(variation_info[i].meta, " ");
}
}
}
}
std::cout << " Digest: " << fnd::SimpleTextOutput::arrayToString(mCnmt.getDigest().data(), mCnmt.getDigest().size(), false, "") << std::endl;
}
void CnmtProcess::displayContentMetaInfo(const nn::hac::ContentMetaInfo& content_meta_info, const std::string& prefix)
{
std::cout << prefix << "Id: 0x" << std::hex << std::setw(16) << std::setfill('0') << content_meta_info.getTitleId() << std::endl;
std::cout << prefix << "Version: " << nn::hac::ContentMetaUtil::getVersionAsString(content_meta_info.getTitleVersion()) << " (v" << std::dec << content_meta_info.getTitleVersion() << ")"<< std::endl;
std::cout << prefix << "Type: " << nn::hac::ContentMetaUtil::getContentMetaTypeAsString(content_meta_info.getContentMetaType()) << " (" << std::dec << (uint32_t)content_meta_info.getContentMetaType() << ")" << std::endl;
std::cout << prefix << "Attributes: 0x" << std::hex << content_meta_info.getAttribute().to_ullong();
if (content_meta_info.getAttribute().any())
{
std::vector<std::string> attribute_list;
for (size_t flag = 0; flag < content_meta_info.getAttribute().size(); flag++)
{
if (content_meta_info.getAttribute().test(flag))
{
attribute_list.push_back(nn::hac::ContentMetaUtil::getContentMetaAttributeFlagAsString(nn::hac::cnmt::ContentMetaAttributeFlag(flag)));
}
}
std::cout << " [";
for (auto itr = attribute_list.begin(); itr != attribute_list.end(); itr++)
{
std::cout << *itr;
if ((itr + 1) != attribute_list.end())
{
std::cout << ", ";
}
}
std::cout << "]";
}
}
void CnmtProcess::displayContentMetaInfoList(const std::vector<nn::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix)
{
for (size_t i = 0; i < content_meta_info_list.size(); i++)
{
const nn::hac::ContentMetaInfo& info = mCnmt.getContentMetaInfo()[i];
std::cout << " " << std::dec << i << std::endl;
std::cout << " Id: 0x" << std::hex << std::setw(16) << std::setfill('0') << info.getTitleId() << std::endl;
std::cout << " Version: v" << std::dec << info.getTitleVersion() << " (" << _SPLIT_VER(info.getTitleVersion()) << ")"<< std::endl;
std::cout << " Type: " << nn::hac::ContentMetaUtil::getContentMetaTypeAsString(info.getContentMetaType()) << " (" << std::dec << info.getContentMetaType() << ")" << std::endl;
std::cout << " Attributes: 0x" << std::hex << (uint32_t)info.getAttributes() << std::endl;
if (info.getAttributes() != 0)
{
for (size_t bit = 0; bit < (sizeof(byte_t)*8); bit++)
{
if (_HAS_BIT(info.getAttributes(), bit))
{
std::cout << " > " << nn::hac::ContentMetaUtil::getContentMetaAttributeAsString((nn::hac::cnmt::ContentMetaAttribute)bit) << std::endl;
std::cout << prefix << std::dec << i << std::endl;
displayContentMetaInfo(info, prefix + " ");
std::cout << std::endl;
}
}
}
}
}
std::cout << " Digest: " << fnd::SimpleTextOutput::arrayToString(mCnmt.getDigest().data, nn::hac::cnmt::kDigestLen, false, "") << std::endl;
#undef _SPLIT_VER
}
const char* CnmtProcess::getBoolStr(bool state) const
{
return state? "TRUE" : "FALSE";
}

View file

@ -32,5 +32,6 @@ private:
void importCnmt();
void displayCnmt();
const char* getBoolStr(bool state) const;
void displayContentMetaInfo(const nn::hac::ContentMetaInfo& content_meta_info, const std::string& prefix);
void displayContentMetaInfoList(const std::vector<nn::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix);
};

View file

@ -3,6 +3,8 @@
#include <fnd/SimpleTextOutput.h>
#include <fnd/OffsetAdjustedIFile.h>
#include <nn/hac/GameCardUtil.h>
#include <nn/hac/ContentMetaUtil.h>
#include <nn/hac/ContentArchiveUtil.h>
#include "GameCardProcess.h"
GameCardProcess::GameCardProcess() :
@ -138,9 +140,9 @@ void GameCardProcess::displayHeader()
}
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " InitialData:" << std::endl;
std::cout << " KekIndex: " << nn::hac::GameCardUtil::getKekIndexAsString((nn::hac::gc::KekIndex)mHdr.getKekIndex()) << " (" << std::dec << (uint32_t)mHdr.getKekIndex() << ")" << std::endl;
std::cout << " TitleKeyDecIndex: " << std::dec << (uint32_t)mHdr.getTitleKeyDecIndex() << std::endl;
std::cout << " InitialData:" << std::endl;
std::cout << " Hash:" << std::endl;
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes, 0x10, true, ":") << std::endl;
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes+0x10, 0x10, true, ":") << std::endl;
@ -197,27 +199,40 @@ void GameCardProcess::displayHeader()
std::cout << " Wait2TimeRead: 0x" << std::hex << mHdr.getWait2TimeRead() << std::endl;
std::cout << " Wait1TimeWrite: 0x" << std::hex << mHdr.getWait1TimeWrite() << std::endl;
std::cout << " Wait2TimeWrite: 0x" << std::hex << mHdr.getWait2TimeWrite() << std::endl;
std::cout << " FwMode: 0x" << std::hex << mHdr.getFwMode() << std::endl;
std::cout << " CompatibilityType: " << nn::hac::GameCardUtil::getCompatibilityTypeAsString((nn::hac::gc::CompatibilityType)mHdr.getCompatibilityType()) << "(" << std::dec << mHdr.getCompatibilityType() << ")" << std::endl;
std::cout << " SdkAddon Version: " << nn::hac::ContentArchiveUtil::getSdkAddonVersionAsString(mHdr.getFwMode()) << " (v" << std::dec << mHdr.getFwMode() << ")" << std::endl;
std::cout << " CompatibilityType: " << nn::hac::GameCardUtil::getCompatibilityTypeAsString((nn::hac::gc::CompatibilityType)mHdr.getCompatibilityType()) << " (" << std::dec << (uint32_t) mHdr.getCompatibilityType() << ")" << std::endl;
std::cout << " Update Partition Info:" << std::endl;
#define _SPLIT_VER(ver) std::dec << ((ver>>26) & 0x3f) << "." << ((ver>>20) & 0x3f) << "." << ((ver>>16) & 0xf) << "." << (ver & 0xffff)
std::cout << " CUP Version: v" << std::dec << mHdr.getUppVersion() << " (" << _SPLIT_VER(mHdr.getUppVersion()) << ")" << std::endl;
#undef _SPLIT_VER
std::cout << " CUP Version: " << nn::hac::ContentMetaUtil::getVersionAsString(mHdr.getUppVersion()) << " (v" << std::dec << mHdr.getUppVersion() << ")" << std::endl;
std::cout << " CUP TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getUppId() << std::endl;
std::cout << " CUP Digest: " << fnd::SimpleTextOutput::arrayToString(mHdr.getUppHash(), 8, true, ":") << std::endl;
}
}
bool GameCardProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash)
bool GameCardProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash, bool use_salt, byte_t salt)
{
fnd::Vec<byte_t> scratch;
fnd::sha::sSha256Hash calc_hash;
if (use_salt)
{
scratch.alloc(len + 1);
scratch.data()[len] = salt;
}
else
{
scratch.alloc(len);
(*mFile)->read(scratch.data(), offset, scratch.size());
}
(*mFile)->read(scratch.data(), offset, len);
fnd::sha::Sha256(scratch.data(), scratch.size(), calc_hash.bytes);
return calc_hash.compare(test_hash);
}
bool GameCardProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash)
{
return validateRegionOfFile(offset, len, test_hash, false, 0);
}
void GameCardProcess::validateXciSignature()
{
fnd::rsa::sRsa2048Key header_sign_key;
@ -231,7 +246,7 @@ void GameCardProcess::validateXciSignature()
void GameCardProcess::processRootPfs()
{
if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize(), mHdr.getPartitionFsHash().bytes) == false)
if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize(), mHdr.getPartitionFsHash().bytes, mHdr.getCompatibilityType() != nn::hac::gc::COMPAT_GLOBAL, mHdr.getCompatibilityType()) == false)
{
std::cout << "[WARNING] GameCard Root HFS0: FAIL (bad hash)" << std::endl;
}

View file

@ -69,6 +69,7 @@ private:
void importHeader();
void displayHeader();
bool validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash, bool use_salt, byte_t salt);
bool validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash);
void validateXciSignature();
void processRootPfs();

View file

@ -16,9 +16,7 @@ KeyConfiguration::KeyConfiguration(const KeyConfiguration& other)
void KeyConfiguration::operator=(const KeyConfiguration& other)
{
mAcidSignKey = other.mAcidSignKey;
mPkg2SignKey = other.mPkg2SignKey;
mContentArchiveHeader0SignKey = other.mContentArchiveHeader0SignKey;
mXciHeaderSignKey = other.mXciHeaderSignKey;
mContentArchiveHeaderKey = other.mContentArchiveHeaderKey;
@ -26,6 +24,9 @@ void KeyConfiguration::operator=(const KeyConfiguration& other)
for (size_t i = 0; i < kMasterKeyNum; i++)
{
mAcidSignKey[i] = other.mAcidSignKey[i];
mContentArchiveHeader0SignKey[i] = other.mContentArchiveHeader0SignKey[i];
mNrrCertificateSignKey[i] = other.mNrrCertificateSignKey[i];
mPkg2Key[i] = other.mPkg2Key[i];
mPkg1Key[i] = other.mPkg1Key[i];
mNcaKeyAreaEncryptionKey[0][i] = other.mNcaKeyAreaEncryptionKey[0][i];
@ -69,6 +70,7 @@ void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path)
#define _CONCAT_2_STRINGS(str1, str2) ((str1) + "_" + (str2))
#define _CONCAT_3_STRINGS(str1, str2, str3) _CONCAT_2_STRINGS(_CONCAT_2_STRINGS(str1, str2), str3)
#define _CONCAT_4_STRINGS(str1, str2, str3, str4) _CONCAT_2_STRINGS(_CONCAT_2_STRINGS(_CONCAT_2_STRINGS(str1, str2), str3), str4)
std::string key,val;
fnd::Vec<byte_t> dec_array;
@ -93,8 +95,8 @@ void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path)
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[2], kSourceStr), key_area_key_source[2].key, 0x10);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kKekGenBase[nameidx], kSourceStr), aes_kek_generation_source.key, 0x10);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kKeyGenBase[nameidx], kSourceStr), aes_key_generation_source.key, 0x10);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kXciHeaderBase[nameidx], kKekStr, kSourceStr), nca_header_kek_source.key, 0x10);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kXciHeaderBase[nameidx], kKeyStr, kSourceStr), nca_header_key_source.key, 0x20);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kContentArchiveHeaderBase[nameidx], kKekStr, kSourceStr), nca_header_kek_source.key, 0x10);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kContentArchiveHeaderBase[nameidx], kKeyStr, kSourceStr), nca_header_key_source.key, 0x20);
// Store Key Variants/Derivatives
for (size_t mkeyidx = 0; mkeyidx < kMasterKeyNum; mkeyidx++)
@ -110,6 +112,13 @@ void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path)
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[0], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[0][mkeyidx].key, 0x10);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[1], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[1][mkeyidx].key, 0x10);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[2], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[2][mkeyidx].key, 0x10);
_SAVE_KEYDATA(_CONCAT_4_STRINGS(kContentArchiveHeaderBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kPrivateStr), mContentArchiveHeader0SignKey[mkeyidx].priv_exponent, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_4_STRINGS(kContentArchiveHeaderBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kModulusStr), mContentArchiveHeader0SignKey[mkeyidx].modulus, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_4_STRINGS(kAcidBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kPrivateStr), mAcidSignKey[mkeyidx].priv_exponent, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_4_STRINGS(kAcidBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kModulusStr), mAcidSignKey[mkeyidx].modulus, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_4_STRINGS(kNrrCertBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kPrivateStr), mNrrCertificateSignKey[mkeyidx].priv_exponent, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_4_STRINGS(kNrrCertBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kModulusStr), mNrrCertificateSignKey[mkeyidx].modulus, fnd::rsa::kRsa2048Size);
}
// store nca header key
@ -119,20 +128,23 @@ void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path)
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kKeyStr), mXciHeaderKey.key, 0x10);
// store rsa keys
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kContentArchiveHeaderBase[nameidx], kRsaKeyPrivate), mContentArchiveHeader0SignKey.priv_exponent, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kContentArchiveHeaderBase[nameidx], kRsaKeyModulus), mContentArchiveHeader0SignKey.modulus, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kRsaKeyPrivate), mXciHeaderSignKey.priv_exponent, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kRsaKeyModulus), mXciHeaderSignKey.modulus, fnd::rsa::kRsa2048Size);
// legacy header nca key name
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kContentArchiveHeaderBase[nameidx], kSignKey, kPrivateStr), mContentArchiveHeader0SignKey[0].priv_exponent, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kContentArchiveHeaderBase[nameidx], kSignKey, kModulusStr), mContentArchiveHeader0SignKey[0].modulus, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase[nameidx], kRsaKeyPrivate), mAcidSignKey.priv_exponent, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase[nameidx], kRsaKeyModulus), mAcidSignKey.modulus, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kXciHeaderBase[nameidx], kSignKey, kPrivateStr), mXciHeaderSignKey.priv_exponent, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kXciHeaderBase[nameidx], kSignKey, kModulusStr), mXciHeaderSignKey.modulus, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkg2Base[nameidx], kRsaKeyPrivate), mPkg2SignKey.priv_exponent, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkg2Base[nameidx], kRsaKeyModulus), mPkg2SignKey.modulus, fnd::rsa::kRsa2048Size);
// legacy acid header key name
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kAcidBase[nameidx], kSignKey, kPrivateStr), mAcidSignKey[0].priv_exponent, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kAcidBase[nameidx], kSignKey, kModulusStr), mAcidSignKey[0].modulus, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase[nameidx], kRsaKeyPrivate), pki_root_sign_key.priv_exponent, fnd::rsa::kRsa4096Size);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase[nameidx], kRsaKeyModulus), pki_root_sign_key.modulus, fnd::rsa::kRsa4096Size);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg2Base[nameidx], kSignKey, kPrivateStr), mPkg2SignKey.priv_exponent, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg2Base[nameidx], kSignKey, kModulusStr), mPkg2SignKey.modulus, fnd::rsa::kRsa2048Size);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkiRootBase[nameidx], kSignKey, kPrivateStr), pki_root_sign_key.priv_exponent, fnd::rsa::kRsa4096Size);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkiRootBase[nameidx], kSignKey, kModulusStr), pki_root_sign_key.modulus, fnd::rsa::kRsa4096Size);
}
#undef _SAVE_KEYDATA
@ -193,9 +205,9 @@ void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path)
void KeyConfiguration::clearGeneralKeyConfiguration()
{
mAcidSignKey = kNullRsa2048Key;
mPkg2SignKey = kNullRsa2048Key;
mContentArchiveHeader0SignKey = kNullRsa2048Key;
mXciHeaderSignKey = kNullRsa2048Key;
mPkiRootKeyList.clear();
@ -204,6 +216,9 @@ void KeyConfiguration::clearGeneralKeyConfiguration()
for (size_t i = 0; i < kMasterKeyNum; i++)
{
mAcidSignKey[i] = kNullRsa2048Key;
mContentArchiveHeader0SignKey[i] = kNullRsa2048Key;
mNrrCertificateSignKey[i] = kNullRsa2048Key;
mPkg1Key[i] = kNullAesKey;
mPkg2Key[i] = kNullAesKey;
mETicketCommonKey[i] = kNullAesKey;
@ -225,14 +240,26 @@ bool KeyConfiguration::getContentArchiveHeaderKey(fnd::aes::sAesXts128Key& key)
return copyOutKeyResourceIfExists(mContentArchiveHeaderKey, key, kNullAesXtsKey);
}
bool KeyConfiguration::getContentArchiveHeader0SignKey(fnd::rsa::sRsa2048Key& key) const
bool KeyConfiguration::getContentArchiveHeader0SignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const
{
return copyOutKeyResourceIfExists(mContentArchiveHeader0SignKey, key, kNullRsa2048Key);
// TODO: This needs to be changed to support multiple keys
if (key_generation >= kMasterKeyNum)
{
return false;
}
bool KeyConfiguration::getAcidSignKey(fnd::rsa::sRsa2048Key& key) const
return copyOutKeyResourceIfExists(mContentArchiveHeader0SignKey[key_generation], key, kNullRsa2048Key);
}
bool KeyConfiguration::getAcidSignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const
{
return copyOutKeyResourceIfExists(mAcidSignKey, key, kNullRsa2048Key);
// TODO: This needs to be changed to support multiple keys
if (key_generation >= kMasterKeyNum)
{
return false;
}
return copyOutKeyResourceIfExists(mAcidSignKey[key_generation], key, kNullRsa2048Key);
}
bool KeyConfiguration::getNcaKeyAreaEncryptionKey(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const
@ -284,6 +311,17 @@ bool KeyConfiguration::getNcaExternalContentKey(const byte_t rights_id[nn::hac::
return res_exists;
}
bool KeyConfiguration::getNrrCertificateSignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const
{
// TODO: This needs to be changed to support multiple keys
if (key_generation >= kMasterKeyNum)
{
return false;
}
return copyOutKeyResourceIfExists(mNrrCertificateSignKey[key_generation], key, kNullRsa2048Key);
}
bool KeyConfiguration::getPkg1Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const
{
if (masterkey_index >= kMasterKeyNum)

View file

@ -25,8 +25,8 @@ public:
// nca keys
bool getContentArchiveHeaderKey(fnd::aes::sAesXts128Key& key) const;
bool getContentArchiveHeader0SignKey(fnd::rsa::sRsa2048Key& key) const;
bool getAcidSignKey(fnd::rsa::sRsa2048Key& key) const;
bool getContentArchiveHeader0SignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const;
bool getAcidSignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const;
bool getNcaKeyAreaEncryptionKey(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const;
bool getNcaKeyAreaEncryptionKeyHw(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const;
@ -34,6 +34,9 @@ public:
void addNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], const fnd::aes::sAes128Key& key);
bool getNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], fnd::aes::sAes128Key& key) const;
// nrr key
bool getNrrCertificateSignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const;
// pkg1/pkg2
bool getPkg1Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const;
bool getPkg2Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const;
@ -73,6 +76,7 @@ private:
const std::string kXciHeaderBase[kNameVariantNum] = { "xci_header", "xci_header", "xci_header" };
const std::string kContentArchiveHeaderBase[kNameVariantNum] = { "nca_header", "header", "nca_header" };
const std::string kAcidBase[kNameVariantNum] = { "acid", "acid", "acid" };
const std::string kNrrCertBase[kNameVariantNum] = { "nrr_certificate", "nrr_certificate", "nrr_certificate" };
const std::string kPkiRootBase[kNameVariantNum] = { "pki_root", "pki_root", "pki_root" };
const std::string kTicketCommonKeyBase[kNameVariantNum] = { "ticket_commonkey", "titlekek", "ticket_commonkey" };
const std::string kNcaKeyAreaEncKeyBase[kNameVariantNum] = { "nca_key_area_key", "key_area_key", "nca_body_keak" };
@ -84,8 +88,9 @@ private:
const std::string kKeyStr = "key";
const std::string kKekStr = "kek";
const std::string kSourceStr = "source";
const std::string kRsaKeyModulus = "sign_key_modulus";
const std::string kRsaKeyPrivate = "sign_key_private";
const std::string kSignKey = "sign_key";
const std::string kModulusStr = "modulus";
const std::string kPrivateStr = "private";
const std::string kNcaKeyAreaKeyIndexStr[kNcaKeakNum] = { "application", "ocean", "system" };
const std::string kKeyIndex[kMasterKeyNum] = {"00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f","10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f"};
@ -167,7 +172,7 @@ private:
/* general key config */
// acid
fnd::rsa::sRsa2048Key mAcidSignKey;
fnd::rsa::sRsa2048Key mAcidSignKey[kMasterKeyNum];
// pkg1 and pkg2
fnd::aes::sAes128Key mPkg1Key[kMasterKeyNum];
@ -175,11 +180,14 @@ private:
fnd::aes::sAes128Key mPkg2Key[kMasterKeyNum];
// nca
fnd::rsa::sRsa2048Key mContentArchiveHeader0SignKey;
fnd::rsa::sRsa2048Key mContentArchiveHeader0SignKey[kMasterKeyNum];
fnd::aes::sAesXts128Key mContentArchiveHeaderKey;
fnd::aes::sAes128Key mNcaKeyAreaEncryptionKey[kNcaKeakNum][kMasterKeyNum];
fnd::aes::sAes128Key mNcaKeyAreaEncryptionKeyHw[kNcaKeakNum][kMasterKeyNum];
// nrr
fnd::rsa::sRsa2048Key mNrrCertificateSignKey[kMasterKeyNum];
// xci
fnd::rsa::sRsa2048Key mXciHeaderSignKey;
fnd::aes::sAes128Key mXciHeaderKey;

View file

@ -8,8 +8,6 @@
#include <fnd/Vec.h>
#include <nn/hac/KernelCapabilityUtil.h>
#include <nn/hac/KernelInitialProcessUtil.h>
KipProcess::KipProcess():
mFile(),
@ -147,10 +145,10 @@ void KipProcess::displayHeader()
std::cout << " Meta:" << std::endl;
std::cout << " Name: " << mHdr.getName() << std::endl;
std::cout << " TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getTitleId() << std::endl;
std::cout << " ProcessCategory: " << nn::hac::KernelInitialProcessUtil::getProcessCategoryAsString(mHdr.getProcessCategory()) << std::endl;
std::cout << " InstructionType: " << getInstructionTypeStr(mHdr.getFlagList().hasElement(nn::hac::kip::FLAG_INSTRUCTION_64BIT)) << std::endl;
std::cout << " AddrSpaceWidth: " << getAddressSpaceStr(mHdr.getFlagList().hasElement(nn::hac::kip::FLAG_ADDR_SPACE_64BIT)) << std::endl;
std::cout << " MemoryPool: " << getMemoryPoolStr(mHdr.getFlagList().hasElement(nn::hac::kip::FLAG_USE_SYSTEM_POOL_PARTITION)) << std::endl;
std::cout << " Version: v" << std::dec << mHdr.getVersion() << std::endl;
std::cout << " Is64BitInstruction: " << std::boolalpha << mHdr.getIs64BitInstructionFlag() << std::endl;
std::cout << " Is64BitAddressSpace: " << std::boolalpha << mHdr.getIs64BitAddressSpaceFlag() << std::endl;
std::cout << " UseSecureMemory: " << std::boolalpha << mHdr.getUseSecureMemoryFlag() << std::endl;
std::cout << " Program Sections:" << std::endl;
std::cout << " .text:" << std::endl;
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
@ -197,25 +195,15 @@ void KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
if (kern.getSystemCalls().isSet())
{
fnd::List<nn::hac::kc::SystemCall> syscalls = kern.getSystemCalls().getSystemCalls();
auto syscall_ids = kern.getSystemCalls().getSystemCallIds();
std::cout << " SystemCalls:" << std::endl;
std::cout << " ";
size_t lineLen = 0;
for (size_t i = 0; i < syscalls.size(); i++)
std::vector<std::string> syscall_names;
for (size_t syscall_id = 0; syscall_id < syscall_ids.size(); syscall_id++)
{
if (lineLen > 60)
{
lineLen = 0;
std::cout << std::endl;
std::cout << " ";
if (syscall_ids.test(syscall_id))
syscall_names.push_back(nn::hac::KernelCapabilityUtil::getSystemCallIdAsString(nn::hac::kc::SystemCallId(syscall_id)));
}
std::string syscall_string = nn::hac::KernelCapabilityUtil::getSystemCallAsString(syscalls[i]);
std::cout << syscall_string;
if (syscalls[i] != syscalls.atBack())
std::cout << ", ";
lineLen += syscall_string.length();
}
std::cout << std::endl;
fnd::SimpleTextOutput::dumpStringList(syscall_names, 60, 4);
}
if (kern.getMemoryMaps().isSet())
{
@ -225,12 +213,12 @@ void KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
std::cout << " MemoryMaps:" << std::endl;
for (size_t i = 0; i < maps.size(); i++)
{
std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)maps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1) << " (perm=" << nn::hac::KernelCapabilityUtil::getMemMapPermAsString(maps[i].perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMemMapTypeAsString(maps[i].type) << ")" << std::endl;
std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)maps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1) << " (perm=" << nn::hac::KernelCapabilityUtil::getMemoryPermissionAsString(maps[i].perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMappingTypeAsString(maps[i].type) << ")" << std::endl;
}
//std::cout << " IoMaps:" << std::endl;
for (size_t i = 0; i < ioMaps.size(); i++)
{
std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)ioMaps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1) << " (perm=" << nn::hac::KernelCapabilityUtil::getMemMapPermAsString(ioMaps[i].perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMemMapTypeAsString(ioMaps[i].type) << ")" << std::endl;
std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)ioMaps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1) << " (perm=" << nn::hac::KernelCapabilityUtil::getMemoryPermissionAsString(ioMaps[i].perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMappingTypeAsString(ioMaps[i].type) << ")" << std::endl;
}
}
if (kern.getInterupts().isSet())
@ -253,7 +241,7 @@ void KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
}
if (kern.getMiscParams().isSet())
{
std::cout << " ProgramType: " << std::dec << (uint32_t)kern.getMiscParams().getProgramType() << std::endl;
std::cout << " ProgramType: " << nn::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()) << " (" << std::dec << (uint32_t)kern.getMiscParams().getProgramType() << ")" << std::endl;
}
if (kern.getKernelVersion().isSet())
{
@ -265,36 +253,14 @@ void KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
}
if (kern.getMiscFlags().isSet())
{
fnd::List<nn::hac::kc::MiscFlags> flagList = kern.getMiscFlags().getFlagList();
auto misc_flags = kern.getMiscFlags().getMiscFlags();
std::cout << " Misc Flags:" << std::endl;
for (uint32_t i = 0; i < flagList.size(); i++)
std::vector<std::string> misc_flags_names;
for (size_t misc_flags_bit = 0; misc_flags_bit < misc_flags.size(); misc_flags_bit++)
{
if (i % 10 == 0)
{
if (i != 0)
std::cout << std::endl;
std::cout << " ";
if (misc_flags.test(misc_flags_bit))
misc_flags_names.push_back(nn::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(nn::hac::kc::MiscFlagsBit(misc_flags_bit)));
}
std::cout << nn::hac::KernelCapabilityUtil::getMiscFlagAsString(flagList[i]);
if (flagList[i] != flagList.atBack())
std::cout << ", ";
std::cout << std::endl;
fnd::SimpleTextOutput::dumpStringList(misc_flags_names, 60, 4);
}
}
}
const char* KipProcess::getInstructionTypeStr(bool is64Bit) const
{
return is64Bit? "64Bit" : "32Bit";
}
const char* KipProcess::getAddressSpaceStr(bool is64Bit) const
{
return is64Bit? "64Bit" : "32Bit";
}
const char* KipProcess::getMemoryPoolStr(bool isSystemPool) const
{
return isSystemPool? "System" : "Application";
}

View file

@ -32,8 +32,4 @@ private:
void importCodeSegments();
void displayHeader();
void displayKernelCap(const nn::hac::KernelCapabilityControl& kern);
const char* getInstructionTypeStr(bool is64Bit) const;
const char* getAddressSpaceStr(bool is64Bit) const;
const char* getMemoryPoolStr(bool isSystemPool) const;
};

View file

@ -8,6 +8,8 @@
#include <nn/hac/KernelCapabilityUtil.h>
#include <nn/hac/MetaUtil.h>
#include <fnd/SimpleTextOutput.h>
MetaProcess::MetaProcess() :
mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
@ -21,8 +23,8 @@ void MetaProcess::process()
if (mVerify)
{
validateAcidSignature(mMeta.getAcid());
validateAciFromAcid(mMeta.getAci(), mMeta.getAcid());
validateAcidSignature(mMeta.getAccessControlInfoDesc(), mMeta.getAccessControlInfoDescKeyGeneration());
validateAciFromAcid(mMeta.getAccessControlInfo(), mMeta.getAccessControlInfoDesc());
}
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
@ -31,18 +33,18 @@ void MetaProcess::process()
displayMetaHeader(mMeta);
// aci binary
displayAciHdr(mMeta.getAci());
displayFac(mMeta.getAci().getFileSystemAccessControl());
displaySac(mMeta.getAci().getServiceAccessControl());
displayKernelCap(mMeta.getAci().getKernelCapabilities());
displayAciHdr(mMeta.getAccessControlInfo());
displayFac(mMeta.getAccessControlInfo().getFileSystemAccessControl());
displaySac(mMeta.getAccessControlInfo().getServiceAccessControl());
displayKernelCap(mMeta.getAccessControlInfo().getKernelCapabilities());
// acid binary
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
displayAciDescHdr(mMeta.getAcid());
displayFac(mMeta.getAcid().getFileSystemAccessControl());
displaySac(mMeta.getAcid().getServiceAccessControl());
displayKernelCap(mMeta.getAcid().getKernelCapabilities());
displayAciDescHdr(mMeta.getAccessControlInfoDesc());
displayFac(mMeta.getAccessControlInfoDesc().getFileSystemAccessControl());
displaySac(mMeta.getAccessControlInfoDesc().getServiceAccessControl());
displayKernelCap(mMeta.getAccessControlInfoDesc().getKernelCapabilities());
}
}
}
@ -87,11 +89,11 @@ void MetaProcess::importMeta()
mMeta.fromBytes(scratch.data(), scratch.size());
}
void MetaProcess::validateAcidSignature(const nn::hac::AccessControlInfoDesc& acid)
void MetaProcess::validateAcidSignature(const nn::hac::AccessControlInfoDesc& acid, byte_t key_generation)
{
try {
fnd::rsa::sRsa2048Key acid_sign_key;
if (mKeyCfg.getAcidSignKey(acid_sign_key) != true)
if (mKeyCfg.getAcidSignKey(acid_sign_key, key_generation) != true)
throw fnd::Exception();
acid.validateSignature(acid_sign_key);
@ -114,19 +116,13 @@ void MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo& aci, con
std::cout << "[WARNING] ACI ProgramId: FAIL (Outside Legal Range)" << std::endl;
}
for (size_t i = 0; i < aci.getFileSystemAccessControl().getFsaRightsList().size(); i++)
auto fs_access = aci.getFileSystemAccessControl().getFsAccess();
auto desc_fs_access = acid.getFileSystemAccessControl().getFsAccess();
for (size_t i = 0; i < fs_access.size(); i++)
{
bool fsaRightFound = false;
for (size_t j = 0; j < acid.getFileSystemAccessControl().getFsaRightsList().size() && fsaRightFound == false; j++)
if (fs_access.test(i) && desc_fs_access.test(i) == false)
{
if (aci.getFileSystemAccessControl().getFsaRightsList()[i] == acid.getFileSystemAccessControl().getFsaRightsList()[j])
fsaRightFound = true;
}
if (fsaRightFound == false)
{
std::cout << "[WARNING] ACI/FAC FsaRights: FAIL (" << nn::hac::FileSystemAccessUtil::getFsaRightAsString(aci.getFileSystemAccessControl().getFsaRightsList()[i]) << " not permitted)" << std::endl;
std::cout << "[WARNING] ACI/FAC FsaRights: FAIL (" << nn::hac::FileSystemAccessUtil::getFsAccessFlagAsString(nn::hac::fac::FsAccessFlag(i)) << " not permitted)" << std::endl;
}
}
@ -197,18 +193,13 @@ void MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo& aci, con
std::cout << "[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMinPriority() << " not permitted)" << std::endl;
}
// check system calls
for (size_t i = 0; i < aci.getKernelCapabilities().getSystemCalls().getSystemCalls().size(); i++)
auto syscall_ids = aci.getKernelCapabilities().getSystemCalls().getSystemCallIds();
auto desc_syscall_ids = acid.getKernelCapabilities().getSystemCalls().getSystemCallIds();
for (size_t i = 0; i < syscall_ids.size(); i++)
{
bool rightFound = false;
for (size_t j = 0; j < acid.getKernelCapabilities().getSystemCalls().getSystemCalls().size() && rightFound == false; j++)
if (syscall_ids.test(i) && desc_syscall_ids.test(i) == false)
{
if (aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i] == acid.getKernelCapabilities().getSystemCalls().getSystemCalls()[j])
rightFound = true;
}
if (rightFound == false)
{
std::cout << "[WARNING] ACI/KC SystemCallList: FAIL (" << nn::hac::KernelCapabilityUtil::getSystemCallAsString(aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i]) << " not permitted)" << std::endl;
std::cout << "[WARNING] ACI/KC SystemCallList: FAIL (" << nn::hac::KernelCapabilityUtil::getSystemCallIdAsString(nn::hac::kc::SystemCallId(i)) << " not permitted)" << std::endl;
}
}
// check memory maps
@ -223,9 +214,9 @@ void MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo& aci, con
if (rightFound == false)
{
const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getMemoryMaps()[i];
auto map = aci.getKernelCapabilities().getMemoryMaps().getMemoryMaps()[i];
std::cout << "[WARNING] ACI/KC MemoryMap: FAIL (0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)map.addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(map.addr + map.size) << 12) - 1) << " (perm=" << nn::hac::KernelCapabilityUtil::getMemMapPermAsString(map.perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMemMapTypeAsString(map.type) << ") not permitted)" << std::endl;
std::cout << "[WARNING] ACI/KC MemoryMap: FAIL (0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)map.addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(map.addr + map.size) << 12) - 1) << " (perm=" << nn::hac::KernelCapabilityUtil::getMemoryPermissionAsString(map.perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMappingTypeAsString(map.type) << ") not permitted)" << std::endl;
}
}
for (size_t i = 0; i < aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps().size(); i++)
@ -239,9 +230,9 @@ void MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo& aci, con
if (rightFound == false)
{
const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps()[i];
auto map = aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps()[i];
std::cout << "[WARNING] ACI/KC IoMemoryMap: FAIL (0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)map.addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(map.addr + map.size) << 12) - 1) << " (perm=" << nn::hac::KernelCapabilityUtil::getMemMapPermAsString(map.perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMemMapTypeAsString(map.type) << ") not permitted)" << std::endl;
std::cout << "[WARNING] ACI/KC IoMemoryMap: FAIL (0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)map.addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(map.addr + map.size) << 12) - 1) << " (perm=" << nn::hac::KernelCapabilityUtil::getMemoryPermissionAsString(map.perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMappingTypeAsString(map.type) << ") not permitted)" << std::endl;
}
}
// check interupts
@ -277,18 +268,13 @@ void MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo& aci, con
std::cout << "[WARNING] ACI/KC HandleTableSize: FAIL (0x" << std::hex << (uint32_t)aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize() << " too large)" << std::endl;
}
// check misc flags
for (size_t i = 0; i < aci.getKernelCapabilities().getMiscFlags().getFlagList().size(); i++)
auto misc_flags = aci.getKernelCapabilities().getMiscFlags().getMiscFlags();
auto desc_misc_flags = acid.getKernelCapabilities().getMiscFlags().getMiscFlags();
for (size_t i = 0; i < misc_flags.size(); i++)
{
bool rightFound = false;
for (size_t j = 0; j < acid.getKernelCapabilities().getMiscFlags().getFlagList().size() && rightFound == false; j++)
if (misc_flags.test(i) && desc_misc_flags.test(i) == false)
{
if (aci.getKernelCapabilities().getMiscFlags().getFlagList()[i] == acid.getKernelCapabilities().getMiscFlags().getFlagList()[j])
rightFound = true;
}
if (rightFound == false)
{
std::cout << "[WARNING] ACI/KC MiscFlag: FAIL (" << nn::hac::KernelCapabilityUtil::getMiscFlagAsString(aci.getKernelCapabilities().getMiscFlags().getFlagList()[i]) << " not permitted)" << std::endl;
std::cout << "[WARNING] ACI/KC MiscFlag: FAIL (" << nn::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(nn::hac::kc::MiscFlagsBit(i)) << " not permitted)" << std::endl;
}
}
}
@ -296,10 +282,12 @@ void MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo& aci, con
void MetaProcess::displayMetaHeader(const nn::hac::Meta& hdr)
{
std::cout << "[Meta Header]" << std::endl;
std::cout << " ACID KeyGeneration: " << std::dec << hdr.getAcidKeyGeneration() << std::endl;
std::cout << " Process Architecture Params:" << std::endl;
std::cout << " Ins. Type: " << nn::hac::MetaUtil::getInstructionTypeAsString(hdr.getInstructionType()) << std::endl;
std::cout << " Addr Space: " << nn::hac::MetaUtil::getProcAddressSpaceTypeAsString(hdr.getProcAddressSpaceType()) << std::endl;
std::cout << " ACID KeyGeneration: " << std::dec << (uint32_t)hdr.getAccessControlInfoDescKeyGeneration() << std::endl;
std::cout << " Flags:" << std::endl;
std::cout << " Is64BitInstruction: " << std::boolalpha << hdr.getIs64BitInstructionFlag() << std::endl;
std::cout << " ProcessAddressSpace: " << nn::hac::MetaUtil::getProcessAddressSpaceAsString(hdr.getProcessAddressSpace()) << std::endl;
std::cout << " OptimizeMemoryAllocation: " << std::boolalpha << hdr.getOptimizeMemoryAllocationFlag() << std::endl;
std::cout << " SystemResourceSize: 0x" << std::hex << hdr.getSystemResourceSize() << std::endl;
std::cout << " Main Thread Params:" << std::endl;
std::cout << " Priority: " << std::dec << (uint32_t)hdr.getMainThreadPriority() << std::endl;
std::cout << " CpuId: " << std::dec << (uint32_t)hdr.getMainThreadCpuId() << std::endl;
@ -322,14 +310,9 @@ void MetaProcess::displayAciHdr(const nn::hac::AccessControlInfo& aci)
void MetaProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDesc& acid)
{
std::cout << "[Access Control Info Desc]" << std::endl;
if (acid.getFlagList().size() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " Flags: " << std::endl;
for (size_t i = 0; i < acid.getFlagList().size(); i++)
{
std::cout << " " << nn::hac::AccessControlInfoUtil::getAcidFlagAsString(acid.getFlagList()[i]) << " (" << std::dec << (uint32_t)acid.getFlagList()[i] << ")" << std::endl;
}
}
std::cout << " Production: " << std::boolalpha << acid.getProductionFlag() << std::endl;
std::cout << " Unqualified Approval: " << std::boolalpha << acid.getUnqualifiedApprovalFlag() << std::endl;
std::cout << " Memory Region: " << nn::hac::AccessControlInfoUtil::getMemoryRegionAsString(acid.getMemoryRegion()) << " (" << std::dec << (uint32_t)acid.getMemoryRegion() << ")" << std::endl;
std::cout << " ProgramID Restriction" << std::endl;
std::cout << " Min: 0x" << std::hex << std::setw(16) << std::setfill('0') << acid.getProgramIdRestrict().min << std::endl;
@ -341,23 +324,38 @@ void MetaProcess::displayFac(const nn::hac::FileSystemAccessControl& fac)
std::cout << "[FS Access Control]" << std::endl;
std::cout << " Format Version: " << std::dec << (uint32_t)fac.getFormatVersion() << std::endl;
if (fac.getFsaRightsList().size())
auto fs_access = fac.getFsAccess();
if (fs_access.any())
{
std::cout << " FS Rights:" << std::endl;
for (size_t i = 0; i < fac.getFsaRightsList().size(); i++)
std::cout << " FsAccess:" << std::endl;
// TODO this formatting loop could be a utils function
for (size_t flag = 0, printed = 0; flag < fs_access.size(); flag++)
{
if (i % 10 == 0)
// skip unset flags
if (fs_access.test(flag) == false)
continue;
// format the strings
// for each 10 printed we do a new line
if (printed % 10 == 0)
{
if (i != 0)
// skip new line when we haven't printed anything
if (printed != 0)
std::cout << std::endl;
std::cout << " ";
}
std::cout << nn::hac::FileSystemAccessUtil::getFsaRightAsString(fac.getFsaRightsList()[i]);
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
std::cout << " (bit " << std::dec << (uint32_t)fac.getFsaRightsList()[i] << ")";
if (fac.getFsaRightsList()[i] != fac.getFsaRightsList().atBack())
// within a line we want to separate the next string from the last one with a comma and a space
else
{
std::cout << ", ";
}
printed++;
// output string info
std::cout << nn::hac::FileSystemAccessUtil::getFsAccessFlagAsString(nn::hac::fac::FsAccessFlag(flag));
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
std::cout << " (bit " << std::dec << (uint32_t)flag << ")";
}
std::cout << std::endl;
}
@ -385,21 +383,12 @@ void MetaProcess::displaySac(const nn::hac::ServiceAccessControl& sac)
{
std::cout << "[Service Access Control]" << std::endl;
std::cout << " Service List:" << std::endl;
std::vector<std::string> service_name_list;
for (size_t i = 0; i < sac.getServiceList().size(); i++)
{
if (i % 10 == 0)
{
if (i != 0)
std::cout << std::endl;
std::cout << " ";
service_name_list.push_back(sac.getServiceList()[i].getName() + (sac.getServiceList()[i].isServer() ? "(isSrv)" : ""));
}
std::cout << sac.getServiceList()[i].getName();
if (sac.getServiceList()[i].isServer())
std::cout << "(isSrv)";
if (sac.getServiceList()[i] != sac.getServiceList().atBack())
std::cout << ", ";
}
std::cout << std::endl;
fnd::SimpleTextOutput::dumpStringList(service_name_list, 60, 4);
}
void MetaProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
@ -418,40 +407,30 @@ void MetaProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
if (kern.getSystemCalls().isSet())
{
fnd::List<nn::hac::kc::SystemCall> syscalls = kern.getSystemCalls().getSystemCalls();
auto syscall_ids = kern.getSystemCalls().getSystemCallIds();
std::cout << " SystemCalls:" << std::endl;
std::cout << " ";
size_t lineLen = 0;
for (size_t i = 0; i < syscalls.size(); i++)
std::vector<std::string> syscall_names;
for (size_t syscall_id = 0; syscall_id < syscall_ids.size(); syscall_id++)
{
if (lineLen > 60)
{
lineLen = 0;
std::cout << std::endl;
std::cout << " ";
if (syscall_ids.test(syscall_id))
syscall_names.push_back(nn::hac::KernelCapabilityUtil::getSystemCallIdAsString(nn::hac::kc::SystemCallId(syscall_id)));
}
std::string syscall_name = nn::hac::KernelCapabilityUtil::getSystemCallAsString(syscalls[i]);
std::cout << syscall_name;
if (syscalls[i] != syscalls.atBack())
std::cout << ", ";
lineLen += syscall_name.length();
}
std::cout << std::endl;
fnd::SimpleTextOutput::dumpStringList(syscall_names, 60, 4);
}
if (kern.getMemoryMaps().isSet())
{
fnd::List<nn::hac::MemoryMappingHandler::sMemoryMapping> maps = kern.getMemoryMaps().getMemoryMaps();
fnd::List<nn::hac::MemoryMappingHandler::sMemoryMapping> ioMaps = kern.getMemoryMaps().getIoMemoryMaps();
auto maps = kern.getMemoryMaps().getMemoryMaps();
auto ioMaps = kern.getMemoryMaps().getIoMemoryMaps();
std::cout << " MemoryMaps:" << std::endl;
for (size_t i = 0; i < maps.size(); i++)
{
std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)maps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1) << " (perm=" << nn::hac::KernelCapabilityUtil::getMemMapPermAsString(maps[i].perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMemMapTypeAsString(maps[i].type) << ")" << std::endl;
std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)maps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1) << " (perm=" << nn::hac::KernelCapabilityUtil::getMemoryPermissionAsString(maps[i].perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMappingTypeAsString(maps[i].type) << ")" << std::endl;
}
//std::cout << " IoMaps:" << std::endl;
for (size_t i = 0; i < ioMaps.size(); i++)
{
std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)ioMaps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1) << " (perm=" << nn::hac::KernelCapabilityUtil::getMemMapPermAsString(ioMaps[i].perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMemMapTypeAsString(ioMaps[i].type) << ")" << std::endl;
std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)ioMaps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1) << " (perm=" << nn::hac::KernelCapabilityUtil::getMemoryPermissionAsString(ioMaps[i].perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMappingTypeAsString(ioMaps[i].type) << ")" << std::endl;
}
}
if (kern.getInterupts().isSet())
@ -474,7 +453,7 @@ void MetaProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
}
if (kern.getMiscParams().isSet())
{
std::cout << " ProgramType: " << std::dec << (uint32_t)kern.getMiscParams().getProgramType() << std::endl;
std::cout << " ProgramType: " << nn::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()) << " (" << std::dec << (uint32_t)kern.getMiscParams().getProgramType() << ")" << std::endl;
}
if (kern.getKernelVersion().isSet())
{
@ -486,21 +465,14 @@ void MetaProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
}
if (kern.getMiscFlags().isSet())
{
fnd::List<nn::hac::kc::MiscFlags> flagList = kern.getMiscFlags().getFlagList();
auto misc_flags = kern.getMiscFlags().getMiscFlags();
std::cout << " Misc Flags:" << std::endl;
for (uint32_t i = 0; i < flagList.size(); i++)
std::vector<std::string> misc_flags_names;
for (size_t misc_flags_bit = 0; misc_flags_bit < misc_flags.size(); misc_flags_bit++)
{
if (i % 10 == 0)
{
if (i != 0)
std::cout << std::endl;
std::cout << " ";
}
std::cout << nn::hac::KernelCapabilityUtil::getMiscFlagAsString(flagList[i]);
if (flagList[i] != flagList.atBack())
std::cout << ", ";
std::cout << std::endl;
if (misc_flags.test(misc_flags_bit))
misc_flags_names.push_back(nn::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(nn::hac::kc::MiscFlagsBit(misc_flags_bit)));
}
fnd::SimpleTextOutput::dumpStringList(misc_flags_names, 60, 4);
}
}

View file

@ -34,7 +34,7 @@ private:
void importMeta();
void validateAcidSignature(const nn::hac::AccessControlInfoDesc& acid);
void validateAcidSignature(const nn::hac::AccessControlInfoDesc& acid, byte_t key_generation);
void validateAciFromAcid(const nn::hac::AccessControlInfo& aci, const nn::hac::AccessControlInfoDesc& acid);
void displayMetaHeader(const nn::hac::Meta& hdr);

View file

@ -62,118 +62,431 @@ void NacpProcess::importNacp()
void NacpProcess::displayNacp()
{
std::cout << "[ApplicationControlProperty]" << std::endl;
std::cout << " Menu Description:" << std::endl;
std::cout << " DisplayVersion: " << mNacp.getDisplayVersion() << std::endl;
if (mNacp.getIsbn().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
std::cout << " ISBN: " << mNacp.getIsbn() << std::endl;
for (size_t i = 0; i < mNacp.getTitle().size(); i++)
// Title
if (mNacp.getTitle().size() > 0)
{
std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getLanguageAsString(mNacp.getTitle()[i].language) << " Title:" << std::endl;
std::cout << " Name: " << mNacp.getTitle()[i].name << std::endl;
std::cout << " Publisher: " << mNacp.getTitle()[i].publisher << std::endl;
}
std::cout << " Logo:" << std::endl;
std::cout << " Type: " << nn::hac::ApplicationControlPropertyUtil::getLogoTypeAsString(mNacp.getLogoType()) << std::endl;
std::cout << " Handling: " << nn::hac::ApplicationControlPropertyUtil::getLogoHandlingAsString(mNacp.getLogoHandling()) << std::endl;
std::cout << " AddOnContent:" << std::endl;
std::cout << " BaseId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getAocBaseId() << std::endl;
std::cout << " RegistrationType: " << nn::hac::ApplicationControlPropertyUtil::getAocRegistrationTypeAsString(mNacp.getAocRegistrationType()) << std::endl;
std::cout << " RuntimeInstallMode: " << nn::hac::ApplicationControlPropertyUtil::getRuntimeAocInstallModeAsString(mNacp.getRuntimeAocInstallMode()) << std::endl;
std::cout << " Play Log:" << std::endl;
std::cout << " PlayLogPolicy: " << nn::hac::ApplicationControlPropertyUtil::getPlayLogPolicyAsString(mNacp.getPlayLogPolicy()) << std::endl;
std::cout << " PlayLogQueryCapability: " << nn::hac::ApplicationControlPropertyUtil::getPlayLogQueryCapabilityAsString(mNacp.getPlayLogQueryCapability()) << std::endl;
if (mNacp.getPlayLogQueryableApplicationId().size() > 0)
std::cout << " Title:" << std::endl;
for (auto itr = mNacp.getTitle().begin(); itr != mNacp.getTitle().end(); itr++)
{
std::cout << " PlayLogQueryableApplicationId:" << std::endl;
for (size_t i = 0; i < mNacp.getPlayLogQueryableApplicationId().size(); i++)
{
std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getPlayLogQueryableApplicationId()[i] << std::endl;
std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getLanguageAsString(itr->language) << ":" << std::endl;
std::cout << " Name: " << itr->name << std::endl;
std::cout << " Publisher: " << itr->publisher << std::endl;
}
}
std::cout << " Parental Controls:" << std::endl;
std::cout << " ParentalControlFlag: " << nn::hac::ApplicationControlPropertyUtil::getParentalControlFlagAsString(mNacp.getParentalControlFlag()) << std::endl;
for (size_t i = 0; i < mNacp.getRatingAge().size(); i++)
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " Age Restriction:" << std::endl;
std::cout << " Agency: " << nn::hac::ApplicationControlPropertyUtil::getOrganisationAsString(mNacp.getRatingAge()[i].organisation) << std::endl;
std::cout << " Age: " << std::dec << (uint32_t)mNacp.getRatingAge()[i].age << std::endl;
std::cout << " Title: None" << std::endl;
}
if (mNacp.getBcatPassphase().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
// Isbn
if (mNacp.getIsbn().empty() == false)
{
std::cout << " BCAT:" << std::endl;
std::cout << " BcatPassphase: " << mNacp.getBcatPassphase() << std::endl;
std::cout << " DeliveryCacheStorageSize: 0x" << std::hex << mNacp.getBcatDeliveryCacheStorageSize() << std::endl;
std::cout << " ISBN: " << mNacp.getIsbn() << std::endl;
}
if (mNacp.getLocalCommunicationId().size() > 0)
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " Local Area Communication:" << std::endl;
std::cout << " LocalCommunicationId:" << std::endl;
for (size_t i = 0; i < mNacp.getLocalCommunicationId().size(); i++)
std::cout << " ISBN: (NotSet)" << std::endl;
}
// StartupUserAccount
if (mNacp.getStartupUserAccount() != nn::hac::nacp::StartupUserAccount::None || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getLocalCommunicationId()[i] << std::endl;
}
}
std::cout << " SaveData:" << std::endl;
std::cout << " SaveDatawOwnerId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getSaveDatawOwnerId() << std::endl;
if (mNacp.getUserAccountSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " UserAccountSaveData:" << std::endl;
std::cout << " Size: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().size) << std::endl;
std::cout << " JournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().journal_size) << std::endl;
}
if (mNacp.getDeviceSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " DeviceSaveData:" << std::endl;
std::cout << " Size: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().size) << std::endl;
std::cout << " JournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().journal_size) << std::endl;
}
if (mNacp.getUserAccountSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " UserAccountSaveDataMax:" << std::endl;
std::cout << " Size: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().size) << std::endl;
std::cout << " JournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().journal_size) << std::endl;
}
if (mNacp.getDeviceSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " DeviceSaveDataMax:" << std::endl;
std::cout << " Size: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().size) << std::endl;
std::cout << " JournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().journal_size) << std::endl;
}
if (mNacp.getTemporaryStorageSize() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " TemporaryStorageSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getTemporaryStorageSize()) << std::endl;
}
if (mNacp.getCacheStorageSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " CacheStorage:" << std::endl;
std::cout << " Size: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().size) << std::endl;
std::cout << " JournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().journal_size) << std::endl;
std::cout << " MaxDataAndJournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageDataAndJournalSizeMax()) << std::endl;
std::cout << " StorageIndexMax: 0x" << std::hex << mNacp.getCacheStorageIndexMax() << std::endl;
}
std::cout << " Other Flags:" << std::endl;
std::cout << " StartupUserAccount: " << nn::hac::ApplicationControlPropertyUtil::getStartupUserAccountAsString(mNacp.getStartupUserAccount()) << std::endl;
std::cout << " UserAccountSwitchLock: " << nn::hac::ApplicationControlPropertyUtil::getUserAccountSwitchLockValueAsString(mNacp.getUserAccountSwitchLockValue()) << std::endl;
std::cout << " AttributeFlag: " << nn::hac::ApplicationControlPropertyUtil::getAttributeFlagAsString(mNacp.getAttributeFlag()) << std::endl;
std::cout << " CrashReportMode: " << nn::hac::ApplicationControlPropertyUtil::getCrashReportModeAsString(mNacp.getCrashReportMode()) << std::endl;
std::cout << " HDCP: " << nn::hac::ApplicationControlPropertyUtil::getHdcpAsString(mNacp.getHdcp()) << std::endl;
std::cout << " ScreenshotMode: " << nn::hac::ApplicationControlPropertyUtil::getScreenshotModeAsString(mNacp.getScreenshotMode()) << std::endl;
std::cout << " VideoCaptureMode: " << nn::hac::ApplicationControlPropertyUtil::getVideoCaptureModeAsString(mNacp.getVideoCaptureMode()) << std::endl;
}
// UserAccountSwitchLock
if (mNacp.getUserAccountSwitchLock() != nn::hac::nacp::UserAccountSwitchLock::Disable || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " UserAccountSwitchLock: " << nn::hac::ApplicationControlPropertyUtil::getUserAccountSwitchLockAsString(mNacp.getUserAccountSwitchLock()) << std::endl;
}
// AddOnContentRegistrationType
if (mNacp.getAddOnContentRegistrationType() != nn::hac::nacp::AddOnContentRegistrationType::AllOnLaunch || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " AddOnContentRegistrationType: " << nn::hac::ApplicationControlPropertyUtil::getAddOnContentRegistrationTypeAsString(mNacp.getAddOnContentRegistrationType()) << std::endl;
}
// Attribute
if (mNacp.getAttribute().size() > 0)
{
std::cout << " Attribute:" << std::endl;
for (auto itr = mNacp.getAttribute().begin(); itr != mNacp.getAttribute().end(); itr++)
{
std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getAttributeFlagAsString(*itr) << std::endl;
}
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " Attribute: None" << std::endl;
}
// SupportedLanguage
if (mNacp.getSupportedLanguage().size() > 0)
{
std::cout << " SupportedLanguage:" << std::endl;
for (auto itr = mNacp.getSupportedLanguage().begin(); itr != mNacp.getSupportedLanguage().end(); itr++)
{
std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getLanguageAsString(*itr) << std::endl;
}
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " SupportedLanguage: None" << std::endl;
}
// ParentalControl
if (mNacp.getParentalControl().size() > 0)
{
std::cout << " ParentalControl:" << std::endl;
for (auto itr = mNacp.getParentalControl().begin(); itr != mNacp.getParentalControl().end(); itr++)
{
std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getParentalControlFlagAsString(*itr) << std::endl;
}
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " ParentalControl: None" << std::endl;
}
// Screenshot
if (mNacp.getScreenshot() != nn::hac::nacp::Screenshot::Allow || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " Screenshot: " << nn::hac::ApplicationControlPropertyUtil::getScreenshotAsString(mNacp.getScreenshot()) << std::endl;
}
// VideoCapture
if (mNacp.getVideoCapture() != nn::hac::nacp::VideoCapture::Disable || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " VideoCapture: " << nn::hac::ApplicationControlPropertyUtil::getVideoCaptureAsString(mNacp.getVideoCapture()) << std::endl;
}
// DataLossConfirmation
if (mNacp.getDataLossConfirmation() != nn::hac::nacp::DataLossConfirmation::None || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " DataLossConfirmation: " << nn::hac::ApplicationControlPropertyUtil::getDataLossConfirmationAsString(mNacp.getDataLossConfirmation()) << std::endl;
std::cout << " RepairFlag: " << nn::hac::ApplicationControlPropertyUtil::getRepairFlagAsString(mNacp.getRepairFlag()) << std::endl;
std::cout << " ProgramIndex: 0x" << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)mNacp.getProgramIndex() << std::endl;
std::cout << " Req NetworkLicenseOnLaunch: " << nn::hac::ApplicationControlPropertyUtil::getRequiredNetworkServiceLicenseOnLaunchValueAsString(mNacp.getRequiredNetworkServiceLicenseOnLaunchValue()) << std::endl;
if (mNacp.getApplicationErrorCodeCategory().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
}
// PlayLogPolicy
if (mNacp.getPlayLogPolicy() != nn::hac::nacp::PlayLogPolicy::All || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " PlayLogPolicy: " << nn::hac::ApplicationControlPropertyUtil::getPlayLogPolicyAsString(mNacp.getPlayLogPolicy()) << std::endl;
}
// PresenceGroupId
if (mNacp.getPresenceGroupId() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " PresenceGroupId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getPresenceGroupId() << std::endl;
}
// RatingAge
if (mNacp.getRatingAge().size() > 0)
{
std::cout << " RatingAge:" << std::endl;
for (auto itr = mNacp.getRatingAge().begin(); itr != mNacp.getRatingAge().end(); itr++)
{
std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getOrganisationAsString(itr->organisation) << ":" << std::endl;
std::cout << " Age: " << std::dec << (uint32_t)itr->age << std::endl;
}
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " RatingAge: None" << std::endl;
}
// DisplayVersion
if (mNacp.getDisplayVersion().empty() == false)
{
std::cout << " DisplayVersion: " << mNacp.getDisplayVersion() << std::endl;
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " DisplayVersion: (NotSet)" << std::endl;
}
// AddOnContentBaseId
if (mNacp.getAddOnContentBaseId() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " AddOnContentBaseId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getAddOnContentBaseId() << std::endl;
}
// SaveDataOwnerId
if (mNacp.getSaveDataOwnerId() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " SaveDataOwnerId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getSaveDataOwnerId() << std::endl;
}
// UserAccountSaveDataSize
if (mNacp.getUserAccountSaveDataSize().size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " UserAccountSaveDataSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().size) << std::endl;
}
// UserAccountSaveDataJournalSize
if (mNacp.getUserAccountSaveDataSize().journal_size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " UserAccountSaveDataJournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataSize().journal_size) << std::endl;
}
// DeviceSaveDataSize
if (mNacp.getDeviceSaveDataSize().size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " DeviceSaveDataSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().size) << std::endl;
}
// DeviceSaveDataJournalSize
if (mNacp.getDeviceSaveDataSize().journal_size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " DeviceSaveDataJournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataSize().journal_size) << std::endl;
}
// BcatDeliveryCacheStorageSize
if (mNacp.getBcatDeliveryCacheStorageSize() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " BcatDeliveryCacheStorageSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getBcatDeliveryCacheStorageSize()) << std::endl;
}
// ApplicationErrorCodeCategory
if (mNacp.getApplicationErrorCodeCategory().empty() == false)
{
std::cout << " ApplicationErrorCodeCategory: " << mNacp.getApplicationErrorCodeCategory() << std::endl;
}
if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " ApplicationErrorCodeCategory: (NotSet)" << std::endl;
}
// LocalCommunicationId
if (mNacp.getLocalCommunicationId().size() > 0)
{
std::cout << " LocalCommunicationId:" << std::endl;
for (auto itr = mNacp.getLocalCommunicationId().begin(); itr != mNacp.getLocalCommunicationId().end(); itr++)
{
std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << *itr << std::endl;
}
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " LocalCommunicationId: None" << std::endl;
}
// LogoType
//if (mNacp.getLogoType() != nn::hac::nacp::LogoType::Nintendo || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
//{
std::cout << " LogoType: " << nn::hac::ApplicationControlPropertyUtil::getLogoTypeAsString(mNacp.getLogoType()) << std::endl;
//}
// LogoHandling
if (mNacp.getLogoHandling() != nn::hac::nacp::LogoHandling::Auto || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " LogoHandling: " << nn::hac::ApplicationControlPropertyUtil::getLogoHandlingAsString(mNacp.getLogoHandling()) << std::endl;
}
// RuntimeAddOnContentInstall
if (mNacp.getRuntimeAddOnContentInstall() != nn::hac::nacp::RuntimeAddOnContentInstall::Deny || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " RuntimeAddOnContentInstall: " << nn::hac::ApplicationControlPropertyUtil::getRuntimeAddOnContentInstallAsString(mNacp.getRuntimeAddOnContentInstall()) << std::endl;
}
// RuntimeParameterDelivery
if (mNacp.getRuntimeParameterDelivery() != nn::hac::nacp::RuntimeParameterDelivery::Always || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " RuntimeParameterDelivery: " << nn::hac::ApplicationControlPropertyUtil::getRuntimeParameterDeliveryAsString(mNacp.getRuntimeParameterDelivery()) << std::endl;
}
// CrashReport
if (mNacp.getCrashReport() != nn::hac::nacp::CrashReport::Deny || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " CrashReport: " << nn::hac::ApplicationControlPropertyUtil::getCrashReportAsString(mNacp.getCrashReport()) << std::endl;
}
// Hdcp
if (mNacp.getHdcp() != nn::hac::nacp::Hdcp::None || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " Hdcp: " << nn::hac::ApplicationControlPropertyUtil::getHdcpAsString(mNacp.getHdcp()) << std::endl;
}
// SeedForPsuedoDeviceId
if (mNacp.getSeedForPsuedoDeviceId() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " Other Ids:" << std::endl;
if (mNacp.getSeedForPsuedoDeviceId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
std::cout << " SeedForPsuedoDeviceId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getSeedForPsuedoDeviceId() << std::endl;
if (mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
std::cout << " PresenceGroupId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getPresenceGroupId() << std::endl;
}
// BcatPassphase
if (mNacp.getBcatPassphase().empty() == false)
{
std::cout << " BcatPassphase: " << mNacp.getBcatPassphase() << std::endl;
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " BcatPassphase: (NotSet)" << std::endl;
}
// StartupUserAccountOption
if (mNacp.getStartupUserAccountOption().size() > 0)
{
std::cout << " StartupUserAccountOption:" << std::endl;
for (auto itr = mNacp.getStartupUserAccountOption().begin(); itr != mNacp.getStartupUserAccountOption().end(); itr++)
{
std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getStartupUserAccountOptionFlagAsString(*itr) << std::endl;
}
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " StartupUserAccountOption: None" << std::endl;
}
// UserAccountSaveDataSizeMax
if (mNacp.getUserAccountSaveDataMax().size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " UserAccountSaveDataSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().size) << std::endl;
}
// UserAccountSaveDataJournalSizeMax
if (mNacp.getUserAccountSaveDataMax().journal_size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " UserAccountSaveDataJournalSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getUserAccountSaveDataMax().journal_size) << std::endl;
}
// DeviceSaveDataSizeMax
if (mNacp.getDeviceSaveDataMax().size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " DeviceSaveDataSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().size) << std::endl;
}
// DeviceSaveDataJournalSizeMax
if (mNacp.getDeviceSaveDataMax().journal_size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " DeviceSaveDataJournalSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getDeviceSaveDataMax().journal_size) << std::endl;
}
// TemporaryStorageSize
if (mNacp.getTemporaryStorageSize() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " TemporaryStorageSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getTemporaryStorageSize()) << std::endl;
}
// CacheStorageSize
if (mNacp.getCacheStorageSize().size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " CacheStorageSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().size) << std::endl;
}
// CacheStorageJournalSize
if (mNacp.getCacheStorageSize().journal_size != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " CacheStorageJournalSize: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageSize().journal_size) << std::endl;
}
// CacheStorageDataAndJournalSizeMax
if (mNacp.getCacheStorageDataAndJournalSizeMax() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " CacheStorageDataAndJournalSizeMax: " << nn::hac::ApplicationControlPropertyUtil::getSaveDataSizeAsString(mNacp.getCacheStorageDataAndJournalSizeMax()) << std::endl;
}
// CacheStorageIndexMax
if (mNacp.getCacheStorageIndexMax() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " CacheStorageIndexMax: 0x" << std::hex << std::setw(4) << std::setfill('0') << mNacp.getCacheStorageIndexMax() << std::endl;
}
// PlayLogQueryableApplicationId
if (mNacp.getPlayLogQueryableApplicationId().size() > 0)
{
std::cout << " PlayLogQueryableApplicationId:" << std::endl;
for (auto itr = mNacp.getPlayLogQueryableApplicationId().begin(); itr != mNacp.getPlayLogQueryableApplicationId().end(); itr++)
{
std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << *itr << std::endl;
}
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " PlayLogQueryableApplicationId: None" << std::endl;
}
// PlayLogQueryCapability
if (mNacp.getPlayLogQueryCapability() != nn::hac::nacp::PlayLogQueryCapability::None || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " PlayLogQueryCapability: " << nn::hac::ApplicationControlPropertyUtil::getPlayLogQueryCapabilityAsString(mNacp.getPlayLogQueryCapability()) << std::endl;
}
// Repair
if (mNacp.getRepair().size() > 0)
{
std::cout << " Repair:" << std::endl;
for (auto itr = mNacp.getRepair().begin(); itr != mNacp.getRepair().end(); itr++)
{
std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getRepairFlagAsString(*itr) << std::endl;
}
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " Repair: None" << std::endl;
}
// ProgramIndex
if (mNacp.getProgramIndex() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " ProgramIndex: 0x" << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)mNacp.getProgramIndex() << std::endl;
}
// RequiredNetworkServiceLicenseOnLaunch
if (mNacp.getRequiredNetworkServiceLicenseOnLaunch().size() > 0)
{
std::cout << " RequiredNetworkServiceLicenseOnLaunch:" << std::endl;
for (auto itr = mNacp.getRequiredNetworkServiceLicenseOnLaunch().begin(); itr != mNacp.getRequiredNetworkServiceLicenseOnLaunch().end(); itr++)
{
std::cout << " " << nn::hac::ApplicationControlPropertyUtil::getRequiredNetworkServiceLicenseOnLaunchFlagAsString(*itr) << std::endl;
}
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " RequiredNetworkServiceLicenseOnLaunch: None" << std::endl;
}
// NeighborDetectionClientConfiguration
auto detect_config = mNacp.getNeighborDetectionClientConfiguration();
if (detect_config.countSendGroupConfig() > 0 || detect_config.countReceivableGroupConfig() > 0)
{
std::cout << " NeighborDetectionClientConfiguration:" << std::endl;
if (detect_config.countSendGroupConfig() > 0)
{
std::cout << " SendGroupConfig:" << std::endl;
std::cout << " GroupId: 0x" << std::hex << std::setw(16) << std::setfill('0') << detect_config.send_data_configuration.group_id << std::endl;
std::cout << " Key: " << fnd::SimpleTextOutput::arrayToString(detect_config.send_data_configuration.key, nn::hac::nacp::kNeighborDetectionGroupConfigurationKeyLength, false, "") << std::endl;
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " SendGroupConfig: None" << std::endl;
}
if (detect_config.countReceivableGroupConfig() > 0)
{
std::cout << " ReceivableGroupConfig:" << std::endl;
for (size_t i = 0; i < nn::hac::nacp::kReceivableGroupConfigurationCount; i++)
{
if (detect_config.receivable_data_configuration[i].isNull())
continue;
std::cout << " GroupId: 0x" << std::hex << std::setw(16) << std::setfill('0') << detect_config.receivable_data_configuration[i].group_id << std::endl;
std::cout << " Key: " << fnd::SimpleTextOutput::arrayToString(detect_config.receivable_data_configuration[i].key, nn::hac::nacp::kNeighborDetectionGroupConfigurationKeyLength, false, "") << std::endl;
}
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " ReceivableGroupConfig: None" << std::endl;
}
}
else if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " NeighborDetectionClientConfiguration: None" << std::endl;
}
// JitConfiguration
if (mNacp.getJitConfiguration().is_enabled || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
std::cout << " JitConfiguration:" << std::endl;
std::cout << " IsEnabled: " << std::boolalpha << mNacp.getJitConfiguration().is_enabled << std::endl;
std::cout << " MemorySize: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getJitConfiguration().memory_size << std::endl;
}
}

View file

@ -232,14 +232,14 @@ void NcaProcess::generatePartitionConfiguration()
{
// get reference to relevant structures
const nn::hac::ContentArchiveHeader::sPartitionEntry& partition = mHdr.getPartitionEntryList()[i];
nn::hac::sNcaFsHeader& fs_header = mHdrBlock.fs_header[partition.header_index];
nn::hac::sContentArchiveFsHeader& fs_header = mHdrBlock.fs_header[partition.header_index];
// output structure
sPartitionInfo& info = mPartitions[partition.header_index];
// validate header hash
fnd::sha::sSha256Hash fs_header_hash;
fnd::sha::Sha256((const byte_t*)&mHdrBlock.fs_header[partition.header_index], sizeof(nn::hac::sNcaFsHeader), fs_header_hash.bytes);
fnd::sha::Sha256((const byte_t*)&mHdrBlock.fs_header[partition.header_index], sizeof(nn::hac::sContentArchiveFsHeader), fs_header_hash.bytes);
if (fs_header_hash.compare(partition.fs_header_hash) == false)
{
error.clear();
@ -265,16 +265,16 @@ void NcaProcess::generatePartitionConfiguration()
info.format_type = (nn::hac::nca::FormatType)fs_header.format_type;
info.hash_type = (nn::hac::nca::HashType)fs_header.hash_type;
info.enc_type = (nn::hac::nca::EncryptionType)fs_header.encryption_type;
if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256)
if (info.hash_type == nn::hac::nca::HashType::HierarchicalSha256)
{
// info.hash_tree_meta.importData(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen, LayeredIntegrityMetadata::HASH_TYPE_SHA256);
// info.hash_tree_meta.importData(fs_header.hash_info, nn::hac::nca::kHashInfoLen, LayeredIntegrityMetadata::HASH_TYPE_SHA256);
nn::hac::HierarchicalSha256Header hdr;
fnd::List<fnd::LayeredIntegrityMetadata::sLayer> hash_layers;
fnd::LayeredIntegrityMetadata::sLayer data_layer;
fnd::List<fnd::sha::sSha256Hash> master_hash_list;
// import raw data
hdr.fromBytes(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen);
hdr.fromBytes(fs_header.hash_info, nn::hac::nca::kHashInfoLen);
for (size_t i = 0; i < hdr.getLayerInfo().size(); i++)
{
fnd::LayeredIntegrityMetadata::sLayer layer;
@ -298,15 +298,15 @@ void NcaProcess::generatePartitionConfiguration()
info.layered_intergrity_metadata.setDataLayerInfo(data_layer);
info.layered_intergrity_metadata.setMasterHashList(master_hash_list);
}
else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY)
else if (info.hash_type == nn::hac::nca::HashType::HierarchicalIntegrity)
{
// info.hash_tree_meta.importData(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen, LayeredIntegrityMetadata::HASH_TYPE_INTEGRITY);
// info.hash_tree_meta.importData(fs_header.hash_info, nn::hac::nca::kHashInfoLen, LayeredIntegrityMetadata::HASH_TYPE_INTEGRITY);
nn::hac::HierarchicalIntegrityHeader hdr;
fnd::List<fnd::LayeredIntegrityMetadata::sLayer> hash_layers;
fnd::LayeredIntegrityMetadata::sLayer data_layer;
fnd::List<fnd::sha::sSha256Hash> master_hash_list;
hdr.fromBytes(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen);
hdr.fromBytes(fs_header.hash_info, nn::hac::nca::kHashInfoLen);
for (size_t i = 0; i < hdr.getLayerInfo().size(); i++)
{
fnd::LayeredIntegrityMetadata::sLayer layer;
@ -336,27 +336,27 @@ void NcaProcess::generatePartitionConfiguration()
// filter out unrecognised format types
switch (info.format_type)
{
case (nn::hac::nca::FORMAT_PFS0):
case (nn::hac::nca::FORMAT_ROMFS):
case (nn::hac::nca::FormatType::PartitionFs):
case (nn::hac::nca::FormatType::RomFs):
break;
default:
error.clear();
error << "FormatType(" << info.format_type << "): UNKNOWN";
error << "FormatType(" << nn::hac::ContentArchiveUtil::getFormatTypeAsString(info.format_type) << "): UNKNOWN";
throw fnd::Exception(kModuleName, error.str());
}
// create reader based on encryption type0
if (info.enc_type == nn::hac::nca::CRYPT_NONE)
if (info.enc_type == nn::hac::nca::EncryptionType::None)
{
info.reader = new fnd::OffsetAdjustedIFile(mFile, info.offset, info.size);
}
else if (info.enc_type == nn::hac::nca::CRYPT_AESCTR)
else if (info.enc_type == nn::hac::nca::EncryptionType::AesCtr)
{
if (mContentKey.aes_ctr.isSet == false)
throw fnd::Exception(kModuleName, "AES-CTR Key was not determined");
info.reader = new fnd::OffsetAdjustedIFile(new fnd::AesCtrWrappedIFile(mFile, mContentKey.aes_ctr.var, info.aes_ctr), info.offset, info.size);
}
else if (info.enc_type == nn::hac::nca::CRYPT_AESXTS || info.enc_type == nn::hac::nca::CRYPT_AESCTREX)
else if (info.enc_type == nn::hac::nca::EncryptionType::AesXts || info.enc_type == nn::hac::nca::EncryptionType::AesCtrEx)
{
error.clear();
error << "EncryptionType(" << nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type) << "): UNSUPPORTED";
@ -365,19 +365,19 @@ void NcaProcess::generatePartitionConfiguration()
else
{
error.clear();
error << "EncryptionType(" << info.enc_type << "): UNKNOWN";
error << "EncryptionType(" << nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type) << "): UNKNOWN";
throw fnd::Exception(kModuleName, error.str());
}
// filter out unrecognised hash types, and hash based readers
if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256 || info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY)
if (info.hash_type == nn::hac::nca::HashType::HierarchicalSha256 || info.hash_type == nn::hac::nca::HashType::HierarchicalIntegrity)
{
info.reader = new fnd::LayeredIntegrityWrappedIFile(info.reader, info.layered_intergrity_metadata);
}
else if (info.hash_type != nn::hac::nca::HASH_NONE)
else if (info.hash_type != nn::hac::nca::HashType::None)
{
error.clear();
error << "HashType(" << info.hash_type << "): UNKNOWN";
error << "HashType(" << nn::hac::ContentArchiveUtil::getHashTypeAsString(info.hash_type) << "): UNKNOWN";
throw fnd::Exception(kModuleName, error.str());
}
}
@ -392,16 +392,16 @@ void NcaProcess::validateNcaSignatures()
{
// validate signature[0]
fnd::rsa::sRsa2048Key sign0_key;
mKeyCfg.getContentArchiveHeader0SignKey(sign0_key);
mKeyCfg.getContentArchiveHeader0SignKey(sign0_key, mHdr.getSignatureKeyGeneration());
if (fnd::rsa::pss::rsaVerify(sign0_key, fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_main) != 0)
{
std::cout << "[WARNING] NCA Header Main Signature: FAIL" << std::endl;
}
// validate signature[1]
if (mHdr.getContentType() == nn::hac::nca::TYPE_PROGRAM)
if (mHdr.getContentType() == nn::hac::nca::ContentType::Program)
{
if (mPartitions[nn::hac::nca::PARTITION_CODE].format_type == nn::hac::nca::FORMAT_PFS0)
if (mPartitions[nn::hac::nca::PARTITION_CODE].format_type == nn::hac::nca::FormatType::PartitionFs)
{
if (*mPartitions[nn::hac::nca::PARTITION_CODE].reader != nullptr)
{
@ -417,10 +417,12 @@ void NcaProcess::validateNcaSignatures()
MetaProcess npdm;
npdm.setInputFile(new fnd::OffsetAdjustedIFile(mPartitions[nn::hac::nca::PARTITION_CODE].reader, file.offset, file.size));
npdm.setKeyCfg(mKeyCfg);
npdm.setVerifyMode(true);
npdm.setCliOutputMode(0);
npdm.process();
if (fnd::rsa::pss::rsaVerify(npdm.getMeta().getAcid().getContentArchiveHeaderSignature2Key(), fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_acid) != 0)
if (fnd::rsa::pss::rsaVerify(npdm.getMeta().getAccessControlInfoDesc().getContentArchiveHeaderSignature2Key(), fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_acid) != 0)
{
std::cout << "[WARNING] NCA Header ACID Signature: FAIL" << std::endl;
}
@ -446,17 +448,16 @@ void NcaProcess::validateNcaSignatures()
void NcaProcess::displayHeader()
{
std::cout << "[NCA Header]" << std::endl;
std::cout << " Format Type: " << nn::hac::ContentArchiveUtil::getFormatVersionAsString((nn::hac::nca::HeaderFormatVersion)mHdr.getFormatVersion()) << std::endl;
std::cout << " Format Type: " << nn::hac::ContentArchiveUtil::getFormatHeaderVersionAsString((nn::hac::nca::HeaderFormatVersion)mHdr.getFormatVersion()) << std::endl;
std::cout << " Dist. Type: " << nn::hac::ContentArchiveUtil::getDistributionTypeAsString(mHdr.getDistributionType()) << std::endl;
std::cout << " Content Type: " << nn::hac::ContentArchiveUtil::getContentTypeAsString(mHdr.getContentType()) << std::endl;
std::cout << " Key Generation: " << std::dec << (uint32_t)mHdr.getKeyGeneration() << std::endl;
std::cout << " Sig. Generation: " << std::dec << (uint32_t)mHdr.getSignatureKeyGeneration() << std::endl;
std::cout << " Kaek Index: " << nn::hac::ContentArchiveUtil::getKeyAreaEncryptionKeyIndexAsString((nn::hac::nca::KeyAreaEncryptionKeyIndex)mHdr.getKeyAreaEncryptionKeyIndex()) << " (" << std::dec << (uint32_t)mHdr.getKeyAreaEncryptionKeyIndex() << ")" << std::endl;
std::cout << " Size: 0x" << std::hex << mHdr.getContentSize() << std::endl;
std::cout << " ProgID: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getProgramId() << std::endl;
std::cout << " Content Index: " << std::dec << mHdr.getContentIndex() << std::endl;
#define _SPLIT_VER(ver) std::dec << (uint32_t)((ver>>24) & 0xff) << "." << (uint32_t)((ver>>16) & 0xff) << "." << (uint32_t)((ver>>8) & 0xff)
std::cout << " SdkAddon Ver.: v" << std::dec << mHdr.getSdkAddonVersion() << " (" << _SPLIT_VER(mHdr.getSdkAddonVersion()) << ")" << std::endl;
#undef _SPLIT_VER
std::cout << " SdkAddon Ver.: " << nn::hac::ContentArchiveUtil::getSdkAddonVersionAsString(mHdr.getSdkAddonVersion()) << " (v" << std::dec << mHdr.getSdkAddonVersion() << ")" << std::endl;
if (mHdr.hasRightsId())
{
std::cout << " RightsId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen, true, "") << std::endl;
@ -500,14 +501,14 @@ void NcaProcess::displayHeader()
std::cout << " Format Type: " << nn::hac::ContentArchiveUtil::getFormatTypeAsString(info.format_type) << std::endl;
std::cout << " Hash Type: " << nn::hac::ContentArchiveUtil::getHashTypeAsString(info.hash_type) << std::endl;
std::cout << " Enc. Type: " << nn::hac::ContentArchiveUtil::getEncryptionTypeAsString(info.enc_type) << std::endl;
if (info.enc_type == nn::hac::nca::CRYPT_AESCTR)
if (info.enc_type == nn::hac::nca::EncryptionType::AesCtr)
{
fnd::aes::sAesIvCtr ctr;
fnd::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv);
std::cout << " AesCtr Counter:" << std::endl;
std::cout << " " << fnd::SimpleTextOutput::arrayToString(ctr.iv, sizeof(fnd::aes::sAesIvCtr), true, ":") << std::endl;
}
if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY)
if (info.hash_type == nn::hac::nca::HashType::HierarchicalIntegrity)
{
fnd::LayeredIntegrityMetadata& hash_hdr = info.layered_intergrity_metadata;
std::cout << " HierarchicalIntegrity Header:" << std::endl;
@ -530,7 +531,7 @@ void NcaProcess::displayHeader()
std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[j].bytes+0x10, 0x10, true, ":") << std::endl;
}
}
else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256)
else if (info.hash_type == nn::hac::nca::HashType::HierarchicalSha256)
{
fnd::LayeredIntegrityMetadata& hash_hdr = info.layered_intergrity_metadata;
std::cout << " HierarchicalSha256 Header:" << std::endl;
@ -569,13 +570,13 @@ void NcaProcess::processPartitions()
continue;
}
if (partition.format_type == nn::hac::nca::FORMAT_PFS0)
if (partition.format_type == nn::hac::nca::FormatType::PartitionFs)
{
PfsProcess pfs;
pfs.setInputFile(partition.reader);
pfs.setCliOutputMode(mCliOutputMode);
pfs.setListFs(mListFs);
if (mHdr.getContentType() == nn::hac::nca::TYPE_PROGRAM)
if (mHdr.getContentType() == nn::hac::nca::ContentType::Program)
{
pfs.setMountPointName(std::string(getContentTypeForMountStr(mHdr.getContentType())) + ":/" + nn::hac::ContentArchiveUtil::getProgramContentParititionIndexAsString((nn::hac::nca::ProgramContentPartitionIndex)index));
}
@ -588,13 +589,13 @@ void NcaProcess::processPartitions()
pfs.setExtractPath(mPartitionPath[index].path);
pfs.process();
}
else if (partition.format_type == nn::hac::nca::FORMAT_ROMFS)
else if (partition.format_type == nn::hac::nca::FormatType::RomFs)
{
RomfsProcess romfs;
romfs.setInputFile(partition.reader);
romfs.setCliOutputMode(mCliOutputMode);
romfs.setListFs(mListFs);
if (mHdr.getContentType() == nn::hac::nca::TYPE_PROGRAM)
if (mHdr.getContentType() == nn::hac::nca::ContentType::Program)
{
romfs.setMountPointName(std::string(getContentTypeForMountStr(mHdr.getContentType())) + ":/" + nn::hac::ContentArchiveUtil::getProgramContentParititionIndexAsString((nn::hac::nca::ProgramContentPartitionIndex)index));
}
@ -616,22 +617,22 @@ const char* NcaProcess::getContentTypeForMountStr(nn::hac::nca::ContentType cont
switch (cont_type)
{
case (nn::hac::nca::TYPE_PROGRAM):
case (nn::hac::nca::ContentType::Program):
str = "program";
break;
case (nn::hac::nca::TYPE_META):
case (nn::hac::nca::ContentType::Meta):
str = "meta";
break;
case (nn::hac::nca::TYPE_CONTROL):
case (nn::hac::nca::ContentType::Control):
str = "control";
break;
case (nn::hac::nca::TYPE_MANUAL):
case (nn::hac::nca::ContentType::Manual):
str = "manual";
break;
case (nn::hac::nca::TYPE_DATA):
case (nn::hac::nca::ContentType::Data):
str = "data";
break;
case (nn::hac::nca::TYPE_PUBLIC_DATA):
case (nn::hac::nca::ContentType::PublicData):
str = "publicdata";
break;
default:

View file

@ -43,9 +43,9 @@ void NroProcess::setVerifyMode(bool verify)
mVerify = verify;
}
void NroProcess::setInstructionType(nn::hac::meta::InstructionType type)
void NroProcess::setIs64BitInstruction(bool flag)
{
mRoMeta.setInstructionType(type);
mRoMeta.setIs64BitInstruction(flag);
}
void NroProcess::setListApi(bool listApi)

View file

@ -22,7 +22,7 @@ public:
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
void setInstructionType(nn::hac::meta::InstructionType type);
void setIs64BitInstruction(bool flag);
void setListApi(bool listApi);
void setListSymbols(bool listSymbols);

View file

@ -9,7 +9,10 @@
NsoProcess::NsoProcess():
mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false)
mVerify(false),
mIs64BitInstruction(true),
mListApi(false),
mListSymbols(false)
{
}
@ -38,9 +41,9 @@ void NsoProcess::setVerifyMode(bool verify)
mVerify = verify;
}
void NsoProcess::setInstructionType(nn::hac::meta::InstructionType type)
void NsoProcess::setIs64BitInstruction(bool flag)
{
mRoMeta.setInstructionType(type);
mRoMeta.setIs64BitInstruction(flag);
}
void NsoProcess::setListApi(bool listApi)

View file

@ -21,7 +21,7 @@ public:
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
void setInstructionType(nn::hac::meta::InstructionType type);
void setIs64BitInstruction(bool flag);
void setListApi(bool listApi);
void setListSymbols(bool listSymbols);
@ -32,7 +32,7 @@ private:
fnd::SharedPtr<fnd::IFile> mFile;
CliOutputMode mCliOutputMode;
bool mVerify;
nn::hac::meta::InstructionType mInstructionType;
bool mIs64BitInstruction;
bool mListApi;
bool mListSymbols;

View file

@ -7,7 +7,7 @@
RoMetadataProcess::RoMetadataProcess() :
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mInstructionType(nn::hac::meta::INSTR_64BIT),
mIs64BitInstruction(true),
mListApi(false),
mListSymbols(false),
mApiInfo(),
@ -57,9 +57,9 @@ void RoMetadataProcess::setCliOutputMode(CliOutputMode type)
mCliOutputMode = type;
}
void RoMetadataProcess::setInstructionType(nn::hac::meta::InstructionType type)
void RoMetadataProcess::setIs64BitInstruction(bool flag)
{
mInstructionType = type;
mIs64BitInstruction = flag;
}
void RoMetadataProcess::setListApi(bool listApi)
@ -92,6 +92,11 @@ const std::vector<SdkApiString>& RoMetadataProcess::getPrivateApiList() const
return mPrivateApiList;
}
const std::vector<SdkApiString>& RoMetadataProcess::getGuidelineApiList() const
{
return mGuidelineApiList;
}
const fnd::List<ElfSymbolParser::sElfSymbol>& RoMetadataProcess::getSymbolList() const
{
return mSymbolList.getSymbolList();
@ -113,20 +118,32 @@ void RoMetadataProcess::importApiList()
{
SdkApiString api(api_str);
if (api.getApiType() == SdkApiString::API_SDK_VERSION)
switch (api.getApiType())
{
case SdkApiString::API_SDK_VERSION:
mSdkVerApiList.push_back(api);
else if (api.getApiType() == SdkApiString::API_MIDDLEWARE)
break;
case SdkApiString::API_MIDDLEWARE:
mPublicApiList.push_back(api);
else if (api.getApiType() == SdkApiString::API_DEBUG)
break;
case SdkApiString::API_DEBUG:
mDebugApiList.push_back(api);
else if (api.getApiType() == SdkApiString::API_PRIVATE)
break;
case SdkApiString::API_PRIVATE:
mPrivateApiList.push_back(api);
break;
case SdkApiString::API_GUIDELINE:
mGuidelineApiList.push_back(api);
break;
default:
break;
}
}
}
if (mDynSym.size > 0)
{
mSymbolList.parseData(mRoBlob.data() + mDynSym.offset, mDynSym.size, mRoBlob.data() + mDynStr.offset, mDynStr.size, mInstructionType == nn::hac::meta::INSTR_64BIT);
mSymbolList.parseData(mRoBlob.data() + mDynSym.offset, mDynSym.size, mRoBlob.data() + mDynStr.offset, mDynStr.size, mIs64BitInstruction);
}
}
@ -165,6 +182,14 @@ void RoMetadataProcess::displayRoMetaData()
std::cout << " " << mPrivateApiList[i].getModuleName() << " (vender: " << mPrivateApiList[i].getVenderName() << ")" << std::endl;
}
}
if (mGuidelineApiList.size() > 0)
{
std::cout << " Guideline APIs:" << std::endl;
for (size_t i = 0; i < mGuidelineApiList.size(); i++)
{
std::cout << " " << mGuidelineApiList[i].getModuleName() << " (vender: " << mGuidelineApiList[i].getVenderName() << ")" << std::endl;
}
}
}
if (mSymbolList.getSymbolList().size() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
{

View file

@ -24,7 +24,7 @@ public:
void setCliOutputMode(CliOutputMode type);
void setInstructionType(nn::hac::meta::InstructionType type);
void setIs64BitInstruction(bool flag);
void setListApi(bool listApi);
void setListSymbols(bool listSymbols);
@ -32,12 +32,13 @@ public:
const std::vector<SdkApiString>& getPublicApiList() const;
const std::vector<SdkApiString>& getDebugApiList() const;
const std::vector<SdkApiString>& getPrivateApiList() const;
const std::vector<SdkApiString>& getGuidelineApiList() const;
const fnd::List<ElfSymbolParser::sElfSymbol>& getSymbolList() const;
private:
const std::string kModuleName = "RoMetadataProcess";
CliOutputMode mCliOutputMode;
nn::hac::meta::InstructionType mInstructionType;
bool mIs64BitInstruction;
bool mListApi;
bool mListSymbols;
@ -56,6 +57,7 @@ private:
std::vector<SdkApiString> mPublicApiList;
std::vector<SdkApiString> mDebugApiList;
std::vector<SdkApiString> mPrivateApiList;
std::vector<SdkApiString> mGuidelineApiList;
ElfSymbolParser mSymbolList;

View file

@ -81,6 +81,14 @@ void SdkApiString::resolveApiString(const std::string& full_str)
{
mApiType = API_PRIVATE;
}
else if (api_type == kSdkGuidelineApiString)
{
mApiType = API_GUIDELINE;
}
else
{
// TODO?
}
mVenderName = vender;
mModuleName = module;

View file

@ -9,7 +9,8 @@ public:
API_MIDDLEWARE,
API_DEBUG,
API_PRIVATE,
API_SDK_VERSION
API_SDK_VERSION,
API_GUIDELINE,
};
SdkApiString(const std::string& full_str);
@ -32,6 +33,7 @@ private:
const std::string kSdkMiddleWareApiString = "SDK MW";
const std::string kSdkDebugApiString = "SDK Debug";
const std::string kSdkPrivateApiString = "SDK Private";
const std::string kSdkGuidelineApiString = "SDK Guideline";
const std::string kVenderNintendo = "Nintendo";
const std::string kSdkVersionString = "NintendoSdk_nnSdk-";

View file

@ -138,9 +138,9 @@ bool UserSettings::isListSymbols() const
return mListSymbols;
}
nn::hac::meta::InstructionType UserSettings::getInstType() const
bool UserSettings::getIs64BitInstruction() const
{
return mInstructionType;
return mIs64BitInstruction;
}
const sOptional<std::string>& UserSettings::getXciUpdatePath() const
@ -564,9 +564,9 @@ void UserSettings::populateUserSettings(sCmdArgs& args)
// determine the architecture type for NSO/NRO
if (args.inst_type.isSet)
mInstructionType = getInstructionTypeFromString(*args.inst_type);
mIs64BitInstruction = getIs64BitInstructionFromString(*args.inst_type);
else
mInstructionType = nn::hac::meta::INSTR_64BIT; // default 64bit
mIs64BitInstruction = true; // default 64bit
mListApi = args.list_api.isSet;
mListSymbols = args.list_sym.isSet;
@ -758,13 +758,16 @@ bool UserSettings::determineValidCnmtFromSample(const fnd::Vec<byte_t>& sample)
if (sample.size() < minimum_size)
return false;
if (data->type == nn::hac::cnmt::METATYPE_APPLICATION)
// include exthdr/data check if applicable
if (data->exhdr_size.get() > 0)
{
if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Application)
{
const nn::hac::sApplicationMetaExtendedHeader* meta = (const nn::hac::sApplicationMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
if ((meta->patch_id.get() & data->id.get()) != data->id.get())
return false;
}
else if (data->type == nn::hac::cnmt::METATYPE_PATCH)
else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Patch)
{
const nn::hac::sPatchMetaExtendedHeader* meta = (const nn::hac::sPatchMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
if ((meta->application_id.get() & data->id.get()) != meta->application_id.get())
@ -772,13 +775,13 @@ bool UserSettings::determineValidCnmtFromSample(const fnd::Vec<byte_t>& sample)
minimum_size += meta->extended_data_size.get();
}
else if (data->type == nn::hac::cnmt::METATYPE_ADD_ON_CONTENT)
else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::AddOnContent)
{
const nn::hac::sAddOnContentMetaExtendedHeader* meta = (const nn::hac::sAddOnContentMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
if ((meta->application_id.get() & data->id.get()) != meta->application_id.get())
return false;
}
else if (data->type == nn::hac::cnmt::METATYPE_DELTA)
else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::Delta)
{
const nn::hac::sDeltaMetaExtendedHeader* meta = (const nn::hac::sDeltaMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
if ((meta->application_id.get() & data->id.get()) != meta->application_id.get())
@ -786,6 +789,13 @@ bool UserSettings::determineValidCnmtFromSample(const fnd::Vec<byte_t>& sample)
minimum_size += meta->extended_data_size.get();
}
else if (data->type == (byte_t)nn::hac::cnmt::ContentMetaType::SystemUpdate)
{
const nn::hac::sSystemUpdateMetaExtendedHeader* meta = (const nn::hac::sSystemUpdateMetaExtendedHeader*)(sample.data() + sizeof(nn::hac::sContentMetaHeader));
minimum_size += meta->extended_data_size.get();
}
}
if (sample.size() != minimum_size)
return false;
@ -800,7 +810,7 @@ bool UserSettings::determineValidNacpFromSample(const fnd::Vec<byte_t>& sample)
const nn::hac::sApplicationControlProperty* data = (const nn::hac::sApplicationControlProperty*)sample.data();
if (data->logo_type > nn::hac::nacp::LOGO_Nintendo)
if (data->logo_type > (byte_t)nn::hac::nacp::LogoType::Nintendo)
return false;
if (data->display_version[0] == 0)
@ -862,20 +872,20 @@ bool UserSettings::determineValidEsTikFromSample(const fnd::Vec<byte_t>& sample)
return true;
}
nn::hac::meta::InstructionType UserSettings::getInstructionTypeFromString(const std::string & type_str)
bool UserSettings::getIs64BitInstructionFromString(const std::string & type_str)
{
std::string str = type_str;
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
nn::hac::meta::InstructionType type;
bool flag;
if (str == "32bit")
type = nn::hac::meta::INSTR_32BIT;
flag = false;
else if (str == "64bit")
type = nn::hac::meta::INSTR_64BIT;
flag = true;
else
throw fnd::Exception(kModuleName, "Unsupported instruction type: " + str);
return type;
return flag;
}
void UserSettings::getHomePath(std::string& path) const
@ -912,10 +922,19 @@ void UserSettings::dumpKeyConfig() const
std::cout << "[KeyConfiguration]" << std::endl;
std::cout << " NCA Keys:" << std::endl;
if (mKeyCfg.getContentArchiveHeader0SignKey(rsa2048_key) == true)
dumpRsa2048Key(rsa2048_key, "Header Signature[0] Key", 2);
for (size_t i = 0; i < kMasterKeyNum; i++)
{
if (mKeyCfg.getContentArchiveHeader0SignKey(rsa2048_key, i) == true)
dumpRsa2048Key(rsa2048_key, "Header0-SignatureKey-" + kKeyIndex[i], 2);
}
for (size_t i = 0; i < kMasterKeyNum; i++)
{
if (mKeyCfg.getAcidSignKey(rsa2048_key, i) == true)
dumpRsa2048Key(rsa2048_key, "Acid-SignatureKey-" + kKeyIndex[i], 2);
}
if (mKeyCfg.getContentArchiveHeaderKey(aesxts_key) == true)
dumpAesXtsKey(aesxts_key, "Header Encryption Key", 2);
dumpAesXtsKey(aesxts_key, "Header-EncryptionKey", 2);
for (size_t i = 0; i < kMasterKeyNum; i++)
{
@ -937,15 +956,20 @@ void UserSettings::dumpKeyConfig() const
dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-System-" + kKeyIndex[i], 2);
}
std::cout << " NRR Keys:" << std::endl;
for (size_t i = 0; i < kMasterKeyNum; i++)
{
if (mKeyCfg.getNrrCertificateSignKey(rsa2048_key, i) == true)
dumpRsa2048Key(rsa2048_key, "Certificate-SignatureKey-" + kKeyIndex[i], 2);
}
std::cout << " XCI Keys:" << std::endl;
if (mKeyCfg.getXciHeaderSignKey(rsa2048_key) == true)
dumpRsa2048Key(rsa2048_key, "Header Signature Key", 2);
dumpRsa2048Key(rsa2048_key, "Header-SignatureKey", 2);
if (mKeyCfg.getXciHeaderKey(aes_key) == true)
dumpAesKey(aes_key, "Extended Header Encryption Key", 2);
dumpAesKey(aes_key, "ExtendedHeader-EncryptionKey", 2);
if (mKeyCfg.getAcidSignKey(rsa2048_key) == true)
dumpRsa2048Key(rsa2048_key, "ACID Signer Key", 1);
std::cout << " Package1 Keys:" << std::endl;

View file

@ -29,7 +29,7 @@ public:
bool isListFs() const;
bool isListApi() const;
bool isListSymbols() const;
nn::hac::meta::InstructionType getInstType() const;
bool getIs64BitInstruction() const;
// specialised paths
const sOptional<std::string>& getXciUpdatePath() const;
@ -114,7 +114,7 @@ private:
bool mListApi;
bool mListSymbols;
nn::hac::meta::InstructionType mInstructionType;
bool mIs64BitInstruction;
void populateCmdArgs(const std::vector<std::string>& arg_list, sCmdArgs& cmd_args);
void populateKeyset(sCmdArgs& args);
@ -126,7 +126,7 @@ private:
bool determineValidNacpFromSample(const fnd::Vec<byte_t>& sample) const;
bool determineValidEsCertFromSample(const fnd::Vec<byte_t>& sample) const;
bool determineValidEsTikFromSample(const fnd::Vec<byte_t>& sample) const;
nn::hac::meta::InstructionType getInstructionTypeFromString(const std::string& type_str);
bool getIs64BitInstructionFromString(const std::string& type_str);
void getHomePath(std::string& path) const;
void getSwitchPath(std::string& path) const;

View file

@ -141,7 +141,7 @@ int main(int argc, char** argv)
obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile());
obj.setInstructionType(user_set.getInstType());
obj.setIs64BitInstruction(user_set.getIs64BitInstruction());
obj.setListApi(user_set.isListApi());
obj.setListSymbols(user_set.isListSymbols());
@ -155,7 +155,7 @@ int main(int argc, char** argv)
obj.setCliOutputMode(user_set.getCliOutputMode());
obj.setVerifyMode(user_set.isVerifyFile());
obj.setInstructionType(user_set.getInstType());
obj.setIs64BitInstruction(user_set.getIs64BitInstruction());
obj.setListApi(user_set.isListApi());
obj.setListSymbols(user_set.isListSymbols());

View file

@ -2,6 +2,6 @@
#define APP_NAME "NSTool"
#define BIN_NAME "nstool"
#define VER_MAJOR 1
#define VER_MINOR 2
#define VER_MINOR 3
#define VER_PATCH 0
#define AUTHORS "jakcron"