diff --git a/lib/libfnd/include/fnd/SimpleTextOutput.h b/lib/libfnd/include/fnd/SimpleTextOutput.h index bbf8e73..ef0516f 100644 --- a/lib/libfnd/include/fnd/SimpleTextOutput.h +++ b/lib/libfnd/include/fnd/SimpleTextOutput.h @@ -1,4 +1,5 @@ #pragma once +#include #include namespace fnd @@ -10,6 +11,7 @@ namespace fnd static void hxdStyleDump(const byte_t* data, size_t len); static void hexDump(const byte_t* data, size_t len, size_t row_len, size_t indent_len); static void hexDump(const byte_t* data, size_t len); + static std::string arrayToString(const byte_t* data, size_t len, bool upper_case, const std::string& separator); private: static const size_t kDefaultRowLen = 0x10; static const size_t kDefaultByteGroupingSize = 1; diff --git a/lib/libfnd/include/fnd/ecdsa.h b/lib/libfnd/include/fnd/ecdsa.h index e06880e..04cfcff 100644 --- a/lib/libfnd/include/fnd/ecdsa.h +++ b/lib/libfnd/include/fnd/ecdsa.h @@ -21,8 +21,8 @@ namespace fnd void operator=(const sEcdsa240Point& other) { - memcpy(this->r, r, kEcdsa240Size); - memcpy(this->s, s, kEcdsa240Size); + memcpy(this->r, other.r, kEcdsa240Size); + memcpy(this->s, other.s, kEcdsa240Size); } bool operator==(const sEcdsa240Point& other) const diff --git a/lib/libfnd/source/SimpleTextOutput.cpp b/lib/libfnd/source/SimpleTextOutput.cpp index 7dbc17d..c7f1582 100644 --- a/lib/libfnd/source/SimpleTextOutput.cpp +++ b/lib/libfnd/source/SimpleTextOutput.cpp @@ -1,5 +1,8 @@ -#include +#include +#include +#include #include +#include void fnd::SimpleTextOutput::hxdStyleDump(const byte_t* data, size_t len, size_t row_len, size_t byte_grouping_size) { @@ -58,31 +61,30 @@ void fnd::SimpleTextOutput::hxdStyleDump(const byte_t* data, size_t len) void fnd::SimpleTextOutput::hexDump(const byte_t* data, size_t len, size_t row_len, size_t indent_len) { - for (size_t i = 0; i < len; i++) + for (size_t i = 0; i < len; i += row_len) { - if ((i % row_len) == 0) - { - if (i > 0) - putchar('\n'); - for (size_t j = 0; j < indent_len; j++) - { - putchar(' '); - } - } - printf("%02X", data[i]); - if ((i+1) >= len) - { - putchar('\n'); - } - + for (size_t j = 0; j < indent_len; j++) + std::cout << " "; + std::cout << arrayToString(data+i, _MIN(len-i, row_len), true, "") << std::endl; } } void fnd::SimpleTextOutput::hexDump(const byte_t* data, size_t len) { + std::cout << arrayToString(data, len, true, "") << std::endl; +} + +std::string fnd::SimpleTextOutput::arrayToString(const byte_t* data, size_t len, bool upper_case, const std::string& separator) +{ + std::stringstream ss; + + if (upper_case) + ss << std::uppercase; for (size_t i = 0; i < len; i++) { - printf("%02X", data[i]); + ss << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)data[i]; + if (i+1 < len) + ss << separator; } - putchar('\n'); + return ss.str(); } \ No newline at end of file diff --git a/programs/nstool/source/AssetProcess.cpp b/programs/nstool/source/AssetProcess.cpp index ef48adf..0128ee1 100644 --- a/programs/nstool/source/AssetProcess.cpp +++ b/programs/nstool/source/AssetProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include "AssetProcess.h" @@ -23,11 +25,6 @@ AssetProcess::~AssetProcess() void AssetProcess::process() { - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - importHeader(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) displayHeader(); @@ -74,6 +71,12 @@ void AssetProcess::setRomfsExtractPath(const std::string& path) void AssetProcess::importHeader() { fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + if (mFile->size() < sizeof(nn::hac::sAssetHeader)) { throw fnd::Exception(kModuleName, "Corrupt ASET: file too small"); @@ -141,16 +144,16 @@ void AssetProcess::displayHeader() { if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - printf("[ASET Header]\n"); - printf(" Icon:\n"); - printf(" Offset: 0x%" PRIx64 "\n", mHdr.getIconInfo().offset); - printf(" Size: 0x%" PRIx64 "\n", mHdr.getIconInfo().size); - printf(" NACP:\n"); - printf(" Offset: 0x%" PRIx64 "\n", mHdr.getNacpInfo().offset); - printf(" Size: 0x%" PRIx64 "\n", mHdr.getNacpInfo().size); - printf(" RomFS:\n"); - printf(" Offset: 0x%" PRIx64 "\n", mHdr.getRomfsInfo().offset); - printf(" Size: 0x%" PRIx64 "\n", mHdr.getRomfsInfo().size); + std::cout << "[ASET Header]" << std::endl; + std::cout << " Icon:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getIconInfo().offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getIconInfo().size << std::endl; + std::cout << " NACP:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getNacpInfo().offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getNacpInfo().size << std::endl; + std::cout << " RomFS:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getRomfsInfo().offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getRomfsInfo().size << std::endl; } } diff --git a/programs/nstool/source/CnmtProcess.cpp b/programs/nstool/source/CnmtProcess.cpp index 1606a9d..f40caab 100644 --- a/programs/nstool/source/CnmtProcess.cpp +++ b/programs/nstool/source/CnmtProcess.cpp @@ -1,146 +1,9 @@ +#include +#include #include #include "OffsetAdjustedIFile.h" #include "CnmtProcess.h" -const std::string kContentTypeStr[7] = -{ - "Meta", - "Program", - "Data", - "Control", - "HtmlDocument", - "LegalInformation", - "DeltaFragment" -}; - -const std::string kContentMetaTypeStr[2][0x80] = -{ - { - "", - "SystemProgram", - "SystemData", - "SystemUpdate", - "BootImagePackage", - "BootImagePackageSafe" - }, - { - "Application", - "Patch", - "AddOnContent", - "Delta" - } -}; - -const std::string kUpdateTypeStr[3] = -{ - "ApplyAsDelta", - "Overwrite", - "Create" -}; - -const std::string kContentMetaAttrStr[3] = -{ - "IncludesExFatDriver", - "Rebootless" -}; - - -std::string kUnknownStr = "Unknown"; - -inline const char* getBoolStr(bool isTrue) -{ - return isTrue? "TRUE" : "FALSE"; -} - -inline const char* getContentTypeStr(byte_t i) -{ - return i < 7 ? kContentTypeStr[i].c_str() : kUnknownStr.c_str(); -} - -inline const char* getContentMetaTypeStr(byte_t i) -{ - return (i < 0x80) ? kContentMetaTypeStr[0][i].c_str() : kContentMetaTypeStr[1][i - 0x80].c_str(); -} - -void CnmtProcess::displayCmnt() -{ -#define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff) -#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0) -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) - - printf("[ContentMeta]\n"); - printf(" TitleId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getTitleId()); - printf(" Version: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)mCnmt.getTitleVersion(), _SPLIT_VER(mCnmt.getTitleVersion())); - printf(" Type: %s (%d)\n", getContentMetaTypeStr(mCnmt.getType()), mCnmt.getType()); - printf(" Attributes: %x\n", mCnmt.getAttributes()); - printf(" IncludesExFatDriver: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER))); - printf(" Rebootless: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_REBOOTLESS))); - printf(" RequiredDownloadSystemVersion: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)mCnmt.getRequiredDownloadSystemVersion(), _SPLIT_VER(mCnmt.getRequiredDownloadSystemVersion())); - switch(mCnmt.getType()) - { - case (nn::hac::cnmt::METATYPE_APPLICATION): - printf(" ApplicationExtendedHeader:\n"); - printf(" RequiredSystemVersion: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)mCnmt.getApplicationMetaExtendedHeader().required_system_version, _SPLIT_VER(mCnmt.getApplicationMetaExtendedHeader().required_system_version)); - printf(" PatchId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getApplicationMetaExtendedHeader().patch_id); - break; - case (nn::hac::cnmt::METATYPE_PATCH): - printf(" PatchMetaExtendedHeader:\n"); - printf(" RequiredSystemVersion: v%" PRId32 " (%d.%d.%d.%d))\n", (uint32_t)mCnmt.getPatchMetaExtendedHeader().required_system_version, _SPLIT_VER(mCnmt.getPatchMetaExtendedHeader().required_system_version)); - printf(" ApplicationId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getPatchMetaExtendedHeader().application_id); - break; - case (nn::hac::cnmt::METATYPE_ADD_ON_CONTENT): - printf(" AddOnContentMetaExtendedHeader:\n"); - printf(" RequiredSystemVersion: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)mCnmt.getAddOnContentMetaExtendedHeader().required_system_version, _SPLIT_VER(mCnmt.getAddOnContentMetaExtendedHeader().required_system_version)); - printf(" ApplicationId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getAddOnContentMetaExtendedHeader().application_id); - break; - case (nn::hac::cnmt::METATYPE_DELTA): - printf(" DeltaMetaExtendedHeader:\n"); - printf(" ApplicationId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getDeltaMetaExtendedHeader().application_id); - break; - default: - break; - } - if (mCnmt.getContentInfo().size() > 0) - { - printf(" ContentInfo:\n"); - for (size_t i = 0; i < mCnmt.getContentInfo().size(); i++) - { - const nn::hac::ContentMetaBinary::ContentInfo& info = mCnmt.getContentInfo()[i]; - printf(" %d\n", (int)i); - printf(" Type: %s (%d)\n", getContentTypeStr(info.type), info.type); - printf(" Id: "); - _HEXDUMP_L(info.nca_id, nn::hac::cnmt::kContentIdLen); - printf("\n"); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size); - printf(" Hash: "); - _HEXDUMP_L(info.hash.bytes, sizeof(info.hash)); - printf("\n"); - } - } - if (mCnmt.getContentMetaInfo().size() > 0) - { - printf(" ContentMetaInfo:\n"); - for (size_t i = 0; i < mCnmt.getContentMetaInfo().size(); i++) - { - const nn::hac::ContentMetaBinary::ContentMetaInfo& info = mCnmt.getContentMetaInfo()[i]; - printf(" %d\n", (int)i); - printf(" Id: 0x%016" PRIx64 "\n", (uint64_t)info.id); - printf(" Version: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)info.version, _SPLIT_VER(info.version)); - printf(" Type: %s (%d)\n", getContentMetaTypeStr(info.type), info.type); - printf(" Attributes: %x\n", mCnmt.getAttributes()); - printf(" IncludesExFatDriver: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER))); - printf(" Rebootless: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_REBOOTLESS))); - } - } - printf(" Digest: "); - _HEXDUMP_L(mCnmt.getDigest().data, nn::hac::cnmt::kDigestLen); - printf("\n"); - -#undef _HEXDUMP_L -#undef _HEXDUMP_U -#undef _SPLIT_VER -} - CnmtProcess::CnmtProcess() : mFile(nullptr), mOwnIFile(false), @@ -159,20 +22,10 @@ CnmtProcess::~CnmtProcess() void CnmtProcess::process() { - fnd::Vec scratch; - - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - - scratch.alloc(mFile->size()); - mFile->read(scratch.data(), 0, scratch.size()); - - mCnmt.fromBytes(scratch.data(), scratch.size()); + importCnmt(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) - displayCmnt(); + displayCnmt(); } void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile) @@ -195,3 +48,212 @@ const nn::hac::ContentMetaBinary& CnmtProcess::getContentMetaBinary() const { return mCnmt; } + +void CnmtProcess::importCnmt() +{ + fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + scratch.alloc(mFile->size()); + mFile->read(scratch.data(), 0, scratch.size()); + + mCnmt.fromBytes(scratch.data(), scratch.size()); +} + +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: " << getContentMetaTypeStr(mCnmt.getType()) << " (" << std::dec << mCnmt.getType() << ")" << std::endl; + std::cout << " Attributes: 0x" << std::hex << (uint32_t)mCnmt.getAttributes() << std::endl; + std::cout << " IncludesExFatDriver: " << getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER)) << std::endl; + std::cout << " Rebootless: " << getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_REBOOTLESS)) << std::endl; + std::cout << " RequiredDownloadSystemVersion: v" << mCnmt.getRequiredDownloadSystemVersion() << " (" << _SPLIT_VER(mCnmt.getRequiredDownloadSystemVersion()) << ")"<< std::endl; + switch(mCnmt.getType()) + { + case (nn::hac::cnmt::METATYPE_APPLICATION): + std::cout << " ApplicationExtendedHeader:" << std::endl; + std::cout << " RequiredSystemVersion: v" << std::dec << mCnmt.getApplicationMetaExtendedHeader().required_system_version << " (" << _SPLIT_VER(mCnmt.getApplicationMetaExtendedHeader().required_system_version) << ")"<< std::endl; + std::cout << " PatchId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getApplicationMetaExtendedHeader().patch_id << std::endl; + break; + case (nn::hac::cnmt::METATYPE_PATCH): + std::cout << " PatchMetaExtendedHeader:" << std::endl; + std::cout << " RequiredSystemVersion: v" << std::dec << mCnmt.getPatchMetaExtendedHeader().required_system_version << " (" << _SPLIT_VER(mCnmt.getPatchMetaExtendedHeader().required_system_version) << ")"<< std::endl; + std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getPatchMetaExtendedHeader().application_id << std::endl; + break; + case (nn::hac::cnmt::METATYPE_ADD_ON_CONTENT): + std::cout << " AddOnContentMetaExtendedHeader:" << std::endl; + std::cout << " RequiredSystemVersion: v" << std::dec << mCnmt.getAddOnContentMetaExtendedHeader().required_system_version << " (" << _SPLIT_VER(mCnmt.getAddOnContentMetaExtendedHeader().required_system_version) << ")"<< std::endl; + std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getAddOnContentMetaExtendedHeader().application_id << std::endl; + break; + case (nn::hac::cnmt::METATYPE_DELTA): + std::cout << " DeltaMetaExtendedHeader:" << std::endl; + std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getDeltaMetaExtendedHeader().application_id << std::endl; + break; + default: + break; + } + if (mCnmt.getContentInfo().size() > 0) + { + printf(" ContentInfo:\n"); + for (size_t i = 0; i < mCnmt.getContentInfo().size(); i++) + { + const nn::hac::ContentMetaBinary::ContentInfo& info = mCnmt.getContentInfo()[i]; + std::cout << " " << std::dec << i << std::endl; + std::cout << " Type: " << getContentTypeStr(info.type) << " (" << std::dec << info.type << ")" << std::endl; + std::cout << " Id: " << fnd::SimpleTextOutput::arrayToString(info.nca_id, nn::hac::cnmt::kContentIdLen, false, "") << std::endl; + std::cout << " Size: 0x" << std::hex << info.size << std::endl; + std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(info.hash.bytes, sizeof(info.hash), false, "") << std::endl; + } + } + if (mCnmt.getContentMetaInfo().size() > 0) + { + std::cout << " ContentMetaInfo:" << std::endl; + for (size_t i = 0; i < mCnmt.getContentMetaInfo().size(); i++) + { + const nn::hac::ContentMetaBinary::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.id << std::endl; + std::cout << " Version: v" << std::dec << info.version << " (" << _SPLIT_VER(info.version) << ")"<< std::endl; + std::cout << " Type: " << getContentMetaTypeStr(info.type) << " (" << std::dec << info.type << ")" << std::endl; + std::cout << " Attributes: 0x" << std::hex << (uint32_t)info.attributes << std::endl; + std::cout << " IncludesExFatDriver: " << getBoolStr(_HAS_BIT(info.attributes, nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER)) << std::endl; + std::cout << " Rebootless: " << getBoolStr(_HAS_BIT(info.attributes, nn::hac::cnmt::ATTRIBUTE_REBOOTLESS)) << 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"; +} + +const char* CnmtProcess::getContentTypeStr(nn::hac::cnmt::ContentType type) const +{ + const char* str = nullptr; + + switch (type) + { + case (nn::hac::cnmt::TYPE_META): + str = "Meta"; + break; + case (nn::hac::cnmt::TYPE_PROGRAM): + str = "Program"; + break; + case (nn::hac::cnmt::TYPE_DATA): + str = "Data"; + break; + case (nn::hac::cnmt::TYPE_CONTROL): + str = "Control"; + break; + case (nn::hac::cnmt::TYPE_HTML_DOCUMENT): + str = "HtmlDocument"; + break; + case (nn::hac::cnmt::TYPE_LEGAL_INFORMATION): + str = "LegalInformation"; + break; + case (nn::hac::cnmt::TYPE_DELTA_FRAGMENT): + str = "DeltaFragment"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* CnmtProcess::getContentMetaTypeStr(nn::hac::cnmt::ContentMetaType type) const +{ + const char* str = nullptr; + + switch (type) + { + case (nn::hac::cnmt::METATYPE_SYSTEM_PROGRAM): + str = "SystemProgram"; + break; + case (nn::hac::cnmt::METATYPE_SYSTEM_DATA): + str = "SystemData"; + break; + case (nn::hac::cnmt::METATYPE_SYSTEM_UPDATE): + str = "SystemUpdate"; + break; + case (nn::hac::cnmt::METATYPE_BOOT_IMAGE_PACKAGE): + str = "BootImagePackage"; + break; + case (nn::hac::cnmt::METATYPE_BOOT_IMAGE_PACKAGE_SAFE): + str = "BootImagePackageSafe"; + break; + case (nn::hac::cnmt::METATYPE_APPLICATION): + str = "Application"; + break; + case (nn::hac::cnmt::METATYPE_PATCH): + str = "Patch"; + break; + case (nn::hac::cnmt::METATYPE_ADD_ON_CONTENT): + str = "AddOnContent"; + break; + case (nn::hac::cnmt::METATYPE_DELTA): + str = "Delta"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* CnmtProcess::getUpdateTypeStr(nn::hac::cnmt::UpdateType type) const +{ + const char* str = nullptr; + + switch (type) + { + case (nn::hac::cnmt::UPDATETYPE_APPLY_AS_DELTA): + str = "ApplyAsDelta"; + break; + case (nn::hac::cnmt::UPDATETYPE_OVERWRITE): + str = "Overwrite"; + break; + case (nn::hac::cnmt::UPDATETYPE_CREATE): + str = "Create"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* CnmtProcess::getContentMetaAttrStr(nn::hac::cnmt::ContentMetaAttribute attr) const +{ + const char* str = nullptr; + + switch (attr) + { + case (nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER): + str = "IncludesExFatDriver"; + break; + case (nn::hac::cnmt::ATTRIBUTE_REBOOTLESS): + str = "Rebootless"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} diff --git a/programs/nstool/source/CnmtProcess.h b/programs/nstool/source/CnmtProcess.h index 1f4ca52..83535ba 100644 --- a/programs/nstool/source/CnmtProcess.h +++ b/programs/nstool/source/CnmtProcess.h @@ -30,5 +30,12 @@ private: nn::hac::ContentMetaBinary mCnmt; - void displayCmnt(); + void importCnmt(); + void displayCnmt(); + + const char* getBoolStr(bool state) const; + const char* getContentTypeStr(nn::hac::cnmt::ContentType type) const; + const char* getContentMetaTypeStr(nn::hac::cnmt::ContentMetaType type) const; + const char* getUpdateTypeStr(nn::hac::cnmt::UpdateType type) const; + const char* getContentMetaAttrStr(nn::hac::cnmt::ContentMetaAttribute attr) const; }; \ No newline at end of file diff --git a/programs/nstool/source/EsTikProcess.cpp b/programs/nstool/source/EsTikProcess.cpp index cec162a..5a3801a 100644 --- a/programs/nstool/source/EsTikProcess.cpp +++ b/programs/nstool/source/EsTikProcess.cpp @@ -1,6 +1,5 @@ #include #include - #include #include #include "OffsetAdjustedIFile.h" @@ -64,12 +63,14 @@ void EsTikProcess::setVerifyMode(bool verify) void EsTikProcess::importTicket() { + fnd::Vec scratch; + + if (mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } - fnd::Vec scratch; scratch.alloc(mFile->size()); mFile->read(scratch.data(), 0, scratch.size()); mTik.fromBytes(scratch.data(), scratch.size()); @@ -106,9 +107,7 @@ void EsTikProcess::verifyTicket() void EsTikProcess::displayTicket() { -#define _SPLIT_VER(ver) ( (ver>>10) & 0x3f), ( (ver>>4) & 0x3f), ( (ver>>0) & 0xf) -#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0) -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) +#define _SPLIT_VER(ver) (uint32_t)((ver>>10) & 0x3f) << "." << (uint32_t)((ver>>4) & 0x3f) << "." << (uint32_t)((ver>>0) & 0xf) const nn::es::TicketBody_V2& body = mTik.getBody(); @@ -127,10 +126,10 @@ void EsTikProcess::displayTicket() size_t size = body.getTitleKeyEncType() == nn::es::ticket::RSA2048 ? fnd::rsa::kRsa2048Size : fnd::aes::kAes128KeySize; fnd::SimpleTextOutput::hexDump(body.getEncTitleKey(), size, 0x10, 6); - printf(" Version: v%d.%d.%d", _SPLIT_VER(body.getTicketVersion())); + std::cout << " Version: v" << _SPLIT_VER(body.getTicketVersion()); if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - printf(" (%d)", body.getTicketVersion()); - printf("\n"); + std::cout << " (" << (uint32_t)body.getTicketVersion() << ")"; + std::cout << std::endl; std::cout << " License Type: " << getLicenseTypeStr(body.getLicenseType()) << std::endl; @@ -163,9 +162,6 @@ void EsTikProcess::displayTicket() std::cout << " SectionNum: 0x" << std::hex << body.getSectionNum() << std::endl; std::cout << " SectionEntrySize: 0x" << std::hex << body.getSectionEntrySize() << std::endl; - -#undef _HEXDUMP_L -#undef _HEXDUMP_U #undef _SPLIT_VER } diff --git a/programs/nstool/source/NacpProcess.cpp b/programs/nstool/source/NacpProcess.cpp index 52cb2f8..fb6d5bf 100644 --- a/programs/nstool/source/NacpProcess.cpp +++ b/programs/nstool/source/NacpProcess.cpp @@ -1,11 +1,195 @@ #include +#include +#include #include #include "OffsetAdjustedIFile.h" #include "NacpProcess.h" -const char* getLanguageStr(nn::hac::nacp::Language var) +NacpProcess::NacpProcess() : + mFile(nullptr), + mOwnIFile(false), + mCliOutputMode(_BIT(OUTPUT_BASIC)), + mVerify(false) +{ +} + +NacpProcess::~NacpProcess() +{ + if (mOwnIFile) + { + delete mFile; + } +} + +void NacpProcess::process() +{ + importNacp(); + + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + displayNacp(); +} + +void NacpProcess::setInputFile(fnd::IFile* file, bool ownIFile) +{ + mFile = file; + mOwnIFile = ownIFile; +} + +void NacpProcess::setCliOutputMode(CliOutputMode type) +{ + mCliOutputMode = type; +} + +void NacpProcess::setVerifyMode(bool verify) +{ + mVerify = verify; +} + +const nn::hac::ApplicationControlPropertyBinary& NacpProcess::getApplicationControlPropertyBinary() const +{ + return mNacp; +} + +void NacpProcess::importNacp() +{ + fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + scratch.alloc(mFile->size()); + mFile->read(scratch.data(), 0, scratch.size()); + + mNacp.fromBytes(scratch.data(), scratch.size()); +} + +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++) + { + std::cout << " " << getLanguageStr(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: " << getLogoTypeStr(mNacp.getLogoType()) << std::endl; + std::cout << " Handling: " << getLogoHandlingStr(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: " << getAocRegistrationTypeStr(mNacp.getAocRegistrationType()) << std::endl; + std::cout << " RuntimeInstallMode: " << getRuntimeAocInstallModeStr(mNacp.getRuntimeAocInstallMode()) << std::endl; + std::cout << " Play Log:" << std::endl; + std::cout << " PlayLogPolicy: " << getPlayLogPolicyStr(mNacp.getPlayLogPolicy()) << std::endl; + std::cout << " PlayLogQueryCapability: " << getPlayLogQueryCapabilityStr(mNacp.getPlayLogQueryCapability()) << std::endl; + if (mNacp.getPlayLogQueryableApplicationId().size() > 0) + { + 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 << " Parental Controls:" << std::endl; + std::cout << " ParentalControlFlag: " << getParentalControlFlagStr(mNacp.getParentalControlFlag()) << std::endl; + for (size_t i = 0; i < mNacp.getRatingAge().size(); i++) + { + std::cout << " Age Restriction:" << std::endl; + std::cout << " Agency: " << getOrganisationStr(mNacp.getRatingAge()[i].organisation) << std::endl; + std::cout << " Age: " << std::dec << (uint32_t)mNacp.getRatingAge()[i].age << std::endl; + } + + if (mNacp.getBcatPassphase().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + { + std::cout << " BCAT:" << std::endl; + std::cout << " BcatPassphase: " << mNacp.getBcatPassphase() << std::endl; + std::cout << " DeliveryCacheStorageSize: 0x" << std::hex << mNacp.getBcatDeliveryCacheStorageSize() << std::endl; + } + if (mNacp.getLocalCommunicationId().size() > 0) + { + std::cout << " Local Area Communication:" << std::endl; + std::cout << " LocalCommunicationId:" << std::endl; + for (size_t i = 0; i < mNacp.getLocalCommunicationId().size(); i++) + { + 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: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().size) << std::endl; + std::cout << " JournalSize: " << getSaveDataSizeStr(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: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().size) << std::endl; + std::cout << " JournalSize: " << getSaveDataSizeStr(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: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().size) << std::endl; + std::cout << " JournalSize: " << getSaveDataSizeStr(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: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().size) << std::endl; + std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().journal_size) << std::endl; + } + if (mNacp.getTemporaryStorageSize() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + { + std::cout << " TemporaryStorageSize: " << getSaveDataSizeStr(mNacp.getTemporaryStorageSize()) << std::endl; + } + if (mNacp.getCacheStorageSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + { + std::cout << " CacheStorage:" << std::endl; + std::cout << " Size: " << getSaveDataSizeStr(mNacp.getCacheStorageSize().size) << std::endl; + std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getCacheStorageSize().journal_size) << std::endl; + std::cout << " MaxDataAndJournalSize: " << getSaveDataSizeStr(mNacp.getCacheStorageDataAndJournalSizeMax()) << std::endl; + std::cout << " StorageIndexMax: 0x" << std::hex << mNacp.getCacheStorageIndexMax() << std::endl; + } + std::cout << " Other Flags:" << std::endl; + std::cout << " StartupUserAccount: " << getStartupUserAccountStr(mNacp.getStartupUserAccount()) << std::endl; + if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + { + std::cout << " TouchScreenUsageMode: " << getTouchScreenUsageModeStr(mNacp.getTouchScreenUsageMode()) << std::endl; + } + std::cout << " AttributeFlag: " << getAttributeFlagStr(mNacp.getAttributeFlag()) << std::endl; + std::cout << " CrashReportMode: " << getCrashReportModeStr(mNacp.getCrashReportMode()) << std::endl; + std::cout << " HDCP: " << getHdcpStr(mNacp.getHdcp()) << std::endl; + std::cout << " ScreenshotMode: " << getScreenshotModeStr(mNacp.getScreenshotMode()) << std::endl; + std::cout << " VideoCaptureMode: " << getVideoCaptureModeStr(mNacp.getVideoCaptureMode()) << std::endl; + std::cout << " DataLossConfirmation: " << getDataLossConfirmationStr(mNacp.getDataLossConfirmation()) << std::endl; + std::cout << " RepairFlag: " << getRepairFlagStr(mNacp.getRepairFlag()) << std::endl; + std::cout << " ProgramIndex: 0x" << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)mNacp.getProgramIndex() << std::endl; + if (mNacp.getApplicationErrorCodeCategory().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + { + std::cout << " ApplicationErrorCodeCategory: " << mNacp.getApplicationErrorCodeCategory() << std::endl; + } + if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 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; + } +} + +const char* NacpProcess::getLanguageStr(nn::hac::nacp::Language var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::LANG_AmericanEnglish): @@ -56,12 +240,14 @@ const char* getLanguageStr(nn::hac::nacp::Language var) default: str = "Unknown"; } + return str; } -const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) +const char* NacpProcess::getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::USER_None): @@ -76,12 +262,14 @@ const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) default: str = "Unknown"; } + return str; } -const char* getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var) +const char* NacpProcess::getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::TOUCH_None): @@ -96,12 +284,14 @@ const char* getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var) default: str = "Unknown"; } + return str; } -const char* getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var) +const char* NacpProcess::getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::AOC_AllOnLaunch): @@ -113,12 +303,14 @@ const char* getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var) default: str = "Unknown"; } + return str; } -const char* getAttributeFlagStr(nn::hac::nacp::AttributeFlag var) +const char* NacpProcess::getAttributeFlagStr(nn::hac::nacp::AttributeFlag var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::ATTR_None): @@ -133,12 +325,14 @@ const char* getAttributeFlagStr(nn::hac::nacp::AttributeFlag var) default: str = "Unknown"; } + return str; } -const char* getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var) +const char* NacpProcess::getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::PC_None): @@ -150,12 +344,14 @@ const char* getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var) default: str = "Unknown"; } + return str; } -const char* getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var) +const char* NacpProcess::getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::SCRN_Allow): @@ -167,12 +363,14 @@ const char* getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var) default: str = "Unknown"; } + return str; } -const char* getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var) +const char* NacpProcess::getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::VCAP_Disable): @@ -187,12 +385,14 @@ const char* getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var) default: str = "Unknown"; } + return str; } -const char* getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var) +const char* NacpProcess::getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::DLOSS_None): @@ -204,12 +404,14 @@ const char* getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var) default: str = "Unknown"; } + return str; } -const char* getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var) +const char* NacpProcess::getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::PLP_All): @@ -224,12 +426,14 @@ const char* getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var) default: str = "Unknown"; } + return str; } -const char* getOrganisationStr(nn::hac::nacp::Organisation var) +const char* NacpProcess::getOrganisationStr(nn::hac::nacp::Organisation var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::ORGN_CERO): @@ -271,12 +475,14 @@ const char* getOrganisationStr(nn::hac::nacp::Organisation var) default: str = "Unknown"; } + return str; } -const char* getLogoTypeStr(nn::hac::nacp::LogoType var) +const char* NacpProcess::getLogoTypeStr(nn::hac::nacp::LogoType var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::LOGO_LicensedByNintendo): @@ -291,12 +497,14 @@ const char* getLogoTypeStr(nn::hac::nacp::LogoType var) default: str = "Unknown"; } + return str; } -const char* getLogoHandlingStr(nn::hac::nacp::LogoHandling var) +const char* NacpProcess::getLogoHandlingStr(nn::hac::nacp::LogoHandling var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::LHND_Auto): @@ -308,12 +516,14 @@ const char* getLogoHandlingStr(nn::hac::nacp::LogoHandling var) default: str = "Unknown"; } + return str; } -const char* getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var) +const char* NacpProcess::getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::RTAOC_Deny): @@ -325,12 +535,14 @@ const char* getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var default: str = "Unknown"; } + return str; } -const char* getCrashReportModeStr(nn::hac::nacp::CrashReportMode var) +const char* NacpProcess::getCrashReportModeStr(nn::hac::nacp::CrashReportMode var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::CREP_Deny): @@ -342,12 +554,14 @@ const char* getCrashReportModeStr(nn::hac::nacp::CrashReportMode var) default: str = "Unknown"; } + return str; } -const char* getHdcpStr(nn::hac::nacp::Hdcp var) +const char* NacpProcess::getHdcpStr(nn::hac::nacp::Hdcp var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::HDCP_None): @@ -359,12 +573,14 @@ const char* getHdcpStr(nn::hac::nacp::Hdcp var) default: str = "Unknown"; } + return str; } -const char* getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability var) +const char* NacpProcess::getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::PLQC_None): @@ -379,12 +595,14 @@ const char* getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability v default: str = "Unknown"; } + return str; } -const char* getRepairFlagStr(nn::hac::nacp::RepairFlag var) +const char* NacpProcess::getRepairFlagStr(nn::hac::nacp::RepairFlag var) const { const char* str = nullptr; + switch(var) { case (nn::hac::nacp::REPF_None): @@ -396,10 +614,11 @@ const char* getRepairFlagStr(nn::hac::nacp::RepairFlag var) default: str = "Unknown"; } + return str; } -std::string getSaveDataSizeStr(int64_t size) +std::string NacpProcess::getSaveDataSizeStr(int64_t size) const { static const int64_t kKiloByte = 1024; static const int64_t kMegaByte = 1024 * 1024; @@ -421,180 +640,4 @@ std::string getSaveDataSizeStr(int64_t size) } return sstr.str(); -} - -NacpProcess::NacpProcess() : - mFile(nullptr), - mOwnIFile(false), - mCliOutputMode(_BIT(OUTPUT_BASIC)), - mVerify(false) -{ -} - -NacpProcess::~NacpProcess() -{ - if (mOwnIFile) - { - delete mFile; - } -} - -void NacpProcess::process() -{ - fnd::Vec scratch; - - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - - scratch.alloc(mFile->size()); - mFile->read(scratch.data(), 0, scratch.size()); - - mNacp.fromBytes(scratch.data(), scratch.size()); - - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) - displayNacp(); -} - -void NacpProcess::setInputFile(fnd::IFile* file, bool ownIFile) -{ - mFile = file; - mOwnIFile = ownIFile; -} - -void NacpProcess::setCliOutputMode(CliOutputMode type) -{ - mCliOutputMode = type; -} - -void NacpProcess::setVerifyMode(bool verify) -{ - mVerify = verify; -} - -const nn::hac::ApplicationControlPropertyBinary& NacpProcess::getApplicationControlPropertyBinary() const -{ - return mNacp; -} - -void NacpProcess::displayNacp() -{ - printf("[ApplicationControlProperty]\n"); - printf(" Menu Description:\n"); - printf(" DisplayVersion: %s\n", mNacp.getDisplayVersion().c_str()); - if (mNacp.getIsbn().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - printf(" ISBN: %s\n", mNacp.getIsbn().c_str()); - for (size_t i = 0; i < mNacp.getTitle().size(); i++) - { - printf(" %s Title:\n", getLanguageStr(mNacp.getTitle()[i].language)); - printf(" Name: %s\n", mNacp.getTitle()[i].name.c_str()); - printf(" Publisher: %s\n", mNacp.getTitle()[i].publisher.c_str()); - } - printf(" Logo:\n"); - printf(" Type: %s\n", getLogoTypeStr(mNacp.getLogoType())); - printf(" Handling: %s\n", getLogoHandlingStr(mNacp.getLogoHandling())); - printf(" AddOnContent:\n"); - printf(" BaseId: 0x%016" PRIx64 "\n", mNacp.getAocBaseId()); - printf(" RegistrationType: %s\n", getAocRegistrationTypeStr(mNacp.getAocRegistrationType())); - printf(" RuntimeInstallMode: %s\n", getRuntimeAocInstallModeStr(mNacp.getRuntimeAocInstallMode())); - printf(" Play Log:\n"); - printf(" PlayLogPolicy: %s\n", getPlayLogPolicyStr(mNacp.getPlayLogPolicy())); - printf(" PlayLogQueryCapability: %s\n", getPlayLogQueryCapabilityStr(mNacp.getPlayLogQueryCapability())); - if (mNacp.getPlayLogQueryableApplicationId().size() > 0) - { - printf(" PlayLogQueryableApplicationId:\n"); - for (size_t i = 0; i < mNacp.getPlayLogQueryableApplicationId().size(); i++) - { - printf(" 0x%016" PRIx64 "\n", mNacp.getPlayLogQueryableApplicationId()[i]); - } - } - printf(" Parental Controls:\n"); - printf(" ParentalControlFlag: %s\n", getParentalControlFlagStr(mNacp.getParentalControlFlag())); - for (size_t i = 0; i < mNacp.getRatingAge().size(); i++) - { - printf(" Age Restriction:\n"); - printf(" Agency: %s\n", getOrganisationStr(mNacp.getRatingAge()[i].organisation)); - printf(" Age: %d\n", mNacp.getRatingAge()[i].age); - } - - if (mNacp.getBcatPassphase().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - { - printf(" BCAT:\n"); - printf(" BcatPassphase: %s\n", mNacp.getBcatPassphase().c_str()); - printf(" DeliveryCacheStorageSize: 0x%016" PRIx64 "\n", mNacp.getBcatDeliveryCacheStorageSize()); - } - if (mNacp.getLocalCommunicationId().size() > 0) - { - printf(" Local Area Communication:\n"); - printf(" LocalCommunicationId:\n"); - for (size_t i = 0; i < mNacp.getLocalCommunicationId().size(); i++) - { - printf(" 0x%016" PRIx64 "\n", mNacp.getLocalCommunicationId()[i]); - } - } - printf(" SaveData:\n"); - printf(" SaveDatawOwnerId: 0x%016" PRIx64 "\n", mNacp.getSaveDatawOwnerId()); - if (mNacp.getUserAccountSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - { - printf(" UserAccountSaveData:\n"); - printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().size).c_str()); - printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().journal_size).c_str()); - } - if (mNacp.getDeviceSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - { - printf(" DeviceSaveData:\n"); - printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().size).c_str()); - printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().journal_size).c_str()); - } - if (mNacp.getUserAccountSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - { - printf(" UserAccountSaveDataMax:\n"); - printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().size).c_str()); - printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().journal_size).c_str()); - } - if (mNacp.getDeviceSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - { - printf(" DeviceSaveDataMax:\n"); - printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().size).c_str()); - printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().journal_size).c_str()); - } - if (mNacp.getTemporaryStorageSize() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - { - printf(" TemporaryStorageSize: %s\n", getSaveDataSizeStr(mNacp.getTemporaryStorageSize()).c_str()); - } - if (mNacp.getCacheStorageSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - { - printf(" CacheStorage:\n"); - printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageSize().size).c_str()); - printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageSize().journal_size).c_str()); - printf(" MaxDataAndJournalSize: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageDataAndJournalSizeMax()).c_str()); - printf(" StorageIndexMax: 0x%" PRIx16 "\n", mNacp.getCacheStorageIndexMax()); - } - printf(" Other Flags:\n"); - printf(" StartupUserAccount: %s\n", getStartupUserAccountStr(mNacp.getStartupUserAccount())); - if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - { - printf(" TouchScreenUsageMode: %s\n", getTouchScreenUsageModeStr(mNacp.getTouchScreenUsageMode())); - } - printf(" AttributeFlag: %s\n", getAttributeFlagStr(mNacp.getAttributeFlag())); - printf(" CrashReportMode: %s\n", getCrashReportModeStr(mNacp.getCrashReportMode())); - printf(" HDCP: %s\n", getHdcpStr(mNacp.getHdcp())); - printf(" ScreenshotMode: %s\n", getScreenshotModeStr(mNacp.getScreenshotMode())); - printf(" VideoCaptureMode: %s\n", getVideoCaptureModeStr(mNacp.getVideoCaptureMode())); - printf(" DataLossConfirmation: %s\n", getDataLossConfirmationStr(mNacp.getDataLossConfirmation())); - printf(" RepairFlag: %s\n", getRepairFlagStr(mNacp.getRepairFlag())); - printf(" ProgramIndex: 0x%02x\n", mNacp.getProgramIndex()); - if (mNacp.getApplicationErrorCodeCategory().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - { - printf(" ApplicationErrorCodeCategory: %s\n", mNacp.getApplicationErrorCodeCategory().c_str()); - } - if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - { - printf(" Other Ids:\n"); - if (mNacp.getSeedForPsuedoDeviceId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - printf(" SeedForPsuedoDeviceId: 0x%016" PRIx64 "\n", mNacp.getSeedForPsuedoDeviceId()); - if (mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - printf(" PresenceGroupId: 0x%016" PRIx64 "\n", mNacp.getPresenceGroupId()); - } -} +} \ No newline at end of file diff --git a/programs/nstool/source/NacpProcess.h b/programs/nstool/source/NacpProcess.h index 7511d79..8d6eb6e 100644 --- a/programs/nstool/source/NacpProcess.h +++ b/programs/nstool/source/NacpProcess.h @@ -30,5 +30,25 @@ private: nn::hac::ApplicationControlPropertyBinary mNacp; + void importNacp(); void displayNacp(); + const char* getLanguageStr(nn::hac::nacp::Language var) const; + const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) const; + const char* getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var) const; + const char* getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var) const; + const char* getAttributeFlagStr(nn::hac::nacp::AttributeFlag var) const; + const char* getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var) const; + const char* getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var) const; + const char* getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var) const; + const char* getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var) const; + const char* getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var) const; + const char* getOrganisationStr(nn::hac::nacp::Organisation var) const; + const char* getLogoTypeStr(nn::hac::nacp::LogoType var) const; + const char* getLogoHandlingStr(nn::hac::nacp::LogoHandling var) const; + const char* getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var) const; + const char* getCrashReportModeStr(nn::hac::nacp::CrashReportMode var) const; + const char* getHdcpStr(nn::hac::nacp::Hdcp var) const; + const char* getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability var) const; + const char* getRepairFlagStr(nn::hac::nacp::RepairFlag var) const; + std::string getSaveDataSizeStr(int64_t size) const; }; \ No newline at end of file diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index bfc9f3f..90de628 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -11,215 +12,6 @@ #include "AesCtrWrappedIFile.h" #include "HashTreeWrappedIFile.h" -const char* getFormatVersionStr(nn::hac::NcaHeader::FormatVersion format_ver) -{ - const char* str; - switch (format_ver) - { - case (nn::hac::NcaHeader::NCA2_FORMAT): - str = "NCA2"; - break; - case (nn::hac::NcaHeader::NCA3_FORMAT): - str = "NCA3"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - -const char* getDistributionTypeStr(nn::hac::nca::DistributionType dist_type) -{ - const char* str; - switch (dist_type) - { - case (nn::hac::nca::DIST_DOWNLOAD): - str = "Download"; - break; - case (nn::hac::nca::DIST_GAME_CARD): - str = "Game Card"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - - - const char* getContentTypeStr(nn::hac::nca::ContentType cont_type) -{ - const char* str; - switch (cont_type) - { - case (nn::hac::nca::TYPE_PROGRAM): - str = "Program"; - break; - case (nn::hac::nca::TYPE_META): - str = "Meta"; - break; - case (nn::hac::nca::TYPE_CONTROL): - str = "Control"; - break; - case (nn::hac::nca::TYPE_MANUAL): - str = "Manual"; - break; - case (nn::hac::nca::TYPE_DATA): - str = "Data"; - break; - case (nn::hac::nca::TYPE_PUBLIC_DATA): - str = "PublicData"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - -const char* getEncryptionTypeStr(nn::hac::nca::EncryptionType enc_type) -{ - const char* str; - switch (enc_type) - { - case (nn::hac::nca::CRYPT_AUTO): - str = "Auto"; - break; - case (nn::hac::nca::CRYPT_NONE): - str = "None"; - break; - case (nn::hac::nca::CRYPT_AESXTS): - str = "AesXts"; - break; - case (nn::hac::nca::CRYPT_AESCTR): - str = "AesCtr"; - break; - case (nn::hac::nca::CRYPT_AESCTREX): - str = "AesCtrEx"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - -inline const char* getHashTypeStr(nn::hac::nca::HashType hash_type) -{ - const char* str; - switch (hash_type) - { - case (nn::hac::nca::HASH_AUTO): - str = "Auto"; - break; - case (nn::hac::nca::HASH_NONE): - str = "None"; - break; - case (nn::hac::nca::HASH_HIERARCHICAL_SHA256): - str = "HierarchicalSha256"; - break; - case (nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY): - str = "HierarchicalIntegrity"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - -inline const char* getFormatTypeStr(nn::hac::nca::FormatType format_type) -{ - const char* str; - switch (format_type) - { - case (nn::hac::nca::FORMAT_ROMFS): - str = "RomFs"; - break; - case (nn::hac::nca::FORMAT_PFS0): - str = "PartitionFs"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - -inline const char* getKaekIndexStr(nn::hac::nca::KeyAreaEncryptionKeyIndex keak_index) -{ - const char* str; - switch (keak_index) - { - case (nn::hac::nca::KAEK_IDX_APPLICATION): - str = "Application"; - break; - case (nn::hac::nca::KAEK_IDX_OCEAN): - str = "Ocean"; - break; - case (nn::hac::nca::KAEK_IDX_SYSTEM): - str = "System"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - -inline const char* getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) -{ - const char* str; - switch (cont_type) - { - case (nn::hac::nca::TYPE_PROGRAM): - str = "program"; - break; - case (nn::hac::nca::TYPE_META): - str = "meta"; - break; - case (nn::hac::nca::TYPE_CONTROL): - str = "control"; - break; - case (nn::hac::nca::TYPE_MANUAL): - str = "manual"; - break; - case (nn::hac::nca::TYPE_DATA): - str = "data"; - break; - case (nn::hac::nca::TYPE_PUBLIC_DATA): - str = "publicData"; - break; - default: - str = ""; - break; - } - return str; -} - -const char* getProgramPartitionNameStr(size_t i) -{ - const char* str; - switch (i) - { - case (nn::hac::nca::PARTITION_CODE): - str = "code"; - break; - case (nn::hac::nca::PARTITION_DATA): - str = "data"; - break; - case (nn::hac::nca::PARTITION_LOGO): - str = "logo"; - break; - default: - str = ""; - break; - } - return str; -} - - NcaProcess::NcaProcess() : mFile(nullptr), mOwnIFile(false), @@ -253,22 +45,8 @@ NcaProcess::~NcaProcess() void NcaProcess::process() { - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - - // read header block - mFile->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock)); - - // decrypt header block - nn::hac::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyset->nca.header_key); - - // generate header hash - fnd::sha::Sha256((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader), mHdrHash.bytes); - - // proccess main header - mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader)); + // import header + importHeader(); // determine keys generateNcaBodyEncryptionKeys(); @@ -338,6 +116,26 @@ void NcaProcess::setListFs(bool list_fs) mListFs = list_fs; } +void NcaProcess::importHeader() +{ + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + // read header block + mFile->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock)); + + // decrypt header block + nn::hac::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyset->nca.header_key); + + // generate header hash + fnd::sha::Sha256((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader), mHdrHash.bytes); + + // proccess main header + mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader)); +} + void NcaProcess::generateNcaBodyEncryptionKeys() { // create zeros key @@ -440,18 +238,15 @@ void NcaProcess::generateNcaBodyEncryptionKeys() { if (mBodyKeys.aes_ctr.isSet) { - printf("[NCA Body Key]\n"); - printf(" AES-CTR Key: "); - fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var)); + std::cout << "[NCA Body Key]" << std::endl; + std::cout << " AES-CTR Key: " << fnd::SimpleTextOutput::arrayToString(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var), true, "") << std::endl; } if (mBodyKeys.aes_xts.isSet) { - printf("[NCA Body Key]\n"); - printf(" AES-XTS Key0: "); - fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var)); - printf(" AES-XTS Key1: "); - fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var)); + std::cout << "[NCA Body Key]" << std::endl; + std::cout << " AES-XTS Key0: " << fnd::SimpleTextOutput::arrayToString(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var), true, "") << std::endl; + std::cout << " AES-XTS Key1: " << fnd::SimpleTextOutput::arrayToString(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var), true, "") << std::endl; } } @@ -572,7 +367,7 @@ void NcaProcess::validateNcaSignatures() // validate signature[0] if (fnd::rsa::pss::rsaVerify(mKeyset->nca.header_sign_key, fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_main) != 0) { - printf("[WARNING] NCA Header Main Signature: FAIL \n"); + std::cout << "[WARNING] NCA Header Main Signature: FAIL" << std::endl; } // validate signature[1] @@ -599,147 +394,125 @@ void NcaProcess::validateNcaSignatures() if (fnd::rsa::pss::rsaVerify(npdm.getNpdmBinary().getAcid().getNcaHeaderSignature2Key(), fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_acid) != 0) { - printf("[WARNING] NCA Header ACID Signature: FAIL \n"); + std::cout << "[WARNING] NCA Header ACID Signature: FAIL" << std::endl; } } else { - printf("[WARNING] NCA Header ACID Signature: FAIL (\"%s\" not present in ExeFs)\n", kNpdmExefsPath.c_str()); + std::cout << "[WARNING] NCA Header ACID Signature: FAIL (\"" << kNpdmExefsPath << "\" not present in ExeFs)" << std::endl; } } else { - printf("[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)\n"); + std::cout << "[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)" << std::endl; } } else { - printf("[WARNING] NCA Header ACID Signature: FAIL (No ExeFs partition)\n"); + std::cout << "[WARNING] NCA Header ACID Signature: FAIL (No ExeFs partition)" << std::endl; } } } void NcaProcess::displayHeader() { -#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0) -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) - - printf("[NCA Header]\n"); - printf(" Format Type: %s\n", getFormatVersionStr(mHdr.getFormatVersion())); - printf(" Dist. Type: %s\n", getDistributionTypeStr(mHdr.getDistributionType())); - printf(" Content Type: %s\n", getContentTypeStr(mHdr.getContentType())); - printf(" Key Generation: %d\n", mHdr.getKeyGeneration()); - printf(" Kaek Index: %s (%d)\n", getKaekIndexStr((nn::hac::nca::KeyAreaEncryptionKeyIndex)mHdr.getKaekIndex()), mHdr.getKaekIndex()); - printf(" Size: 0x%" PRIx64 "\n", mHdr.getContentSize()); - printf(" ProgID: 0x%016" PRIx64 "\n", mHdr.getProgramId()); - printf(" Content Index: %" PRIu32 "\n", mHdr.getContentIndex()); -#define _SPLIT_VER(ver) ( (ver>>24) & 0xff), ( (ver>>16) & 0xff), ( (ver>>8) & 0xff) - printf(" SdkAddon Ver.: v%" PRIu32 " (%d.%d.%d)\n", mHdr.getSdkAddonVersion(), _SPLIT_VER(mHdr.getSdkAddonVersion())); + std::cout << "[NCA Header]" << std::endl; + std::cout << " Format Type: " << getFormatVersionStr(mHdr.getFormatVersion()) << std::endl; + std::cout << " Dist. Type: " << getDistributionTypeStr(mHdr.getDistributionType()) << std::endl; + std::cout << " Content Type: " << getContentTypeStr(mHdr.getContentType()) << std::endl; + std::cout << " Key Generation: " << std::dec << (uint32_t)mHdr.getKeyGeneration() << std::endl; + std::cout << " Kaek Index: " << getKaekIndexStr((nn::hac::nca::KeyAreaEncryptionKeyIndex)mHdr.getKaekIndex()) << " (" << std::dec << (uint32_t)mHdr.getKaekIndex() << ")" << 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 if (mHdr.hasRightsId()) { - printf(" RightsId: "); - fnd::SimpleTextOutput::hexDump(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen); + std::cout << " RightsId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen, true, "") << std::endl; } - if (mBodyKeys.keak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) { - printf(" Key Area: \n"); - printf(" <--------------------------------------------------------------------------->\n"); - printf(" | IDX | ENCRYPTED KEY | DECRYPTED KEY |\n"); - printf(" |-----|----------------------------------|----------------------------------|\n"); + std::cout << " Key Area:" << std::endl; + std::cout << " <--------------------------------------------------------------------------->" << std::endl; + std::cout << " | IDX | ENCRYPTED KEY | DECRYPTED KEY |" << std::endl; + std::cout << " |-----|----------------------------------|----------------------------------|" << std::endl; for (size_t i = 0; i < mBodyKeys.keak_list.size(); i++) { - printf(" | %3d | ", mBodyKeys.keak_list[i].index); + std::cout << " | " << std::dec << std::setw(3) << std::setfill(' ') << (uint32_t)mBodyKeys.keak_list[i].index << " | "; - _HEXDUMP_L(mBodyKeys.keak_list[i].enc.key, 16); - //for (size_t j = 0; j < 16; j++) printf("%02x", mBodyKeys.keak_list[i].enc.key[j]); + std::cout << fnd::SimpleTextOutput::arrayToString(mBodyKeys.keak_list[i].enc.key, 16, false, "") << " | "; - printf(" | "); if (mBodyKeys.keak_list[i].decrypted) - _HEXDUMP_L(mBodyKeys.keak_list[i].dec.key, 16); + std::cout << fnd::SimpleTextOutput::arrayToString(mBodyKeys.keak_list[i].dec.key, 16, false, ""); else - printf(" "); + std::cout << " "; - printf(" |\n"); + std::cout << " |" << std::endl; } - printf(" <--------------------------------------------------------------------------->\n"); + std::cout << " <--------------------------------------------------------------------------->" << std::endl; } if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - printf(" Partitions:\n"); + std::cout << " Partitions:" << std::endl; for (size_t i = 0; i < mHdr.getPartitions().size(); i++) { size_t index = mHdr.getPartitions()[i].index; sPartitionInfo& info = mPartitions[index]; - printf(" %d:\n", (int)index); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)info.offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size); - printf(" Format Type: %s\n", getFormatTypeStr(info.format_type)); - printf(" Hash Type: %s\n", getHashTypeStr(info.hash_type)); - printf(" Enc. Type: %s\n", getEncryptionTypeStr(info.enc_type)); + std::cout << " " << std::dec << index << ":" << std::endl; + std::cout << " Offset: 0x" << std::hex << (uint64_t)info.offset << std::endl; + std::cout << " Size: 0x" << std::hex << (uint64_t)info.size << std::endl; + std::cout << " Format Type: " << getFormatTypeStr(info.format_type) << std::endl; + std::cout << " Hash Type: " << getHashTypeStr(info.hash_type) << std::endl; + std::cout << " Enc. Type: " << getEncryptionTypeStr(info.enc_type) << std::endl; if (info.enc_type == nn::hac::nca::CRYPT_AESCTR) { - printf(" AES-CTR: "); fnd::aes::sAesIvCtr ctr; fnd::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv); - fnd::SimpleTextOutput::hexDump(ctr.iv, sizeof(fnd::aes::sAesIvCtr)); + std::cout << " AES-CTR: " << fnd::SimpleTextOutput::arrayToString(ctr.iv, sizeof(fnd::aes::sAesIvCtr), true, "") << std::endl; } if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY) { HashTreeMeta& hash_hdr = info.hash_tree_meta; - printf(" HierarchicalIntegrity Header:\n"); - //printf(" TypeId: 0x%x\n", hash_hdr.type_id.get()); - //printf(" MasterHashSize: 0x%x\n", hash_hdr.master_hash_size.get()); - //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().size()); + std::cout << " HierarchicalIntegrity Header:" << std::endl; for (size_t j = 0; j < hash_hdr.getHashLayerInfo().size(); j++) { - printf(" Hash Layer %d:\n", (int)j); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].size); - printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getHashLayerInfo()[j].block_size); + std::cout << " Hash Layer " << std::dec << j << ":" << std::endl; + std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[j].offset << std::endl; + std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[j].size << std::endl; + std::cout << " BlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getHashLayerInfo()[j].block_size << std::endl; } - printf(" Data Layer:\n"); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size); - printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size); + std::cout << " Data Layer:" << std::endl; + std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().offset << std::endl; + std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().size << std::endl; + std::cout << " BlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl; for (size_t j = 0; j < hash_hdr.getMasterHashList().size(); j++) { - printf(" Master Hash %d: ", (int)j); - fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[j].bytes, sizeof(fnd::sha::sSha256Hash)); + std::cout << " Master Hash " << std::dec << j << ": " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[j].bytes, sizeof(fnd::sha::sSha256Hash), true, "") << std::endl; } } else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256) { HashTreeMeta& hash_hdr = info.hash_tree_meta; - printf(" HierarchicalSha256 Header:\n"); - printf(" Master Hash: "); - fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[0].bytes, sizeof(fnd::sha::sSha256Hash)); - printf(" HashBlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size); - //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().size()); - printf(" Hash Layer:\n"); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].size); - printf(" Data Layer:\n"); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size); + std::cout << " HierarchicalSha256 Header:" << std::endl; + std::cout << " Master Hash: " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[0].bytes, sizeof(fnd::sha::sSha256Hash), true, "") << std::endl; + std::cout << " HashBlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl; + std::cout << " Hash Layer:" << std::endl; + std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].offset << std::endl; + std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].size << std::endl; + std::cout << " Data Layer:" << std::endl; + std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().offset << std::endl; + std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().size << std::endl; } - //else - //{ - // printf(" Hash Superblock:\n"); - // fnd::SimpleTextOutput::hxdStyleDump(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen); - //} } } - -#undef _HEXDUMP_U -#undef _HEXDUMP_L } @@ -753,12 +526,12 @@ void NcaProcess::processPartitions() // if the reader is null, skip if (partition.reader == nullptr) { - printf("[WARNING] NCA Partition %d not readable.", (int)index); + std::cout << "[WARNING] NCA Partition " << std::dec << index << " not readable."; if (partition.fail_reason.empty() == false) { - printf(" (%s)", partition.fail_reason.c_str()); + std::cout << " (" << partition.fail_reason << ")"; } - printf("\n"); + std::cout << std::endl; continue; } @@ -779,9 +552,7 @@ void NcaProcess::processPartitions() if (mPartitionPath[index].doExtract) pfs.setExtractPath(mPartitionPath[index].path); - //printf("pfs.process(%lx)\n",partition.data_offset); pfs.process(); - //printf("pfs.process() end\n"); } else if (partition.format_type == nn::hac::nca::FORMAT_ROMFS) { @@ -800,9 +571,233 @@ void NcaProcess::processPartitions() if (mPartitionPath[index].doExtract) romfs.setExtractPath(mPartitionPath[index].path); - //printf("romfs.process(%lx)\n", partition.data_offset); romfs.process(); - //printf("romfs.process() end\n"); } } } + +const char* NcaProcess::getFormatVersionStr(nn::hac::NcaHeader::FormatVersion format_ver) const +{ + const char* str = nullptr; + + switch (format_ver) + { + case (nn::hac::NcaHeader::NCA2_FORMAT): + str = "NCA2"; + break; + case (nn::hac::NcaHeader::NCA3_FORMAT): + str = "NCA3"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NcaProcess::getDistributionTypeStr(nn::hac::nca::DistributionType dist_type) const +{ + const char* str = nullptr; + + switch (dist_type) + { + case (nn::hac::nca::DIST_DOWNLOAD): + str = "Download"; + break; + case (nn::hac::nca::DIST_GAME_CARD): + str = "Game Card"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + + +const char* NcaProcess::getContentTypeStr(nn::hac::nca::ContentType cont_type) const +{ + const char* str = nullptr; + + switch (cont_type) + { + case (nn::hac::nca::TYPE_PROGRAM): + str = "Program"; + break; + case (nn::hac::nca::TYPE_META): + str = "Meta"; + break; + case (nn::hac::nca::TYPE_CONTROL): + str = "Control"; + break; + case (nn::hac::nca::TYPE_MANUAL): + str = "Manual"; + break; + case (nn::hac::nca::TYPE_DATA): + str = "Data"; + break; + case (nn::hac::nca::TYPE_PUBLIC_DATA): + str = "PublicData"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NcaProcess::getEncryptionTypeStr(nn::hac::nca::EncryptionType enc_type) const +{ + const char* str = nullptr; + + switch (enc_type) + { + case (nn::hac::nca::CRYPT_AUTO): + str = "Auto"; + break; + case (nn::hac::nca::CRYPT_NONE): + str = "None"; + break; + case (nn::hac::nca::CRYPT_AESXTS): + str = "AesXts"; + break; + case (nn::hac::nca::CRYPT_AESCTR): + str = "AesCtr"; + break; + case (nn::hac::nca::CRYPT_AESCTREX): + str = "AesCtrEx"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NcaProcess::getHashTypeStr(nn::hac::nca::HashType hash_type) const +{ + const char* str = nullptr; + + switch (hash_type) + { + case (nn::hac::nca::HASH_AUTO): + str = "Auto"; + break; + case (nn::hac::nca::HASH_NONE): + str = "None"; + break; + case (nn::hac::nca::HASH_HIERARCHICAL_SHA256): + str = "HierarchicalSha256"; + break; + case (nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY): + str = "HierarchicalIntegrity"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NcaProcess::getFormatTypeStr(nn::hac::nca::FormatType format_type) const +{ + const char* str = nullptr; + + switch (format_type) + { + case (nn::hac::nca::FORMAT_ROMFS): + str = "RomFs"; + break; + case (nn::hac::nca::FORMAT_PFS0): + str = "PartitionFs"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NcaProcess::getKaekIndexStr(nn::hac::nca::KeyAreaEncryptionKeyIndex keak_index) const +{ + const char* str = nullptr; + + switch (keak_index) + { + case (nn::hac::nca::KAEK_IDX_APPLICATION): + str = "Application"; + break; + case (nn::hac::nca::KAEK_IDX_OCEAN): + str = "Ocean"; + break; + case (nn::hac::nca::KAEK_IDX_SYSTEM): + str = "System"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NcaProcess::getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const +{ + const char* str = nullptr; + + switch (cont_type) + { + case (nn::hac::nca::TYPE_PROGRAM): + str = "program"; + break; + case (nn::hac::nca::TYPE_META): + str = "meta"; + break; + case (nn::hac::nca::TYPE_CONTROL): + str = "control"; + break; + case (nn::hac::nca::TYPE_MANUAL): + str = "manual"; + break; + case (nn::hac::nca::TYPE_DATA): + str = "data"; + break; + case (nn::hac::nca::TYPE_PUBLIC_DATA): + str = "publicData"; + break; + default: + str = ""; + break; + } + + return str; +} + +const char* NcaProcess::getProgramPartitionNameStr(size_t i) const +{ + const char* str = nullptr; + + switch (i) + { + case (nn::hac::nca::PARTITION_CODE): + str = "code"; + break; + case (nn::hac::nca::PARTITION_DATA): + str = "data"; + break; + case (nn::hac::nca::PARTITION_LOGO): + str = "logo"; + break; + default: + str = ""; + break; + } + + return str; +} \ No newline at end of file diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h index e21ded8..a9b0806 100644 --- a/programs/nstool/source/NcaProcess.h +++ b/programs/nstool/source/NcaProcess.h @@ -105,9 +105,20 @@ private: fnd::aes::sAesIvCtr aes_ctr; } mPartitions[nn::hac::nca::kPartitionNum]; + void importHeader(); void generateNcaBodyEncryptionKeys(); void generatePartitionConfiguration(); void validateNcaSignatures(); void displayHeader(); void processPartitions(); + + const char* getFormatVersionStr(nn::hac::NcaHeader::FormatVersion format_ver) const; + const char* getDistributionTypeStr(nn::hac::nca::DistributionType dist_type) const; + const char* getContentTypeStr(nn::hac::nca::ContentType cont_type) const; + const char* getEncryptionTypeStr(nn::hac::nca::EncryptionType enc_type) const; + const char* getHashTypeStr(nn::hac::nca::HashType hash_type) const; + const char* getFormatTypeStr(nn::hac::nca::FormatType format_type) const; + const char* getKaekIndexStr(nn::hac::nca::KeyAreaEncryptionKeyIndex keak_index) const; + const char* getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const; + const char* getProgramPartitionNameStr(size_t i) const; }; \ No newline at end of file diff --git a/programs/nstool/source/NpdmProcess.cpp b/programs/nstool/source/NpdmProcess.cpp index 6a7f977..b9f5fe6 100644 --- a/programs/nstool/source/NpdmProcess.cpp +++ b/programs/nstool/source/NpdmProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include "NpdmProcess.h" NpdmProcess::NpdmProcess() : @@ -19,17 +21,7 @@ NpdmProcess::~NpdmProcess() void NpdmProcess::process() { - fnd::Vec scratch; - - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - - scratch.alloc(mFile->size()); - mFile->read(scratch.data(), 0, scratch.size()); - - mNpdm.fromBytes(scratch.data(), scratch.size()); + importNpdm(); if (mVerify) { @@ -85,256 +77,20 @@ const nn::hac::NpdmBinary& NpdmProcess::getNpdmBinary() const return mNpdm; } -const std::string kInstructionType[2] = { "32Bit", "64Bit" }; -const std::string kProcAddrSpace[4] = { "Unknown", "64Bit", "32Bit", "32Bit no reserved" }; -const std::string kAcidFlag[32] = +void NpdmProcess::importNpdm() { - "Production", - "UnqualifiedApproval", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown" -}; -const std::string kMiscFlag[15] = { "EnableDebug", "ForceDebug", "bit2", "bit3", "bit4", "bit5", "bit6", "bit7", "bit8", "bit9", "bit10", "bit11", "bit12", "bit13", "bit14"}; -const std::string kFsaFlag[64] = -{ - "ApplicationInfo", - "BootModeControl", - "Calibration", - "SystemSaveData", - "GameCard", - "SaveDataBackUp", - "SaveDataManagement", - "BisAllRaw", - "GameCardRaw", - "GameCardPrivate", - "SetTime", - "ContentManager", - "ImageManager", - "CreateSaveData", - "SystemSaveDataManagement", - "BisFileSystem", - "SystemUpdate", - "SaveDataMeta", - "DeviceSaveData", - "SettingsControl", - "Bit20", - "Bit21", - "Bit22", - "Bit23", - "Bit24", - "Bit25", - "Bit26", - "Bit27", - "Bit28", - "Bit29", - "Bit30", - "Bit31", - "Bit32", - "Bit33", - "Bit34", - "Bit35", - "Bit36", - "Bit37", - "Bit38", - "Bit39", - "Bit40", - "Bit41", - "Bit42", - "Bit43", - "Bit44", - "Bit45", - "Bit46", - "Bit47", - "Bit48", - "Bit49", - "Bit50", - "Bit51", - "Bit52", - "Bit53", - "Bit54", - "Bit55", - "Bit56", - "Bit57", - "Bit58", - "Bit59", - "Bit60", - "Bit61", - "Debug", - "FullPermission" -}; + fnd::Vec scratch; -const std::string kSaveDataOwnerAccessMode[4] = -{ - "IllegalAccessCondition", - "Read", - "Write", - "ReadWrite" -}; + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } -const std::string kSysCall[0x80] = -{ - "svc00", - "SetHeapSize", - "SetMemoryPermission", - "SetMemoryAttribute", - "MapMemory", - "UnmapMemory", - "QueryMemory", - "ExitProcess", - "CreateThread", - "StartThread", - "ExitThread", - "SleepThread", - "GetThreadPriority", - "SetThreadPriority", - "GetThreadCoreMask", - "SetThreadCoreMask", - "GetCurrentProcessorNumber", - "SignalEvent", - "ClearEvent", - "MapSharedMemory", - "UnmapSharedMemory", - "CreateTransferMemory", - "CloseHandle", - "ResetSignal", - "WaitSynchronization", - "CancelSynchronization", - "ArbitrateLock", - "ArbitrateUnlock", - "WaitProcessWideKeyAtomic", - "SignalProcessWideKey", - "GetSystemTick", - "ConnectToNamedPort", - "SendSyncRequestLight", - "SendSyncRequest", - "SendSyncRequestWithUserBuffer", - "SendAsyncRequestWithUserBuffer", - "GetProcessId", - "GetThreadId", - "Break", - "OutputDebugString", - "ReturnFromException", - "GetInfo", - "FlushEntireDataCache", - "FlushDataCache", - "MapPhysicalMemory", - "UnmapPhysicalMemory", - "svc2E", - "GetLastThreadInfo", - "GetResourceLimitLimitValue", - "GetResourceLimitCurrentValue", - "SetThreadActivity", - "GetThreadContext3", - "svc34", - "svc35", - "svc36", - "svc37", - "svc38", - "svc39", - "svc3A", - "svc3B", - "DumpInfo", - "svc3D", - "svc3E", - "svc3F", - "CreateSession", - "AcceptSession", - "ReplyAndReceiveLight", - "ReplyAndReceive", - "ReplyAndReceiveWithUserBuffer", - "CreateEvent", - "svc46", - "svc47", - "svc48", - "svc49", - "svc4A", - "svc4B", - "svc4C", - "SleepSystem", - "ReadWriteRegister", - "SetProcessActivity", - "CreateSharedMemory", - "MapTransferMemory", - "UnmapTransferMemory", - "CreateInterruptEvent", - "QueryPhysicalAddress", - "QueryIoMapping", - "CreateDeviceAddressSpace", - "AttachDeviceAddressSpace", - "DetachDeviceAddressSpace", - "MapDeviceAddressSpaceByForce", - "MapDeviceAddressSpaceAligned", - "MapDeviceAddressSpace", - "UnmapDeviceAddressSpace", - "InvalidateProcessDataCache", - "StoreProcessDataCache", - "FlushProcessDataCache", - "DebugActiveProcess", - "BreakDebugProcess", - "TerminateDebugProcess", - "GetDebugEvent", - "ContinueDebugEvent", - "GetProcessList", - "GetThreadList", - "GetDebugThreadContext", - "SetDebugThreadContext", - "QueryDebugProcessMemory", - "ReadDebugProcessMemory", - "WriteDebugProcessMemory", - "SetHardwareBreakPoint", - "GetDebugThreadParam", - "svc6E", - "svc6F", - "CreatePort", - "ManageNamedPort", - "ConnectToPort", - "SetProcessMemoryPermission", - "MapProcessMemory", - "UnmapProcessMemory", - "QueryProcessMemory", - "MapProcessCodeMemory", - "UnmapProcessCodeMemory", - "CreateProcess", - "StartProcess", - "TerminateProcess", - "GetProcessInfo", - "CreateResourceLimit", - "SetResourceLimitLimitValue", - "CallSecureMonitor" -}; + scratch.alloc(mFile->size()); + mFile->read(scratch.data(), 0, scratch.size()); -const std::string kMemMapPerm[2] = { "RW", "RO" }; -const std::string kMemMapType[2] = { "Io", "Static" }; - -const std::string kAcidTarget[2] = { "Development", "Production" }; + mNpdm.fromBytes(scratch.data(), scratch.size()); +} void NpdmProcess::validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid) { @@ -342,7 +98,7 @@ void NpdmProcess::validateAcidSignature(const nn::hac::AccessControlInfoDescBina acid.validateSignature(mKeyset->acid_sign_key); } catch (...) { - printf("[WARNING] ACID Signature: FAIL\n"); + std::cout << "[WARNING] ACID Signature: FAIL" << std::endl; } } @@ -352,11 +108,11 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac // check Program ID if (acid.getProgramIdRestrict().min > 0 && aci.getProgramId() < acid.getProgramIdRestrict().min) { - printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n"); + std::cout << "[WARNING] ACI ProgramId: FAIL (Outside Legal Range)" << std::endl; } else if (acid.getProgramIdRestrict().max > 0 && aci.getProgramId() > acid.getProgramIdRestrict().max) { - printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n"); + std::cout << "[WARNING] ACI ProgramId: FAIL (Outside Legal Range)" << std::endl; } for (size_t i = 0; i < aci.getFileSystemAccessControl().getFsaRightsList().size(); i++) @@ -371,7 +127,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (fsaRightFound == false) { - printf("[WARNING] ACI/FAC FsaRights: FAIL (%s not permitted)\n", kFsaFlag[aci.getFileSystemAccessControl().getFsaRightsList()[i]].c_str()); + std::cout << "[WARNING] ACI/FAC FsaRights: FAIL (" << getFsaRightStr(aci.getFileSystemAccessControl().getFsaRightsList()[i]) << " not permitted)" << std::endl; } } @@ -387,7 +143,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%016" PRIx64 " not permitted)\n", aci.getFileSystemAccessControl().getContentOwnerIdList()[i]); + std::cout << "[WARNING] ACI/FAC ContentOwnerId: FAIL (" << std::hex << std::setw(16) << std::setfill('0') << aci.getFileSystemAccessControl().getContentOwnerIdList()[i] << " not permitted)" << std::endl; } } @@ -403,7 +159,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%016" PRIx64 "(%d) not permitted)\n", aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id, aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type); + std::cout << "[WARNING] ACI/FAC SaveDataOwnerId: FAIL (" << std::hex << std::setw(16) << std::setfill('0') << aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id << "(" << std::dec << (uint32_t)aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type << ") not permitted)" << std::endl; } } @@ -419,7 +175,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/SAC ServiceList: FAIL (%s%s not permitted)\n", aci.getServiceAccessControl().getServiceList()[i].getName().c_str(), aci.getServiceAccessControl().getServiceList()[i].isServer()? " (Server)" : ""); + std::cout << "[WARNING] ACI/SAC ServiceList: FAIL (" << aci.getServiceAccessControl().getServiceList()[i].getName() << (aci.getServiceAccessControl().getServiceList()[i].isServer()? " (Server)" : "") << " not permitted)" << std::endl; } } @@ -427,19 +183,19 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac // check thread info if (aci.getKernelCapabilities().getThreadInfo().getMaxCpuId() != acid.getKernelCapabilities().getThreadInfo().getMaxCpuId()) { - printf("[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMaxCpuId()); + std::cout << "[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMaxCpuId() << " not permitted)" << std::endl; } if (aci.getKernelCapabilities().getThreadInfo().getMinCpuId() != acid.getKernelCapabilities().getThreadInfo().getMinCpuId()) { - printf("[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMinCpuId()); + std::cout << "[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMinCpuId() << " not permitted)" << std::endl; } if (aci.getKernelCapabilities().getThreadInfo().getMaxPriority() != acid.getKernelCapabilities().getThreadInfo().getMaxPriority()) { - printf("[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMaxPriority()); + std::cout << "[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMaxPriority() << " not permitted)" << std::endl; } if (aci.getKernelCapabilities().getThreadInfo().getMinPriority() != acid.getKernelCapabilities().getThreadInfo().getMinPriority()) { - printf("[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMinPriority()); + 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++) @@ -453,7 +209,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/KC SystemCallList: FAIL (%s not permitted)\n", kSysCall[aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i]].c_str()); + std::cout << "[WARNING] ACI/KC SystemCallList: FAIL (" << getSystemCallStr(aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i]) << " not permitted)" << std::endl; } } // check memory maps @@ -470,7 +226,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac { const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getMemoryMaps()[i]; - printf("[WARNING] ACI/KC MemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str()); + 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=" << getMemMapPermStr(map.perm) << ") (type=" << getMemMapTypeStr(map.type) << ") not permitted)" << std::endl; } } for (size_t i = 0; i < aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps().size(); i++) @@ -486,7 +242,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac { const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps()[i]; - printf("[WARNING] ACI/KC IoMemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str()); + 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=" << getMemMapPermStr(map.perm) << ") (type=" << getMemMapTypeStr(map.type) << ") not permitted)" << std::endl; } } // check interupts @@ -501,25 +257,25 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/KC InteruptsList: FAIL (0x%0x not permitted)\n", aci.getKernelCapabilities().getInterupts().getInteruptList()[i]); + std::cout << "[WARNING] ACI/KC InteruptsList: FAIL (0x" << std::hex << (uint32_t)aci.getKernelCapabilities().getInterupts().getInteruptList()[i] << " not permitted)" << std::endl; } } // check misc params if (aci.getKernelCapabilities().getMiscParams().getProgramType() != acid.getKernelCapabilities().getMiscParams().getProgramType()) { - printf("[WARNING] ACI/KC ProgramType: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getMiscParams().getProgramType()); + std::cout << "[WARNING] ACI/KC ProgramType: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getMiscParams().getProgramType() << " not permitted)" << std::endl; } // check kernel version uint32_t aciKernelVersion = (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMinor(); uint32_t acidKernelVersion = (uint32_t)acid.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)acid.getKernelCapabilities().getKernelVersion().getVerMinor(); if (aciKernelVersion < acidKernelVersion) { - printf("[WARNING] ACI/KC RequiredKernelVersion: FAIL (%d.%d not permitted)\n", aci.getKernelCapabilities().getKernelVersion().getVerMajor(), aci.getKernelCapabilities().getKernelVersion().getVerMinor()); + std::cout << "[WARNING] ACI/KC RequiredKernelVersion: FAIL (" << std::dec << aci.getKernelCapabilities().getKernelVersion().getVerMajor() << "." << aci.getKernelCapabilities().getKernelVersion().getVerMinor() << " not permitted)" << std::endl; } // check handle table size if (aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize() > acid.getKernelCapabilities().getHandleTableSize().getHandleTableSize()) { - printf("[WARNING] ACI/KC HandleTableSize: FAIL (0x%x too large)\n", aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize()); + 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++) @@ -533,88 +289,92 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/KC MiscFlag: FAIL (%s not permitted)\n", kMiscFlag[aci.getKernelCapabilities().getMiscFlags().getFlagList()[i]].c_str()); + std::cout << "[WARNING] ACI/KC MiscFlag: FAIL (" << getMiscFlagStr(aci.getKernelCapabilities().getMiscFlags().getFlagList()[i]) << " not permitted)" << std::endl; } } } void NpdmProcess::displayNpdmHeader(const nn::hac::NpdmBinary& hdr) { - printf("[NPDM HEADER]\n"); - printf(" Process Architecture Params:\n"); - printf(" Ins. Type: %s\n", kInstructionType[hdr.getInstructionType()].c_str()); - printf(" Addr Space: %s\n", kProcAddrSpace[hdr.getProcAddressSpaceType()].c_str()); - printf(" Main Thread Params:\n"); - printf(" Priority: %d\n", hdr.getMainThreadPriority()); - printf(" CpuId: %d\n", hdr.getMainThreadCpuId()); - printf(" StackSize: 0x%x\n", hdr.getMainThreadStackSize()); - printf(" TitleInfo:\n"); - printf(" Version: v%" PRIu32 "\n", hdr.getVersion()); - printf(" Name: %s\n", hdr.getName().c_str()); + std::cout << "[NPDM HEADER]" << std::endl; + std::cout << " Process Architecture Params:" << std::endl; + std::cout << " Ins. Type: " << getInstructionTypeStr(hdr.getInstructionType()) << std::endl; + std::cout << " Addr Space: " << getProcAddressSpaceTypeStr(hdr.getProcAddressSpaceType()) << 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; + std::cout << " StackSize: 0x" << std::hex << hdr.getMainThreadStackSize() << std::endl; + std::cout << " TitleInfo:" << std::endl; + std::cout << " Version: v" << std::dec << hdr.getVersion() << std::endl; + std::cout << " Name: " << hdr.getName() << std::endl; if (hdr.getProductCode().length()) { - printf(" ProductCode: %s\n", hdr.getProductCode().c_str()); + std::cout << " ProductCode: " << hdr.getProductCode() << std::endl; } } void NpdmProcess::displayAciHdr(const nn::hac::AccessControlInfoBinary& aci) { - printf("[Access Control Info]\n"); - printf(" ProgramID: 0x%016" PRIx64 "\n", aci.getProgramId()); + std::cout << "[Access Control Info]" << std::endl; + std::cout << " ProgramID: 0x" << std::hex << std::setw(16) << std::setfill('0') << aci.getProgramId() << std::endl; } void NpdmProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDescBinary& acid) { - printf("[Access Control Info Desc]\n"); + std::cout << "[Access Control Info Desc]" << std::endl; if (acid.getFlagList().size() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Flags: \n"); + std::cout << " Flags: " << std::endl; for (size_t i = 0; i < acid.getFlagList().size(); i++) { - printf(" %s (%d)\n", kAcidFlag[acid.getFlagList()[i]].c_str(), acid.getFlagList()[i]); + std::cout << " " << getAcidFlagStr(acid.getFlagList()[i]) << " (" << std::dec << (uint32_t)acid.getFlagList()[i] << ")" << std::endl; } } - printf(" ProgramID Restriction\n"); - printf(" Min: 0x%016" PRIx64 "\n", acid.getProgramIdRestrict().min); - printf(" Max: 0x%016" PRIx64 "\n", acid.getProgramIdRestrict().max); + std::cout << " ProgramID Restriction" << std::endl; + std::cout << " Min: 0x" << std::hex << std::setw(16) << std::setfill('0') << acid.getProgramIdRestrict().min << std::endl; + std::cout << " Max: 0x" << std::hex << std::setw(16) << std::setfill('0') << acid.getProgramIdRestrict().max << std::endl; } void NpdmProcess::displayFac(const nn::hac::FileSystemAccessControlBinary& fac) { - printf("[FS Access Control]\n"); - printf(" Format Version: %d\n", fac.getFormatVersion()); + std::cout << "[FS Access Control]" << std::endl; + std::cout << " Format Version: " << std::dec << (uint32_t)fac.getFormatVersion() << std::endl; if (fac.getFsaRightsList().size()) { - printf(" FS Rights:\n"); + std::cout << " FS Rights:" << std::endl; for (size_t i = 0; i < fac.getFsaRightsList().size(); i++) { if (i % 10 == 0) { - printf("%s ", i != 0 ? "\n" : ""); + if (i != 0) + std::cout << std::endl; + std::cout << " "; } - printf("%s", kFsaFlag[fac.getFsaRightsList()[i]].c_str()); + std::cout << getFsaRightStr(fac.getFsaRightsList()[i]); if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - printf(" (bit %" PRId32 ")", fac.getFsaRightsList()[i]); - printf("%s", fac.getFsaRightsList()[i] != fac.getFsaRightsList().atBack() ? ", " : "\n"); + std::cout << " (bit " << std::dec << (uint32_t)fac.getFsaRightsList()[i] << ")"; + if (fac.getFsaRightsList()[i] != fac.getFsaRightsList().atBack()) + std::cout << ", "; + std::cout << std::endl; } } if (fac.getContentOwnerIdList().size()) { - printf(" Content Owner IDs:\n"); + std::cout << " Content Owner IDs:" << std::endl; for (size_t i = 0; i < fac.getContentOwnerIdList().size(); i++) { - printf(" 0x%016" PRIx64 "\n", fac.getContentOwnerIdList()[i]); + std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << fac.getContentOwnerIdList()[i] << std::endl; } } if (fac.getSaveDataOwnerIdList().size()) { - printf(" Save Data Owner IDs:\n"); + std::cout << " Save Data Owner IDs:" << std::endl; for (size_t i = 0; i < fac.getSaveDataOwnerIdList().size(); i++) { - printf(" 0x%016" PRIx64 " (%s)\n", fac.getSaveDataOwnerIdList()[i].id, kSaveDataOwnerAccessMode[fac.getSaveDataOwnerIdList()[i].access_type].c_str()); + std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << fac.getSaveDataOwnerIdList()[i].id << " (" << getSaveDataOwnerAccessModeStr(fac.getSaveDataOwnerIdList()[i].access_type) << ")" << std::endl; } } @@ -622,101 +382,744 @@ void NpdmProcess::displayFac(const nn::hac::FileSystemAccessControlBinary& fac) void NpdmProcess::displaySac(const nn::hac::ServiceAccessControlBinary& sac) { - printf("[Service Access Control]\n"); - printf(" Service List:\n"); + std::cout << "[Service Access Control]" << std::endl; + std::cout << " Service List:" << std::endl; for (size_t i = 0; i < sac.getServiceList().size(); i++) { if (i % 10 == 0) { - printf("%s ", i != 0 ? "\n" : ""); + if (i != 0) + std::cout << std::endl; + std::cout << " "; } - printf("%s%s%s", sac.getServiceList()[i].getName().c_str(), sac.getServiceList()[i].isServer() ? "(isSrv)" : "", sac.getServiceList()[i] != sac.getServiceList().atBack() ? ", " : "\n"); + 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; } void NpdmProcess::displayKernelCap(const nn::hac::KernelCapabilityBinary& kern) { - printf("[Kernel Capabilities]\n"); + std::cout << "[Kernel Capabilities]" << std::endl; if (kern.getThreadInfo().isSet()) { nn::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo(); - printf(" Thread Priority:\n"); - printf(" Min: %d\n", threadInfo.getMinPriority()); - printf(" Max: %d\n", threadInfo.getMaxPriority()); - printf(" CpuId:\n"); - printf(" Min: %d\n", threadInfo.getMinCpuId()); - printf(" Max: %d\n", threadInfo.getMaxCpuId()); + std::cout << " Thread Priority:" << std::endl; + std::cout << " Min: " << std::dec << (uint32_t)threadInfo.getMinPriority() << std::endl; + std::cout << " Max: " << std::dec << (uint32_t)threadInfo.getMaxPriority() << std::endl; + std::cout << " CpuId:" << std::endl; + std::cout << " Min: " << std::dec << (uint32_t)threadInfo.getMinCpuId() << std::endl; + std::cout << " Max: " << std::dec << (uint32_t)threadInfo.getMaxCpuId() << std::endl; } + if (kern.getSystemCalls().isSet()) { fnd::List syscalls = kern.getSystemCalls().getSystemCalls(); - printf(" SystemCalls:"); - printf("\n "); + std::cout << " SystemCalls:" << std::endl; + std::cout << " "; size_t lineLen = 0; for (size_t i = 0; i < syscalls.size(); i++) { if (lineLen > 60) { lineLen = 0; - printf("\n "); + std::cout << std::endl; + std::cout << " "; } - printf("%s%s", kSysCall[syscalls[i]].c_str(), syscalls[i] != syscalls.atBack() ? ", " : "\n"); - lineLen += kSysCall[syscalls[i]].length(); + std::cout << getSystemCallStr(syscalls[i]); + if (syscalls[i] != syscalls.atBack()) + std::cout << ", "; + lineLen += strlen(getSystemCallStr(syscalls[i])); } + std::cout << std::endl; } if (kern.getMemoryMaps().isSet()) { fnd::List maps = kern.getMemoryMaps().getMemoryMaps(); fnd::List ioMaps = kern.getMemoryMaps().getIoMemoryMaps(); - printf(" MemoryMaps:\n"); + std::cout << " MemoryMaps:" << std::endl; for (size_t i = 0; i < maps.size(); i++) { - printf(" 0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s)\n", (uint64_t)maps[i].addr << 12, ((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1, kMemMapPerm[maps[i].perm].c_str(), kMemMapType[maps[i].type].c_str()); + 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=" << getMemMapPermStr(maps[i].perm) << ") (type=" << getMemMapTypeStr(maps[i].type) << ") not permitted)" << std::endl; } - //printf(" IoMaps:\n"); + //std::cout << " IoMaps:" << std::endl; for (size_t i = 0; i < ioMaps.size(); i++) { - printf(" 0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s)\n", (uint64_t)ioMaps[i].addr << 12, ((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1, kMemMapPerm[ioMaps[i].perm].c_str(), kMemMapType[ioMaps[i].type].c_str()); + 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=" << getMemMapPermStr(ioMaps[i].perm) << ") (type=" << getMemMapTypeStr(ioMaps[i].type) << ") not permitted)" << std::endl; } } if (kern.getInterupts().isSet()) { fnd::List interupts = kern.getInterupts().getInteruptList(); - printf(" Interupts Flags:\n"); + std::cout << " Interupts Flags:" << std::endl; for (uint32_t i = 0; i < interupts.size(); i++) { if (i % 10 == 0) { - printf("%s ", i != 0 ? "\n" : ""); + if (i != 0) + std::cout << std::endl; + std::cout << " "; } - printf("0x%x%s", interupts[i], interupts[i] != interupts.atBack() ? ", " : "\n"); + std::cout << "0x" << std::hex << (uint32_t)interupts[i]; + if (interupts[i] != interupts.atBack()) + std::cout << ", "; + std::cout << std::endl; } } if (kern.getMiscParams().isSet()) { - printf(" ProgramType: %d\n", kern.getMiscParams().getProgramType()); + std::cout << " ProgramType: " << std::dec << (uint32_t)kern.getMiscParams().getProgramType() << std::endl; } if (kern.getKernelVersion().isSet()) { - printf(" Kernel Version: %d.%d\n", kern.getKernelVersion().getVerMajor(), kern.getKernelVersion().getVerMinor()); + std::cout << " Kernel Version: " << std::dec << (uint32_t)kern.getKernelVersion().getVerMajor() << "." << (uint32_t)kern.getKernelVersion().getVerMinor() << std::endl; } if (kern.getHandleTableSize().isSet()) { - printf(" Handle Table Size: 0x%x\n", kern.getHandleTableSize().getHandleTableSize()); + std::cout << " Handle Table Size: 0x" << std::hex << kern.getHandleTableSize().getHandleTableSize() << std::endl; } if (kern.getMiscFlags().isSet()) { fnd::List flagList = kern.getMiscFlags().getFlagList(); - printf(" Misc Flags:\n"); + std::cout << " Misc Flags:" << std::endl; for (uint32_t i = 0; i < flagList.size(); i++) { if (i % 10 == 0) { - printf("%s ", i != 0 ? "\n" : ""); + if (i != 0) + std::cout << std::endl; + std::cout << " "; } - printf("%s%s", kMiscFlag[flagList[i]].c_str(), flagList[i] != flagList.atBack() ? ", " : "\n"); + std::cout << getMiscFlagStr(flagList[i]); + if (flagList[i] != flagList.atBack()) + std::cout << ", "; + std::cout << std::endl; } } } + +const char* NpdmProcess::getInstructionTypeStr(nn::hac::npdm::InstructionType type) const +{ + const char* str = nullptr; + + switch(type) + { + case (nn::hac::npdm::INSTR_32BIT): + str = "32Bit"; + break; + case (nn::hac::npdm::INSTR_64BIT): + str = "64Bit"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getProcAddressSpaceTypeStr(nn::hac::npdm::ProcAddrSpaceType type) const +{ + const char* str = nullptr; + + switch(type) + { + case (nn::hac::npdm::ADDR_SPACE_64BIT): + str = "64Bit"; + break; + case (nn::hac::npdm::ADDR_SPACE_32BIT): + str = "32Bit"; + break; + case (nn::hac::npdm::ADDR_SPACE_32BIT_NO_RESERVED): + str = "32Bit no reserved"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getAcidFlagStr(nn::hac::aci::Flag flag) const +{ + const char* str = nullptr; + + switch(flag) + { + case (nn::hac::aci::FLAG_PRODUCTION): + str = "Production"; + break; + case (nn::hac::aci::FLAG_UNQUALIFIED_APPROVAL): + str = "UnqualifiedApproval"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getMiscFlagStr(nn::hac::MiscFlagsHandler::Flags flag) const +{ + const char* str = nullptr; + + switch(flag) + { + case (nn::hac::MiscFlagsHandler::FLAG_ENABLE_DEBUG): + str = "EnableDebug"; + break; + case (nn::hac::MiscFlagsHandler::FLAG_FORCE_DEBUG): + str = "ForceDebug"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getFsaRightStr(nn::hac::fac::FsAccessFlag flag) const +{ + const char* str = nullptr; + + switch(flag) + { + case (nn::hac::fac::FSA_APPLICATION_INFO): + str = "ApplicationInfo"; + break; + case (nn::hac::fac::FSA_BOOT_MODE_CONTROL): + str = "BootModeControl"; + break; + case (nn::hac::fac::FSA_CALIBRATION): + str = "Calibration"; + break; + case (nn::hac::fac::FSA_SYSTEM_SAVE_DATA): + str = "SystemSaveData"; + break; + case (nn::hac::fac::FSA_GAME_CARD): + str = "GameCard"; + break; + case (nn::hac::fac::FSA_SAVE_DATA_BACKUP): + str = "SaveDataBackUp"; + break; + case (nn::hac::fac::FSA_SAVE_DATA_MANAGEMENT): + str = "SaveDataManagement"; + break; + case (nn::hac::fac::FSA_BIS_ALL_RAW): + str = "BisAllRaw"; + break; + case (nn::hac::fac::FSA_GAME_CARD_RAW): + str = "GameCardRaw"; + break; + case (nn::hac::fac::FSA_GAME_CARD_PRIVATE): + str = "GameCardPrivate"; + break; + case (nn::hac::fac::FSA_SET_TIME): + str = "SetTime"; + break; + case (nn::hac::fac::FSA_CONTENT_MANAGER): + str = "ContentManager"; + break; + case (nn::hac::fac::FSA_IMAGE_MANAGER): + str = "ImageManager"; + break; + case (nn::hac::fac::FSA_CREATE_SAVE_DATA): + str = "CreateSaveData"; + break; + case (nn::hac::fac::FSA_SYSTEM_SAVE_DATA_MANAGEMENT): + str = "SystemSaveDataManagement"; + break; + case (nn::hac::fac::FSA_BIS_FILE_SYSTEM): + str = "BisFileSystem"; + break; + case (nn::hac::fac::FSA_SYSTEM_UPDATE): + str = "SystemUpdate"; + break; + case (nn::hac::fac::FSA_SAVE_DATA_META): + str = "SaveDataMeta"; + break; + case (nn::hac::fac::FSA_DEVICE_SAVE_CONTROL): + str = "DeviceSaveData"; + break; + case (nn::hac::fac::FSA_SETTINGS_CONTROL): + str = "SettingsControl"; + break; + case (nn::hac::fac::FSA_DEBUG): + str = "Debug"; + break; + case (nn::hac::fac::FSA_FULL_PERMISSION): + str = "FullPermission"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getSaveDataOwnerAccessModeStr(nn::hac::fac::SaveDataOwnerIdAccessType type) const +{ + const char* str = nullptr; + + switch(type) + { + case (nn::hac::fac::SDO_READ): + str = "Read"; + break; + case (nn::hac::fac::SDO_WRITE): + str = "Write"; + break; + case (nn::hac::fac::SDO_READWRITE): + str = "ReadWrite"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getSystemCallStr(byte_t syscall_id) const +{ + const char* str = nullptr; + + switch(syscall_id) + { + case (0x01): + str = "SetHeapSize"; + break; + case (0x02): + str = "SetMemoryPermission"; + break; + case (0x03): + str = "SetMemoryAttribute"; + break; + case (0x04): + str = "MapMemory"; + break; + case (0x05): + str = "UnmapMemory"; + break; + case (0x06): + str = "QueryMemory"; + break; + case (0x07): + str = "ExitProcess"; + break; + case (0x08): + str = "CreateThread"; + break; + case (0x09): + str = "StartThread"; + break; + case (0x0a): + str = "ExitThread"; + break; + case (0x0b): + str = "SleepThread"; + break; + case (0x0c): + str = "GetThreadPriority"; + break; + case (0x0d): + str = "SetThreadPriority"; + break; + case (0x0e): + str = "GetThreadCoreMask"; + break; + case (0x0f): + str = "SetThreadCoreMask"; + break; + case (0x10): + str = "GetCurrentProcessorNumber"; + break; + case (0x11): + str = "SignalEvent"; + break; + case (0x12): + str = "ClearEvent"; + break; + case (0x13): + str = "MapSharedMemory"; + break; + case (0x14): + str = "UnmapSharedMemory"; + break; + case (0x15): + str = "CreateTransferMemory"; + break; + case (0x16): + str = "CloseHandle"; + break; + case (0x17): + str = "ResetSignal"; + break; + case (0x18): + str = "WaitSynchronization"; + break; + case (0x19): + str = "CancelSynchronization"; + break; + case (0x1a): + str = "ArbitrateLock"; + break; + case (0x1b): + str = "ArbitrateUnlock"; + break; + case (0x1c): + str = "WaitProcessWideKeyAtomic"; + break; + case (0x1d): + str = "SignalProcessWideKey"; + break; + case (0x1e): + str = "GetSystemTick"; + break; + case (0x1f): + str = "ConnectToNamedPort"; + break; + case (0x20): + str = "SendSyncRequestLight"; + break; + case (0x21): + str = "SendSyncRequest"; + break; + case (0x22): + str = "SendSyncRequestWithUserBuffer"; + break; + case (0x23): + str = "SendAsyncRequestWithUserBuffer"; + break; + case (0x24): + str = "GetProcessId"; + break; + case (0x25): + str = "GetThreadId"; + break; + case (0x26): + str = "Break"; + break; + case (0x27): + str = "OutputDebugString"; + break; + case (0x28): + str = "ReturnFromException"; + break; + case (0x29): + str = "GetInfo"; + break; + case (0x2a): + str = "FlushEntireDataCache"; + break; + case (0x2b): + str = "FlushDataCache"; + break; + case (0x2c): + str = "MapPhysicalMemory"; + break; + case (0x2d): + str = "UnmapPhysicalMemory"; + break; + case (0x2e): + str = "GetFutureThreadInfo"; + break; + case (0x2f): + str = "GetLastThreadInfo"; + break; + case (0x30): + str = "GetResourceLimitLimitValue"; + break; + case (0x31): + str = "GetResourceLimitCurrentValue"; + break; + case (0x32): + str = "SetThreadActivity"; + break; + case (0x33): + str = "GetThreadContext3"; + break; + case (0x34): + str = "WaitForAddress"; + break; + case (0x35): + str = "SignalToAddress"; + break; + case (0x36): + str = "svc36"; + break; + case (0x37): + str = "svc37"; + break; + case (0x38): + str = "svc38"; + break; + case (0x39): + str = "svc39"; + break; + case (0x3a): + str = "svc3A"; + break; + case (0x3b): + str = "svc3B"; + break; + case (0x3c): + str = "DumpInfo"; + break; + case (0x3d): + str = "DumpInfoNew"; + break; + case (0x3e): + str = "svc3E"; + break; + case (0x3f): + str = "svc3F"; + break; + case (0x40): + str = "CreateSession"; + break; + case (0x41): + str = "AcceptSession"; + break; + case (0x42): + str = "ReplyAndReceiveLight"; + break; + case (0x43): + str = "ReplyAndReceive"; + break; + case (0x44): + str = "ReplyAndReceiveWithUserBuffer"; + break; + case (0x45): + str = "CreateEvent"; + break; + case (0x46): + str = "svc46"; + break; + case (0x47): + str = "svc47"; + break; + case (0x48): + str = "MapPhysicalMemoryUnsafe"; + break; + case (0x49): + str = "UnmapPhysicalMemoryUnsafe"; + break; + case (0x4a): + str = "SetUnsafeLimit"; + break; + case (0x4b): + str = "CreateCodeMemory"; + break; + case (0x4c): + str = "ControlCodeMemory"; + break; + case (0x4d): + str = "SleepSystem"; + break; + case (0x4e): + str = "ReadWriteRegister"; + break; + case (0x4f): + str = "SetProcessActivity"; + break; + case (0x50): + str = "CreateSharedMemory"; + break; + case (0x51): + str = "MapTransferMemory"; + break; + case (0x52): + str = "UnmapTransferMemory"; + break; + case (0x53): + str = "CreateInterruptEvent"; + break; + case (0x54): + str = "QueryPhysicalAddress"; + break; + case (0x55): + str = "QueryIoMapping"; + break; + case (0x56): + str = "CreateDeviceAddressSpace"; + break; + case (0x57): + str = "AttachDeviceAddressSpace"; + break; + case (0x58): + str = "DetachDeviceAddressSpace"; + break; + case (0x59): + str = "MapDeviceAddressSpaceByForce"; + break; + case (0x5a): + str = "MapDeviceAddressSpaceAligned"; + break; + case (0x5b): + str = "MapDeviceAddressSpace"; + break; + case (0x5c): + str = "UnmapDeviceAddressSpace"; + break; + case (0x5d): + str = "InvalidateProcessDataCache"; + break; + case (0x5e): + str = "StoreProcessDataCache"; + break; + case (0x5f): + str = "FlushProcessDataCache"; + break; + case (0x60): + str = "DebugActiveProcess"; + break; + case (0x61): + str = "BreakDebugProcess"; + break; + case (0x62): + str = "TerminateDebugProcess"; + break; + case (0x63): + str = "GetDebugEvent"; + break; + case (0x64): + str = "ContinueDebugEvent"; + break; + case (0x65): + str = "GetProcessList"; + break; + case (0x66): + str = "GetThreadList"; + break; + case (0x67): + str = "GetDebugThreadContext"; + break; + case (0x68): + str = "SetDebugThreadContext"; + break; + case (0x69): + str = "QueryDebugProcessMemory"; + break; + case (0x6a): + str = "ReadDebugProcessMemory"; + break; + case (0x6b): + str = "WriteDebugProcessMemory"; + break; + case (0x6c): + str = "SetHardwareBreakPoint"; + break; + case (0x6d): + str = "GetDebugThreadParam"; + break; + case (0x6e): + str = "svc6E"; + break; + case (0x6f): + str = "GetSystemInfo"; + break; + case (0x70): + str = "CreatePort"; + break; + case (0x71): + str = "ManageNamedPort"; + break; + case (0x72): + str = "ConnectToPort"; + break; + case (0x73): + str = "SetProcessMemoryPermission"; + break; + case (0x74): + str = "MapProcessMemory"; + break; + case (0x75): + str = "UnmapProcessMemory"; + break; + case (0x76): + str = "QueryProcessMemory"; + break; + case (0x77): + str = "MapProcessCodeMemory"; + break; + case (0x78): + str = "UnmapProcessCodeMemory"; + break; + case (0x79): + str = "CreateProcess"; + break; + case (0x7a): + str = "StartProcess"; + break; + case (0x7b): + str = "TerminateProcess"; + break; + case (0x7c): + str = "GetProcessInfo"; + break; + case (0x7d): + str = "CreateResourceLimit"; + break; + case (0x7e): + str = "SetResourceLimitLimitValue"; + break; + case (0x7f): + str = "CallSecureMonitor"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getMemMapPermStr(nn::hac::MemoryMappingHandler::MemoryPerm type) const +{ + const char* str = nullptr; + + switch(type) + { + case (nn::hac::MemoryMappingHandler::MEM_RW): + str = "RW"; + break; + case (nn::hac::MemoryMappingHandler::MEM_RO): + str = "RO"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getMemMapTypeStr(nn::hac::MemoryMappingHandler::MappingType type) const +{ + const char* str = nullptr; + + switch(type) + { + case (nn::hac::MemoryMappingHandler::MAP_IO): + str = "Io"; + break; + case (nn::hac::MemoryMappingHandler::MAP_STATIC): + str = "Static"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} \ No newline at end of file diff --git a/programs/nstool/source/NpdmProcess.h b/programs/nstool/source/NpdmProcess.h index 6ed8959..d476493 100644 --- a/programs/nstool/source/NpdmProcess.h +++ b/programs/nstool/source/NpdmProcess.h @@ -32,6 +32,8 @@ private: nn::hac::NpdmBinary mNpdm; + void importNpdm(); + void validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid); void validateAciFromAcid(const nn::hac::AccessControlInfoBinary& aci, const nn::hac::AccessControlInfoDescBinary& acid); @@ -41,4 +43,14 @@ private: void displayFac(const nn::hac::FileSystemAccessControlBinary& fac); void displaySac(const nn::hac::ServiceAccessControlBinary& sac); void displayKernelCap(const nn::hac::KernelCapabilityBinary& kern); + + const char* getInstructionTypeStr(nn::hac::npdm::InstructionType type) const; + const char* getProcAddressSpaceTypeStr(nn::hac::npdm::ProcAddrSpaceType type) const; + const char* getAcidFlagStr(nn::hac::aci::Flag flag) const; + const char* getMiscFlagStr(nn::hac::MiscFlagsHandler::Flags flag) const; + const char* getFsaRightStr(nn::hac::fac::FsAccessFlag flag) const; + const char* getSaveDataOwnerAccessModeStr(nn::hac::fac::SaveDataOwnerIdAccessType type) const; + const char* getSystemCallStr(byte_t syscall_id) const; + const char* getMemMapPermStr(nn::hac::MemoryMappingHandler::MemoryPerm type) const; + const char* getMemMapTypeStr(nn::hac::MemoryMappingHandler::MappingType type) const; }; \ No newline at end of file diff --git a/programs/nstool/source/NroProcess.cpp b/programs/nstool/source/NroProcess.cpp index 3beb776..577cc95 100644 --- a/programs/nstool/source/NroProcess.cpp +++ b/programs/nstool/source/NroProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -23,11 +25,6 @@ NroProcess::~NroProcess() void NroProcess::process() { - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - importHeader(); importCodeSegments(); @@ -99,6 +96,12 @@ const RoMetadataProcess& NroProcess::getRoMetadataProcess() const void NroProcess::importHeader() { fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + if (mFile->size() < sizeof(nn::hac::sNroHeader)) { throw fnd::Exception(kModuleName, "Corrupt NRO: file too small"); @@ -134,41 +137,34 @@ void NroProcess::importCodeSegments() void NroProcess::displayHeader() { -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) - printf("[NRO Header]\n"); - printf(" RoCrt: "); - _HEXDUMP_L(mHdr.getRoCrt().data, nn::hac::nro::kRoCrtSize); - printf("\n"); - printf(" ModuleId: "); - _HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nro::kModuleIdSize); - printf("\n"); - printf(" NroSize: 0x%" PRIx32 "\n", mHdr.getNroSize()); - printf(" Program Sections:\n"); - printf(" .text:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getTextInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getTextInfo().size); - printf(" .ro:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoInfo().size); + std::cout << "[NRO Header]" << std::endl; + std::cout << " RoCrt: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRoCrt().data, nn::hac::nro::kRoCrtSize, false, "") << std::endl; + std::cout << " ModuleId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getModuleId().data, nn::hac::nro::kModuleIdSize, false, "") << std::endl; + std::cout << " NroSize: 0x" << std::hex << mHdr.getNroSize() << std::endl; + std::cout << " Program Sections:" << std::endl; + std::cout << " .text:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getTextInfo().memory_offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getTextInfo().size << std::endl; + std::cout << " .ro:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getRoInfo().memory_offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getRoInfo().size << std::endl; if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" .api_info:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size); - printf(" .dynstr:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size); - printf(" .dynsym:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size); + std::cout << " .api_info:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getRoEmbeddedInfo().memory_offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getRoEmbeddedInfo().size << std::endl; + std::cout << " .dynstr:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getRoDynStrInfo().memory_offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getRoDynStrInfo().size << std::endl; + std::cout << " .dynsym:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getRoDynSymInfo().memory_offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getRoDynSymInfo().size << std::endl; } - printf(" .data:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getDataInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getDataInfo().size); - printf(" .bss:\n"); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getBssSize()); - -#undef _HEXDUMP_L + std::cout << " .data:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getDataInfo().memory_offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getDataInfo().size << std::endl; + std::cout << " .bss:" << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getBssSize() << std::endl; } void NroProcess::processRoMeta() diff --git a/programs/nstool/source/NsoProcess.cpp b/programs/nstool/source/NsoProcess.cpp index 3113be5..c99cd78 100644 --- a/programs/nstool/source/NsoProcess.cpp +++ b/programs/nstool/source/NsoProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -22,11 +24,6 @@ NsoProcess::~NsoProcess() void NsoProcess::process() { - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - importHeader(); importCodeSegments(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) @@ -74,6 +71,12 @@ const RoMetadataProcess& NsoProcess::getRoMetadataProcess() const void NsoProcess::importHeader() { fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + if (mFile->size() < sizeof(nn::hac::sNsoHeader)) { throw fnd::Exception(kModuleName, "Corrupt NSO: file too small"); @@ -172,72 +175,61 @@ void NsoProcess::importCodeSegments() void NsoProcess::displayNsoHeader() { -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) - - printf("[NSO Header]\n"); - printf(" ModuleId: "); - _HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize); - printf("\n"); + std::cout << "[NSO Header]" << std::endl; + std::cout << " ModuleId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize, false, "") << std::endl; if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - printf(" Program Segments:\n"); - printf(" .module_name:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().offset); - printf(" FileSize: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().size); - printf(" .text:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().file_layout.offset); - printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getTextSegmentInfo().file_layout.size, mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : ""); - printf(" .ro:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().file_layout.offset); - printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getRoSegmentInfo().file_layout.size, mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : ""); - printf(" .data:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().file_layout.offset); - printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getDataSegmentInfo().file_layout.size, mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : ""); + std::cout << " Program Segments:" << std::endl; + std::cout << " .module_name:" << std::endl; + std::cout << " FileOffset: 0x" << std::hex << mHdr.getModuleNameInfo().offset << std::endl; + std::cout << " FileSize: 0x" << std::hex << mHdr.getModuleNameInfo().size << std::endl; + std::cout << " .text:" << std::endl; + std::cout << " FileOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().file_layout.offset << std::endl; + std::cout << " FileSize: 0x" << std::hex << mHdr.getTextSegmentInfo().file_layout.size << (mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl; + std::cout << " .ro:" << std::endl; + std::cout << " FileOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().file_layout.offset << std::endl; + std::cout << " FileSize: 0x" << std::hex << mHdr.getRoSegmentInfo().file_layout.size << (mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl; + std::cout << " .data:" << std::endl; + std::cout << " FileOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().file_layout.offset << std::endl; + std::cout << " FileSize: 0x" << std::hex << mHdr.getDataSegmentInfo().file_layout.size << (mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl; } - printf(" Program Sections:\n"); - printf(" .text:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.size); + std::cout << " Program Sections:" << std::endl; + std::cout << " .text:" << std::endl; + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.size << std::endl; if (mHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Hash: "); - _HEXDUMP_L(mHdr.getTextSegmentInfo().hash.bytes, 32); - printf("\n"); + std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getTextSegmentInfo().hash.bytes, 32, false, "") << std::endl; } - printf(" .ro:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.size); + std::cout << " .ro:" << std::endl; + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.size << std::endl; if (mHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Hash: "); - _HEXDUMP_L(mHdr.getRoSegmentInfo().hash.bytes, 32); - printf("\n"); + std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRoSegmentInfo().hash.bytes, 32, false, "") << std::endl; } if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" .api_info:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size); - printf(" .dynstr:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size); - printf(" .dynsym:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size); + std::cout << " .api_info:" << std::endl; + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoEmbeddedInfo().offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoEmbeddedInfo().size << std::endl; + std::cout << " .dynstr:" << std::endl; + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoDynStrInfo().offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoDynStrInfo().size << std::endl; + std::cout << " .dynsym:" << std::endl; + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoDynSymInfo().offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoDynSymInfo().size << std::endl; } - printf(" .data:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.size); + std::cout << " .data:" << std::endl; + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.size << std::endl; if (mHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Hash: "); - _HEXDUMP_L(mHdr.getDataSegmentInfo().hash.bytes, 32); - printf("\n"); + std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getDataSegmentInfo().hash.bytes, 32, false, "") << std::endl; } - printf(" .bss:\n"); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getBssSize()); -#undef _HEXDUMP_L + std::cout << " .bss:" << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getBssSize() << std::endl; } void NsoProcess::processRoMeta() diff --git a/programs/nstool/source/PfsProcess.cpp b/programs/nstool/source/PfsProcess.cpp index c44fca0..f878a4f 100644 --- a/programs/nstool/source/PfsProcess.cpp +++ b/programs/nstool/source/PfsProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include "PfsProcess.h" @@ -25,26 +27,7 @@ PfsProcess::~PfsProcess() void PfsProcess::process() { - fnd::Vec scratch; - - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - - // open minimum header to get full header size - scratch.alloc(sizeof(nn::hac::sPfsHeader)); - mFile->read(scratch.data(), 0, scratch.size()); - if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false) - { - throw fnd::Exception(kModuleName, "Corrupt Header"); - } - size_t pfsHeaderSize = determineHeaderSize(((nn::hac::sPfsHeader*)scratch.data())); - - // open minimum header to get full header size - scratch.alloc(pfsHeaderSize); - mFile->read(scratch.data(), 0, scratch.size()); - mPfs.fromBytes(scratch.data(), scratch.size()); + importHeader(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) { @@ -95,32 +78,64 @@ const nn::hac::PfsHeader& PfsProcess::getPfsHeader() const return mPfs; } +void PfsProcess::importHeader() +{ + fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + // open minimum header to get full header size + scratch.alloc(sizeof(nn::hac::sPfsHeader)); + mFile->read(scratch.data(), 0, scratch.size()); + if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false) + { + throw fnd::Exception(kModuleName, "Corrupt Header"); + } + size_t pfsHeaderSize = determineHeaderSize(((nn::hac::sPfsHeader*)scratch.data())); + + // open minimum header to get full header size + scratch.alloc(pfsHeaderSize); + mFile->read(scratch.data(), 0, scratch.size()); + mPfs.fromBytes(scratch.data(), scratch.size()); +} + void PfsProcess::displayHeader() { - printf("[PartitionFS]\n"); - printf(" Type: %s\n", mPfs.getFsType() == mPfs.TYPE_PFS0? "PFS0" : "HFS0"); - printf(" FileNum: %" PRId64 "\n", (uint64_t)mPfs.getFileList().size()); - if (mMountName.empty() == false) - printf(" MountPoint: %s%s\n", mMountName.c_str(), mMountName.at(mMountName.length()-1) != '/' ? "/" : ""); + std::cout << "[PartitionFS]" << std::endl; + std::cout << " Type: " << getFsTypeStr(mPfs.getFsType()) << std::endl; + std::cout << " FileNum: " << std::dec << mPfs.getFileList().size() << std::endl; + if (mMountName.empty() == false) + { + std::cout << " MountPoint: " << mMountName; + if (mMountName.at(mMountName.length()-1) != '/') + std::cout << "/"; + std::cout << std::endl; + } } void PfsProcess::displayFs() { for (size_t i = 0; i < mPfs.getFileList().size(); i++) { - printf(" %s", mPfs.getFileList()[i].name.c_str()); + const nn::hac::PfsHeader::sFile& file = mPfs.getFileList()[i]; + std::cout << " " << file.name; if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - if (mPfs.getFsType() == mPfs.TYPE_PFS0) - printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")\n", (uint64_t)mPfs.getFileList()[i].offset, (uint64_t)mPfs.getFileList()[i].size); - else - printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ", hash_protected_size=0x%" PRIx64 ")\n", (uint64_t)mPfs.getFileList()[i].offset, (uint64_t)mPfs.getFileList()[i].size, (uint64_t)mPfs.getFileList()[i].hash_protected_size); + switch (mPfs.getFsType()) + { + case (nn::hac::PfsHeader::TYPE_PFS0): + std::cout << std::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ")"; + break; + case (nn::hac::PfsHeader::TYPE_HFS0): + std::cout << std::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ", hash_protected_size=0x" << file.hash_protected_size << ")"; + break; + } + } - else - { - printf("\n"); - } - + std::cout << std::endl; } } @@ -187,3 +202,23 @@ void PfsProcess::extractFs() outFile.close(); } } + +const char* PfsProcess::getFsTypeStr(nn::hac::PfsHeader::FsType type) const +{ + const char* str = nullptr; + + switch (type) + { + case (nn::hac::PfsHeader::TYPE_PFS0): + str = "PFS0"; + break; + case (nn::hac::PfsHeader::TYPE_HFS0): + str = "HFS0"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} \ No newline at end of file diff --git a/programs/nstool/source/PfsProcess.h b/programs/nstool/source/PfsProcess.h index 4b15c05..96c56aa 100644 --- a/programs/nstool/source/PfsProcess.h +++ b/programs/nstool/source/PfsProcess.h @@ -44,10 +44,13 @@ private: nn::hac::PfsHeader mPfs; + void importHeader(); void displayHeader(); void displayFs(); size_t determineHeaderSize(const nn::hac::sPfsHeader* hdr); bool validateHeaderMagic(const nn::hac::sPfsHeader* hdr); void validateHfs(); void extractFs(); + + const char* getFsTypeStr(nn::hac::PfsHeader::FsType type) const; }; \ No newline at end of file diff --git a/programs/nstool/source/PkiCertProcess.cpp b/programs/nstool/source/PkiCertProcess.cpp index db7c629..bc71e09 100644 --- a/programs/nstool/source/PkiCertProcess.cpp +++ b/programs/nstool/source/PkiCertProcess.cpp @@ -1,6 +1,5 @@ #include #include - #include #include #include "OffsetAdjustedIFile.h" @@ -25,12 +24,8 @@ PkiCertProcess::~PkiCertProcess() void PkiCertProcess::process() { - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - importCerts(); + if (mVerify) validateCerts(); @@ -63,6 +58,11 @@ void PkiCertProcess::importCerts() { fnd::Vec scratch; + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + scratch.alloc(mFile->size()); mFile->read(scratch.data(), 0, scratch.size()); @@ -100,15 +100,11 @@ void PkiCertProcess::displayCerts() void PkiCertProcess::displayCert(const nn::pki::SignedData& cert) { -#define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff) -#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0) -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) - std::cout << "[NNPKI Certificate]" << std::endl; std::cout << " SignType " << getSignTypeStr(cert.getSignature().getSignType()); if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - std::cout << " (0x" << std::hex << cert.getSignature().getSignType() << ") (" << getEndiannessStr(cert.getSignature().isLittleEndian()); + std::cout << " (0x" << std::hex << cert.getSignature().getSignType() << ") (" << getEndiannessStr(cert.getSignature().isLittleEndian()) << ")"; std::cout << std::endl; std::cout << " Issuer: " << cert.getBody().getIssuer() << std::endl; @@ -130,9 +126,9 @@ void PkiCertProcess::displayCert(const nn::pki::SignedData #include #include #include +#include "PkiValidator.h" PkiValidator::PkiValidator() { diff --git a/programs/nstool/source/RoMetadataProcess.cpp b/programs/nstool/source/RoMetadataProcess.cpp index 3c44d2b..afbb982 100644 --- a/programs/nstool/source/RoMetadataProcess.cpp +++ b/programs/nstool/source/RoMetadataProcess.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include "RoMetadataProcess.h" @@ -23,12 +25,8 @@ RoMetadataProcess::RoMetadataProcess() : void RoMetadataProcess::process() { - if (mRoBlob.size() == 0) - { - throw fnd::Exception(kModuleName, "No ro binary set."); - } - importApiList(); + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) displayRoMetaData(); } @@ -101,6 +99,11 @@ const fnd::List& RoMetadataProcess::getSymbolList() void RoMetadataProcess::importApiList() { + if (mRoBlob.size() == 0) + { + throw fnd::Exception(kModuleName, "No ro binary set."); + } + if (mApiInfo.size > 0) { std::stringstream list_stream(std::string((char*)mRoBlob.data() + mApiInfo.offset, mApiInfo.size)); @@ -133,43 +136,43 @@ void RoMetadataProcess::displayRoMetaData() if (api_num > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) { - printf("[SDK API List]\n"); + std::cout << "[SDK API List]" << std::endl; if (mSdkVerApiList.size() > 0) { - printf(" Sdk Revision: %s\n", mSdkVerApiList[0].getModuleName().c_str()); + std::cout << " Sdk Revision: " << mSdkVerApiList[0].getModuleName() << std::endl; } if (mPublicApiList.size() > 0) { - printf(" Public APIs:\n"); + std::cout << " Public APIs:" << std::endl; for (size_t i = 0; i < mPublicApiList.size(); i++) { - printf(" %s (vender: %s)\n", mPublicApiList[i].getModuleName().c_str(), mPublicApiList[i].getVenderName().c_str()); + std::cout << " " << mPublicApiList[i].getModuleName() << " (vender: " << mPublicApiList[i].getVenderName() << ")" << std::endl; } } if (mDebugApiList.size() > 0) { - printf(" Debug APIs:\n"); + std::cout << " Debug APIs:" << std::endl; for (size_t i = 0; i < mDebugApiList.size(); i++) { - printf(" %s (vender: %s)\n", mDebugApiList[i].getModuleName().c_str(), mDebugApiList[i].getVenderName().c_str()); + std::cout << " " << mDebugApiList[i].getModuleName() << " (vender: " << mDebugApiList[i].getVenderName() << ")" << std::endl; } } if (mPrivateApiList.size() > 0) { - printf(" Private APIs:\n"); + std::cout << " Private APIs:" << std::endl; for (size_t i = 0; i < mPrivateApiList.size(); i++) { - printf(" %s (vender: %s)\n", mPrivateApiList[i].getModuleName().c_str(), mPrivateApiList[i].getVenderName().c_str()); + std::cout << " " << mPrivateApiList[i].getModuleName() << " (vender: " << mPrivateApiList[i].getVenderName() << ")" << std::endl; } } } if (mSymbolList.getSymbolList().size() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) { - printf("[Symbol List]\n"); + std::cout << "[Symbol List]" << std::endl; for (size_t i = 0; i < mSymbolList.getSymbolList().size(); i++) { const ElfSymbolParser::sElfSymbol& symbol = mSymbolList.getSymbolList()[i]; - printf(" %s [SHN=%s (%04x)][STT=%s][STB=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type), getSymbolBindingStr(symbol.symbol_binding)); + std::cout << " " << symbol.name << " [SHN=" << getSectionIndexStr(symbol.shn_index) << " (" << std::hex << std::setw(4) << std::setfill('0') << symbol.shn_index << ")][STT=" << getSymbolTypeStr(symbol.symbol_type) << "][STB=" << getSymbolBindingStr(symbol.symbol_binding) << "]" << std::endl; } } } diff --git a/programs/nstool/source/RomfsProcess.cpp b/programs/nstool/source/RomfsProcess.cpp index c2baf8c..cf68257 100644 --- a/programs/nstool/source/RomfsProcess.cpp +++ b/programs/nstool/source/RomfsProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -30,18 +32,15 @@ RomfsProcess::~RomfsProcess() void RomfsProcess::process() { - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - resolveRomfs(); + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) { displayHeader(); if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) displayFs(); } + if (mExtract) extractFs(); } @@ -87,19 +86,19 @@ void RomfsProcess::printTab(size_t tab) const { for (size_t i = 0; i < tab; i++) { - printf(" "); + std::cout << " "; } } void RomfsProcess::displayFile(const sFile& file, size_t tab) const { printTab(tab); - printf("%s", file.name.c_str()); + std::cout << file.name; if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")", file.offset, file.size); + std::cout << std::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ")"; } - putchar('\n'); + std::cout << std::endl; } void RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const @@ -107,7 +106,7 @@ void RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const if (dir.name.empty() == false) { printTab(tab); - printf("%s\n", dir.name.c_str()); + std::cout << dir.name << std::endl; } for (size_t i = 0; i < dir.dir_list.size(); i++) @@ -122,11 +121,16 @@ void RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const void RomfsProcess::displayHeader() { - printf("[RomFS]\n"); - printf(" DirNum: %" PRId64 "\n", (uint64_t)mDirNum); - printf(" FileNum: %" PRId64 "\n", (uint64_t)mFileNum); - if (mMountName.empty() == false) - printf(" MountPoint: %s%s\n", mMountName.c_str(), mMountName.at(mMountName.length()-1) != '/' ? "/" : ""); + std::cout << "[RomFS]" << std::endl; + std::cout << " DirNum: " << std::dec << mDirNum << std::endl; + std::cout << " FileNum: " << std::dec << mFileNum << std::endl; + if (mMountName.empty() == false) + { + std::cout << " MountPoint: " << mMountName; + if (mMountName.at(mMountName.length()-1) != '/') + std::cout << "/"; + std::cout << std::endl; + } } void RomfsProcess::displayFs() @@ -156,7 +160,7 @@ void RomfsProcess::extractDir(const std::string& path, const sDirectory& dir) fnd::io::appendToPath(file_path, dir.file_list[i].name); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) - printf("extract=[%s]\n", file_path.c_str()); + std::cout << "extract=[" << file_path << "]" << std::endl; outFile.open(file_path, outFile.Create); mFile->seek(dir.file_list[i].offset); @@ -254,6 +258,11 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir) void RomfsProcess::resolveRomfs() { + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + // read header mFile->read((byte_t*)&mHdr, 0, sizeof(nn::hac::sRomfsHeader)); diff --git a/programs/nstool/source/XciProcess.cpp b/programs/nstool/source/XciProcess.cpp index 230b1b9..b535204 100644 --- a/programs/nstool/source/XciProcess.cpp +++ b/programs/nstool/source/XciProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include "OffsetAdjustedIFile.h" @@ -25,28 +27,11 @@ XciProcess::~XciProcess() void XciProcess::process() { - fnd::Vec scratch; - - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - - // read header page - mFile->read((byte_t*)&mHdrPage, 0, sizeof(nn::hac::sXciHeaderPage)); - - // allocate memory for and decrypt sXciHeader - scratch.alloc(sizeof(nn::hac::sXciHeader)); - nn::hac::XciUtils::decryptXciHeader((const byte_t*)&mHdrPage.header, scratch.data(), mKeyset->xci.header_key.key); + importHeader(); // validate header signature if (mVerify) - { validateXciSignature(); - } - - // deserialise header - mHdr.fromBytes(scratch.data(), scratch.size()); // display header if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) @@ -90,94 +75,115 @@ void XciProcess::setListFs(bool list_fs) mListFs = list_fs; } +void XciProcess::importHeader() +{ + fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + // read header page + mFile->read((byte_t*)&mHdrPage, 0, sizeof(nn::hac::sXciHeaderPage)); + + // allocate memory for and decrypt sXciHeader + scratch.alloc(sizeof(nn::hac::sXciHeader)); + nn::hac::XciUtils::decryptXciHeader((const byte_t*)&mHdrPage.header, scratch.data(), mKeyset->xci.header_key.key); + + // deserialise header + mHdr.fromBytes(scratch.data(), scratch.size()); +} + void XciProcess::displayHeader() { - printf("[XCI Header]\n"); - printf(" CardHeaderVersion: %d\n", mHdr.getCardHeaderVersion()); - printf(" RomSize: %s", getRomSizeStr(mHdr.getRomSizeType())); + std::cout << "[XCI Header]" << std::endl; + std::cout << " CardHeaderVersion: " << std::dec << (uint32_t)mHdr.getCardHeaderVersion() << std::endl; + std::cout << " RomSize: " << getRomSizeStr(mHdr.getRomSizeType()); if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - printf(" (0x%x)", mHdr.getRomSizeType()); - printf("\n"); - printf(" PackageId: 0x%" PRIx64 "\n", mHdr.getPackageId()); - printf(" Flags: 0x%x\n", mHdr.getFlags()); + std::cout << " (0x" << std::hex << (uint32_t)mHdr.getRomSizeType() << ")"; + std::cout << std::endl; + std::cout << " PackageId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getPackageId() << std::endl; + std::cout << " Flags: 0x" << std::dec << (uint32_t)mHdr.getFlags() << std::endl; if (mHdr.getFlags() != 0) { for (uint32_t i = 0; i < 8; i++) { if (_HAS_BIT(mHdr.getFlags(), i)) { - printf(" %s\n", getHeaderFlagStr(i)); + std::cout << " " << getHeaderFlagStr(i) << std::endl; } } } if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" InitialData:\n"); - printf(" KekIndex: %d\n", mHdr.getKekIndex()); - printf(" TitleKeyDecIndex: %d\n", mHdr.getTitleKeyDecIndex()); - printf(" Hash:\n"); - fnd::SimpleTextOutput::hexDump(mHdr.getInitialDataHash().bytes, sizeof(mHdr.getInitialDataHash().bytes), 0x10, 6); + std::cout << " InitialData:" << std::endl; + std::cout << " KekIndex: " << std::dec << (uint32_t)mHdr.getKekIndex() << std::endl; + std::cout << " TitleKeyDecIndex: " << std::dec << (uint32_t)mHdr.getTitleKeyDecIndex() << 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; } if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Enc Header AES-IV:\n"); - fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), 0x10, 4); + std::cout << " Extended Header AES-IV:" << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), true, "") << std::endl; } - printf(" SelSec: 0x%x\n", mHdr.getSelSec()); - printf(" SelT1Key: 0x%x\n", mHdr.getSelT1Key()); - printf(" SelKey: 0x%x\n", mHdr.getSelKey()); + std::cout << " SelSec: 0x" << std::hex << mHdr.getSelSec() << std::endl; + std::cout << " SelT1Key: 0x" << std::hex << mHdr.getSelT1Key() << std::endl; + std::cout << " SelKey: 0x" << std::hex << mHdr.getSelKey() << std::endl; if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - printf(" RomAreaStartPage: 0x%0x", mHdr.getRomAreaStartPage()); + std::cout << " RomAreaStartPage: 0x" << std::hex << mHdr.getRomAreaStartPage(); if (mHdr.getRomAreaStartPage() != (uint32_t)(-1)) - printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getRomAreaStartPage())); - printf("\n"); + std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getRomAreaStartPage()) << ")"; + std::cout << std::endl; - printf(" BackupAreaStartPage: 0x%0x", mHdr.getBackupAreaStartPage()); + std::cout << " BackupAreaStartPage: 0x" << std::hex << mHdr.getBackupAreaStartPage(); if (mHdr.getBackupAreaStartPage() != (uint32_t)(-1)) - printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage())); - printf("\n"); + std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage()) << ")"; + std::cout << std::endl; - printf(" ValidDataEndPage: 0x%x", mHdr.getValidDataEndPage()); + std::cout << " ValidDataEndPage: 0x" << std::hex << mHdr.getValidDataEndPage(); if (mHdr.getValidDataEndPage() != (uint32_t)(-1)) - printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getValidDataEndPage())); - printf("\n"); + std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getValidDataEndPage()) << ")"; + std::cout << std::endl; - printf(" LimArea: 0x%x", mHdr.getLimAreaPage()); + std::cout << " LimArea: 0x" << std::hex << mHdr.getLimAreaPage(); if (mHdr.getLimAreaPage() != (uint32_t)(-1)) - printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getLimAreaPage())); - printf("\n"); + std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getLimAreaPage()) << ")"; + std::cout << std::endl; - printf(" PartitionFs Header:\n"); - printf(" Offset: 0x%" PRIx64 "\n", mHdr.getPartitionFsAddress()); - printf(" Size: 0x%" PRIx64 "\n", mHdr.getPartitionFsSize()); + std::cout << " PartitionFs Header:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getPartitionFsAddress() << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getPartitionFsSize() << std::endl; if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Hash:\n"); - fnd::SimpleTextOutput::hexDump(mHdr.getPartitionFsHash().bytes, sizeof(mHdr.getPartitionFsHash().bytes), 0x10, 6); + std::cout << " Hash:" << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes, 0x10, true, "") << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes+0x10, 0x10, true, "") << std::endl; } } if (mHdr.getFwVerMinor() != 0) { - printf("[XCI Extended Header]\n"); - printf(" FwVersion: v%d.%d\n", mHdr.getFwVerMajor(), mHdr.getFwVerMinor()); - printf(" AccCtrl1: 0x%x\n", mHdr.getAccCtrl1()); - printf(" CardClockRate: %s\n", getCardClockRate(mHdr.getAccCtrl1())); - printf(" Wait1TimeRead: 0x%x\n", mHdr.getWait1TimeRead()); - printf(" Wait2TimeRead: 0x%x\n", mHdr.getWait2TimeRead()); - printf(" Wait1TimeWrite: 0x%x\n", mHdr.getWait1TimeWrite()); - printf(" Wait2TimeWrite: 0x%x\n", mHdr.getWait2TimeWrite()); - printf(" FwMode: 0x%x\n", mHdr.getFwMode()); - printf(" Update Partition Info:\n"); -#define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff) - printf(" CUP Version: v%" PRId32 " (%d.%d.%d.%d)\n", mHdr.getUppVersion(), _SPLIT_VER(mHdr.getUppVersion())); + std::cout << "[XCI Extended Header]" << std::endl; + std::cout << " FwVersion: v" << std::dec << mHdr.getFwVerMajor() << "." << mHdr.getFwVerMinor() << std::endl; + std::cout << " AccCtrl1: 0x" << std::hex << mHdr.getAccCtrl1() << std::endl; + std::cout << " CardClockRate: " << getCardClockRate(mHdr.getAccCtrl1()) << std::endl; + std::cout << " Wait1TimeRead: 0x" << std::hex << mHdr.getWait1TimeRead() << std::endl; + 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 << " 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 - printf(" CUP TitleId: %016" PRIx64 "\n", mHdr.getUppId()); - printf(" Partition Hash: "); - fnd::SimpleTextOutput::hexDump(mHdr.getUppHash(), 8); - } + std::cout << " CUP TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getUppId() << std::endl; + std::cout << " Partition Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getUppHash(), 8, true, "") << std::endl; + } } bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash) @@ -196,7 +202,7 @@ void XciProcess::validateXciSignature() fnd::sha::Sha256((byte_t*)&mHdrPage.header, sizeof(nn::hac::sXciHeader), calc_hash.bytes); if (fnd::rsa::pkcs::rsaVerify(mKeyset->xci.header_sign_key, fnd::sha::HASH_SHA256, calc_hash.bytes, mHdrPage.signature) != 0) { - printf("[WARNING] XCI Header Signature: FAIL \n"); + std::cout << "[WARNING] XCI Header Signature: FAIL" << std::endl; } } @@ -204,7 +210,7 @@ void XciProcess::processRootPfs() { if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize(), mHdr.getPartitionFsHash().bytes) == false) { - printf("[WARNING] XCI Root HFS0: FAIL (bad hash)\n"); + std::cout << "[WARNING] XCI Root HFS0: FAIL (bad hash)" << std::endl; } mRootPfs.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()), OWN_IFILE); mRootPfs.setListFs(mListFs); @@ -222,7 +228,7 @@ void XciProcess::processPartitionPfs() // this must be validated here because only the size of the root partiton header is known at verification time if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].hash_protected_size, rootPartitions[i].hash.bytes) == false) { - printf("[WARNING] XCI %s Partition HFS0: FAIL (bad hash)\n", rootPartitions[i].name.c_str()); + std::cout << "[WARNING] XCI " << rootPartitions[i].name << " Partition HFS0: FAIL (bad hash)" << std::endl; } PfsProcess tmp; @@ -240,7 +246,8 @@ void XciProcess::processPartitionPfs() const char* XciProcess::getRomSizeStr(byte_t rom_size) const { - const char* str = "unknown"; + const char* str = nullptr; + switch (rom_size) { case (nn::hac::xci::ROM_SIZE_1GB): @@ -261,13 +268,18 @@ const char* XciProcess::getRomSizeStr(byte_t rom_size) const case (nn::hac::xci::ROM_SIZE_32GB): str = "32GB"; break; + default: + str = "Unknown"; + break; } + return str; } const char* XciProcess::getHeaderFlagStr(byte_t flag) const { - const char* str = "unknown"; + const char* str = nullptr; + switch (flag) { case (nn::hac::xci::FLAG_AUTOBOOT): @@ -279,14 +291,19 @@ const char* XciProcess::getHeaderFlagStr(byte_t flag) const case (nn::hac::xci::FLAG_REPAIR_TOOL): str = "RepairTool"; break; + default: + str = "Unknown"; + break; } + return str; } const char* XciProcess::getCardClockRate(uint32_t acc_ctrl_1) const { - const char* str = "unknown"; + const char* str = nullptr; + switch (acc_ctrl_1) { case (nn::hac::xci::CLOCK_RATE_25): @@ -295,7 +312,10 @@ const char* XciProcess::getCardClockRate(uint32_t acc_ctrl_1) const case (nn::hac::xci::CLOCK_RATE_50): str = "50 MHz"; break; - + default: + str = "Unknown"; + break; } + return str; } diff --git a/programs/nstool/source/XciProcess.h b/programs/nstool/source/XciProcess.h index 32fc038..c3da185 100644 --- a/programs/nstool/source/XciProcess.h +++ b/programs/nstool/source/XciProcess.h @@ -62,6 +62,7 @@ private: PfsProcess mRootPfs; fnd::List mExtractInfo; + void importHeader(); void displayHeader(); bool validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash); void validateXciSignature();