[nstool] Migrated printf to std::cout

This commit is contained in:
jakcron 2018-08-14 01:14:21 +08:00
parent 3ad02fb5cc
commit 70cea402e5
20 changed files with 613 additions and 522 deletions

View file

@ -1,7 +1,7 @@
#include <fnd/SimpleFile.h>
#include <fnd/Vec.h>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <fnd/SimpleFile.h>
#include <fnd/Vec.h>
#include "AssetProcess.h" #include "AssetProcess.h"
#include "OffsetAdjustedIFile.h" #include "OffsetAdjustedIFile.h"
@ -25,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();
@ -76,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");

View file

@ -1,6 +1,6 @@
#include <fnd/SimpleTextOutput.h>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <fnd/SimpleTextOutput.h>
#include "OffsetAdjustedIFile.h" #include "OffsetAdjustedIFile.h"
#include "CnmtProcess.h" #include "CnmtProcess.h"
@ -22,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)
@ -59,7 +49,22 @@ const nn::hac::ContentMetaBinary& CnmtProcess::getContentMetaBinary() const
return mCnmt; return mCnmt;
} }
void CnmtProcess::displayCmnt() 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) #define _SPLIT_VER(ver) (uint32_t)((ver>>26) & 0x3f) << "." << (uint32_t)((ver>>20) & 0x3f) << "." << (uint32_t)((ver>>16) & 0xf) << "." << (uint32_t)(ver & 0xffff)
#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
@ -68,7 +73,7 @@ void CnmtProcess::displayCmnt()
std::cout << " TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getTitleId() << 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 << " 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 << " Type: " << getContentMetaTypeStr(mCnmt.getType()) << " (" << std::dec << mCnmt.getType() << ")" << std::endl;
std::cout << " Attributes: " << std::hex << mCnmt.getAttributes() << 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 << " 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 << " 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; std::cout << " RequiredDownloadSystemVersion: v" << mCnmt.getRequiredDownloadSystemVersion() << " (" << _SPLIT_VER(mCnmt.getRequiredDownloadSystemVersion()) << ")"<< std::endl;
@ -123,7 +128,7 @@ void CnmtProcess::displayCmnt()
std::cout << " Id: 0x" << std::hex << std::setw(16) << std::setfill('0') << info.id << 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 << " 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 << " Type: " << getContentMetaTypeStr(info.type) << " (" << std::dec << info.type << ")" << std::endl;
std::cout << " Attributes: " << std::hex << info.attributes << 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 << " 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 << " Rebootless: " << getBoolStr(_HAS_BIT(info.attributes, nn::hac::cnmt::ATTRIBUTE_REBOOTLESS)) << std::endl;
} }

View file

@ -30,7 +30,8 @@ private:
nn::hac::ContentMetaBinary mCnmt; nn::hac::ContentMetaBinary mCnmt;
void displayCmnt(); void importCnmt();
void displayCnmt();
const char* getBoolStr(bool state) const; const char* getBoolStr(bool state) const;
const char* getContentTypeStr(nn::hac::cnmt::ContentType type) const; const char* getContentTypeStr(nn::hac::cnmt::ContentType type) const;

View file

@ -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());

View file

@ -1,4 +1,6 @@
#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"
@ -21,17 +23,7 @@ NacpProcess::~NacpProcess()
void NacpProcess::process() void NacpProcess::process()
{ {
fnd::Vec<byte_t> scratch; importNacp();
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)) if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
displayNacp(); displayNacp();
@ -58,124 +50,139 @@ const nn::hac::ApplicationControlPropertyBinary& NacpProcess::getApplicationCont
return mNacp; 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() void NacpProcess::displayNacp()
{ {
printf("[ApplicationControlProperty]\n"); std::cout << "[ApplicationControlProperty]" << std::endl;
printf(" Menu Description:\n"); std::cout << " Menu Description:" << std::endl;
printf(" DisplayVersion: %s\n", mNacp.getDisplayVersion().c_str()); std::cout << " DisplayVersion: " << mNacp.getDisplayVersion() << std::endl;
if (mNacp.getIsbn().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mNacp.getIsbn().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
printf(" ISBN: %s\n", mNacp.getIsbn().c_str()); std::cout << " ISBN: " << mNacp.getIsbn() << std::endl;
for (size_t i = 0; i < mNacp.getTitle().size(); i++) for (size_t i = 0; i < mNacp.getTitle().size(); i++)
{ {
printf(" %s Title:\n", getLanguageStr(mNacp.getTitle()[i].language)); std::cout << " " << getLanguageStr(mNacp.getTitle()[i].language) << " Title:" << std::endl;
printf(" Name: %s\n", mNacp.getTitle()[i].name.c_str()); std::cout << " Name: " << mNacp.getTitle()[i].name << std::endl;
printf(" Publisher: %s\n", mNacp.getTitle()[i].publisher.c_str()); std::cout << " Publisher: " << mNacp.getTitle()[i].publisher << std::endl;
} }
printf(" Logo:\n"); std::cout << " Logo:" << std::endl;
printf(" Type: %s\n", getLogoTypeStr(mNacp.getLogoType())); std::cout << " Type: " << getLogoTypeStr(mNacp.getLogoType()) << std::endl;
printf(" Handling: %s\n", getLogoHandlingStr(mNacp.getLogoHandling())); std::cout << " Handling: " << getLogoHandlingStr(mNacp.getLogoHandling()) << std::endl;
printf(" AddOnContent:\n"); std::cout << " AddOnContent:" << std::endl;
printf(" BaseId: 0x%016" PRIx64 "\n", mNacp.getAocBaseId()); std::cout << " BaseId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getAocBaseId() << std::endl;
printf(" RegistrationType: %s\n", getAocRegistrationTypeStr(mNacp.getAocRegistrationType())); std::cout << " RegistrationType: " << getAocRegistrationTypeStr(mNacp.getAocRegistrationType()) << std::endl;
printf(" RuntimeInstallMode: %s\n", getRuntimeAocInstallModeStr(mNacp.getRuntimeAocInstallMode())); std::cout << " RuntimeInstallMode: " << getRuntimeAocInstallModeStr(mNacp.getRuntimeAocInstallMode()) << std::endl;
printf(" Play Log:\n"); std::cout << " Play Log:" << std::endl;
printf(" PlayLogPolicy: %s\n", getPlayLogPolicyStr(mNacp.getPlayLogPolicy())); std::cout << " PlayLogPolicy: " << getPlayLogPolicyStr(mNacp.getPlayLogPolicy()) << std::endl;
printf(" PlayLogQueryCapability: %s\n", getPlayLogQueryCapabilityStr(mNacp.getPlayLogQueryCapability())); std::cout << " PlayLogQueryCapability: " << getPlayLogQueryCapabilityStr(mNacp.getPlayLogQueryCapability()) << std::endl;
if (mNacp.getPlayLogQueryableApplicationId().size() > 0) if (mNacp.getPlayLogQueryableApplicationId().size() > 0)
{ {
printf(" PlayLogQueryableApplicationId:\n"); std::cout << " PlayLogQueryableApplicationId:" << std::endl;
for (size_t i = 0; i < mNacp.getPlayLogQueryableApplicationId().size(); i++) for (size_t i = 0; i < mNacp.getPlayLogQueryableApplicationId().size(); i++)
{ {
printf(" 0x%016" PRIx64 "\n", mNacp.getPlayLogQueryableApplicationId()[i]); std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getPlayLogQueryableApplicationId()[i] << std::endl;
} }
} }
printf(" Parental Controls:\n"); std::cout << " Parental Controls:" << std::endl;
printf(" ParentalControlFlag: %s\n", getParentalControlFlagStr(mNacp.getParentalControlFlag())); std::cout << " ParentalControlFlag: " << getParentalControlFlagStr(mNacp.getParentalControlFlag()) << std::endl;
for (size_t i = 0; i < mNacp.getRatingAge().size(); i++) for (size_t i = 0; i < mNacp.getRatingAge().size(); i++)
{ {
printf(" Age Restriction:\n"); std::cout << " Age Restriction:" << std::endl;
printf(" Agency: %s\n", getOrganisationStr(mNacp.getRatingAge()[i].organisation)); std::cout << " Agency: " << getOrganisationStr(mNacp.getRatingAge()[i].organisation) << std::endl;
printf(" Age: %d\n", mNacp.getRatingAge()[i].age); std::cout << " Age: " << std::dec << (uint32_t)mNacp.getRatingAge()[i].age << std::endl;
} }
if (mNacp.getBcatPassphase().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mNacp.getBcatPassphase().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" BCAT:\n"); std::cout << " BCAT:" << std::endl;
printf(" BcatPassphase: %s\n", mNacp.getBcatPassphase().c_str()); std::cout << " BcatPassphase: " << mNacp.getBcatPassphase() << std::endl;
printf(" DeliveryCacheStorageSize: 0x%016" PRIx64 "\n", mNacp.getBcatDeliveryCacheStorageSize()); std::cout << " DeliveryCacheStorageSize: 0x" << std::hex << mNacp.getBcatDeliveryCacheStorageSize() << std::endl;
} }
if (mNacp.getLocalCommunicationId().size() > 0) if (mNacp.getLocalCommunicationId().size() > 0)
{ {
printf(" Local Area Communication:\n"); std::cout << " Local Area Communication:" << std::endl;
printf(" LocalCommunicationId:\n"); std::cout << " LocalCommunicationId:" << std::endl;
for (size_t i = 0; i < mNacp.getLocalCommunicationId().size(); i++) for (size_t i = 0; i < mNacp.getLocalCommunicationId().size(); i++)
{ {
printf(" 0x%016" PRIx64 "\n", mNacp.getLocalCommunicationId()[i]); std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getLocalCommunicationId()[i] << std::endl;
} }
} }
printf(" SaveData:\n"); std::cout << " SaveData:" << std::endl;
printf(" SaveDatawOwnerId: 0x%016" PRIx64 "\n", mNacp.getSaveDatawOwnerId()); 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)) if (mNacp.getUserAccountSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" UserAccountSaveData:\n"); std::cout << " UserAccountSaveData:" << std::endl;
printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().size).c_str()); std::cout << " Size: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().size) << std::endl;
printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().journal_size).c_str()); std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().journal_size) << std::endl;
} }
if (mNacp.getDeviceSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mNacp.getDeviceSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" DeviceSaveData:\n"); std::cout << " DeviceSaveData:" << std::endl;
printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().size).c_str()); std::cout << " Size: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().size) << std::endl;
printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().journal_size).c_str()); std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().journal_size) << std::endl;
} }
if (mNacp.getUserAccountSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mNacp.getUserAccountSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" UserAccountSaveDataMax:\n"); std::cout << " UserAccountSaveDataMax:" << std::endl;
printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().size).c_str()); std::cout << " Size: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().size) << std::endl;
printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().journal_size).c_str()); std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().journal_size) << std::endl;
} }
if (mNacp.getDeviceSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mNacp.getDeviceSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" DeviceSaveDataMax:\n"); std::cout << " DeviceSaveDataMax:" << std::endl;
printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().size).c_str()); std::cout << " Size: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().size) << std::endl;
printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().journal_size).c_str()); std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().journal_size) << std::endl;
} }
if (mNacp.getTemporaryStorageSize() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mNacp.getTemporaryStorageSize() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" TemporaryStorageSize: %s\n", getSaveDataSizeStr(mNacp.getTemporaryStorageSize()).c_str()); std::cout << " TemporaryStorageSize: " << getSaveDataSizeStr(mNacp.getTemporaryStorageSize()) << std::endl;
} }
if (mNacp.getCacheStorageSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mNacp.getCacheStorageSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" CacheStorage:\n"); std::cout << " CacheStorage:" << std::endl;
printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageSize().size).c_str()); std::cout << " Size: " << getSaveDataSizeStr(mNacp.getCacheStorageSize().size) << std::endl;
printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageSize().journal_size).c_str()); std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getCacheStorageSize().journal_size) << std::endl;
printf(" MaxDataAndJournalSize: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageDataAndJournalSizeMax()).c_str()); std::cout << " MaxDataAndJournalSize: " << getSaveDataSizeStr(mNacp.getCacheStorageDataAndJournalSizeMax()) << std::endl;
printf(" StorageIndexMax: 0x%" PRIx16 "\n", mNacp.getCacheStorageIndexMax()); std::cout << " StorageIndexMax: 0x" << std::hex << mNacp.getCacheStorageIndexMax() << std::endl;
} }
printf(" Other Flags:\n"); std::cout << " Other Flags:" << std::endl;
printf(" StartupUserAccount: %s\n", getStartupUserAccountStr(mNacp.getStartupUserAccount())); std::cout << " StartupUserAccount: " << getStartupUserAccountStr(mNacp.getStartupUserAccount()) << std::endl;
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" TouchScreenUsageMode: %s\n", getTouchScreenUsageModeStr(mNacp.getTouchScreenUsageMode())); std::cout << " TouchScreenUsageMode: " << getTouchScreenUsageModeStr(mNacp.getTouchScreenUsageMode()) << std::endl;
} }
printf(" AttributeFlag: %s\n", getAttributeFlagStr(mNacp.getAttributeFlag())); std::cout << " AttributeFlag: " << getAttributeFlagStr(mNacp.getAttributeFlag()) << std::endl;
printf(" CrashReportMode: %s\n", getCrashReportModeStr(mNacp.getCrashReportMode())); std::cout << " CrashReportMode: " << getCrashReportModeStr(mNacp.getCrashReportMode()) << std::endl;
printf(" HDCP: %s\n", getHdcpStr(mNacp.getHdcp())); std::cout << " HDCP: " << getHdcpStr(mNacp.getHdcp()) << std::endl;
printf(" ScreenshotMode: %s\n", getScreenshotModeStr(mNacp.getScreenshotMode())); std::cout << " ScreenshotMode: " << getScreenshotModeStr(mNacp.getScreenshotMode()) << std::endl;
printf(" VideoCaptureMode: %s\n", getVideoCaptureModeStr(mNacp.getVideoCaptureMode())); std::cout << " VideoCaptureMode: " << getVideoCaptureModeStr(mNacp.getVideoCaptureMode()) << std::endl;
printf(" DataLossConfirmation: %s\n", getDataLossConfirmationStr(mNacp.getDataLossConfirmation())); std::cout << " DataLossConfirmation: " << getDataLossConfirmationStr(mNacp.getDataLossConfirmation()) << std::endl;
printf(" RepairFlag: %s\n", getRepairFlagStr(mNacp.getRepairFlag())); std::cout << " RepairFlag: " << getRepairFlagStr(mNacp.getRepairFlag()) << std::endl;
printf(" ProgramIndex: 0x%02x\n", mNacp.getProgramIndex()); 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)) if (mNacp.getApplicationErrorCodeCategory().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" ApplicationErrorCodeCategory: %s\n", mNacp.getApplicationErrorCodeCategory().c_str()); std::cout << " ApplicationErrorCodeCategory: " << mNacp.getApplicationErrorCodeCategory() << std::endl;
} }
if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" Other Ids:\n"); std::cout << " Other Ids:" << std::endl;
if (mNacp.getSeedForPsuedoDeviceId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mNacp.getSeedForPsuedoDeviceId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
printf(" SeedForPsuedoDeviceId: 0x%016" PRIx64 "\n", mNacp.getSeedForPsuedoDeviceId()); 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)) if (mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
printf(" PresenceGroupId: 0x%016" PRIx64 "\n", mNacp.getPresenceGroupId()); std::cout << " PresenceGroupId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getPresenceGroupId() << std::endl;
} }
} }

View file

@ -30,6 +30,7 @@ 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* getLanguageStr(nn::hac::nacp::Language var) const;
const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) const; const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) const;

View file

@ -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>
@ -44,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();
@ -129,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
@ -231,17 +238,17 @@ 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::hexDump(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var)); 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::hexDump(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var)); fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var));
printf(" AES-XTS Key1: "); std::cout << " AES-XTS Key1: ";
fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var)); fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var));
} }
} }
@ -363,7 +370,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]
@ -390,93 +397,90 @@ 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::hexDump(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen); fnd::SimpleTextOutput::hexDump(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen);
} }
#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) std::cout << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)var[a__a__A]; } while(0)
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); _HEXDUMP_L(mBodyKeys.keak_list[i].enc.key, 16);
//for (size_t j = 0; j < 16; j++) printf("%02x", mBodyKeys.keak_list[i].enc.key[j]);
printf(" | "); std::cout << " | ";
if (mBodyKeys.keak_list[i].decrypted) if (mBodyKeys.keak_list[i].decrypted)
_HEXDUMP_L(mBodyKeys.keak_list[i].dec.key, 16); _HEXDUMP_L(mBodyKeys.keak_list[i].dec.key, 16);
else else
printf("<unable to decrypt> "); std::cout << "<unable to decrypt> ";
printf(" |\n"); std::cout << " |" << std::endl;
} }
printf(" <--------------------------------------------------------------------------->\n"); std::cout << " <--------------------------------------------------------------------------->" << std::endl;
} }
#undef _HEXDUMP_L
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: "); std::cout << " 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)); fnd::SimpleTextOutput::hexDump(ctr.iv, sizeof(fnd::aes::sAesIvCtr));
@ -484,53 +488,41 @@ void NcaProcess::displayHeader()
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::hexDump(hash_hdr.getMasterHashList()[j].bytes, sizeof(fnd::sha::sSha256Hash)); 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::hexDump(hash_hdr.getMasterHashList()[0].bytes, sizeof(fnd::sha::sSha256Hash)); fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[0].bytes, sizeof(fnd::sha::sSha256Hash));
printf(" HashBlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size); std::cout << " HashBlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl;
//printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().size()); std::cout << " Hash Layer:" << std::endl;
printf(" Hash Layer:\n"); std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].offset << std::endl;
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].offset); std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].size << std::endl;
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].size); std::cout << " Data Layer:" << std::endl;
printf(" Data Layer:\n"); std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().offset << std::endl;
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset); std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().size << std::endl;
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
} }
@ -544,12 +536,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;
} }
@ -570,9 +562,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)
{ {
@ -591,9 +581,7 @@ 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");
} }
} }
} }

View file

@ -105,6 +105,7 @@ 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();

View file

@ -1,3 +1,5 @@
#include <iostream>
#include <iomanip>
#include "NpdmProcess.h" #include "NpdmProcess.h"
NpdmProcess::NpdmProcess() : NpdmProcess::NpdmProcess() :
@ -19,17 +21,7 @@ NpdmProcess::~NpdmProcess()
void NpdmProcess::process() void NpdmProcess::process()
{ {
fnd::Vec<byte_t> scratch; importNpdm();
if (mFile == nullptr)
{
throw fnd::Exception(kModuleName, "No file reader set.");
}
scratch.alloc(mFile->size());
mFile->read(scratch.data(), 0, scratch.size());
mNpdm.fromBytes(scratch.data(), scratch.size());
if (mVerify) if (mVerify)
{ {
@ -85,13 +77,28 @@ const nn::hac::NpdmBinary& NpdmProcess::getNpdmBinary() const
return mNpdm; return mNpdm;
} }
void NpdmProcess::importNpdm()
{
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());
mNpdm.fromBytes(scratch.data(), scratch.size());
}
void NpdmProcess::validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid) void NpdmProcess::validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid)
{ {
try { try {
acid.validateSignature(mKeyset->acid_sign_key); acid.validateSignature(mKeyset->acid_sign_key);
} }
catch (...) { catch (...) {
printf("[WARNING] ACID Signature: FAIL\n"); std::cout << "[WARNING] ACID Signature: FAIL" << std::endl;
} }
} }
@ -101,11 +108,11 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
// check Program ID // check Program ID
if (acid.getProgramIdRestrict().min > 0 && aci.getProgramId() < acid.getProgramIdRestrict().min) if (acid.getProgramIdRestrict().min > 0 && aci.getProgramId() < acid.getProgramIdRestrict().min)
{ {
printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n"); std::cout << "[WARNING] ACI ProgramId: FAIL (Outside Legal Range)" << std::endl;
} }
else if (acid.getProgramIdRestrict().max > 0 && aci.getProgramId() > acid.getProgramIdRestrict().max) else if (acid.getProgramIdRestrict().max > 0 && aci.getProgramId() > acid.getProgramIdRestrict().max)
{ {
printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n"); std::cout << "[WARNING] ACI ProgramId: FAIL (Outside Legal Range)" << std::endl;
} }
for (size_t i = 0; i < aci.getFileSystemAccessControl().getFsaRightsList().size(); i++) for (size_t i = 0; i < aci.getFileSystemAccessControl().getFsaRightsList().size(); i++)
@ -120,7 +127,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (fsaRightFound == false) if (fsaRightFound == false)
{ {
printf("[WARNING] ACI/FAC FsaRights: FAIL (%s not permitted)\n", getFsaRightStr(aci.getFileSystemAccessControl().getFsaRightsList()[i])); std::cout << "[WARNING] ACI/FAC FsaRights: FAIL (" << getFsaRightStr(aci.getFileSystemAccessControl().getFsaRightsList()[i]) << " not permitted)" << std::endl;
} }
} }
@ -136,7 +143,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (rightFound == false) if (rightFound == false)
{ {
printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%016" PRIx64 " not permitted)\n", aci.getFileSystemAccessControl().getContentOwnerIdList()[i]); std::cout << "[WARNING] ACI/FAC ContentOwnerId: FAIL (" << std::hex << std::setw(16) << std::setfill('0') << aci.getFileSystemAccessControl().getContentOwnerIdList()[i] << " not permitted)" << std::endl;
} }
} }
@ -152,7 +159,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (rightFound == false) if (rightFound == false)
{ {
printf("[WARNING] ACI/FAC SaveDataOwnerId: FAIL (%016" PRIx64 "(%d) not permitted)\n", aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id, aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type); std::cout << "[WARNING] ACI/FAC SaveDataOwnerId: FAIL (" << std::hex << std::setw(16) << std::setfill('0') << aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id << "(" << std::dec << (uint32_t)aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type << ") not permitted)" << std::endl;
} }
} }
@ -168,7 +175,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (rightFound == false) if (rightFound == false)
{ {
printf("[WARNING] ACI/SAC ServiceList: FAIL (%s%s not permitted)\n", aci.getServiceAccessControl().getServiceList()[i].getName().c_str(), aci.getServiceAccessControl().getServiceList()[i].isServer()? " (Server)" : ""); std::cout << "[WARNING] ACI/SAC ServiceList: FAIL (" << aci.getServiceAccessControl().getServiceList()[i].getName() << (aci.getServiceAccessControl().getServiceList()[i].isServer()? " (Server)" : "") << " not permitted)" << std::endl;
} }
} }
@ -176,19 +183,19 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
// check thread info // check thread info
if (aci.getKernelCapabilities().getThreadInfo().getMaxCpuId() != acid.getKernelCapabilities().getThreadInfo().getMaxCpuId()) if (aci.getKernelCapabilities().getThreadInfo().getMaxCpuId() != acid.getKernelCapabilities().getThreadInfo().getMaxCpuId())
{ {
printf("[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMaxCpuId()); std::cout << "[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMaxCpuId() << " not permitted)" << std::endl;
} }
if (aci.getKernelCapabilities().getThreadInfo().getMinCpuId() != acid.getKernelCapabilities().getThreadInfo().getMinCpuId()) if (aci.getKernelCapabilities().getThreadInfo().getMinCpuId() != acid.getKernelCapabilities().getThreadInfo().getMinCpuId())
{ {
printf("[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMinCpuId()); std::cout << "[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMinCpuId() << " not permitted)" << std::endl;
} }
if (aci.getKernelCapabilities().getThreadInfo().getMaxPriority() != acid.getKernelCapabilities().getThreadInfo().getMaxPriority()) if (aci.getKernelCapabilities().getThreadInfo().getMaxPriority() != acid.getKernelCapabilities().getThreadInfo().getMaxPriority())
{ {
printf("[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMaxPriority()); std::cout << "[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMaxPriority() << " not permitted)" << std::endl;
} }
if (aci.getKernelCapabilities().getThreadInfo().getMinPriority() != acid.getKernelCapabilities().getThreadInfo().getMinPriority()) if (aci.getKernelCapabilities().getThreadInfo().getMinPriority() != acid.getKernelCapabilities().getThreadInfo().getMinPriority())
{ {
printf("[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMinPriority()); std::cout << "[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMinPriority() << " not permitted)" << std::endl;
} }
// check system calls // check system calls
for (size_t i = 0; i < aci.getKernelCapabilities().getSystemCalls().getSystemCalls().size(); i++) for (size_t i = 0; i < aci.getKernelCapabilities().getSystemCalls().getSystemCalls().size(); i++)
@ -202,7 +209,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (rightFound == false) if (rightFound == false)
{ {
printf("[WARNING] ACI/KC SystemCallList: FAIL (%s not permitted)\n", getSystemCallStr(aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i])); std::cout << "[WARNING] ACI/KC SystemCallList: FAIL (" << getSystemCallStr(aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i]) << " not permitted)" << std::endl;
} }
} }
// check memory maps // check memory maps
@ -219,7 +226,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
{ {
const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getMemoryMaps()[i]; const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getMemoryMaps()[i];
printf("[WARNING] ACI/KC MemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, getMemMapPermStr(map.perm), getMemMapTypeStr(map.type)); std::cout << "[WARNING] ACI/KC MemoryMap: FAIL (0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)map.addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(map.addr + map.size) << 12) - 1) << " (perm=" << getMemMapPermStr(map.perm) << ") (type=" << getMemMapTypeStr(map.type) << ") not permitted)" << std::endl;
} }
} }
for (size_t i = 0; i < aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps().size(); i++) for (size_t i = 0; i < aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps().size(); i++)
@ -235,7 +242,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
{ {
const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps()[i]; const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps()[i];
printf("[WARNING] ACI/KC IoMemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, getMemMapPermStr(map.perm), getMemMapTypeStr(map.type)); std::cout << "[WARNING] ACI/KC IoMemoryMap: FAIL (0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)map.addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(map.addr + map.size) << 12) - 1) << " (perm=" << getMemMapPermStr(map.perm) << ") (type=" << getMemMapTypeStr(map.type) << ") not permitted)" << std::endl;
} }
} }
// check interupts // check interupts
@ -250,25 +257,25 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (rightFound == false) if (rightFound == false)
{ {
printf("[WARNING] ACI/KC InteruptsList: FAIL (0x%0x not permitted)\n", aci.getKernelCapabilities().getInterupts().getInteruptList()[i]); std::cout << "[WARNING] ACI/KC InteruptsList: FAIL (0x" << std::hex << (uint32_t)aci.getKernelCapabilities().getInterupts().getInteruptList()[i] << " not permitted)" << std::endl;
} }
} }
// check misc params // check misc params
if (aci.getKernelCapabilities().getMiscParams().getProgramType() != acid.getKernelCapabilities().getMiscParams().getProgramType()) if (aci.getKernelCapabilities().getMiscParams().getProgramType() != acid.getKernelCapabilities().getMiscParams().getProgramType())
{ {
printf("[WARNING] ACI/KC ProgramType: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getMiscParams().getProgramType()); std::cout << "[WARNING] ACI/KC ProgramType: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getMiscParams().getProgramType() << " not permitted)" << std::endl;
} }
// check kernel version // check kernel version
uint32_t aciKernelVersion = (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMinor(); uint32_t aciKernelVersion = (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMinor();
uint32_t acidKernelVersion = (uint32_t)acid.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)acid.getKernelCapabilities().getKernelVersion().getVerMinor(); uint32_t acidKernelVersion = (uint32_t)acid.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)acid.getKernelCapabilities().getKernelVersion().getVerMinor();
if (aciKernelVersion < acidKernelVersion) if (aciKernelVersion < acidKernelVersion)
{ {
printf("[WARNING] ACI/KC RequiredKernelVersion: FAIL (%d.%d not permitted)\n", aci.getKernelCapabilities().getKernelVersion().getVerMajor(), aci.getKernelCapabilities().getKernelVersion().getVerMinor()); std::cout << "[WARNING] ACI/KC RequiredKernelVersion: FAIL (" << std::dec << aci.getKernelCapabilities().getKernelVersion().getVerMajor() << "." << aci.getKernelCapabilities().getKernelVersion().getVerMinor() << " not permitted)" << std::endl;
} }
// check handle table size // check handle table size
if (aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize() > acid.getKernelCapabilities().getHandleTableSize().getHandleTableSize()) if (aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize() > acid.getKernelCapabilities().getHandleTableSize().getHandleTableSize())
{ {
printf("[WARNING] ACI/KC HandleTableSize: FAIL (0x%x too large)\n", aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize()); std::cout << "[WARNING] ACI/KC HandleTableSize: FAIL (0x" << std::hex << (uint32_t)aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize() << " too large)" << std::endl;
} }
// check misc flags // check misc flags
for (size_t i = 0; i < aci.getKernelCapabilities().getMiscFlags().getFlagList().size(); i++) for (size_t i = 0; i < aci.getKernelCapabilities().getMiscFlags().getFlagList().size(); i++)
@ -282,88 +289,92 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (rightFound == false) if (rightFound == false)
{ {
printf("[WARNING] ACI/KC MiscFlag: FAIL (%s not permitted)\n", getMiscFlagStr(aci.getKernelCapabilities().getMiscFlags().getFlagList()[i])); std::cout << "[WARNING] ACI/KC MiscFlag: FAIL (" << getMiscFlagStr(aci.getKernelCapabilities().getMiscFlags().getFlagList()[i]) << " not permitted)" << std::endl;
} }
} }
} }
void NpdmProcess::displayNpdmHeader(const nn::hac::NpdmBinary& hdr) void NpdmProcess::displayNpdmHeader(const nn::hac::NpdmBinary& hdr)
{ {
printf("[NPDM HEADER]\n"); std::cout << "[NPDM HEADER]" << std::endl;
printf(" Process Architecture Params:\n"); std::cout << " Process Architecture Params:" << std::endl;
printf(" Ins. Type: %s\n", getInstructionTypeStr(hdr.getInstructionType())); std::cout << " Ins. Type: " << getInstructionTypeStr(hdr.getInstructionType()) << std::endl;
printf(" Addr Space: %s\n", getProcAddressSpaceTypeStr(hdr.getProcAddressSpaceType())); std::cout << " Addr Space: " << getProcAddressSpaceTypeStr(hdr.getProcAddressSpaceType()) << std::endl;
printf(" Main Thread Params:\n"); std::cout << " Main Thread Params:" << std::endl;
printf(" Priority: %d\n", hdr.getMainThreadPriority()); std::cout << " Priority: " << std::dec << (uint32_t)hdr.getMainThreadPriority() << std::endl;
printf(" CpuId: %d\n", hdr.getMainThreadCpuId()); std::cout << " CpuId: " << std::dec << (uint32_t)hdr.getMainThreadCpuId() << std::endl;
printf(" StackSize: 0x%x\n", hdr.getMainThreadStackSize()); std::cout << " StackSize: 0x" << std::hex << hdr.getMainThreadStackSize() << std::endl;
printf(" TitleInfo:\n"); std::cout << " TitleInfo:" << std::endl;
printf(" Version: v%" PRIu32 "\n", hdr.getVersion()); std::cout << " Version: v" << std::dec << hdr.getVersion() << std::endl;
printf(" Name: %s\n", hdr.getName().c_str()); std::cout << " Name: " << hdr.getName() << std::endl;
if (hdr.getProductCode().length()) if (hdr.getProductCode().length())
{ {
printf(" ProductCode: %s\n", hdr.getProductCode().c_str()); std::cout << " ProductCode: " << hdr.getProductCode() << std::endl;
} }
} }
void NpdmProcess::displayAciHdr(const nn::hac::AccessControlInfoBinary& aci) void NpdmProcess::displayAciHdr(const nn::hac::AccessControlInfoBinary& aci)
{ {
printf("[Access Control Info]\n"); std::cout << "[Access Control Info]" << std::endl;
printf(" ProgramID: 0x%016" PRIx64 "\n", aci.getProgramId()); std::cout << " ProgramID: 0x" << std::hex << std::setw(16) << std::setfill('0') << aci.getProgramId() << std::endl;
} }
void NpdmProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDescBinary& acid) void NpdmProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDescBinary& acid)
{ {
printf("[Access Control Info Desc]\n"); std::cout << "[Access Control Info Desc]" << std::endl;
if (acid.getFlagList().size() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (acid.getFlagList().size() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" Flags: \n"); std::cout << " Flags: " << std::endl;
for (size_t i = 0; i < acid.getFlagList().size(); i++) for (size_t i = 0; i < acid.getFlagList().size(); i++)
{ {
printf(" %s (%d)\n", getAcidFlagStr(acid.getFlagList()[i]), acid.getFlagList()[i]); std::cout << " " << getAcidFlagStr(acid.getFlagList()[i]) << " (" << std::dec << (uint32_t)acid.getFlagList()[i] << ")" << std::endl;
} }
} }
printf(" ProgramID Restriction\n"); std::cout << " ProgramID Restriction" << std::endl;
printf(" Min: 0x%016" PRIx64 "\n", acid.getProgramIdRestrict().min); std::cout << " Min: 0x" << std::hex << std::setw(16) << std::setfill('0') << acid.getProgramIdRestrict().min << std::endl;
printf(" Max: 0x%016" PRIx64 "\n", acid.getProgramIdRestrict().max); std::cout << " Max: 0x" << std::hex << std::setw(16) << std::setfill('0') << acid.getProgramIdRestrict().max << std::endl;
} }
void NpdmProcess::displayFac(const nn::hac::FileSystemAccessControlBinary& fac) void NpdmProcess::displayFac(const nn::hac::FileSystemAccessControlBinary& fac)
{ {
printf("[FS Access Control]\n"); std::cout << "[FS Access Control]" << std::endl;
printf(" Format Version: %d\n", fac.getFormatVersion()); std::cout << " Format Version: " << std::dec << (uint32_t)fac.getFormatVersion() << std::endl;
if (fac.getFsaRightsList().size()) if (fac.getFsaRightsList().size())
{ {
printf(" FS Rights:\n"); std::cout << " FS Rights:" << std::endl;
for (size_t i = 0; i < fac.getFsaRightsList().size(); i++) for (size_t i = 0; i < fac.getFsaRightsList().size(); i++)
{ {
if (i % 10 == 0) if (i % 10 == 0)
{ {
printf("%s ", i != 0 ? "\n" : ""); if (i != 0)
std::cout << std::endl;
std::cout << " ";
} }
printf("%s", getFsaRightStr(fac.getFsaRightsList()[i])); std::cout << getFsaRightStr(fac.getFsaRightsList()[i]);
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
printf(" (bit %" PRId32 ")", fac.getFsaRightsList()[i]); std::cout << " (bit " << std::dec << (uint32_t)fac.getFsaRightsList()[i] << ")";
printf("%s", fac.getFsaRightsList()[i] != fac.getFsaRightsList().atBack() ? ", " : "\n"); if (fac.getFsaRightsList()[i] != fac.getFsaRightsList().atBack())
std::cout << ", ";
std::cout << std::endl;
} }
} }
if (fac.getContentOwnerIdList().size()) if (fac.getContentOwnerIdList().size())
{ {
printf(" Content Owner IDs:\n"); std::cout << " Content Owner IDs:" << std::endl;
for (size_t i = 0; i < fac.getContentOwnerIdList().size(); i++) for (size_t i = 0; i < fac.getContentOwnerIdList().size(); i++)
{ {
printf(" 0x%016" PRIx64 "\n", fac.getContentOwnerIdList()[i]); std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << fac.getContentOwnerIdList()[i] << std::endl;
} }
} }
if (fac.getSaveDataOwnerIdList().size()) if (fac.getSaveDataOwnerIdList().size())
{ {
printf(" Save Data Owner IDs:\n"); std::cout << " Save Data Owner IDs:" << std::endl;
for (size_t i = 0; i < fac.getSaveDataOwnerIdList().size(); i++) for (size_t i = 0; i < fac.getSaveDataOwnerIdList().size(); i++)
{ {
printf(" 0x%016" PRIx64 " (%s)\n", fac.getSaveDataOwnerIdList()[i].id, getSaveDataOwnerAccessModeStr(fac.getSaveDataOwnerIdList()[i].access_type)); std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << fac.getSaveDataOwnerIdList()[i].id << " (" << getSaveDataOwnerAccessModeStr(fac.getSaveDataOwnerIdList()[i].access_type) << ")" << std::endl;
} }
} }
@ -371,102 +382,123 @@ void NpdmProcess::displayFac(const nn::hac::FileSystemAccessControlBinary& fac)
void NpdmProcess::displaySac(const nn::hac::ServiceAccessControlBinary& sac) void NpdmProcess::displaySac(const nn::hac::ServiceAccessControlBinary& sac)
{ {
printf("[Service Access Control]\n"); std::cout << "[Service Access Control]" << std::endl;
printf(" Service List:\n"); std::cout << " Service List:" << std::endl;
for (size_t i = 0; i < sac.getServiceList().size(); i++) for (size_t i = 0; i < sac.getServiceList().size(); i++)
{ {
if (i % 10 == 0) if (i % 10 == 0)
{ {
printf("%s ", i != 0 ? "\n" : ""); if (i != 0)
std::cout << std::endl;
std::cout << " ";
} }
printf("%s%s%s", sac.getServiceList()[i].getName().c_str(), sac.getServiceList()[i].isServer() ? "(isSrv)" : "", sac.getServiceList()[i] != sac.getServiceList().atBack() ? ", " : "\n"); std::cout << sac.getServiceList()[i].getName();
if (sac.getServiceList()[i].isServer())
std::cout << "(isSrv)";
if (sac.getServiceList()[i] != sac.getServiceList().atBack())
std::cout << ", ";
} }
std::cout << std::endl;
} }
void NpdmProcess::displayKernelCap(const nn::hac::KernelCapabilityBinary& kern) void NpdmProcess::displayKernelCap(const nn::hac::KernelCapabilityBinary& kern)
{ {
printf("[Kernel Capabilities]\n"); std::cout << "[Kernel Capabilities]" << std::endl;
if (kern.getThreadInfo().isSet()) if (kern.getThreadInfo().isSet())
{ {
nn::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo(); nn::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo();
printf(" Thread Priority:\n"); std::cout << " Thread Priority:" << std::endl;
printf(" Min: %d\n", threadInfo.getMinPriority()); std::cout << " Min: " << std::dec << (uint32_t)threadInfo.getMinPriority() << std::endl;
printf(" Max: %d\n", threadInfo.getMaxPriority()); std::cout << " Max: " << std::dec << (uint32_t)threadInfo.getMaxPriority() << std::endl;
printf(" CpuId:\n"); std::cout << " CpuId:" << std::endl;
printf(" Min: %d\n", threadInfo.getMinCpuId()); std::cout << " Min: " << std::dec << (uint32_t)threadInfo.getMinCpuId() << std::endl;
printf(" Max: %d\n", threadInfo.getMaxCpuId()); std::cout << " Max: " << std::dec << (uint32_t)threadInfo.getMaxCpuId() << std::endl;
} }
if (kern.getSystemCalls().isSet()) if (kern.getSystemCalls().isSet())
{ {
fnd::List<uint8_t> syscalls = kern.getSystemCalls().getSystemCalls(); fnd::List<uint8_t> syscalls = kern.getSystemCalls().getSystemCalls();
printf(" SystemCalls:"); std::cout << " SystemCalls:" << std::endl;
printf("\n "); std::cout << " ";
size_t lineLen = 0; size_t lineLen = 0;
for (size_t i = 0; i < syscalls.size(); i++) for (size_t i = 0; i < syscalls.size(); i++)
{ {
if (lineLen > 60) if (lineLen > 60)
{ {
lineLen = 0; lineLen = 0;
printf("\n "); std::cout << std::endl;
std::cout << " ";
} }
printf("%s%s", getSystemCallStr(syscalls[i]), syscalls[i] != syscalls.atBack() ? ", " : "\n"); std::cout << getSystemCallStr(syscalls[i]);
if (syscalls[i] != syscalls.atBack())
std::cout << ", ";
lineLen += strlen(getSystemCallStr(syscalls[i])); lineLen += strlen(getSystemCallStr(syscalls[i]));
} }
std::cout << std::endl;
} }
if (kern.getMemoryMaps().isSet()) if (kern.getMemoryMaps().isSet())
{ {
fnd::List<nn::hac::MemoryMappingHandler::sMemoryMapping> maps = kern.getMemoryMaps().getMemoryMaps(); fnd::List<nn::hac::MemoryMappingHandler::sMemoryMapping> maps = kern.getMemoryMaps().getMemoryMaps();
fnd::List<nn::hac::MemoryMappingHandler::sMemoryMapping> ioMaps = kern.getMemoryMaps().getIoMemoryMaps(); fnd::List<nn::hac::MemoryMappingHandler::sMemoryMapping> ioMaps = kern.getMemoryMaps().getIoMemoryMaps();
printf(" MemoryMaps:\n"); std::cout << " MemoryMaps:" << std::endl;
for (size_t i = 0; i < maps.size(); i++) for (size_t i = 0; i < maps.size(); i++)
{ {
printf(" 0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s)\n", (uint64_t)maps[i].addr << 12, ((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1, getMemMapPermStr(maps[i].perm), getMemMapTypeStr(maps[i].type)); std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)maps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1) << " (perm=" << getMemMapPermStr(maps[i].perm) << ") (type=" << getMemMapTypeStr(maps[i].type) << ") not permitted)" << std::endl;
} }
//printf(" IoMaps:\n"); //std::cout << " IoMaps:" << std::endl;
for (size_t i = 0; i < ioMaps.size(); i++) for (size_t i = 0; i < ioMaps.size(); i++)
{ {
printf(" 0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s)\n", (uint64_t)ioMaps[i].addr << 12, ((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1, getMemMapPermStr(ioMaps[i].perm), getMemMapTypeStr(ioMaps[i].type)); std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)ioMaps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1) << " (perm=" << getMemMapPermStr(ioMaps[i].perm) << ") (type=" << getMemMapTypeStr(ioMaps[i].type) << ") not permitted)" << std::endl;
} }
} }
if (kern.getInterupts().isSet()) if (kern.getInterupts().isSet())
{ {
fnd::List<uint16_t> interupts = kern.getInterupts().getInteruptList(); fnd::List<uint16_t> interupts = kern.getInterupts().getInteruptList();
printf(" Interupts Flags:\n"); std::cout << " Interupts Flags:" << std::endl;
for (uint32_t i = 0; i < interupts.size(); i++) for (uint32_t i = 0; i < interupts.size(); i++)
{ {
if (i % 10 == 0) if (i % 10 == 0)
{ {
printf("%s ", i != 0 ? "\n" : ""); if (i != 0)
std::cout << std::endl;
std::cout << " ";
} }
printf("0x%x%s", interupts[i], interupts[i] != interupts.atBack() ? ", " : "\n"); std::cout << "0x" << std::hex << (uint32_t)interupts[i];
if (interupts[i] != interupts.atBack())
std::cout << ", ";
std::cout << std::endl;
} }
} }
if (kern.getMiscParams().isSet()) if (kern.getMiscParams().isSet())
{ {
printf(" ProgramType: %d\n", kern.getMiscParams().getProgramType()); std::cout << " ProgramType: " << std::dec << (uint32_t)kern.getMiscParams().getProgramType() << std::endl;
} }
if (kern.getKernelVersion().isSet()) if (kern.getKernelVersion().isSet())
{ {
printf(" Kernel Version: %d.%d\n", kern.getKernelVersion().getVerMajor(), kern.getKernelVersion().getVerMinor()); std::cout << " Kernel Version: " << std::dec << (uint32_t)kern.getKernelVersion().getVerMajor() << "." << (uint32_t)kern.getKernelVersion().getVerMinor() << std::endl;
} }
if (kern.getHandleTableSize().isSet()) if (kern.getHandleTableSize().isSet())
{ {
printf(" Handle Table Size: 0x%x\n", kern.getHandleTableSize().getHandleTableSize()); std::cout << " Handle Table Size: 0x" << std::hex << kern.getHandleTableSize().getHandleTableSize() << std::endl;
} }
if (kern.getMiscFlags().isSet()) if (kern.getMiscFlags().isSet())
{ {
fnd::List<nn::hac::MiscFlagsHandler::Flags> flagList = kern.getMiscFlags().getFlagList(); fnd::List<nn::hac::MiscFlagsHandler::Flags> flagList = kern.getMiscFlags().getFlagList();
printf(" Misc Flags:\n"); std::cout << " Misc Flags:" << std::endl;
for (uint32_t i = 0; i < flagList.size(); i++) for (uint32_t i = 0; i < flagList.size(); i++)
{ {
if (i % 10 == 0) if (i % 10 == 0)
{ {
printf("%s ", i != 0 ? "\n" : ""); if (i != 0)
std::cout << std::endl;
std::cout << " ";
} }
printf("%s%s", getMiscFlagStr(flagList[i]), flagList[i] != flagList.atBack() ? ", " : "\n"); std::cout << getMiscFlagStr(flagList[i]);
if (flagList[i] != flagList.atBack())
std::cout << ", ";
std::cout << std::endl;
} }
} }
} }

View file

@ -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);

View file

@ -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,39 +137,39 @@ 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) #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) std::cout << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)var[a__a__A]; } while(0)
printf("[NRO Header]\n"); std::cout << "[NRO Header]" << std::endl;
printf(" RoCrt: "); std::cout << " RoCrt: ";
_HEXDUMP_L(mHdr.getRoCrt().data, nn::hac::nro::kRoCrtSize); _HEXDUMP_L(mHdr.getRoCrt().data, nn::hac::nro::kRoCrtSize);
printf("\n"); std::cout << std::endl;
printf(" ModuleId: "); std::cout << " ModuleId: ";
_HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nro::kModuleIdSize); _HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nro::kModuleIdSize);
printf("\n"); std::cout << std::endl;
printf(" NroSize: 0x%" PRIx32 "\n", mHdr.getNroSize()); std::cout << " NroSize: 0x" << std::hex << mHdr.getNroSize() << std::endl;
printf(" Program Sections:\n"); std::cout << " Program Sections:" << std::endl;
printf(" .text:\n"); std::cout << " .text:" << std::endl;
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getTextInfo().memory_offset); std::cout << " Offset: 0x" << std::hex << mHdr.getTextInfo().memory_offset << std::endl;
printf(" Size: 0x%" PRIx32 "\n", mHdr.getTextInfo().size); std::cout << " Size: 0x" << std::hex << mHdr.getTextInfo().size << std::endl;
printf(" .ro:\n"); std::cout << " .ro:" << std::endl;
printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoInfo().memory_offset); std::cout << " Offset: 0x" << std::hex << mHdr.getRoInfo().memory_offset << std::endl;
printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoInfo().size); std::cout << " Size: 0x" << std::hex << mHdr.getRoInfo().size << std::endl;
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 #undef _HEXDUMP_L
} }

View file

@ -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,71 +175,71 @@ 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) #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) std::cout << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)var[a__a__A]; } while(0)
printf("[NSO Header]\n"); std::cout << "[NSO Header]" << std::endl;
printf(" ModuleId: "); std::cout << " ModuleId: ";
_HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize); _HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize);
printf("\n"); std::cout << std::endl;
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: ";
_HEXDUMP_L(mHdr.getTextSegmentInfo().hash.bytes, 32); _HEXDUMP_L(mHdr.getTextSegmentInfo().hash.bytes, 32);
printf("\n"); std::cout << std::endl;
} }
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: ";
_HEXDUMP_L(mHdr.getRoSegmentInfo().hash.bytes, 32); _HEXDUMP_L(mHdr.getRoSegmentInfo().hash.bytes, 32);
printf("\n"); std::cout << std::endl;
} }
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: ";
_HEXDUMP_L(mHdr.getDataSegmentInfo().hash.bytes, 32); _HEXDUMP_L(mHdr.getDataSegmentInfo().hash.bytes, 32);
printf("\n"); std::cout << std::endl;
} }
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 #undef _HEXDUMP_L
} }

View file

@ -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;
else 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 << ")";
printf("\n"); break;
} }
}
std::cout << std::endl;
} }
} }
@ -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;
}

View file

@ -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;
}; };

View file

@ -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,10 +100,6 @@ 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());
@ -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

View file

@ -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()
{ {

View file

@ -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;
} }
} }
} }

View file

@ -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));

View file

@ -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,70 +75,90 @@ 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); fnd::SimpleTextOutput::hexDump(mHdr.getInitialDataHash().bytes, sizeof(mHdr.getInitialDataHash().bytes), 0x10, 6);
} }
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" Extended Header AES-IV:\n"); std::cout << " Extended Header AES-IV:" << std::endl;
fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), 0x10, 4); fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), 0x10, 4);
} }
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); fnd::SimpleTextOutput::hexDump(mHdr.getPartitionFsHash().bytes, sizeof(mHdr.getPartitionFsHash().bytes), 0x10, 6);
} }
} }
@ -161,21 +166,21 @@ void XciProcess::displayHeader()
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::hexDump(mHdr.getUppHash(), 8); fnd::SimpleTextOutput::hexDump(mHdr.getUppHash(), 8);
} }
} }
@ -196,7 +201,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 +209,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 +227,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;

View file

@ -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();