mirror of
https://github.com/jakcron/nstool
synced 2024-11-15 02:06:40 +00:00
commit
740bbb0f16
23 changed files with 1906 additions and 1301 deletions
|
@ -1,4 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
|
|
||||||
namespace fnd
|
namespace fnd
|
||||||
|
@ -10,6 +11,7 @@ namespace fnd
|
||||||
static void hxdStyleDump(const byte_t* data, size_t len);
|
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, size_t row_len, size_t indent_len);
|
||||||
static void hexDump(const byte_t* data, size_t 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:
|
private:
|
||||||
static const size_t kDefaultRowLen = 0x10;
|
static const size_t kDefaultRowLen = 0x10;
|
||||||
static const size_t kDefaultByteGroupingSize = 1;
|
static const size_t kDefaultByteGroupingSize = 1;
|
||||||
|
|
|
@ -21,8 +21,8 @@ namespace fnd
|
||||||
|
|
||||||
void operator=(const sEcdsa240Point& other)
|
void operator=(const sEcdsa240Point& other)
|
||||||
{
|
{
|
||||||
memcpy(this->r, r, kEcdsa240Size);
|
memcpy(this->r, other.r, kEcdsa240Size);
|
||||||
memcpy(this->s, s, kEcdsa240Size);
|
memcpy(this->s, other.s, kEcdsa240Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const sEcdsa240Point& other) const
|
bool operator==(const sEcdsa240Point& other) const
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <fnd/SimpleTextOutput.h>
|
||||||
|
|
||||||
void fnd::SimpleTextOutput::hxdStyleDump(const byte_t* data, size_t len, size_t row_len, size_t byte_grouping_size)
|
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)
|
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)
|
for (size_t j = 0; j < indent_len; j++)
|
||||||
{
|
std::cout << " ";
|
||||||
if (i > 0)
|
std::cout << arrayToString(data+i, _MIN(len-i, row_len), true, "") << std::endl;
|
||||||
putchar('\n');
|
|
||||||
for (size_t j = 0; j < indent_len; j++)
|
|
||||||
{
|
|
||||||
putchar(' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("%02X", data[i]);
|
|
||||||
if ((i+1) >= len)
|
|
||||||
{
|
|
||||||
putchar('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fnd::SimpleTextOutput::hexDump(const byte_t* data, size_t len)
|
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++)
|
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();
|
||||||
}
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <fnd/SimpleFile.h>
|
#include <fnd/SimpleFile.h>
|
||||||
#include <fnd/Vec.h>
|
#include <fnd/Vec.h>
|
||||||
#include "AssetProcess.h"
|
#include "AssetProcess.h"
|
||||||
|
@ -23,11 +25,6 @@ AssetProcess::~AssetProcess()
|
||||||
|
|
||||||
void AssetProcess::process()
|
void AssetProcess::process()
|
||||||
{
|
{
|
||||||
if (mFile == nullptr)
|
|
||||||
{
|
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
|
||||||
}
|
|
||||||
|
|
||||||
importHeader();
|
importHeader();
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||||
displayHeader();
|
displayHeader();
|
||||||
|
@ -74,6 +71,12 @@ void AssetProcess::setRomfsExtractPath(const std::string& path)
|
||||||
void AssetProcess::importHeader()
|
void AssetProcess::importHeader()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
|
if (mFile == nullptr)
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
|
}
|
||||||
|
|
||||||
if (mFile->size() < sizeof(nn::hac::sAssetHeader))
|
if (mFile->size() < sizeof(nn::hac::sAssetHeader))
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "Corrupt ASET: file too small");
|
throw fnd::Exception(kModuleName, "Corrupt ASET: file too small");
|
||||||
|
@ -141,16 +144,16 @@ void AssetProcess::displayHeader()
|
||||||
{
|
{
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
|
||||||
{
|
{
|
||||||
printf("[ASET Header]\n");
|
std::cout << "[ASET Header]" << std::endl;
|
||||||
printf(" Icon:\n");
|
std::cout << " Icon:" << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx64 "\n", mHdr.getIconInfo().offset);
|
std::cout << " Offset: 0x" << std::hex << mHdr.getIconInfo().offset << std::endl;
|
||||||
printf(" Size: 0x%" PRIx64 "\n", mHdr.getIconInfo().size);
|
std::cout << " Size: 0x" << std::hex << mHdr.getIconInfo().size << std::endl;
|
||||||
printf(" NACP:\n");
|
std::cout << " NACP:" << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx64 "\n", mHdr.getNacpInfo().offset);
|
std::cout << " Offset: 0x" << std::hex << mHdr.getNacpInfo().offset << std::endl;
|
||||||
printf(" Size: 0x%" PRIx64 "\n", mHdr.getNacpInfo().size);
|
std::cout << " Size: 0x" << std::hex << mHdr.getNacpInfo().size << std::endl;
|
||||||
printf(" RomFS:\n");
|
std::cout << " RomFS:" << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx64 "\n", mHdr.getRomfsInfo().offset);
|
std::cout << " Offset: 0x" << std::hex << mHdr.getRomfsInfo().offset << std::endl;
|
||||||
printf(" Size: 0x%" PRIx64 "\n", mHdr.getRomfsInfo().size);
|
std::cout << " Size: 0x" << std::hex << mHdr.getRomfsInfo().size << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,146 +1,9 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
#include "OffsetAdjustedIFile.h"
|
||||||
#include "CnmtProcess.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() :
|
CnmtProcess::CnmtProcess() :
|
||||||
mFile(nullptr),
|
mFile(nullptr),
|
||||||
mOwnIFile(false),
|
mOwnIFile(false),
|
||||||
|
@ -159,20 +22,10 @@ CnmtProcess::~CnmtProcess()
|
||||||
|
|
||||||
void CnmtProcess::process()
|
void CnmtProcess::process()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
importCnmt();
|
||||||
|
|
||||||
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());
|
|
||||||
|
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||||
displayCmnt();
|
displayCnmt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||||
|
@ -195,3 +48,212 @@ const nn::hac::ContentMetaBinary& CnmtProcess::getContentMetaBinary() const
|
||||||
{
|
{
|
||||||
return mCnmt;
|
return mCnmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CnmtProcess::importCnmt()
|
||||||
|
{
|
||||||
|
fnd::Vec<byte_t> 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;
|
||||||
|
}
|
||||||
|
|
|
@ -30,5 +30,12 @@ private:
|
||||||
|
|
||||||
nn::hac::ContentMetaBinary mCnmt;
|
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;
|
||||||
};
|
};
|
|
@ -1,6 +1,5 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include <nn/pki/SignUtils.h>
|
#include <nn/pki/SignUtils.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
#include "OffsetAdjustedIFile.h"
|
||||||
|
@ -64,12 +63,14 @@ void EsTikProcess::setVerifyMode(bool verify)
|
||||||
|
|
||||||
void EsTikProcess::importTicket()
|
void EsTikProcess::importTicket()
|
||||||
{
|
{
|
||||||
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
|
|
||||||
if (mFile == nullptr)
|
if (mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fnd::Vec<byte_t> scratch;
|
|
||||||
scratch.alloc(mFile->size());
|
scratch.alloc(mFile->size());
|
||||||
mFile->read(scratch.data(), 0, scratch.size());
|
mFile->read(scratch.data(), 0, scratch.size());
|
||||||
mTik.fromBytes(scratch.data(), scratch.size());
|
mTik.fromBytes(scratch.data(), scratch.size());
|
||||||
|
@ -106,9 +107,7 @@ void EsTikProcess::verifyTicket()
|
||||||
|
|
||||||
void EsTikProcess::displayTicket()
|
void EsTikProcess::displayTicket()
|
||||||
{
|
{
|
||||||
#define _SPLIT_VER(ver) ( (ver>>10) & 0x3f), ( (ver>>4) & 0x3f), ( (ver>>0) & 0xf)
|
#define _SPLIT_VER(ver) (uint32_t)((ver>>10) & 0x3f) << "." << (uint32_t)((ver>>4) & 0x3f) << "." << (uint32_t)((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)
|
|
||||||
|
|
||||||
const nn::es::TicketBody_V2& body = mTik.getBody();
|
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;
|
size_t size = body.getTitleKeyEncType() == nn::es::ticket::RSA2048 ? fnd::rsa::kRsa2048Size : fnd::aes::kAes128KeySize;
|
||||||
fnd::SimpleTextOutput::hexDump(body.getEncTitleKey(), size, 0x10, 6);
|
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))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
printf(" (%d)", body.getTicketVersion());
|
std::cout << " (" << (uint32_t)body.getTicketVersion() << ")";
|
||||||
printf("\n");
|
std::cout << std::endl;
|
||||||
|
|
||||||
std::cout << " License Type: " << getLicenseTypeStr(body.getLicenseType()) << 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 << " SectionNum: 0x" << std::hex << body.getSectionNum() << std::endl;
|
||||||
std::cout << " SectionEntrySize: 0x" << std::hex << body.getSectionEntrySize() << std::endl;
|
std::cout << " SectionEntrySize: 0x" << std::hex << body.getSectionEntrySize() << std::endl;
|
||||||
|
|
||||||
|
|
||||||
#undef _HEXDUMP_L
|
|
||||||
#undef _HEXDUMP_U
|
|
||||||
#undef _SPLIT_VER
|
#undef _SPLIT_VER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,195 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
#include "OffsetAdjustedIFile.h"
|
||||||
#include "NacpProcess.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<byte_t> 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;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::LANG_AmericanEnglish):
|
case (nn::hac::nacp::LANG_AmericanEnglish):
|
||||||
|
@ -56,12 +240,14 @@ const char* getLanguageStr(nn::hac::nacp::Language var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var)
|
const char* NacpProcess::getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::USER_None):
|
case (nn::hac::nacp::USER_None):
|
||||||
|
@ -76,12 +262,14 @@ const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var)
|
const char* NacpProcess::getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::TOUCH_None):
|
case (nn::hac::nacp::TOUCH_None):
|
||||||
|
@ -96,12 +284,14 @@ const char* getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var)
|
const char* NacpProcess::getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::AOC_AllOnLaunch):
|
case (nn::hac::nacp::AOC_AllOnLaunch):
|
||||||
|
@ -113,12 +303,14 @@ const char* getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getAttributeFlagStr(nn::hac::nacp::AttributeFlag var)
|
const char* NacpProcess::getAttributeFlagStr(nn::hac::nacp::AttributeFlag var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::ATTR_None):
|
case (nn::hac::nacp::ATTR_None):
|
||||||
|
@ -133,12 +325,14 @@ const char* getAttributeFlagStr(nn::hac::nacp::AttributeFlag var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var)
|
const char* NacpProcess::getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::PC_None):
|
case (nn::hac::nacp::PC_None):
|
||||||
|
@ -150,12 +344,14 @@ const char* getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var)
|
const char* NacpProcess::getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::SCRN_Allow):
|
case (nn::hac::nacp::SCRN_Allow):
|
||||||
|
@ -167,12 +363,14 @@ const char* getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var)
|
const char* NacpProcess::getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::VCAP_Disable):
|
case (nn::hac::nacp::VCAP_Disable):
|
||||||
|
@ -187,12 +385,14 @@ const char* getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var)
|
const char* NacpProcess::getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::DLOSS_None):
|
case (nn::hac::nacp::DLOSS_None):
|
||||||
|
@ -204,12 +404,14 @@ const char* getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var)
|
const char* NacpProcess::getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::PLP_All):
|
case (nn::hac::nacp::PLP_All):
|
||||||
|
@ -224,12 +426,14 @@ const char* getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getOrganisationStr(nn::hac::nacp::Organisation var)
|
const char* NacpProcess::getOrganisationStr(nn::hac::nacp::Organisation var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::ORGN_CERO):
|
case (nn::hac::nacp::ORGN_CERO):
|
||||||
|
@ -271,12 +475,14 @@ const char* getOrganisationStr(nn::hac::nacp::Organisation var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getLogoTypeStr(nn::hac::nacp::LogoType var)
|
const char* NacpProcess::getLogoTypeStr(nn::hac::nacp::LogoType var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::LOGO_LicensedByNintendo):
|
case (nn::hac::nacp::LOGO_LicensedByNintendo):
|
||||||
|
@ -291,12 +497,14 @@ const char* getLogoTypeStr(nn::hac::nacp::LogoType var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getLogoHandlingStr(nn::hac::nacp::LogoHandling var)
|
const char* NacpProcess::getLogoHandlingStr(nn::hac::nacp::LogoHandling var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::LHND_Auto):
|
case (nn::hac::nacp::LHND_Auto):
|
||||||
|
@ -308,12 +516,14 @@ const char* getLogoHandlingStr(nn::hac::nacp::LogoHandling var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var)
|
const char* NacpProcess::getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::RTAOC_Deny):
|
case (nn::hac::nacp::RTAOC_Deny):
|
||||||
|
@ -325,12 +535,14 @@ const char* getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getCrashReportModeStr(nn::hac::nacp::CrashReportMode var)
|
const char* NacpProcess::getCrashReportModeStr(nn::hac::nacp::CrashReportMode var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::CREP_Deny):
|
case (nn::hac::nacp::CREP_Deny):
|
||||||
|
@ -342,12 +554,14 @@ const char* getCrashReportModeStr(nn::hac::nacp::CrashReportMode var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getHdcpStr(nn::hac::nacp::Hdcp var)
|
const char* NacpProcess::getHdcpStr(nn::hac::nacp::Hdcp var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::HDCP_None):
|
case (nn::hac::nacp::HDCP_None):
|
||||||
|
@ -359,12 +573,14 @@ const char* getHdcpStr(nn::hac::nacp::Hdcp var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability var)
|
const char* NacpProcess::getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::PLQC_None):
|
case (nn::hac::nacp::PLQC_None):
|
||||||
|
@ -379,12 +595,14 @@ const char* getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability v
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getRepairFlagStr(nn::hac::nacp::RepairFlag var)
|
const char* NacpProcess::getRepairFlagStr(nn::hac::nacp::RepairFlag var) const
|
||||||
{
|
{
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch(var)
|
switch(var)
|
||||||
{
|
{
|
||||||
case (nn::hac::nacp::REPF_None):
|
case (nn::hac::nacp::REPF_None):
|
||||||
|
@ -396,10 +614,11 @@ const char* getRepairFlagStr(nn::hac::nacp::RepairFlag var)
|
||||||
default:
|
default:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
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 kKiloByte = 1024;
|
||||||
static const int64_t kMegaByte = 1024 * 1024;
|
static const int64_t kMegaByte = 1024 * 1024;
|
||||||
|
@ -421,180 +640,4 @@ std::string getSaveDataSizeStr(int64_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sstr.str();
|
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<byte_t> 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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -30,5 +30,25 @@ private:
|
||||||
|
|
||||||
nn::hac::ApplicationControlPropertyBinary mNacp;
|
nn::hac::ApplicationControlPropertyBinary mNacp;
|
||||||
|
|
||||||
|
void importNacp();
|
||||||
void displayNacp();
|
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;
|
||||||
};
|
};
|
|
@ -1,4 +1,5 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include <nn/hac/NcaUtils.h>
|
#include <nn/hac/NcaUtils.h>
|
||||||
|
@ -11,215 +12,6 @@
|
||||||
#include "AesCtrWrappedIFile.h"
|
#include "AesCtrWrappedIFile.h"
|
||||||
#include "HashTreeWrappedIFile.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() :
|
NcaProcess::NcaProcess() :
|
||||||
mFile(nullptr),
|
mFile(nullptr),
|
||||||
mOwnIFile(false),
|
mOwnIFile(false),
|
||||||
|
@ -253,22 +45,8 @@ NcaProcess::~NcaProcess()
|
||||||
|
|
||||||
void NcaProcess::process()
|
void NcaProcess::process()
|
||||||
{
|
{
|
||||||
if (mFile == nullptr)
|
// import header
|
||||||
{
|
importHeader();
|
||||||
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));
|
|
||||||
|
|
||||||
// determine keys
|
// determine keys
|
||||||
generateNcaBodyEncryptionKeys();
|
generateNcaBodyEncryptionKeys();
|
||||||
|
@ -338,6 +116,26 @@ void NcaProcess::setListFs(bool list_fs)
|
||||||
mListFs = 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()
|
void NcaProcess::generateNcaBodyEncryptionKeys()
|
||||||
{
|
{
|
||||||
// create zeros key
|
// create zeros key
|
||||||
|
@ -440,18 +238,15 @@ void NcaProcess::generateNcaBodyEncryptionKeys()
|
||||||
{
|
{
|
||||||
if (mBodyKeys.aes_ctr.isSet)
|
if (mBodyKeys.aes_ctr.isSet)
|
||||||
{
|
{
|
||||||
printf("[NCA Body Key]\n");
|
std::cout << "[NCA Body Key]" << std::endl;
|
||||||
printf(" AES-CTR Key: ");
|
std::cout << " AES-CTR Key: " << fnd::SimpleTextOutput::arrayToString(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var), true, "") << std::endl;
|
||||||
fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mBodyKeys.aes_xts.isSet)
|
if (mBodyKeys.aes_xts.isSet)
|
||||||
{
|
{
|
||||||
printf("[NCA Body Key]\n");
|
std::cout << "[NCA Body Key]" << std::endl;
|
||||||
printf(" AES-XTS Key0: ");
|
std::cout << " AES-XTS Key0: " << fnd::SimpleTextOutput::arrayToString(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var), true, "") << std::endl;
|
||||||
fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var));
|
std::cout << " AES-XTS Key1: " << fnd::SimpleTextOutput::arrayToString(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var), true, "") << std::endl;
|
||||||
printf(" AES-XTS Key1: ");
|
|
||||||
fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,7 +367,7 @@ void NcaProcess::validateNcaSignatures()
|
||||||
// validate signature[0]
|
// validate signature[0]
|
||||||
if (fnd::rsa::pss::rsaVerify(mKeyset->nca.header_sign_key, fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_main) != 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]
|
// 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)
|
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
|
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
|
else
|
||||||
{
|
{
|
||||||
printf("[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)\n");
|
std::cout << "[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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()
|
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)
|
std::cout << "[NCA Header]" << std::endl;
|
||||||
#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 << " Format Type: " << getFormatVersionStr(mHdr.getFormatVersion()) << std::endl;
|
||||||
|
std::cout << " Dist. Type: " << getDistributionTypeStr(mHdr.getDistributionType()) << std::endl;
|
||||||
printf("[NCA Header]\n");
|
std::cout << " Content Type: " << getContentTypeStr(mHdr.getContentType()) << std::endl;
|
||||||
printf(" Format Type: %s\n", getFormatVersionStr(mHdr.getFormatVersion()));
|
std::cout << " Key Generation: " << std::dec << (uint32_t)mHdr.getKeyGeneration() << std::endl;
|
||||||
printf(" Dist. Type: %s\n", getDistributionTypeStr(mHdr.getDistributionType()));
|
std::cout << " Kaek Index: " << getKaekIndexStr((nn::hac::nca::KeyAreaEncryptionKeyIndex)mHdr.getKaekIndex()) << " (" << std::dec << (uint32_t)mHdr.getKaekIndex() << ")" << std::endl;
|
||||||
printf(" Content Type: %s\n", getContentTypeStr(mHdr.getContentType()));
|
std::cout << " Size: 0x" << std::hex << mHdr.getContentSize() << std::endl;
|
||||||
printf(" Key Generation: %d\n", mHdr.getKeyGeneration());
|
std::cout << " ProgID: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getProgramId() << std::endl;
|
||||||
printf(" Kaek Index: %s (%d)\n", getKaekIndexStr((nn::hac::nca::KeyAreaEncryptionKeyIndex)mHdr.getKaekIndex()), mHdr.getKaekIndex());
|
std::cout << " Content Index: " << std::dec << mHdr.getContentIndex() << std::endl;
|
||||||
printf(" Size: 0x%" PRIx64 "\n", mHdr.getContentSize());
|
#define _SPLIT_VER(ver) std::dec << (uint32_t)((ver>>24) & 0xff) << "." << (uint32_t)((ver>>16) & 0xff) << "." << (uint32_t)((ver>>8) & 0xff)
|
||||||
printf(" ProgID: 0x%016" PRIx64 "\n", mHdr.getProgramId());
|
std::cout << " SdkAddon Ver.: v" << std::dec << mHdr.getSdkAddonVersion() << " (" << _SPLIT_VER(mHdr.getSdkAddonVersion()) << ")" << std::endl;
|
||||||
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()));
|
|
||||||
#undef _SPLIT_VER
|
#undef _SPLIT_VER
|
||||||
if (mHdr.hasRightsId())
|
if (mHdr.hasRightsId())
|
||||||
{
|
{
|
||||||
printf(" RightsId: ");
|
std::cout << " RightsId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen, true, "") << std::endl;
|
||||||
fnd::SimpleTextOutput::hexDump(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (mBodyKeys.keak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA))
|
if (mBodyKeys.keak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA))
|
||||||
{
|
{
|
||||||
printf(" Key Area: \n");
|
std::cout << " Key Area:" << std::endl;
|
||||||
printf(" <--------------------------------------------------------------------------->\n");
|
std::cout << " <--------------------------------------------------------------------------->" << std::endl;
|
||||||
printf(" | IDX | ENCRYPTED KEY | DECRYPTED KEY |\n");
|
std::cout << " | IDX | ENCRYPTED KEY | DECRYPTED KEY |" << std::endl;
|
||||||
printf(" |-----|----------------------------------|----------------------------------|\n");
|
std::cout << " |-----|----------------------------------|----------------------------------|" << std::endl;
|
||||||
for (size_t i = 0; i < mBodyKeys.keak_list.size(); i++)
|
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);
|
std::cout << fnd::SimpleTextOutput::arrayToString(mBodyKeys.keak_list[i].enc.key, 16, false, "") << " | ";
|
||||||
//for (size_t j = 0; j < 16; j++) printf("%02x", mBodyKeys.keak_list[i].enc.key[j]);
|
|
||||||
|
|
||||||
printf(" | ");
|
|
||||||
|
|
||||||
if (mBodyKeys.keak_list[i].decrypted)
|
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
|
else
|
||||||
printf("<unable to decrypt> ");
|
std::cout << "<unable to decrypt> ";
|
||||||
|
|
||||||
printf(" |\n");
|
std::cout << " |" << std::endl;
|
||||||
}
|
}
|
||||||
printf(" <--------------------------------------------------------------------------->\n");
|
std::cout << " <--------------------------------------------------------------------------->" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
|
||||||
{
|
{
|
||||||
printf(" Partitions:\n");
|
std::cout << " Partitions:" << std::endl;
|
||||||
for (size_t i = 0; i < mHdr.getPartitions().size(); i++)
|
for (size_t i = 0; i < mHdr.getPartitions().size(); i++)
|
||||||
{
|
{
|
||||||
size_t index = mHdr.getPartitions()[i].index;
|
size_t index = mHdr.getPartitions()[i].index;
|
||||||
sPartitionInfo& info = mPartitions[index];
|
sPartitionInfo& info = mPartitions[index];
|
||||||
|
|
||||||
printf(" %d:\n", (int)index);
|
std::cout << " " << std::dec << index << ":" << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)info.offset);
|
std::cout << " Offset: 0x" << std::hex << (uint64_t)info.offset << std::endl;
|
||||||
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size);
|
std::cout << " Size: 0x" << std::hex << (uint64_t)info.size << std::endl;
|
||||||
printf(" Format Type: %s\n", getFormatTypeStr(info.format_type));
|
std::cout << " Format Type: " << getFormatTypeStr(info.format_type) << std::endl;
|
||||||
printf(" Hash Type: %s\n", getHashTypeStr(info.hash_type));
|
std::cout << " Hash Type: " << getHashTypeStr(info.hash_type) << std::endl;
|
||||||
printf(" Enc. Type: %s\n", getEncryptionTypeStr(info.enc_type));
|
std::cout << " Enc. Type: " << getEncryptionTypeStr(info.enc_type) << std::endl;
|
||||||
if (info.enc_type == nn::hac::nca::CRYPT_AESCTR)
|
if (info.enc_type == nn::hac::nca::CRYPT_AESCTR)
|
||||||
{
|
{
|
||||||
printf(" AES-CTR: ");
|
|
||||||
fnd::aes::sAesIvCtr ctr;
|
fnd::aes::sAesIvCtr ctr;
|
||||||
fnd::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv);
|
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)
|
if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY)
|
||||||
{
|
{
|
||||||
HashTreeMeta& hash_hdr = info.hash_tree_meta;
|
HashTreeMeta& hash_hdr = info.hash_tree_meta;
|
||||||
printf(" HierarchicalIntegrity Header:\n");
|
std::cout << " HierarchicalIntegrity Header:" << std::endl;
|
||||||
//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());
|
|
||||||
for (size_t j = 0; j < hash_hdr.getHashLayerInfo().size(); j++)
|
for (size_t j = 0; j < hash_hdr.getHashLayerInfo().size(); j++)
|
||||||
{
|
{
|
||||||
printf(" Hash Layer %d:\n", (int)j);
|
std::cout << " Hash Layer " << std::dec << j << ":" << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].offset);
|
std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[j].offset << std::endl;
|
||||||
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].size);
|
std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[j].size << std::endl;
|
||||||
printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getHashLayerInfo()[j].block_size);
|
std::cout << " BlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getHashLayerInfo()[j].block_size << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" Data Layer:\n");
|
std::cout << " Data Layer:" << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset);
|
std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().offset << std::endl;
|
||||||
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size);
|
std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().size << std::endl;
|
||||||
printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size);
|
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++)
|
for (size_t j = 0; j < hash_hdr.getMasterHashList().size(); j++)
|
||||||
{
|
{
|
||||||
printf(" Master Hash %d: ", (int)j);
|
std::cout << " Master Hash " << std::dec << j << ": " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[j].bytes, sizeof(fnd::sha::sSha256Hash), true, "") << std::endl;
|
||||||
fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[j].bytes, sizeof(fnd::sha::sSha256Hash));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256)
|
else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256)
|
||||||
{
|
{
|
||||||
HashTreeMeta& hash_hdr = info.hash_tree_meta;
|
HashTreeMeta& hash_hdr = info.hash_tree_meta;
|
||||||
printf(" HierarchicalSha256 Header:\n");
|
std::cout << " HierarchicalSha256 Header:" << std::endl;
|
||||||
printf(" Master Hash: ");
|
std::cout << " Master Hash: " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[0].bytes, sizeof(fnd::sha::sSha256Hash), true, "") << std::endl;
|
||||||
fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[0].bytes, sizeof(fnd::sha::sSha256Hash));
|
std::cout << " HashBlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl;
|
||||||
printf(" HashBlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size);
|
std::cout << " Hash Layer:" << std::endl;
|
||||||
//printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().size());
|
std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].offset << std::endl;
|
||||||
printf(" Hash Layer:\n");
|
std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].size << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].offset);
|
std::cout << " Data Layer:" << std::endl;
|
||||||
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].size);
|
std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().offset << std::endl;
|
||||||
printf(" Data Layer:\n");
|
std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().size << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset);
|
|
||||||
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size);
|
|
||||||
}
|
}
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// printf(" Hash Superblock:\n");
|
|
||||||
// fnd::SimpleTextOutput::hxdStyleDump(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef _HEXDUMP_U
|
|
||||||
#undef _HEXDUMP_L
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -753,12 +526,12 @@ void NcaProcess::processPartitions()
|
||||||
// if the reader is null, skip
|
// if the reader is null, skip
|
||||||
if (partition.reader == nullptr)
|
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)
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -779,9 +552,7 @@ void NcaProcess::processPartitions()
|
||||||
|
|
||||||
if (mPartitionPath[index].doExtract)
|
if (mPartitionPath[index].doExtract)
|
||||||
pfs.setExtractPath(mPartitionPath[index].path);
|
pfs.setExtractPath(mPartitionPath[index].path);
|
||||||
//printf("pfs.process(%lx)\n",partition.data_offset);
|
|
||||||
pfs.process();
|
pfs.process();
|
||||||
//printf("pfs.process() end\n");
|
|
||||||
}
|
}
|
||||||
else if (partition.format_type == nn::hac::nca::FORMAT_ROMFS)
|
else if (partition.format_type == nn::hac::nca::FORMAT_ROMFS)
|
||||||
{
|
{
|
||||||
|
@ -800,9 +571,233 @@ void NcaProcess::processPartitions()
|
||||||
|
|
||||||
if (mPartitionPath[index].doExtract)
|
if (mPartitionPath[index].doExtract)
|
||||||
romfs.setExtractPath(mPartitionPath[index].path);
|
romfs.setExtractPath(mPartitionPath[index].path);
|
||||||
//printf("romfs.process(%lx)\n", partition.data_offset);
|
|
||||||
romfs.process();
|
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;
|
||||||
|
}
|
|
@ -105,9 +105,20 @@ private:
|
||||||
fnd::aes::sAesIvCtr aes_ctr;
|
fnd::aes::sAesIvCtr aes_ctr;
|
||||||
} mPartitions[nn::hac::nca::kPartitionNum];
|
} mPartitions[nn::hac::nca::kPartitionNum];
|
||||||
|
|
||||||
|
void importHeader();
|
||||||
void generateNcaBodyEncryptionKeys();
|
void generateNcaBodyEncryptionKeys();
|
||||||
void generatePartitionConfiguration();
|
void generatePartitionConfiguration();
|
||||||
void validateNcaSignatures();
|
void validateNcaSignatures();
|
||||||
void displayHeader();
|
void displayHeader();
|
||||||
void processPartitions();
|
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;
|
||||||
};
|
};
|
File diff suppressed because it is too large
Load diff
|
@ -32,6 +32,8 @@ private:
|
||||||
|
|
||||||
nn::hac::NpdmBinary mNpdm;
|
nn::hac::NpdmBinary mNpdm;
|
||||||
|
|
||||||
|
void importNpdm();
|
||||||
|
|
||||||
void validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid);
|
void validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid);
|
||||||
void validateAciFromAcid(const nn::hac::AccessControlInfoBinary& aci, 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 displayFac(const nn::hac::FileSystemAccessControlBinary& fac);
|
||||||
void displaySac(const nn::hac::ServiceAccessControlBinary& sac);
|
void displaySac(const nn::hac::ServiceAccessControlBinary& sac);
|
||||||
void displayKernelCap(const nn::hac::KernelCapabilityBinary& kern);
|
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;
|
||||||
};
|
};
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include <fnd/Vec.h>
|
#include <fnd/Vec.h>
|
||||||
#include <fnd/lz4.h>
|
#include <fnd/lz4.h>
|
||||||
|
@ -23,11 +25,6 @@ NroProcess::~NroProcess()
|
||||||
|
|
||||||
void NroProcess::process()
|
void NroProcess::process()
|
||||||
{
|
{
|
||||||
if (mFile == nullptr)
|
|
||||||
{
|
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
|
||||||
}
|
|
||||||
|
|
||||||
importHeader();
|
importHeader();
|
||||||
importCodeSegments();
|
importCodeSegments();
|
||||||
|
|
||||||
|
@ -99,6 +96,12 @@ const RoMetadataProcess& NroProcess::getRoMetadataProcess() const
|
||||||
void NroProcess::importHeader()
|
void NroProcess::importHeader()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
|
if (mFile == nullptr)
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
|
}
|
||||||
|
|
||||||
if (mFile->size() < sizeof(nn::hac::sNroHeader))
|
if (mFile->size() < sizeof(nn::hac::sNroHeader))
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "Corrupt NRO: file too small");
|
throw fnd::Exception(kModuleName, "Corrupt NRO: file too small");
|
||||||
|
@ -134,41 +137,34 @@ void NroProcess::importCodeSegments()
|
||||||
|
|
||||||
void NroProcess::displayHeader()
|
void NroProcess::displayHeader()
|
||||||
{
|
{
|
||||||
#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
|
std::cout << "[NRO Header]" << std::endl;
|
||||||
printf("[NRO Header]\n");
|
std::cout << " RoCrt: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRoCrt().data, nn::hac::nro::kRoCrtSize, false, "") << std::endl;
|
||||||
printf(" RoCrt: ");
|
std::cout << " ModuleId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getModuleId().data, nn::hac::nro::kModuleIdSize, false, "") << std::endl;
|
||||||
_HEXDUMP_L(mHdr.getRoCrt().data, nn::hac::nro::kRoCrtSize);
|
std::cout << " NroSize: 0x" << std::hex << mHdr.getNroSize() << std::endl;
|
||||||
printf("\n");
|
std::cout << " Program Sections:" << std::endl;
|
||||||
printf(" ModuleId: ");
|
std::cout << " .text:" << std::endl;
|
||||||
_HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nro::kModuleIdSize);
|
std::cout << " Offset: 0x" << std::hex << mHdr.getTextInfo().memory_offset << std::endl;
|
||||||
printf("\n");
|
std::cout << " Size: 0x" << std::hex << mHdr.getTextInfo().size << std::endl;
|
||||||
printf(" NroSize: 0x%" PRIx32 "\n", mHdr.getNroSize());
|
std::cout << " .ro:" << std::endl;
|
||||||
printf(" Program Sections:\n");
|
std::cout << " Offset: 0x" << std::hex << mHdr.getRoInfo().memory_offset << std::endl;
|
||||||
printf(" .text:\n");
|
std::cout << " Size: 0x" << std::hex << mHdr.getRoInfo().size << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getTextInfo().memory_offset);
|
|
||||||
printf(" Size: 0x%" PRIx32 "\n", mHdr.getTextInfo().size);
|
|
||||||
printf(" .ro:\n");
|
|
||||||
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoInfo().memory_offset);
|
|
||||||
printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoInfo().size);
|
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
{
|
{
|
||||||
printf(" .api_info:\n");
|
std::cout << " .api_info:" << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().memory_offset);
|
std::cout << " Offset: 0x" << std::hex << mHdr.getRoEmbeddedInfo().memory_offset << std::endl;
|
||||||
printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size);
|
std::cout << " Size: 0x" << std::hex << mHdr.getRoEmbeddedInfo().size << std::endl;
|
||||||
printf(" .dynstr:\n");
|
std::cout << " .dynstr:" << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().memory_offset);
|
std::cout << " Offset: 0x" << std::hex << mHdr.getRoDynStrInfo().memory_offset << std::endl;
|
||||||
printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size);
|
std::cout << " Size: 0x" << std::hex << mHdr.getRoDynStrInfo().size << std::endl;
|
||||||
printf(" .dynsym:\n");
|
std::cout << " .dynsym:" << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().memory_offset);
|
std::cout << " Offset: 0x" << std::hex << mHdr.getRoDynSymInfo().memory_offset << std::endl;
|
||||||
printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size);
|
std::cout << " Size: 0x" << std::hex << mHdr.getRoDynSymInfo().size << std::endl;
|
||||||
}
|
}
|
||||||
printf(" .data:\n");
|
std::cout << " .data:" << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getDataInfo().memory_offset);
|
std::cout << " Offset: 0x" << std::hex << mHdr.getDataInfo().memory_offset << std::endl;
|
||||||
printf(" Size: 0x%" PRIx32 "\n", mHdr.getDataInfo().size);
|
std::cout << " Size: 0x" << std::hex << mHdr.getDataInfo().size << std::endl;
|
||||||
printf(" .bss:\n");
|
std::cout << " .bss:" << std::endl;
|
||||||
printf(" Size: 0x%" PRIx32 "\n", mHdr.getBssSize());
|
std::cout << " Size: 0x" << std::hex << mHdr.getBssSize() << std::endl;
|
||||||
|
|
||||||
#undef _HEXDUMP_L
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NroProcess::processRoMeta()
|
void NroProcess::processRoMeta()
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include <fnd/Vec.h>
|
#include <fnd/Vec.h>
|
||||||
#include <fnd/lz4.h>
|
#include <fnd/lz4.h>
|
||||||
|
@ -22,11 +24,6 @@ NsoProcess::~NsoProcess()
|
||||||
|
|
||||||
void NsoProcess::process()
|
void NsoProcess::process()
|
||||||
{
|
{
|
||||||
if (mFile == nullptr)
|
|
||||||
{
|
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
|
||||||
}
|
|
||||||
|
|
||||||
importHeader();
|
importHeader();
|
||||||
importCodeSegments();
|
importCodeSegments();
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||||
|
@ -74,6 +71,12 @@ const RoMetadataProcess& NsoProcess::getRoMetadataProcess() const
|
||||||
void NsoProcess::importHeader()
|
void NsoProcess::importHeader()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
|
if (mFile == nullptr)
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
|
}
|
||||||
|
|
||||||
if (mFile->size() < sizeof(nn::hac::sNsoHeader))
|
if (mFile->size() < sizeof(nn::hac::sNsoHeader))
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "Corrupt NSO: file too small");
|
throw fnd::Exception(kModuleName, "Corrupt NSO: file too small");
|
||||||
|
@ -172,72 +175,61 @@ void NsoProcess::importCodeSegments()
|
||||||
|
|
||||||
void NsoProcess::displayNsoHeader()
|
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)
|
std::cout << "[NSO Header]" << std::endl;
|
||||||
|
std::cout << " ModuleId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize, false, "") << std::endl;
|
||||||
printf("[NSO Header]\n");
|
|
||||||
printf(" ModuleId: ");
|
|
||||||
_HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize);
|
|
||||||
printf("\n");
|
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
|
||||||
{
|
{
|
||||||
printf(" Program Segments:\n");
|
std::cout << " Program Segments:" << std::endl;
|
||||||
printf(" .module_name:\n");
|
std::cout << " .module_name:" << std::endl;
|
||||||
printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().offset);
|
std::cout << " FileOffset: 0x" << std::hex << mHdr.getModuleNameInfo().offset << std::endl;
|
||||||
printf(" FileSize: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().size);
|
std::cout << " FileSize: 0x" << std::hex << mHdr.getModuleNameInfo().size << std::endl;
|
||||||
printf(" .text:\n");
|
std::cout << " .text:" << std::endl;
|
||||||
printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().file_layout.offset);
|
std::cout << " FileOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().file_layout.offset << std::endl;
|
||||||
printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getTextSegmentInfo().file_layout.size, mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : "");
|
std::cout << " FileSize: 0x" << std::hex << mHdr.getTextSegmentInfo().file_layout.size << (mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl;
|
||||||
printf(" .ro:\n");
|
std::cout << " .ro:" << std::endl;
|
||||||
printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().file_layout.offset);
|
std::cout << " FileOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().file_layout.offset << std::endl;
|
||||||
printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getRoSegmentInfo().file_layout.size, mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : "");
|
std::cout << " FileSize: 0x" << std::hex << mHdr.getRoSegmentInfo().file_layout.size << (mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl;
|
||||||
printf(" .data:\n");
|
std::cout << " .data:" << std::endl;
|
||||||
printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().file_layout.offset);
|
std::cout << " FileOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().file_layout.offset << std::endl;
|
||||||
printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getDataSegmentInfo().file_layout.size, mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : "");
|
std::cout << " FileSize: 0x" << std::hex << mHdr.getDataSegmentInfo().file_layout.size << (mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl;
|
||||||
}
|
}
|
||||||
printf(" Program Sections:\n");
|
std::cout << " Program Sections:" << std::endl;
|
||||||
printf(" .text:\n");
|
std::cout << " .text:" << std::endl;
|
||||||
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.offset);
|
std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.offset << std::endl;
|
||||||
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.size);
|
std::cout << " MemorySize: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.size << std::endl;
|
||||||
if (mHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
if (mHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
{
|
{
|
||||||
printf(" Hash: ");
|
std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getTextSegmentInfo().hash.bytes, 32, false, "") << std::endl;
|
||||||
_HEXDUMP_L(mHdr.getTextSegmentInfo().hash.bytes, 32);
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
printf(" .ro:\n");
|
std::cout << " .ro:" << std::endl;
|
||||||
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset);
|
std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.offset << std::endl;
|
||||||
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.size);
|
std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.size << std::endl;
|
||||||
if (mHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
if (mHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
{
|
{
|
||||||
printf(" Hash: ");
|
std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRoSegmentInfo().hash.bytes, 32, false, "") << std::endl;
|
||||||
_HEXDUMP_L(mHdr.getRoSegmentInfo().hash.bytes, 32);
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
{
|
{
|
||||||
printf(" .api_info:\n");
|
std::cout << " .api_info:" << std::endl;
|
||||||
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().offset);
|
std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoEmbeddedInfo().offset << std::endl;
|
||||||
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size);
|
std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoEmbeddedInfo().size << std::endl;
|
||||||
printf(" .dynstr:\n");
|
std::cout << " .dynstr:" << std::endl;
|
||||||
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().offset);
|
std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoDynStrInfo().offset << std::endl;
|
||||||
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size);
|
std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoDynStrInfo().size << std::endl;
|
||||||
printf(" .dynsym:\n");
|
std::cout << " .dynsym:" << std::endl;
|
||||||
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().offset);
|
std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoDynSymInfo().offset << std::endl;
|
||||||
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size);
|
std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoDynSymInfo().size << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" .data:\n");
|
std::cout << " .data:" << std::endl;
|
||||||
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.offset);
|
std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.offset << std::endl;
|
||||||
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.size);
|
std::cout << " MemorySize: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.size << std::endl;
|
||||||
if (mHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
if (mHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
{
|
{
|
||||||
printf(" Hash: ");
|
std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getDataSegmentInfo().hash.bytes, 32, false, "") << std::endl;
|
||||||
_HEXDUMP_L(mHdr.getDataSegmentInfo().hash.bytes, 32);
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
printf(" .bss:\n");
|
std::cout << " .bss:" << std::endl;
|
||||||
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getBssSize());
|
std::cout << " MemorySize: 0x" << std::hex << mHdr.getBssSize() << std::endl;
|
||||||
#undef _HEXDUMP_L
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NsoProcess::processRoMeta()
|
void NsoProcess::processRoMeta()
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <fnd/SimpleFile.h>
|
#include <fnd/SimpleFile.h>
|
||||||
#include <fnd/io.h>
|
#include <fnd/io.h>
|
||||||
#include "PfsProcess.h"
|
#include "PfsProcess.h"
|
||||||
|
@ -25,26 +27,7 @@ PfsProcess::~PfsProcess()
|
||||||
|
|
||||||
void PfsProcess::process()
|
void PfsProcess::process()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
importHeader();
|
||||||
|
|
||||||
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());
|
|
||||||
|
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||||
{
|
{
|
||||||
|
@ -95,32 +78,64 @@ const nn::hac::PfsHeader& PfsProcess::getPfsHeader() const
|
||||||
return mPfs;
|
return mPfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PfsProcess::importHeader()
|
||||||
|
{
|
||||||
|
fnd::Vec<byte_t> 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()
|
void PfsProcess::displayHeader()
|
||||||
{
|
{
|
||||||
printf("[PartitionFS]\n");
|
std::cout << "[PartitionFS]" << std::endl;
|
||||||
printf(" Type: %s\n", mPfs.getFsType() == mPfs.TYPE_PFS0? "PFS0" : "HFS0");
|
std::cout << " Type: " << getFsTypeStr(mPfs.getFsType()) << std::endl;
|
||||||
printf(" FileNum: %" PRId64 "\n", (uint64_t)mPfs.getFileList().size());
|
std::cout << " FileNum: " << std::dec << mPfs.getFileList().size() << std::endl;
|
||||||
if (mMountName.empty() == false)
|
if (mMountName.empty() == false)
|
||||||
printf(" MountPoint: %s%s\n", mMountName.c_str(), mMountName.at(mMountName.length()-1) != '/' ? "/" : "");
|
{
|
||||||
|
std::cout << " MountPoint: " << mMountName;
|
||||||
|
if (mMountName.at(mMountName.length()-1) != '/')
|
||||||
|
std::cout << "/";
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PfsProcess::displayFs()
|
void PfsProcess::displayFs()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < mPfs.getFileList().size(); i++)
|
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 (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
|
||||||
{
|
{
|
||||||
if (mPfs.getFsType() == mPfs.TYPE_PFS0)
|
switch (mPfs.getFsType())
|
||||||
printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")\n", (uint64_t)mPfs.getFileList()[i].offset, (uint64_t)mPfs.getFileList()[i].size);
|
{
|
||||||
else
|
case (nn::hac::PfsHeader::TYPE_PFS0):
|
||||||
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);
|
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
|
std::cout << std::endl;
|
||||||
{
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,3 +202,23 @@ void PfsProcess::extractFs()
|
||||||
outFile.close();
|
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;
|
||||||
|
}
|
|
@ -44,10 +44,13 @@ private:
|
||||||
|
|
||||||
nn::hac::PfsHeader mPfs;
|
nn::hac::PfsHeader mPfs;
|
||||||
|
|
||||||
|
void importHeader();
|
||||||
void displayHeader();
|
void displayHeader();
|
||||||
void displayFs();
|
void displayFs();
|
||||||
size_t determineHeaderSize(const nn::hac::sPfsHeader* hdr);
|
size_t determineHeaderSize(const nn::hac::sPfsHeader* hdr);
|
||||||
bool validateHeaderMagic(const nn::hac::sPfsHeader* hdr);
|
bool validateHeaderMagic(const nn::hac::sPfsHeader* hdr);
|
||||||
void validateHfs();
|
void validateHfs();
|
||||||
void extractFs();
|
void extractFs();
|
||||||
|
|
||||||
|
const char* getFsTypeStr(nn::hac::PfsHeader::FsType type) const;
|
||||||
};
|
};
|
|
@ -1,6 +1,5 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include <nn/pki/SignUtils.h>
|
#include <nn/pki/SignUtils.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
#include "OffsetAdjustedIFile.h"
|
||||||
|
@ -25,12 +24,8 @@ PkiCertProcess::~PkiCertProcess()
|
||||||
|
|
||||||
void PkiCertProcess::process()
|
void PkiCertProcess::process()
|
||||||
{
|
{
|
||||||
if (mFile == nullptr)
|
|
||||||
{
|
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
|
||||||
}
|
|
||||||
|
|
||||||
importCerts();
|
importCerts();
|
||||||
|
|
||||||
if (mVerify)
|
if (mVerify)
|
||||||
validateCerts();
|
validateCerts();
|
||||||
|
|
||||||
|
@ -63,6 +58,11 @@ void PkiCertProcess::importCerts()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
|
if (mFile == nullptr)
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
|
}
|
||||||
|
|
||||||
scratch.alloc(mFile->size());
|
scratch.alloc(mFile->size());
|
||||||
mFile->read(scratch.data(), 0, scratch.size());
|
mFile->read(scratch.data(), 0, scratch.size());
|
||||||
|
|
||||||
|
@ -100,15 +100,11 @@ void PkiCertProcess::displayCerts()
|
||||||
|
|
||||||
void PkiCertProcess::displayCert(const nn::pki::SignedData<nn::pki::CertificateBody>& cert)
|
void PkiCertProcess::displayCert(const nn::pki::SignedData<nn::pki::CertificateBody>& 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 << "[NNPKI Certificate]" << std::endl;
|
||||||
|
|
||||||
std::cout << " SignType " << getSignTypeStr(cert.getSignature().getSignType());
|
std::cout << " SignType " << getSignTypeStr(cert.getSignature().getSignType());
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
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 << std::endl;
|
||||||
|
|
||||||
std::cout << " Issuer: " << cert.getBody().getIssuer() << std::endl;
|
std::cout << " Issuer: " << cert.getBody().getIssuer() << std::endl;
|
||||||
|
@ -130,9 +126,9 @@ void PkiCertProcess::displayCert(const nn::pki::SignedData<nn::pki::CertificateB
|
||||||
else if (cert.getBody().getPublicKeyType() == nn::pki::cert::RSA2048)
|
else if (cert.getBody().getPublicKeyType() == nn::pki::cert::RSA2048)
|
||||||
{
|
{
|
||||||
std::cout << " PublicKey:" << std::endl;
|
std::cout << " PublicKey:" << std::endl;
|
||||||
std::cout << " Public Exponent:" << std::endl;
|
|
||||||
fnd::SimpleTextOutput::hexDump(cert.getBody().getRsa2048PublicKey().modulus, getHexDumpLen(fnd::rsa::kRsa2048Size), 0x10, 6);
|
|
||||||
std::cout << " Modulus:" << std::endl;
|
std::cout << " Modulus:" << std::endl;
|
||||||
|
fnd::SimpleTextOutput::hexDump(cert.getBody().getRsa2048PublicKey().modulus, getHexDumpLen(fnd::rsa::kRsa2048Size), 0x10, 6);
|
||||||
|
std::cout << " Public Exponent:" << std::endl;
|
||||||
fnd::SimpleTextOutput::hexDump(cert.getBody().getRsa2048PublicKey().public_exponent, fnd::rsa::kRsaPublicExponentSize, 0x10, 6);
|
fnd::SimpleTextOutput::hexDump(cert.getBody().getRsa2048PublicKey().public_exponent, fnd::rsa::kRsaPublicExponentSize, 0x10, 6);
|
||||||
}
|
}
|
||||||
else if (cert.getBody().getPublicKeyType() == nn::pki::cert::ECDSA240)
|
else if (cert.getBody().getPublicKeyType() == nn::pki::cert::ECDSA240)
|
||||||
|
@ -143,12 +139,6 @@ void PkiCertProcess::displayCert(const nn::pki::SignedData<nn::pki::CertificateB
|
||||||
std::cout << " S:" << std::endl;
|
std::cout << " S:" << std::endl;
|
||||||
fnd::SimpleTextOutput::hexDump(cert.getBody().getEcdsa240PublicKey().s, getHexDumpLen(fnd::ecdsa::kEcdsa240Size), 0x10, 6);
|
fnd::SimpleTextOutput::hexDump(cert.getBody().getEcdsa240PublicKey().s, getHexDumpLen(fnd::ecdsa::kEcdsa240Size), 0x10, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#undef _HEXDUMP_L
|
|
||||||
#undef _HEXDUMP_U
|
|
||||||
#undef _SPLIT_VER
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t PkiCertProcess::getHexDumpLen(size_t max_size) const
|
size_t PkiCertProcess::getHexDumpLen(size_t max_size) const
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#include "PkiValidator.h"
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <nn/pki/SignUtils.h>
|
#include <nn/pki/SignUtils.h>
|
||||||
|
#include "PkiValidator.h"
|
||||||
|
|
||||||
PkiValidator::PkiValidator()
|
PkiValidator::PkiValidator()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
|
|
||||||
#include "RoMetadataProcess.h"
|
#include "RoMetadataProcess.h"
|
||||||
|
@ -23,12 +25,8 @@ RoMetadataProcess::RoMetadataProcess() :
|
||||||
|
|
||||||
void RoMetadataProcess::process()
|
void RoMetadataProcess::process()
|
||||||
{
|
{
|
||||||
if (mRoBlob.size() == 0)
|
|
||||||
{
|
|
||||||
throw fnd::Exception(kModuleName, "No ro binary set.");
|
|
||||||
}
|
|
||||||
|
|
||||||
importApiList();
|
importApiList();
|
||||||
|
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||||
displayRoMetaData();
|
displayRoMetaData();
|
||||||
}
|
}
|
||||||
|
@ -101,6 +99,11 @@ const fnd::List<ElfSymbolParser::sElfSymbol>& RoMetadataProcess::getSymbolList()
|
||||||
|
|
||||||
void RoMetadataProcess::importApiList()
|
void RoMetadataProcess::importApiList()
|
||||||
{
|
{
|
||||||
|
if (mRoBlob.size() == 0)
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "No ro binary set.");
|
||||||
|
}
|
||||||
|
|
||||||
if (mApiInfo.size > 0)
|
if (mApiInfo.size > 0)
|
||||||
{
|
{
|
||||||
std::stringstream list_stream(std::string((char*)mRoBlob.data() + mApiInfo.offset, mApiInfo.size));
|
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)))
|
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)
|
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)
|
if (mPublicApiList.size() > 0)
|
||||||
{
|
{
|
||||||
printf(" Public APIs:\n");
|
std::cout << " Public APIs:" << std::endl;
|
||||||
for (size_t i = 0; i < mPublicApiList.size(); i++)
|
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)
|
if (mDebugApiList.size() > 0)
|
||||||
{
|
{
|
||||||
printf(" Debug APIs:\n");
|
std::cout << " Debug APIs:" << std::endl;
|
||||||
for (size_t i = 0; i < mDebugApiList.size(); i++)
|
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)
|
if (mPrivateApiList.size() > 0)
|
||||||
{
|
{
|
||||||
printf(" Private APIs:\n");
|
std::cout << " Private APIs:" << std::endl;
|
||||||
for (size_t i = 0; i < mPrivateApiList.size(); i++)
|
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)))
|
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++)
|
for (size_t i = 0; i < mSymbolList.getSymbolList().size(); i++)
|
||||||
{
|
{
|
||||||
const ElfSymbolParser::sElfSymbol& symbol = mSymbolList.getSymbolList()[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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include <fnd/SimpleFile.h>
|
#include <fnd/SimpleFile.h>
|
||||||
#include <fnd/io.h>
|
#include <fnd/io.h>
|
||||||
|
@ -30,18 +32,15 @@ RomfsProcess::~RomfsProcess()
|
||||||
|
|
||||||
void RomfsProcess::process()
|
void RomfsProcess::process()
|
||||||
{
|
{
|
||||||
if (mFile == nullptr)
|
|
||||||
{
|
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
|
||||||
}
|
|
||||||
|
|
||||||
resolveRomfs();
|
resolveRomfs();
|
||||||
|
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||||
{
|
{
|
||||||
displayHeader();
|
displayHeader();
|
||||||
if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
displayFs();
|
displayFs();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mExtract)
|
if (mExtract)
|
||||||
extractFs();
|
extractFs();
|
||||||
}
|
}
|
||||||
|
@ -87,19 +86,19 @@ void RomfsProcess::printTab(size_t tab) const
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < tab; i++)
|
for (size_t i = 0; i < tab; i++)
|
||||||
{
|
{
|
||||||
printf(" ");
|
std::cout << " ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RomfsProcess::displayFile(const sFile& file, size_t tab) const
|
void RomfsProcess::displayFile(const sFile& file, size_t tab) const
|
||||||
{
|
{
|
||||||
printTab(tab);
|
printTab(tab);
|
||||||
printf("%s", file.name.c_str());
|
std::cout << file.name;
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
|
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
|
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)
|
if (dir.name.empty() == false)
|
||||||
{
|
{
|
||||||
printTab(tab);
|
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++)
|
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()
|
void RomfsProcess::displayHeader()
|
||||||
{
|
{
|
||||||
printf("[RomFS]\n");
|
std::cout << "[RomFS]" << std::endl;
|
||||||
printf(" DirNum: %" PRId64 "\n", (uint64_t)mDirNum);
|
std::cout << " DirNum: " << std::dec << mDirNum << std::endl;
|
||||||
printf(" FileNum: %" PRId64 "\n", (uint64_t)mFileNum);
|
std::cout << " FileNum: " << std::dec << mFileNum << std::endl;
|
||||||
if (mMountName.empty() == false)
|
if (mMountName.empty() == false)
|
||||||
printf(" MountPoint: %s%s\n", mMountName.c_str(), mMountName.at(mMountName.length()-1) != '/' ? "/" : "");
|
{
|
||||||
|
std::cout << " MountPoint: " << mMountName;
|
||||||
|
if (mMountName.at(mMountName.length()-1) != '/')
|
||||||
|
std::cout << "/";
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RomfsProcess::displayFs()
|
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);
|
fnd::io::appendToPath(file_path, dir.file_list[i].name);
|
||||||
|
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
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);
|
outFile.open(file_path, outFile.Create);
|
||||||
mFile->seek(dir.file_list[i].offset);
|
mFile->seek(dir.file_list[i].offset);
|
||||||
|
@ -254,6 +258,11 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir)
|
||||||
|
|
||||||
void RomfsProcess::resolveRomfs()
|
void RomfsProcess::resolveRomfs()
|
||||||
{
|
{
|
||||||
|
if (mFile == nullptr)
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
|
}
|
||||||
|
|
||||||
// read header
|
// read header
|
||||||
mFile->read((byte_t*)&mHdr, 0, sizeof(nn::hac::sRomfsHeader));
|
mFile->read((byte_t*)&mHdr, 0, sizeof(nn::hac::sRomfsHeader));
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include <nn/hac/XciUtils.h>
|
#include <nn/hac/XciUtils.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
#include "OffsetAdjustedIFile.h"
|
||||||
|
@ -25,28 +27,11 @@ XciProcess::~XciProcess()
|
||||||
|
|
||||||
void XciProcess::process()
|
void XciProcess::process()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
importHeader();
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
// validate header signature
|
// validate header signature
|
||||||
if (mVerify)
|
if (mVerify)
|
||||||
{
|
|
||||||
validateXciSignature();
|
validateXciSignature();
|
||||||
}
|
|
||||||
|
|
||||||
// deserialise header
|
|
||||||
mHdr.fromBytes(scratch.data(), scratch.size());
|
|
||||||
|
|
||||||
// display header
|
// display header
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||||
|
@ -90,94 +75,115 @@ void XciProcess::setListFs(bool list_fs)
|
||||||
mListFs = list_fs;
|
mListFs = list_fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XciProcess::importHeader()
|
||||||
|
{
|
||||||
|
fnd::Vec<byte_t> 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()
|
void XciProcess::displayHeader()
|
||||||
{
|
{
|
||||||
printf("[XCI Header]\n");
|
std::cout << "[XCI Header]" << std::endl;
|
||||||
printf(" CardHeaderVersion: %d\n", mHdr.getCardHeaderVersion());
|
std::cout << " CardHeaderVersion: " << std::dec << (uint32_t)mHdr.getCardHeaderVersion() << std::endl;
|
||||||
printf(" RomSize: %s", getRomSizeStr(mHdr.getRomSizeType()));
|
std::cout << " RomSize: " << getRomSizeStr(mHdr.getRomSizeType());
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
printf(" (0x%x)", mHdr.getRomSizeType());
|
std::cout << " (0x" << std::hex << (uint32_t)mHdr.getRomSizeType() << ")";
|
||||||
printf("\n");
|
std::cout << std::endl;
|
||||||
printf(" PackageId: 0x%" PRIx64 "\n", mHdr.getPackageId());
|
std::cout << " PackageId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getPackageId() << std::endl;
|
||||||
printf(" Flags: 0x%x\n", mHdr.getFlags());
|
std::cout << " Flags: 0x" << std::dec << (uint32_t)mHdr.getFlags() << std::endl;
|
||||||
if (mHdr.getFlags() != 0)
|
if (mHdr.getFlags() != 0)
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < 8; i++)
|
for (uint32_t i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
if (_HAS_BIT(mHdr.getFlags(), i))
|
if (_HAS_BIT(mHdr.getFlags(), i))
|
||||||
{
|
{
|
||||||
printf(" %s\n", getHeaderFlagStr(i));
|
std::cout << " " << getHeaderFlagStr(i) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
{
|
{
|
||||||
printf(" InitialData:\n");
|
std::cout << " InitialData:" << std::endl;
|
||||||
printf(" KekIndex: %d\n", mHdr.getKekIndex());
|
std::cout << " KekIndex: " << std::dec << (uint32_t)mHdr.getKekIndex() << std::endl;
|
||||||
printf(" TitleKeyDecIndex: %d\n", mHdr.getTitleKeyDecIndex());
|
std::cout << " TitleKeyDecIndex: " << std::dec << (uint32_t)mHdr.getTitleKeyDecIndex() << std::endl;
|
||||||
printf(" Hash:\n");
|
std::cout << " Hash:" << std::endl;
|
||||||
fnd::SimpleTextOutput::hexDump(mHdr.getInitialDataHash().bytes, sizeof(mHdr.getInitialDataHash().bytes), 0x10, 6);
|
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))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
{
|
{
|
||||||
printf(" Enc Header AES-IV:\n");
|
std::cout << " Extended Header AES-IV:" << std::endl;
|
||||||
fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), 0x10, 4);
|
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), true, "") << std::endl;
|
||||||
}
|
}
|
||||||
printf(" SelSec: 0x%x\n", mHdr.getSelSec());
|
std::cout << " SelSec: 0x" << std::hex << mHdr.getSelSec() << std::endl;
|
||||||
printf(" SelT1Key: 0x%x\n", mHdr.getSelT1Key());
|
std::cout << " SelT1Key: 0x" << std::hex << mHdr.getSelT1Key() << std::endl;
|
||||||
printf(" SelKey: 0x%x\n", mHdr.getSelKey());
|
std::cout << " SelKey: 0x" << std::hex << mHdr.getSelKey() << std::endl;
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
|
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))
|
if (mHdr.getRomAreaStartPage() != (uint32_t)(-1))
|
||||||
printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getRomAreaStartPage()));
|
std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getRomAreaStartPage()) << ")";
|
||||||
printf("\n");
|
std::cout << std::endl;
|
||||||
|
|
||||||
printf(" BackupAreaStartPage: 0x%0x", mHdr.getBackupAreaStartPage());
|
std::cout << " BackupAreaStartPage: 0x" << std::hex << mHdr.getBackupAreaStartPage();
|
||||||
if (mHdr.getBackupAreaStartPage() != (uint32_t)(-1))
|
if (mHdr.getBackupAreaStartPage() != (uint32_t)(-1))
|
||||||
printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage()));
|
std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage()) << ")";
|
||||||
printf("\n");
|
std::cout << std::endl;
|
||||||
|
|
||||||
printf(" ValidDataEndPage: 0x%x", mHdr.getValidDataEndPage());
|
std::cout << " ValidDataEndPage: 0x" << std::hex << mHdr.getValidDataEndPage();
|
||||||
if (mHdr.getValidDataEndPage() != (uint32_t)(-1))
|
if (mHdr.getValidDataEndPage() != (uint32_t)(-1))
|
||||||
printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getValidDataEndPage()));
|
std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getValidDataEndPage()) << ")";
|
||||||
printf("\n");
|
std::cout << std::endl;
|
||||||
|
|
||||||
printf(" LimArea: 0x%x", mHdr.getLimAreaPage());
|
std::cout << " LimArea: 0x" << std::hex << mHdr.getLimAreaPage();
|
||||||
if (mHdr.getLimAreaPage() != (uint32_t)(-1))
|
if (mHdr.getLimAreaPage() != (uint32_t)(-1))
|
||||||
printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getLimAreaPage()));
|
std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getLimAreaPage()) << ")";
|
||||||
printf("\n");
|
std::cout << std::endl;
|
||||||
|
|
||||||
printf(" PartitionFs Header:\n");
|
std::cout << " PartitionFs Header:" << std::endl;
|
||||||
printf(" Offset: 0x%" PRIx64 "\n", mHdr.getPartitionFsAddress());
|
std::cout << " Offset: 0x" << std::hex << mHdr.getPartitionFsAddress() << std::endl;
|
||||||
printf(" Size: 0x%" PRIx64 "\n", mHdr.getPartitionFsSize());
|
std::cout << " Size: 0x" << std::hex << mHdr.getPartitionFsSize() << std::endl;
|
||||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
{
|
{
|
||||||
printf(" Hash:\n");
|
std::cout << " Hash:" << std::endl;
|
||||||
fnd::SimpleTextOutput::hexDump(mHdr.getPartitionFsHash().bytes, sizeof(mHdr.getPartitionFsHash().bytes), 0x10, 6);
|
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)
|
if (mHdr.getFwVerMinor() != 0)
|
||||||
{
|
{
|
||||||
printf("[XCI Extended Header]\n");
|
std::cout << "[XCI Extended Header]" << std::endl;
|
||||||
printf(" FwVersion: v%d.%d\n", mHdr.getFwVerMajor(), mHdr.getFwVerMinor());
|
std::cout << " FwVersion: v" << std::dec << mHdr.getFwVerMajor() << "." << mHdr.getFwVerMinor() << std::endl;
|
||||||
printf(" AccCtrl1: 0x%x\n", mHdr.getAccCtrl1());
|
std::cout << " AccCtrl1: 0x" << std::hex << mHdr.getAccCtrl1() << std::endl;
|
||||||
printf(" CardClockRate: %s\n", getCardClockRate(mHdr.getAccCtrl1()));
|
std::cout << " CardClockRate: " << getCardClockRate(mHdr.getAccCtrl1()) << std::endl;
|
||||||
printf(" Wait1TimeRead: 0x%x\n", mHdr.getWait1TimeRead());
|
std::cout << " Wait1TimeRead: 0x" << std::hex << mHdr.getWait1TimeRead() << std::endl;
|
||||||
printf(" Wait2TimeRead: 0x%x\n", mHdr.getWait2TimeRead());
|
std::cout << " Wait2TimeRead: 0x" << std::hex << mHdr.getWait2TimeRead() << std::endl;
|
||||||
printf(" Wait1TimeWrite: 0x%x\n", mHdr.getWait1TimeWrite());
|
std::cout << " Wait1TimeWrite: 0x" << std::hex << mHdr.getWait1TimeWrite() << std::endl;
|
||||||
printf(" Wait2TimeWrite: 0x%x\n", mHdr.getWait2TimeWrite());
|
std::cout << " Wait2TimeWrite: 0x" << std::hex << mHdr.getWait2TimeWrite() << std::endl;
|
||||||
printf(" FwMode: 0x%x\n", mHdr.getFwMode());
|
std::cout << " FwMode: 0x" << std::hex << mHdr.getFwMode() << std::endl;
|
||||||
printf(" Update Partition Info:\n");
|
std::cout << " Update Partition Info:" << std::endl;
|
||||||
#define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff)
|
#define _SPLIT_VER(ver) std::dec << ((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 << " CUP Version: v" << std::dec << mHdr.getUppVersion() << " (" << _SPLIT_VER(mHdr.getUppVersion()) << ")" << std::endl;
|
||||||
#undef _SPLIT_VER
|
#undef _SPLIT_VER
|
||||||
printf(" CUP TitleId: %016" PRIx64 "\n", mHdr.getUppId());
|
std::cout << " CUP TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getUppId() << std::endl;
|
||||||
printf(" Partition Hash: ");
|
std::cout << " Partition Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getUppHash(), 8, true, "") << std::endl;
|
||||||
fnd::SimpleTextOutput::hexDump(mHdr.getUppHash(), 8);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash)
|
bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash)
|
||||||
|
@ -196,7 +202,7 @@ void XciProcess::validateXciSignature()
|
||||||
fnd::sha::Sha256((byte_t*)&mHdrPage.header, sizeof(nn::hac::sXciHeader), calc_hash.bytes);
|
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)
|
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)
|
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.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()), OWN_IFILE);
|
||||||
mRootPfs.setListFs(mListFs);
|
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
|
// 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)
|
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;
|
PfsProcess tmp;
|
||||||
|
@ -240,7 +246,8 @@ void XciProcess::processPartitionPfs()
|
||||||
|
|
||||||
const char* XciProcess::getRomSizeStr(byte_t rom_size) const
|
const char* XciProcess::getRomSizeStr(byte_t rom_size) const
|
||||||
{
|
{
|
||||||
const char* str = "unknown";
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch (rom_size)
|
switch (rom_size)
|
||||||
{
|
{
|
||||||
case (nn::hac::xci::ROM_SIZE_1GB):
|
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):
|
case (nn::hac::xci::ROM_SIZE_32GB):
|
||||||
str = "32GB";
|
str = "32GB";
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
str = "Unknown";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* XciProcess::getHeaderFlagStr(byte_t flag) const
|
const char* XciProcess::getHeaderFlagStr(byte_t flag) const
|
||||||
{
|
{
|
||||||
const char* str = "unknown";
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch (flag)
|
switch (flag)
|
||||||
{
|
{
|
||||||
case (nn::hac::xci::FLAG_AUTOBOOT):
|
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):
|
case (nn::hac::xci::FLAG_REPAIR_TOOL):
|
||||||
str = "RepairTool";
|
str = "RepairTool";
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
str = "Unknown";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char* XciProcess::getCardClockRate(uint32_t acc_ctrl_1) const
|
const char* XciProcess::getCardClockRate(uint32_t acc_ctrl_1) const
|
||||||
{
|
{
|
||||||
const char* str = "unknown";
|
const char* str = nullptr;
|
||||||
|
|
||||||
switch (acc_ctrl_1)
|
switch (acc_ctrl_1)
|
||||||
{
|
{
|
||||||
case (nn::hac::xci::CLOCK_RATE_25):
|
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):
|
case (nn::hac::xci::CLOCK_RATE_50):
|
||||||
str = "50 MHz";
|
str = "50 MHz";
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
str = "Unknown";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ private:
|
||||||
PfsProcess mRootPfs;
|
PfsProcess mRootPfs;
|
||||||
fnd::List<sExtractInfo> mExtractInfo;
|
fnd::List<sExtractInfo> mExtractInfo;
|
||||||
|
|
||||||
|
void importHeader();
|
||||||
void displayHeader();
|
void displayHeader();
|
||||||
bool validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash);
|
bool validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash);
|
||||||
void validateXciSignature();
|
void validateXciSignature();
|
||||||
|
|
Loading…
Reference in a new issue