From bac8fb57ffa9572a482bf92f9eb80e44f034be9f Mon Sep 17 00:00:00 2001 From: jakcron Date: Sat, 27 Oct 2018 15:46:17 +0800 Subject: [PATCH 01/11] [hac] Add IniHeader & KernelInitialProcessHeader --- lib/libhac/include/nn/hac/IniHeader.h | 46 +++ .../nn/hac/KernelInitialProcessHeader.h | 137 +++++++ lib/libhac/include/nn/hac/define/ini.h | 26 ++ lib/libhac/include/nn/hac/define/kip.h | 65 ++++ lib/libhac/source/IniHeader.cpp | 114 ++++++ .../source/KernelInitialProcessHeader.cpp | 341 ++++++++++++++++++ 6 files changed, 729 insertions(+) create mode 100644 lib/libhac/include/nn/hac/IniHeader.h create mode 100644 lib/libhac/include/nn/hac/KernelInitialProcessHeader.h create mode 100644 lib/libhac/include/nn/hac/define/ini.h create mode 100644 lib/libhac/include/nn/hac/define/kip.h create mode 100644 lib/libhac/source/IniHeader.cpp create mode 100644 lib/libhac/source/KernelInitialProcessHeader.cpp diff --git a/lib/libhac/include/nn/hac/IniHeader.h b/lib/libhac/include/nn/hac/IniHeader.h new file mode 100644 index 0000000..4463397 --- /dev/null +++ b/lib/libhac/include/nn/hac/IniHeader.h @@ -0,0 +1,46 @@ +#pragma once +#include +#include +#include +#include + +namespace nn +{ +namespace hac +{ + class IniHeader : + public fnd::IByteModel + { + public: + IniHeader(); + IniHeader(const IniHeader& other); + + void operator=(const IniHeader& other); + bool operator==(const IniHeader& other) const; + bool operator!=(const IniHeader& other) const; + + // IByteModel + void toBytes(); + void fromBytes(const byte_t* data, size_t len); + const fnd::Vec& getBytes() const; + + // variables + void clear(); + + uint32_t getSize() const; + void setSize(uint32_t size); + + uint32_t getKipNum() const; + void setKipNum(uint32_t num); + private: + const std::string kModuleName = "INI_HEADER"; + + // raw binary + fnd::Vec mRawBinary; + + // variables + uint32_t mSize; + uint32_t mKipNum; + }; +} +} \ No newline at end of file diff --git a/lib/libhac/include/nn/hac/KernelInitialProcessHeader.h b/lib/libhac/include/nn/hac/KernelInitialProcessHeader.h new file mode 100644 index 0000000..cf476a6 --- /dev/null +++ b/lib/libhac/include/nn/hac/KernelInitialProcessHeader.h @@ -0,0 +1,137 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace nn +{ +namespace hac +{ + class KernelInitialProcessHeader : + public fnd::IByteModel + { + public: + struct sLayout + { + uint32_t offset; + uint32_t size; + + void operator=(const sLayout& other) + { + offset = other.offset; + size = other.size; + } + + bool operator==(const sLayout& other) const + { + return (offset == other.offset) \ + && (size == other.size); + } + + bool operator!=(const sLayout& other) const + { + return !(*this == other); + } + }; + + struct sCodeSegment + { + sLayout file_layout; + sLayout memory_layout; + bool is_compressed; + + void operator=(const sCodeSegment& other) + { + file_layout = other.file_layout; + memory_layout = other.memory_layout; + is_compressed = other.is_compressed; + } + + bool operator==(const sCodeSegment& other) const + { + return (file_layout == other.file_layout) \ + && (memory_layout == other.memory_layout) \ + && (is_compressed == other.is_compressed); + } + + bool operator!=(const sCodeSegment& other) const + { + return !(*this == other); + } + }; + + KernelInitialProcessHeader(); + KernelInitialProcessHeader(const KernelInitialProcessHeader& other); + + void operator=(const KernelInitialProcessHeader& other); + bool operator==(const KernelInitialProcessHeader& other) const; + bool operator!=(const KernelInitialProcessHeader& other) const; + + // export/import binary + void toBytes(); + void fromBytes(const byte_t* data, size_t len); + const fnd::Vec& getBytes() const; + + // variables + void clear(); + + const std::string& getName() const; + void setName(const std::string& name); + + uint64_t getTitleId() const; + void setTitleId(uint64_t title_id); + + kip::ProcessCategory getProcessCategory() const; + void setProcessCategory(kip::ProcessCategory cat); + + const fnd::List& getFlagList() const; + void setFlagList(const fnd::List& flags); + + byte_t getMainThreadPriority() const; + void setMainThreadPriority(byte_t priority); + + byte_t getMainThreadCpuId() const; + void setMainThreadCpuId(byte_t cpu_id); + + uint32_t getMainThreadStackSize() const; + void setMainThreadStackSize(uint32_t size); + + const sCodeSegment& getTextSegmentInfo() const; + void setTextSegmentInfo(const sCodeSegment& info); + + const sCodeSegment& getRoSegmentInfo() const; + void setRoSegmentInfo(const sCodeSegment& info); + + const sCodeSegment& getDataSegmentInfo() const; + void setDataSegmentInfo(const sCodeSegment& info); + + uint32_t getBssSize() const; + void setBssSize(uint32_t size); + + const nn::hac::KernelCapabilityControl& getKernelCapabilities() const; + void setKernelCapabilities(const KernelCapabilityControl& kc); + + private: + const std::string kModuleName = "KERNEL_INITIAL_PROCESS_HEADER"; + + // raw binary + fnd::Vec mRawBinary; + + // variables + std::string mName; + uint64_t mTitleId; + kip::ProcessCategory mProcessCategory; + fnd::List mFlagList; + byte_t mMainThreadPriority; + byte_t mMainThreadCpuId; + uint32_t mMainThreadStackSize; + sCodeSegment mTextInfo; + sCodeSegment mRoInfo; + sCodeSegment mDataInfo; + uint32_t mBssSize; + nn::hac::KernelCapabilityControl mKernelCapabilities; + }; +} +} \ No newline at end of file diff --git a/lib/libhac/include/nn/hac/define/ini.h b/lib/libhac/include/nn/hac/define/ini.h new file mode 100644 index 0000000..d51a3aa --- /dev/null +++ b/lib/libhac/include/nn/hac/define/ini.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include + +namespace nn +{ +namespace hac +{ + namespace ini + { + static const uint32_t kIniStructMagic = _MAKE_STRUCT_MAGIC_U32("INI1"); + static const size_t kMaxKipNum = 0x50; + } + +#pragma pack(push,1) + struct sIniHeader + { + le_uint32_t st_magic; + le_uint32_t size; + le_uint32_t kip_num; + byte_t reserved_01[0x4]; + }; +#pragma pack(pop) +} +} \ No newline at end of file diff --git a/lib/libhac/include/nn/hac/define/kip.h b/lib/libhac/include/nn/hac/define/kip.h new file mode 100644 index 0000000..c1a9360 --- /dev/null +++ b/lib/libhac/include/nn/hac/define/kip.h @@ -0,0 +1,65 @@ +#pragma once +#include +#include +#include + +namespace nn +{ +namespace hac +{ + namespace kip + { + static const uint32_t kKipStructMagic = _MAKE_STRUCT_MAGIC_U32("KIP1"); + static const size_t kNameMaxLen = 0xC; + static const size_t kKernCapabilityNum = 0x20; + static const size_t kKernCapabilitySize = kKernCapabilityNum * sizeof(uint32_t); + + enum ProcessCategory + { + PROCCAT_REGULAR, + PROCCAT_KERNAL_KIP + }; + + enum HeaderFlags + { + FLAG_TEXT_COMPRESS, + FLAG_RO_COMPRESS, + FLAG_DATA_COMPRESS, + FLAG_INSTRUCTION_64BIT, + FLAG_ADDR_SPACE_64BIT, + FLAG_USE_SYSTEM_POOL_PARTITION + }; + } + +#pragma pack(push,1) + struct sKipCodeSegment + { + le_uint32_t memory_offset; + le_uint32_t memory_size; + le_uint32_t file_size; + }; + + struct sKipHeader + { + le_uint32_t st_magic; + char name[kip::kNameMaxLen]; + le_uint64_t title_id; + le_uint32_t process_category; + byte_t main_thread_priority; + byte_t main_thread_cpu_id; + byte_t reserved_01; + byte_t flags; + sKipCodeSegment text; + byte_t reserved_02[4]; + sKipCodeSegment ro; + le_uint32_t main_thread_stack_size; + sKipCodeSegment data; + byte_t reserved_03[4]; + sKipCodeSegment bss; + byte_t reserved_04[4]; + byte_t reserved_05[0x20]; + byte_t capabilities[kip::kKernCapabilitySize]; + }; +#pragma pack(pop) +} +} \ No newline at end of file diff --git a/lib/libhac/source/IniHeader.cpp b/lib/libhac/source/IniHeader.cpp new file mode 100644 index 0000000..15c2689 --- /dev/null +++ b/lib/libhac/source/IniHeader.cpp @@ -0,0 +1,114 @@ +#include + +nn::hac::IniHeader::IniHeader() +{ + clear(); +} + +nn::hac::IniHeader::IniHeader(const IniHeader& other) +{ + *this = other; +} + +void nn::hac::IniHeader::operator=(const IniHeader& other) +{ + clear(); + this->mSize = other.mSize; + this->mKipNum = other.mKipNum; +} + +bool nn::hac::IniHeader::operator==(const IniHeader& other) const +{ + return (this->mSize == other.mSize) \ + && (this->mKipNum == other.mKipNum); +} + +bool nn::hac::IniHeader::operator!=(const IniHeader& other) const +{ + return !(*this == other); +} + +void nn::hac::IniHeader::toBytes() +{ + mRawBinary.alloc(sizeof(sIniHeader)); + nn::hac::sIniHeader* hdr = (nn::hac::sIniHeader*)mRawBinary.data(); + + // set header identifers + hdr->st_magic = ini::kIniStructMagic; + + if (mKipNum > ini::kMaxKipNum) + { + throw fnd::Exception(kModuleName, "Cannot generate INI Header (Too many KIPs)"); + } + + // write variables + hdr->size = mSize; + hdr->kip_num = mKipNum; +} + +void nn::hac::IniHeader::fromBytes(const byte_t* data, size_t len) +{ + // check input data size + if (len < sizeof(sIniHeader)) + { + throw fnd::Exception(kModuleName, "INI header corrupt (header size is too small)"); + } + + // clear internal members + clear(); + + // allocate internal local binary copy + mRawBinary.alloc(sizeof(sIniHeader)); + memcpy(mRawBinary.data(), data, mRawBinary.size()); + + // get sIniHeader ptr + const nn::hac::sIniHeader* hdr = (const nn::hac::sIniHeader*)mRawBinary.data(); + + // check INI signature + if (hdr->st_magic.get() != ini::kIniStructMagic) + { + throw fnd::Exception(kModuleName, "INI header corrupt (unrecognised header signature)"); + } + + // check KIP num + if (hdr->kip_num.get() > ini::kMaxKipNum) + { + throw fnd::Exception(kModuleName, "INI header corrupt (too many KIPs)"); + } + + // save variables + mSize = hdr->size.get(); + mKipNum = hdr->kip_num.get(); +} + +const fnd::Vec& nn::hac::IniHeader::getBytes() const +{ + return mRawBinary; +} + +void nn::hac::IniHeader::clear() +{ + mRawBinary.clear(); + mSize = 0; + mKipNum = 0; +} + +uint32_t nn::hac::IniHeader::getSize() const +{ + return mSize; +} + +void nn::hac::IniHeader::setSize(uint32_t size) +{ + mSize = size; +} + +uint32_t nn::hac::IniHeader::getKipNum() const +{ + return mKipNum; +} + +void nn::hac::IniHeader::setKipNum(uint32_t num) +{ + mKipNum = num; +} \ No newline at end of file diff --git a/lib/libhac/source/KernelInitialProcessHeader.cpp b/lib/libhac/source/KernelInitialProcessHeader.cpp new file mode 100644 index 0000000..988c95e --- /dev/null +++ b/lib/libhac/source/KernelInitialProcessHeader.cpp @@ -0,0 +1,341 @@ +#include + +nn::hac::KernelInitialProcessHeader::KernelInitialProcessHeader() +{ + clear(); +} + +nn::hac::KernelInitialProcessHeader::KernelInitialProcessHeader(const KernelInitialProcessHeader& other) +{ + *this = other; +} + +void nn::hac::KernelInitialProcessHeader::operator=(const KernelInitialProcessHeader& other) +{ + clear(); + this->mName = other.mName; + this->mTitleId = other.mTitleId; + this->mProcessCategory = other.mProcessCategory; + this->mFlagList = other.mFlagList; + this->mMainThreadPriority = other.mMainThreadPriority; + this->mMainThreadCpuId = other.mMainThreadCpuId; + this->mMainThreadStackSize = other.mMainThreadStackSize; + this->mTextInfo = other.mTextInfo; + this->mRoInfo = other.mRoInfo; + this->mDataInfo = other.mDataInfo; + this->mBssSize = other.mBssSize; + this->mKernelCapabilities = other.mKernelCapabilities; +} + +bool nn::hac::KernelInitialProcessHeader::operator==(const KernelInitialProcessHeader& other) const +{ + return (this->mName == other.mName) \ + && (this->mTitleId == other.mTitleId) \ + && (this->mProcessCategory == other.mProcessCategory) \ + && (this->mFlagList == other.mFlagList) \ + && (this->mMainThreadPriority == other.mMainThreadPriority) \ + && (this->mMainThreadCpuId == other.mMainThreadCpuId) \ + && (this->mMainThreadStackSize == other.mMainThreadStackSize) \ + && (this->mTextInfo == other.mTextInfo) \ + && (this->mRoInfo == other.mRoInfo) \ + && (this->mDataInfo == other.mDataInfo) \ + && (this->mBssSize == other.mBssSize) \ + && (this->mKernelCapabilities == other.mKernelCapabilities); +} + +bool nn::hac::KernelInitialProcessHeader::operator!=(const KernelInitialProcessHeader& other) const +{ + return !(*this == other); +} + +void nn::hac::KernelInitialProcessHeader::toBytes() +{ + mRawBinary.alloc(sizeof(sKipHeader)); + nn::hac::sKipHeader* hdr = (nn::hac::sKipHeader*)mRawBinary.data(); + + // set header identifers + hdr->st_magic = kip::kKipStructMagic; + + // variable to store flags before commiting to header + byte_t flags = 0; + + // properties + strncpy(hdr->name, mName.c_str(), kip::kNameMaxLen); + hdr->title_id = mTitleId; + hdr->process_category = mProcessCategory; + hdr->main_thread_priority = mMainThreadPriority; + hdr->main_thread_cpu_id = mMainThreadCpuId; + hdr->main_thread_stack_size = mMainThreadStackSize; + + // kernel caps + mKernelCapabilities.toBytes(); + if (mKernelCapabilities.getBytes().size() > kip::kKernCapabilitySize) + { + throw fnd::Exception(kModuleName, "Too many kernel capabilities"); + } + memcpy(hdr->capabilities, mKernelCapabilities.getBytes().data(), mKernelCapabilities.getBytes().size()); + //memset(hdr->capabilities + mKernelCapabilities.getBytes().size(), 0xff, kip::kKernCapabilitySize - mKernelCapabilities.getBytes().size()); + + // flags + for (size_t i = 0; i < mFlagList.size(); i++) + { + switch(mFlagList[i]) + { + case (kip::FLAG_TEXT_COMPRESS) : + case (kip::FLAG_RO_COMPRESS) : + case (kip::FLAG_DATA_COMPRESS) : + break; + default: + flags |= _BIT(mFlagList[i] & 7); + break; + } + } + + // set bss size + hdr->bss.file_size = 0; + hdr->bss.memory_offset = 0; + hdr->bss.memory_size = mBssSize; + + // set text segment + hdr->text.memory_offset = mTextInfo.memory_layout.offset; + hdr->text.memory_size = mTextInfo.memory_layout.size; + hdr->text.file_size = mTextInfo.file_layout.size; + if (mTextInfo.is_compressed) + { + flags |= _BIT(kip::FLAG_TEXT_COMPRESS); + } + + // set ro segment + hdr->ro.memory_offset = mRoInfo.memory_layout.offset; + hdr->ro.memory_size = mRoInfo.memory_layout.size; + hdr->ro.file_size = mRoInfo.file_layout.size; + if (mRoInfo.is_compressed) + { + flags |= _BIT(kip::FLAG_TEXT_COMPRESS); + } + + // set data segment + hdr->data.memory_offset = mDataInfo.memory_layout.offset; + hdr->data.memory_size = mDataInfo.memory_layout.size; + hdr->data.file_size = mDataInfo.file_layout.size; + if (mDataInfo.is_compressed) + { + flags |= _BIT(kip::FLAG_TEXT_COMPRESS); + } + + hdr->flags = flags; +} + +void nn::hac::KernelInitialProcessHeader::fromBytes(const byte_t* data, size_t len) +{ + // check input data size + if (len < sizeof(sKipHeader)) + { + throw fnd::Exception(kModuleName, "KIP header size is too small"); + } + + // clear internal members + clear(); + + // allocate internal local binary copy + mRawBinary.alloc(sizeof(sKipHeader)); + memcpy(mRawBinary.data(), data, mRawBinary.size()); + + // get sKipHeader ptr + const nn::hac::sKipHeader* hdr = (const nn::hac::sKipHeader*)mRawBinary.data(); + + // check KIP signature + if (hdr->st_magic.get() != kip::kKipStructMagic) + { + throw fnd::Exception(kModuleName, "KIP header corrupt (unrecognised header signature)"); + } + + // properties + if (hdr->name[0] != 0) + mName = std::string(hdr->name, _MIN(strlen(hdr->name), kip::kNameMaxLen)); + mTitleId = hdr->title_id.get(); + mProcessCategory = (kip::ProcessCategory)hdr->process_category.get(); + mMainThreadPriority = hdr->main_thread_priority; + mMainThreadCpuId = hdr->main_thread_cpu_id; + mMainThreadStackSize = hdr->main_thread_stack_size.get(); + mKernelCapabilities.fromBytes(hdr->capabilities, kip::kKernCapabilitySize); + + for (byte_t i = 0; i < 8; i++) + { + if (_HAS_BIT(hdr->flags, i)) + { + switch(i) + { + case (kip::FLAG_TEXT_COMPRESS) : + case (kip::FLAG_RO_COMPRESS) : + case (kip::FLAG_DATA_COMPRESS) : + break; + default: + mFlagList.addElement((kip::HeaderFlags)i); + break; + } + } + } + + // code segment info + mTextInfo.file_layout.offset = sizeof(sKipHeader); + mTextInfo.file_layout.size = hdr->text.file_size.get(); + mTextInfo.memory_layout.offset = hdr->text.memory_offset.get(); + mTextInfo.memory_layout.size = hdr->text.memory_size.get(); + mTextInfo.is_compressed = _HAS_BIT(hdr->flags, kip::FLAG_TEXT_COMPRESS); + + mRoInfo.file_layout.offset = mTextInfo.file_layout.offset + mTextInfo.file_layout.size; + mRoInfo.file_layout.size = hdr->ro.file_size.get(); + mRoInfo.memory_layout.offset = hdr->ro.memory_offset.get(); + mRoInfo.memory_layout.size = hdr->ro.memory_size.get(); + mRoInfo.is_compressed = _HAS_BIT(hdr->flags, kip::FLAG_RO_COMPRESS); + + mDataInfo.file_layout.offset = mRoInfo.file_layout.offset + mRoInfo.file_layout.size; + mDataInfo.file_layout.size = hdr->data.file_size.get(); + mDataInfo.memory_layout.offset = hdr->data.memory_offset.get(); + mDataInfo.memory_layout.size = hdr->data.memory_size.get(); + mDataInfo.is_compressed = _HAS_BIT(hdr->flags, kip::FLAG_DATA_COMPRESS); + + mBssSize = hdr->bss.memory_size.get(); +} + +const fnd::Vec& nn::hac::KernelInitialProcessHeader::getBytes() const +{ + return mRawBinary; +} + +void nn::hac::KernelInitialProcessHeader::clear() +{ + mRawBinary.clear(); + mName.clear(); + mTitleId = 0; + mProcessCategory = (kip::ProcessCategory)0; + mFlagList.clear(); + mMainThreadPriority = 0; + mMainThreadCpuId = 0; + mMainThreadStackSize = 0; + mTextInfo = sCodeSegment(); + mRoInfo = sCodeSegment(); + mDataInfo = sCodeSegment(); + mBssSize = 0; + mKernelCapabilities.clear();; +} + +const std::string& nn::hac::KernelInitialProcessHeader::getName() const +{ + return mName; +} + +void nn::hac::KernelInitialProcessHeader::setName(const std::string& name) +{ + mName = name; +} + +uint64_t nn::hac::KernelInitialProcessHeader::getTitleId() const +{ + return mTitleId; +} + +void nn::hac::KernelInitialProcessHeader::setTitleId(uint64_t title_id) +{ + mTitleId = title_id; +} + +nn::hac::kip::ProcessCategory nn::hac::KernelInitialProcessHeader::getProcessCategory() const +{ + return mProcessCategory; +} + +void nn::hac::KernelInitialProcessHeader::setProcessCategory(kip::ProcessCategory cat) +{ + mProcessCategory = cat; +} + +const fnd::List& nn::hac::KernelInitialProcessHeader::getFlagList() const +{ + return mFlagList; +} +void nn::hac::KernelInitialProcessHeader::setFlagList(const fnd::List& flags) +{ + mFlagList = flags; +} + +byte_t nn::hac::KernelInitialProcessHeader::getMainThreadPriority() const +{ + return mMainThreadPriority; +} + +void nn::hac::KernelInitialProcessHeader::setMainThreadPriority(byte_t priority) +{ + mMainThreadPriority = priority; +} + +byte_t nn::hac::KernelInitialProcessHeader::getMainThreadCpuId() const +{ + return mMainThreadCpuId; +} + +void nn::hac::KernelInitialProcessHeader::setMainThreadCpuId(byte_t cpu_id) +{ + mMainThreadCpuId = cpu_id; +} + +uint32_t nn::hac::KernelInitialProcessHeader::getMainThreadStackSize() const +{ + return mMainThreadStackSize; +} + +void nn::hac::KernelInitialProcessHeader::setMainThreadStackSize(uint32_t size) +{ + mMainThreadStackSize = size; +} + +const nn::hac::KernelInitialProcessHeader::sCodeSegment& nn::hac::KernelInitialProcessHeader::getTextSegmentInfo() const +{ + return mTextInfo; +} + +void nn::hac::KernelInitialProcessHeader::setTextSegmentInfo(const sCodeSegment& info) +{ + mTextInfo = info; +} + +const nn::hac::KernelInitialProcessHeader::sCodeSegment& nn::hac::KernelInitialProcessHeader::getRoSegmentInfo() const +{ + return mRoInfo; +} + +void nn::hac::KernelInitialProcessHeader::setRoSegmentInfo(const sCodeSegment& info) +{ + mRoInfo = info; +} + +const nn::hac::KernelInitialProcessHeader::sCodeSegment& nn::hac::KernelInitialProcessHeader::getDataSegmentInfo() const +{ + return mDataInfo; +} + +void nn::hac::KernelInitialProcessHeader::setDataSegmentInfo(const sCodeSegment& info) +{ + mDataInfo = info; +} + +uint32_t nn::hac::KernelInitialProcessHeader::getBssSize() const +{ + return mBssSize; +} + +void nn::hac::KernelInitialProcessHeader::setBssSize(uint32_t size) +{ + mBssSize = size; +} + +const nn::hac::KernelCapabilityControl& nn::hac::KernelInitialProcessHeader::getKernelCapabilities() const +{ + return mKernelCapabilities; +} + +void nn::hac::KernelInitialProcessHeader::setKernelCapabilities(const KernelCapabilityControl& kc) +{ + mKernelCapabilities = kc; +} \ No newline at end of file From da00e5298cf43204aa486328a542cb015596c903 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sat, 27 Oct 2018 15:46:44 +0800 Subject: [PATCH 02/11] [hac] Fix bug where stubbed kernel cap u32s were not processed correctly --- lib/libhac/include/nn/hac/KernelCapabilityEntry.h | 1 + lib/libhac/include/nn/hac/define/kc.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/libhac/include/nn/hac/KernelCapabilityEntry.h b/lib/libhac/include/nn/hac/KernelCapabilityEntry.h index 1a5f3cc..7b39302 100644 --- a/lib/libhac/include/nn/hac/KernelCapabilityEntry.h +++ b/lib/libhac/include/nn/hac/KernelCapabilityEntry.h @@ -45,6 +45,7 @@ namespace hac break; } } + if (id == kc::KC_INVALID && cap == (uint32_t)0xffffffff) return id; } }; diff --git a/lib/libhac/include/nn/hac/define/kc.h b/lib/libhac/include/nn/hac/define/kc.h index 1bf2d73..4716a9f 100644 --- a/lib/libhac/include/nn/hac/define/kc.h +++ b/lib/libhac/include/nn/hac/define/kc.h @@ -20,7 +20,8 @@ namespace hac KC_MISC_PARAMS = 13, KC_KERNEL_VERSION = 14, KC_HANDLE_TABLE_SIZE = 15, - KC_MISC_FLAGS = 16 + KC_MISC_FLAGS = 16, + KC_STUB = 32 }; } } From 9bc40e3a995bab47f691c0d708ff1acc3b386c20 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sat, 27 Oct 2018 15:51:21 +0800 Subject: [PATCH 03/11] Commit unsaved changes. --- lib/libhac/include/nn/hac/KernelCapabilityEntry.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/libhac/include/nn/hac/KernelCapabilityEntry.h b/lib/libhac/include/nn/hac/KernelCapabilityEntry.h index 7b39302..9da90ef 100644 --- a/lib/libhac/include/nn/hac/KernelCapabilityEntry.h +++ b/lib/libhac/include/nn/hac/KernelCapabilityEntry.h @@ -37,6 +37,7 @@ namespace hac inline kc::KernelCapId getCapId(uint32_t cap) const { kc::KernelCapId id = kc::KC_INVALID; + for (byte_t tmp = 0; tmp < 31; tmp++) { if (((cap >> tmp) & 1) == 0) @@ -45,7 +46,10 @@ namespace hac break; } } + if (id == kc::KC_INVALID && cap == (uint32_t)0xffffffff) + id == kc::KC_STUB; + return id; } }; From cd29ed80e645c7e0ac7ab6eb484b4ea095c0aa9e Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 29 Oct 2018 19:11:48 +0800 Subject: [PATCH 04/11] [hac] Fix bug where stubbed kernel entries were not ignored. --- lib/libhac/include/nn/hac/KernelCapabilityEntry.h | 2 +- lib/libhac/source/KernelCapabilityControl.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/libhac/include/nn/hac/KernelCapabilityEntry.h b/lib/libhac/include/nn/hac/KernelCapabilityEntry.h index 9da90ef..2df6ef3 100644 --- a/lib/libhac/include/nn/hac/KernelCapabilityEntry.h +++ b/lib/libhac/include/nn/hac/KernelCapabilityEntry.h @@ -48,7 +48,7 @@ namespace hac } if (id == kc::KC_INVALID && cap == (uint32_t)0xffffffff) - id == kc::KC_STUB; + id = kc::KC_STUB; return id; } diff --git a/lib/libhac/source/KernelCapabilityControl.cpp b/lib/libhac/source/KernelCapabilityControl.cpp index dc04074..b3f198f 100644 --- a/lib/libhac/source/KernelCapabilityControl.cpp +++ b/lib/libhac/source/KernelCapabilityControl.cpp @@ -117,6 +117,9 @@ void nn::hac::KernelCapabilityControl::fromBytes(const byte_t * data, size_t len case (kc::KC_MISC_FLAGS): miscFlagsCaps.addElement(cap); break; + case (kc::KC_STUB): + // ignore stubbed + break; default: throw fnd::Exception(kModuleName, "Unsupported kernel capability type"); } From 8f9694a76956f69ff1e7be0ddc239a1523629811 Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 5 Nov 2018 14:53:23 +0800 Subject: [PATCH 05/11] [libhac] Fix bug related to previous changes to fnd::List. --- lib/libhac/source/InteruptHandler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/libhac/source/InteruptHandler.cpp b/lib/libhac/source/InteruptHandler.cpp index 421ee19..ca74daf 100644 --- a/lib/libhac/source/InteruptHandler.cpp +++ b/lib/libhac/source/InteruptHandler.cpp @@ -26,12 +26,11 @@ void nn::hac::InteruptHandler::importKernelCapabilityList(const fnd::List interupts; for (size_t i = 0; i < caps.size(); i++) { - interupts[i].setKernelCapability(caps[i]); + interupts.addElement(InteruptEntry(caps[i])); } mInterupts.clear(); From 5af7558a1b83c044da49b2bf47fbf934784e804b Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 5 Nov 2018 14:54:30 +0800 Subject: [PATCH 06/11] [nstool] Add definitons and code for recognising INI/KIP files. --- programs/nstool/source/UserSettings.cpp | 16 ++++++++++++++-- programs/nstool/source/common.h | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/programs/nstool/source/UserSettings.cpp b/programs/nstool/source/UserSettings.cpp index 186eb33..e1e2675 100644 --- a/programs/nstool/source/UserSettings.cpp +++ b/programs/nstool/source/UserSettings.cpp @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -52,7 +54,7 @@ void UserSettings::showHelp() printf("\n General Options:\n"); printf(" -d, --dev Use devkit keyset.\n"); printf(" -k, --keyset Specify keyset file.\n"); - printf(" -t, --type Specify input file type. [xci, pfs, romfs, nca, meta, cnmt, nso, nro, nacp, aset, cert, tik]\n"); + printf(" -t, --type Specify input file type. [xci, pfs, romfs, nca, meta, cnmt, nso, nro, ini, kip, nacp, aset, cert, tik]\n"); printf(" -y, --verify Verify file.\n"); printf("\n Output Options:\n"); printf(" --showkeys Show keys generated.\n"); @@ -610,6 +612,10 @@ FileType UserSettings::getFileTypeFromString(const std::string& type_str) type = FILE_NSO; else if (str == "nro") type = FILE_NRO; + else if (str == "ini") + type = FILE_INI; + else if (str == "kip") + type = FILE_KIP; else if (str == "nacp") type = FILE_NACP; else if (str == "cert") @@ -665,9 +671,15 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path) // test nso else if (_ASSERT_SIZE(sizeof(nn::hac::sNsoHeader)) && _TYPE_PTR(nn::hac::sNsoHeader)->st_magic.get() == nn::hac::nso::kNsoStructMagic) file_type = FILE_NSO; - // test nso + // test nro else if (_ASSERT_SIZE(sizeof(nn::hac::sNroHeader)) && _TYPE_PTR(nn::hac::sNroHeader)->st_magic.get() == nn::hac::nro::kNroStructMagic) file_type = FILE_NRO; + // test ini + else if (_ASSERT_SIZE(sizeof(nn::hac::sIniHeader)) && _TYPE_PTR(nn::hac::sIniHeader)->st_magic.get() == nn::hac::ini::kIniStructMagic) + file_type = FILE_INI; + // test kip + else if (_ASSERT_SIZE(sizeof(nn::hac::sKipHeader)) && _TYPE_PTR(nn::hac::sKipHeader)->st_magic.get() == nn::hac::kip::kKipStructMagic) + file_type = FILE_KIP; // test pki certificate else if (determineValidEsCertFromSample(scratch)) file_type = FILE_PKI_CERT; diff --git a/programs/nstool/source/common.h b/programs/nstool/source/common.h index 7b34922..d8f637e 100644 --- a/programs/nstool/source/common.h +++ b/programs/nstool/source/common.h @@ -20,6 +20,8 @@ enum FileType FILE_NSO, FILE_NRO, FILE_NACP, + FILE_INI, + FILE_KIP, FILE_PKI_CERT, FILE_ES_TIK, FILE_HB_ASSET, From 696cd481e3d2e1fe57f85320a90c1d3efd7191d0 Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 5 Nov 2018 14:57:47 +0800 Subject: [PATCH 07/11] [libhac] Stub unused entries in KIP KernelCapList. --- lib/libhac/source/KernelInitialProcessHeader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/libhac/source/KernelInitialProcessHeader.cpp b/lib/libhac/source/KernelInitialProcessHeader.cpp index 988c95e..81c23c9 100644 --- a/lib/libhac/source/KernelInitialProcessHeader.cpp +++ b/lib/libhac/source/KernelInitialProcessHeader.cpp @@ -74,7 +74,11 @@ void nn::hac::KernelInitialProcessHeader::toBytes() throw fnd::Exception(kModuleName, "Too many kernel capabilities"); } memcpy(hdr->capabilities, mKernelCapabilities.getBytes().data(), mKernelCapabilities.getBytes().size()); - //memset(hdr->capabilities + mKernelCapabilities.getBytes().size(), 0xff, kip::kKernCapabilitySize - mKernelCapabilities.getBytes().size()); + if (mKernelCapabilities.getBytes().size() < kip::kKernCapabilitySize) + { + + } + memset(hdr->capabilities + mKernelCapabilities.getBytes().size(), 0xff, kip::kKernCapabilitySize - mKernelCapabilities.getBytes().size()); // flags for (size_t i = 0; i < mFlagList.size(); i++) From 735ace17494e2cd80e6819b81be0c6db1b443f0d Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 5 Nov 2018 14:58:10 +0800 Subject: [PATCH 08/11] [libhac] Misc. --- lib/libhac/source/KernelCapabilityControl.cpp | 4 ++-- lib/libhac/source/KernelInitialProcessHeader.cpp | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/libhac/source/KernelCapabilityControl.cpp b/lib/libhac/source/KernelCapabilityControl.cpp index b3f198f..f20ef55 100644 --- a/lib/libhac/source/KernelCapabilityControl.cpp +++ b/lib/libhac/source/KernelCapabilityControl.cpp @@ -84,12 +84,12 @@ void nn::hac::KernelCapabilityControl::fromBytes(const byte_t * data, size_t len fnd::List handleTableSizeCaps; fnd::List miscFlagsCaps; - const uint32_t* raw_caps = (const uint32_t*)mRawBinary.data(); + const le_uint32_t* raw_caps = (const le_uint32_t*)mRawBinary.data(); size_t cap_num = mRawBinary.size() / sizeof(uint32_t); KernelCapabilityEntry cap; for (size_t i = 0; i < cap_num; i++) { - cap.setCap(le_word(raw_caps[i])); + cap.setCap(raw_caps[i].get()); switch (cap.getType()) { case (kc::KC_THREAD_INFO) : diff --git a/lib/libhac/source/KernelInitialProcessHeader.cpp b/lib/libhac/source/KernelInitialProcessHeader.cpp index 81c23c9..aa504e2 100644 --- a/lib/libhac/source/KernelInitialProcessHeader.cpp +++ b/lib/libhac/source/KernelInitialProcessHeader.cpp @@ -74,11 +74,12 @@ void nn::hac::KernelInitialProcessHeader::toBytes() throw fnd::Exception(kModuleName, "Too many kernel capabilities"); } memcpy(hdr->capabilities, mKernelCapabilities.getBytes().data(), mKernelCapabilities.getBytes().size()); + + // stub remaining entries if (mKernelCapabilities.getBytes().size() < kip::kKernCapabilitySize) { - - } - memset(hdr->capabilities + mKernelCapabilities.getBytes().size(), 0xff, kip::kKernCapabilitySize - mKernelCapabilities.getBytes().size()); + memset(hdr->capabilities + mKernelCapabilities.getBytes().size(), 0xff, kip::kKernCapabilitySize - mKernelCapabilities.getBytes().size()); + } // flags for (size_t i = 0; i < mFlagList.size(); i++) From 1458e267d5b10013a1961ef875a4a6a91b00fd77 Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 5 Nov 2018 21:11:08 +0800 Subject: [PATCH 09/11] [nstool] Add initial support for INI/KIP. --- programs/nstool/source/IniProcess.cpp | 170 ++++++ programs/nstool/source/IniProcess.h | 47 ++ programs/nstool/source/KipProcess.cpp | 767 ++++++++++++++++++++++++ programs/nstool/source/KipProcess.h | 44 ++ programs/nstool/source/UserSettings.cpp | 16 + programs/nstool/source/UserSettings.h | 4 + programs/nstool/source/main.cpp | 159 +++-- 7 files changed, 1142 insertions(+), 65 deletions(-) create mode 100644 programs/nstool/source/IniProcess.cpp create mode 100644 programs/nstool/source/IniProcess.h create mode 100644 programs/nstool/source/KipProcess.cpp create mode 100644 programs/nstool/source/KipProcess.h diff --git a/programs/nstool/source/IniProcess.cpp b/programs/nstool/source/IniProcess.cpp new file mode 100644 index 0000000..d6b6af1 --- /dev/null +++ b/programs/nstool/source/IniProcess.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include +#include +#include +#include "IniProcess.h" +#include "KipProcess.h" + + +IniProcess::IniProcess() : + mFile(), + mCliOutputMode(_BIT(OUTPUT_BASIC)), + mVerify(false), + mDoExtractKip(false), + mKipExtractPath() +{ +} + +void IniProcess::process() +{ + importHeader(); + importKipList(); + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + { + displayHeader(); + displayKipList(); + } + if (mDoExtractKip) + { + extractKipList(); + } +} + +void IniProcess::setInputFile(const fnd::SharedPtr& file) +{ + mFile = file; +} + +void IniProcess::setCliOutputMode(CliOutputMode type) +{ + mCliOutputMode = type; +} + +void IniProcess::setVerifyMode(bool verify) +{ + mVerify = verify; +} + +void IniProcess::setKipExtractPath(const std::string& path) +{ + mDoExtractKip = true; + mKipExtractPath = path; +} + +void IniProcess::importHeader() +{ + fnd::Vec scratch; + + if (*mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + if ((*mFile)->size() < sizeof(nn::hac::sIniHeader)) + { + throw fnd::Exception(kModuleName, "Corrupt INI: file too small"); + } + + scratch.alloc(sizeof(nn::hac::sIniHeader)); + (*mFile)->read(scratch.data(), 0, scratch.size()); + + mHdr.fromBytes(scratch.data(), scratch.size()); +} + +void IniProcess::importKipList() +{ + // kip pos info + size_t kip_pos = sizeof(nn::hac::sIniHeader); + size_t kip_size = 0; + + // tmp data to determine size + fnd::Vec hdr_raw; + nn::hac::KernelInitialProcessHeader hdr; + + hdr_raw.alloc(sizeof(nn::hac::sKipHeader)); + for (size_t i = 0; i < mHdr.getKipNum(); i++) + { + (*mFile)->read(hdr_raw.data(), kip_pos, hdr_raw.size()); + hdr.fromBytes(hdr_raw.data(), hdr_raw.size()); + kip_size = getKipSizeFromHeader(hdr); + mKipList.addElement(new fnd::OffsetAdjustedIFile(mFile, kip_pos, kip_size)); + kip_pos += kip_size; + } +} + +void IniProcess::displayHeader() +{ + std::cout << "[INI Header]" << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getSize() << std::endl; + std::cout << " KIP Num: " << std::dec << (uint32_t)mHdr.getKipNum() << std::endl; +} + +void IniProcess::displayKipList() +{ + for (size_t i = 0; i < mKipList.size(); i++) + { + KipProcess obj; + + obj.setInputFile(mKipList[i]); + obj.setCliOutputMode(mCliOutputMode); + obj.setVerifyMode(mVerify); + + obj.process(); + } +} + +void IniProcess::extractKipList() +{ + fnd::Vec cache; + nn::hac::KernelInitialProcessHeader hdr; + + + // allocate cache memory + cache.alloc(kCacheSize); + + // make extract dir + fnd::io::makeDirectory(mKipExtractPath); + + + // outfile object for writing KIP + fnd::SimpleFile out_file; + std::string out_path; + size_t out_size; + + for (size_t i = 0; i < mKipList.size(); i++) + { + // read header + (*mKipList[i])->read(cache.data(), 0, cache.size()); + hdr.fromBytes(cache.data(), cache.size()); + + // generate path + out_path.clear(); + fnd::io::appendToPath(out_path, mKipExtractPath); + fnd::io::appendToPath(out_path, hdr.getName() + kKipExtention); + + // open file + out_file.open(out_path, fnd::SimpleFile::Create); + + // get kip file size + out_size = (*mKipList[i])->size(); + // extract kip + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + printf("extract=[%s]\n", out_path.c_str()); + + (*mKipList[i])->seek(0); + for (size_t j = 0; j < ((out_size / kCacheSize) + ((out_size % kCacheSize) != 0)); j++) + { + (*mKipList[i])->read(cache.data(), _MIN(out_size - (kCacheSize * j), kCacheSize)); + out_file.write(cache.data(), _MIN(out_size - (kCacheSize * j), kCacheSize)); + } + out_file.close(); + } +} + +size_t IniProcess::getKipSizeFromHeader(const nn::hac::KernelInitialProcessHeader& hdr) const +{ + return sizeof(nn::hac::sKipHeader) + hdr.getTextSegmentInfo().file_layout.size + hdr.getRoSegmentInfo().file_layout.size + hdr.getDataSegmentInfo().file_layout.size; +} \ No newline at end of file diff --git a/programs/nstool/source/IniProcess.h b/programs/nstool/source/IniProcess.h new file mode 100644 index 0000000..dbfad5e --- /dev/null +++ b/programs/nstool/source/IniProcess.h @@ -0,0 +1,47 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +class IniProcess +{ +public: + IniProcess(); + + void process(); + + void setInputFile(const fnd::SharedPtr& file); + void setCliOutputMode(CliOutputMode type); + void setVerifyMode(bool verify); + + void setKipExtractPath(const std::string& path); +private: + const std::string kModuleName = "IniProcess"; + const std::string kKipExtention = ".kip"; + const size_t kCacheSize = 0x10000; + + fnd::SharedPtr mFile; + CliOutputMode mCliOutputMode; + bool mVerify; + + bool mDoExtractKip; + std::string mKipExtractPath; + + nn::hac::IniHeader mHdr; + fnd::List> mKipList; + + void importHeader(); + void importKipList(); + void displayHeader(); + void displayKipList(); + void extractKipList(); + + size_t getKipSizeFromHeader(const nn::hac::KernelInitialProcessHeader& hdr) const; +}; \ No newline at end of file diff --git a/programs/nstool/source/KipProcess.cpp b/programs/nstool/source/KipProcess.cpp new file mode 100644 index 0000000..48b04dc --- /dev/null +++ b/programs/nstool/source/KipProcess.cpp @@ -0,0 +1,767 @@ +#include +#include +#include +#include +#include +#include "KipProcess.h" + +KipProcess::KipProcess(): + mFile(), + mCliOutputMode(_BIT(OUTPUT_BASIC)), + mVerify(false) +{ +} + +void KipProcess::process() +{ + importHeader(); + //importCodeSegments(); + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + { + displayHeader(); + displayKernelCap(mHdr.getKernelCapabilities()); + } +} + +void KipProcess::setInputFile(const fnd::SharedPtr& file) +{ + mFile = file; +} + +void KipProcess::setCliOutputMode(CliOutputMode type) +{ + mCliOutputMode = type; +} + +void KipProcess::setVerifyMode(bool verify) +{ + mVerify = verify; +} + +void KipProcess::importHeader() +{ + fnd::Vec scratch; + + if (*mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + if ((*mFile)->size() < sizeof(nn::hac::sKipHeader)) + { + throw fnd::Exception(kModuleName, "Corrupt KIP: file too small"); + } + + scratch.alloc(sizeof(nn::hac::sKipHeader)); + (*mFile)->read(scratch.data(), 0, scratch.size()); + + mHdr.fromBytes(scratch.data(), scratch.size()); +} + +void KipProcess::importCodeSegments() +{ +#ifdef _KIP_COMPRESSION_IMPLEMENTED + fnd::Vec scratch; + uint32_t decompressed_len; +#endif + + // process text segment +#ifdef _KIP_COMPRESSION_IMPLEMENTED + if (mHdr.getTextSegmentInfo().is_compressed) + { + scratch.alloc(mHdr.getTextSegmentInfo().file_layout.size); + (*mFile)->read(scratch.data(), mHdr.getTextSegmentInfo().file_layout.offset, scratch.size()); + mTextBlob.alloc(mHdr.getTextSegmentInfo().memory_layout.size); + fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mTextBlob.data(), (uint32_t)mTextBlob.size(), decompressed_len); + if (decompressed_len != mTextBlob.size()) + { + throw fnd::Exception(kModuleName, "KIP text segment failed to decompress"); + } + } + else + { + mTextBlob.alloc(mHdr.getTextSegmentInfo().file_layout.size); + (*mFile)->read(mTextBlob.data(), mHdr.getTextSegmentInfo().file_layout.offset, mTextBlob.size()); + } +#else + mTextBlob.alloc(mHdr.getTextSegmentInfo().file_layout.size); + (*mFile)->read(mTextBlob.data(), mHdr.getTextSegmentInfo().file_layout.offset, mTextBlob.size()); +#endif + + // process ro segment +#ifdef _KIP_COMPRESSION_IMPLEMENTED + if (mHdr.getRoSegmentInfo().is_compressed) + { + scratch.alloc(mHdr.getRoSegmentInfo().file_layout.size); + (*mFile)->read(scratch.data(), mHdr.getRoSegmentInfo().file_layout.offset, scratch.size()); + mRoBlob.alloc(mHdr.getRoSegmentInfo().memory_layout.size); + fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mRoBlob.data(), (uint32_t)mRoBlob.size(), decompressed_len); + if (decompressed_len != mRoBlob.size()) + { + throw fnd::Exception(kModuleName, "KIP ro segment failed to decompress"); + } + } + else + { + mRoBlob.alloc(mHdr.getRoSegmentInfo().file_layout.size); + (*mFile)->read(mRoBlob.data(), mHdr.getRoSegmentInfo().file_layout.offset, mRoBlob.size()); + } +#else + mRoBlob.alloc(mHdr.getRoSegmentInfo().file_layout.size); + (*mFile)->read(mRoBlob.data(), mHdr.getRoSegmentInfo().file_layout.offset, mRoBlob.size()); +#endif + + // process data segment +#ifdef _KIP_COMPRESSION_IMPLEMENTED + if (mHdr.getDataSegmentInfo().is_compressed) + { + scratch.alloc(mHdr.getDataSegmentInfo().file_layout.size); + (*mFile)->read(scratch.data(), mHdr.getDataSegmentInfo().file_layout.offset, scratch.size()); + mDataBlob.alloc(mHdr.getDataSegmentInfo().memory_layout.size); + fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mDataBlob.data(), (uint32_t)mDataBlob.size(), decompressed_len); + if (decompressed_len != mDataBlob.size()) + { + throw fnd::Exception(kModuleName, "KIP data segment failed to decompress"); + } + } + else + { + mDataBlob.alloc(mHdr.getDataSegmentInfo().file_layout.size); + (*mFile)->read(mDataBlob.data(), mHdr.getDataSegmentInfo().file_layout.offset, mDataBlob.size()); + } +#else + mDataBlob.alloc(mHdr.getDataSegmentInfo().file_layout.size); + (*mFile)->read(mDataBlob.data(), mHdr.getDataSegmentInfo().file_layout.offset, mDataBlob.size()); +#endif +} + +void KipProcess::displayHeader() +{ + std::cout << "[KIP Header]" << std::endl; + std::cout << " Meta:" << std::endl; + std::cout << " Name: " << mHdr.getName() << std::endl; + std::cout << " TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getTitleId() << std::endl; + std::cout << " ProcessCategory: " << getProcessCategoryStr(mHdr.getProcessCategory()) << std::endl; + std::cout << " InstructionType: " << getInstructionTypeStr(mHdr.getFlagList().hasElement(nn::hac::kip::FLAG_INSTRUCTION_64BIT)) << std::endl; + std::cout << " AddrSpaceWidth: " << getAddressSpaceStr(mHdr.getFlagList().hasElement(nn::hac::kip::FLAG_ADDR_SPACE_64BIT)) << std::endl; + std::cout << " MemoryPool: " << getMemoryPoolStr(mHdr.getFlagList().hasElement(nn::hac::kip::FLAG_USE_SYSTEM_POOL_PARTITION)) << std::endl; + std::cout << " Program Sections:" << std::endl; + std::cout << " .text:" << std::endl; + if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + { + std::cout << " FileOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().file_layout.offset << std::endl; + std::cout << " FileSize: 0x" << std::hex << mHdr.getTextSegmentInfo().file_layout.size << (mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl; + } + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.size << std::endl; + std::cout << " .ro:" << std::endl; + if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + { + std::cout << " FileOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().file_layout.offset << std::endl; + std::cout << " FileSize: 0x" << std::hex << mHdr.getRoSegmentInfo().file_layout.size << (mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl; + } + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.size << std::endl; + std::cout << " .data:" << std::endl; + if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + { + std::cout << " FileOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().file_layout.offset << std::endl; + std::cout << " FileSize: 0x" << std::hex << mHdr.getDataSegmentInfo().file_layout.size << (mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl; + } + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.size << std::endl; + std::cout << " .bss:" << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getBssSize() << std::endl; + +} + +void KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern) +{ + std::cout << "[Kernel Capabilities]" << std::endl; + if (kern.getThreadInfo().isSet()) + { + nn::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo(); + std::cout << " Thread Priority:" << std::endl; + std::cout << " Min: " << std::dec << (uint32_t)threadInfo.getMinPriority() << std::endl; + std::cout << " Max: " << std::dec << (uint32_t)threadInfo.getMaxPriority() << std::endl; + std::cout << " CpuId:" << std::endl; + std::cout << " Min: " << std::dec << (uint32_t)threadInfo.getMinCpuId() << std::endl; + std::cout << " Max: " << std::dec << (uint32_t)threadInfo.getMaxCpuId() << std::endl; + } + + if (kern.getSystemCalls().isSet()) + { + fnd::List syscalls = kern.getSystemCalls().getSystemCalls(); + std::cout << " SystemCalls:" << std::endl; + std::cout << " "; + size_t lineLen = 0; + for (size_t i = 0; i < syscalls.size(); i++) + { + if (lineLen > 60) + { + lineLen = 0; + std::cout << std::endl; + std::cout << " "; + } + std::cout << getSystemCallStr(syscalls[i]); + if (syscalls[i] != syscalls.atBack()) + std::cout << ", "; + lineLen += strlen(getSystemCallStr(syscalls[i])); + } + std::cout << std::endl; + } + if (kern.getMemoryMaps().isSet()) + { + fnd::List maps = kern.getMemoryMaps().getMemoryMaps(); + fnd::List ioMaps = kern.getMemoryMaps().getIoMemoryMaps(); + + std::cout << " MemoryMaps:" << std::endl; + for (size_t i = 0; i < maps.size(); i++) + { + std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)maps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1) << " (perm=" << getMemMapPermStr(maps[i].perm) << ") (type=" << getMemMapTypeStr(maps[i].type) << ")" << std::endl; + } + //std::cout << " IoMaps:" << std::endl; + for (size_t i = 0; i < ioMaps.size(); i++) + { + std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)ioMaps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1) << " (perm=" << getMemMapPermStr(ioMaps[i].perm) << ") (type=" << getMemMapTypeStr(ioMaps[i].type) << ")" << std::endl; + } + } + if (kern.getInterupts().isSet()) + { + fnd::List interupts = kern.getInterupts().getInteruptList(); + std::cout << " Interupts Flags:" << std::endl; + for (uint32_t i = 0; i < interupts.size(); i++) + { + if (i % 10 == 0) + { + if (i != 0) + std::cout << std::endl; + std::cout << " "; + } + std::cout << "0x" << std::hex << (uint32_t)interupts[i]; + if (interupts[i] != interupts.atBack()) + std::cout << ", "; + } + std::cout << std::endl; + } + if (kern.getMiscParams().isSet()) + { + std::cout << " ProgramType: " << std::dec << (uint32_t)kern.getMiscParams().getProgramType() << std::endl; + } + if (kern.getKernelVersion().isSet()) + { + std::cout << " Kernel Version: " << std::dec << (uint32_t)kern.getKernelVersion().getVerMajor() << "." << (uint32_t)kern.getKernelVersion().getVerMinor() << std::endl; + } + if (kern.getHandleTableSize().isSet()) + { + std::cout << " Handle Table Size: 0x" << std::hex << kern.getHandleTableSize().getHandleTableSize() << std::endl; + } + if (kern.getMiscFlags().isSet()) + { + fnd::List flagList = kern.getMiscFlags().getFlagList(); + + std::cout << " Misc Flags:" << std::endl; + for (uint32_t i = 0; i < flagList.size(); i++) + { + if (i % 10 == 0) + { + if (i != 0) + std::cout << std::endl; + std::cout << " "; + } + std::cout << getMiscFlagStr(flagList[i]); + if (flagList[i] != flagList.atBack()) + std::cout << ", "; + std::cout << std::endl; + } + } +} + +const char* KipProcess::getProcessCategoryStr(nn::hac::kip::ProcessCategory var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::kip::PROCCAT_REGULAR): + str = "NormalProcess"; + break; + case (nn::hac::kip::PROCCAT_KERNAL_KIP): + str = "KernelInitalProcess"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* KipProcess::getInstructionTypeStr(bool is64Bit) const +{ + return is64Bit? "64Bit" : "32Bit"; +} + +const char* KipProcess::getAddressSpaceStr(bool is64Bit) const +{ + return is64Bit? "64Bit" : "32Bit"; +} + +const char* KipProcess::getMemoryPoolStr(bool isSystemPool) const +{ + return isSystemPool? "System" : "Application"; +} + +const char* KipProcess::getMiscFlagStr(nn::hac::MiscFlagsHandler::Flags flag) const +{ + const char* str = nullptr; + + switch(flag) + { + case (nn::hac::MiscFlagsHandler::FLAG_ENABLE_DEBUG): + str = "EnableDebug"; + break; + case (nn::hac::MiscFlagsHandler::FLAG_FORCE_DEBUG): + str = "ForceDebug"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* KipProcess::getSystemCallStr(byte_t syscall_id) const +{ + const char* str = nullptr; + + switch(syscall_id) + { + case (0x01): + str = "SetHeapSize"; + break; + case (0x02): + str = "SetMemoryPermission"; + break; + case (0x03): + str = "SetMemoryAttribute"; + break; + case (0x04): + str = "MapMemory"; + break; + case (0x05): + str = "UnmapMemory"; + break; + case (0x06): + str = "QueryMemory"; + break; + case (0x07): + str = "ExitProcess"; + break; + case (0x08): + str = "CreateThread"; + break; + case (0x09): + str = "StartThread"; + break; + case (0x0a): + str = "ExitThread"; + break; + case (0x0b): + str = "SleepThread"; + break; + case (0x0c): + str = "GetThreadPriority"; + break; + case (0x0d): + str = "SetThreadPriority"; + break; + case (0x0e): + str = "GetThreadCoreMask"; + break; + case (0x0f): + str = "SetThreadCoreMask"; + break; + case (0x10): + str = "GetCurrentProcessorNumber"; + break; + case (0x11): + str = "SignalEvent"; + break; + case (0x12): + str = "ClearEvent"; + break; + case (0x13): + str = "MapSharedMemory"; + break; + case (0x14): + str = "UnmapSharedMemory"; + break; + case (0x15): + str = "CreateTransferMemory"; + break; + case (0x16): + str = "CloseHandle"; + break; + case (0x17): + str = "ResetSignal"; + break; + case (0x18): + str = "WaitSynchronization"; + break; + case (0x19): + str = "CancelSynchronization"; + break; + case (0x1a): + str = "ArbitrateLock"; + break; + case (0x1b): + str = "ArbitrateUnlock"; + break; + case (0x1c): + str = "WaitProcessWideKeyAtomic"; + break; + case (0x1d): + str = "SignalProcessWideKey"; + break; + case (0x1e): + str = "GetSystemTick"; + break; + case (0x1f): + str = "ConnectToNamedPort"; + break; + case (0x20): + str = "SendSyncRequestLight"; + break; + case (0x21): + str = "SendSyncRequest"; + break; + case (0x22): + str = "SendSyncRequestWithUserBuffer"; + break; + case (0x23): + str = "SendAsyncRequestWithUserBuffer"; + break; + case (0x24): + str = "GetProcessId"; + break; + case (0x25): + str = "GetThreadId"; + break; + case (0x26): + str = "Break"; + break; + case (0x27): + str = "OutputDebugString"; + break; + case (0x28): + str = "ReturnFromException"; + break; + case (0x29): + str = "GetInfo"; + break; + case (0x2a): + str = "FlushEntireDataCache"; + break; + case (0x2b): + str = "FlushDataCache"; + break; + case (0x2c): + str = "MapPhysicalMemory"; + break; + case (0x2d): + str = "UnmapPhysicalMemory"; + break; + case (0x2e): + str = "GetFutureThreadInfo"; + break; + case (0x2f): + str = "GetLastThreadInfo"; + break; + case (0x30): + str = "GetResourceLimitLimitValue"; + break; + case (0x31): + str = "GetResourceLimitCurrentValue"; + break; + case (0x32): + str = "SetThreadActivity"; + break; + case (0x33): + str = "GetThreadContext3"; + break; + case (0x34): + str = "WaitForAddress"; + break; + case (0x35): + str = "SignalToAddress"; + break; + case (0x36): + str = "svc36"; + break; + case (0x37): + str = "svc37"; + break; + case (0x38): + str = "svc38"; + break; + case (0x39): + str = "svc39"; + break; + case (0x3a): + str = "svc3A"; + break; + case (0x3b): + str = "svc3B"; + break; + case (0x3c): + str = "DumpInfo"; + break; + case (0x3d): + str = "DumpInfoNew"; + break; + case (0x3e): + str = "svc3E"; + break; + case (0x3f): + str = "svc3F"; + break; + case (0x40): + str = "CreateSession"; + break; + case (0x41): + str = "AcceptSession"; + break; + case (0x42): + str = "ReplyAndReceiveLight"; + break; + case (0x43): + str = "ReplyAndReceive"; + break; + case (0x44): + str = "ReplyAndReceiveWithUserBuffer"; + break; + case (0x45): + str = "CreateEvent"; + break; + case (0x46): + str = "svc46"; + break; + case (0x47): + str = "svc47"; + break; + case (0x48): + str = "MapPhysicalMemoryUnsafe"; + break; + case (0x49): + str = "UnmapPhysicalMemoryUnsafe"; + break; + case (0x4a): + str = "SetUnsafeLimit"; + break; + case (0x4b): + str = "CreateCodeMemory"; + break; + case (0x4c): + str = "ControlCodeMemory"; + break; + case (0x4d): + str = "SleepSystem"; + break; + case (0x4e): + str = "ReadWriteRegister"; + break; + case (0x4f): + str = "SetProcessActivity"; + break; + case (0x50): + str = "CreateSharedMemory"; + break; + case (0x51): + str = "MapTransferMemory"; + break; + case (0x52): + str = "UnmapTransferMemory"; + break; + case (0x53): + str = "CreateInterruptEvent"; + break; + case (0x54): + str = "QueryPhysicalAddress"; + break; + case (0x55): + str = "QueryIoMapping"; + break; + case (0x56): + str = "CreateDeviceAddressSpace"; + break; + case (0x57): + str = "AttachDeviceAddressSpace"; + break; + case (0x58): + str = "DetachDeviceAddressSpace"; + break; + case (0x59): + str = "MapDeviceAddressSpaceByForce"; + break; + case (0x5a): + str = "MapDeviceAddressSpaceAligned"; + break; + case (0x5b): + str = "MapDeviceAddressSpace"; + break; + case (0x5c): + str = "UnmapDeviceAddressSpace"; + break; + case (0x5d): + str = "InvalidateProcessDataCache"; + break; + case (0x5e): + str = "StoreProcessDataCache"; + break; + case (0x5f): + str = "FlushProcessDataCache"; + break; + case (0x60): + str = "DebugActiveProcess"; + break; + case (0x61): + str = "BreakDebugProcess"; + break; + case (0x62): + str = "TerminateDebugProcess"; + break; + case (0x63): + str = "GetDebugEvent"; + break; + case (0x64): + str = "ContinueDebugEvent"; + break; + case (0x65): + str = "GetProcessList"; + break; + case (0x66): + str = "GetThreadList"; + break; + case (0x67): + str = "GetDebugThreadContext"; + break; + case (0x68): + str = "SetDebugThreadContext"; + break; + case (0x69): + str = "QueryDebugProcessMemory"; + break; + case (0x6a): + str = "ReadDebugProcessMemory"; + break; + case (0x6b): + str = "WriteDebugProcessMemory"; + break; + case (0x6c): + str = "SetHardwareBreakPoint"; + break; + case (0x6d): + str = "GetDebugThreadParam"; + break; + case (0x6e): + str = "svc6E"; + break; + case (0x6f): + str = "GetSystemInfo"; + break; + case (0x70): + str = "CreatePort"; + break; + case (0x71): + str = "ManageNamedPort"; + break; + case (0x72): + str = "ConnectToPort"; + break; + case (0x73): + str = "SetProcessMemoryPermission"; + break; + case (0x74): + str = "MapProcessMemory"; + break; + case (0x75): + str = "UnmapProcessMemory"; + break; + case (0x76): + str = "QueryProcessMemory"; + break; + case (0x77): + str = "MapProcessCodeMemory"; + break; + case (0x78): + str = "UnmapProcessCodeMemory"; + break; + case (0x79): + str = "CreateProcess"; + break; + case (0x7a): + str = "StartProcess"; + break; + case (0x7b): + str = "TerminateProcess"; + break; + case (0x7c): + str = "GetProcessInfo"; + break; + case (0x7d): + str = "CreateResourceLimit"; + break; + case (0x7e): + str = "SetResourceLimitLimitValue"; + break; + case (0x7f): + str = "CallSecureMonitor"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* KipProcess::getMemMapPermStr(nn::hac::MemoryMappingHandler::MemoryPerm type) const +{ + const char* str = nullptr; + + switch(type) + { + case (nn::hac::MemoryMappingHandler::MEM_RW): + str = "RW"; + break; + case (nn::hac::MemoryMappingHandler::MEM_RO): + str = "RO"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* KipProcess::getMemMapTypeStr(nn::hac::MemoryMappingHandler::MappingType type) const +{ + const char* str = nullptr; + + switch(type) + { + case (nn::hac::MemoryMappingHandler::MAP_IO): + str = "Io"; + break; + case (nn::hac::MemoryMappingHandler::MAP_STATIC): + str = "Static"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} \ No newline at end of file diff --git a/programs/nstool/source/KipProcess.h b/programs/nstool/source/KipProcess.h new file mode 100644 index 0000000..798f9af --- /dev/null +++ b/programs/nstool/source/KipProcess.h @@ -0,0 +1,44 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +#include "common.h" + +class KipProcess +{ +public: + KipProcess(); + + void process(); + + void setInputFile(const fnd::SharedPtr& file); + void setCliOutputMode(CliOutputMode type); + void setVerifyMode(bool verify); +private: + const std::string kModuleName = "KipProcess"; + + fnd::SharedPtr mFile; + CliOutputMode mCliOutputMode; + bool mVerify; + + nn::hac::KernelInitialProcessHeader mHdr; + fnd::Vec mTextBlob, mRoBlob, mDataBlob; + + void importHeader(); + void importCodeSegments(); + void displayHeader(); + void displayKernelCap(const nn::hac::KernelCapabilityControl& kern); + + const char* getProcessCategoryStr(nn::hac::kip::ProcessCategory var) const; + const char* getInstructionTypeStr(bool is64Bit) const; + const char* getAddressSpaceStr(bool is64Bit) const; + const char* getMemoryPoolStr(bool isSystemPool) const; + const char* getMiscFlagStr(nn::hac::MiscFlagsHandler::Flags flag) const; + const char* getSystemCallStr(byte_t syscall_id) const; + const char* getMemMapPermStr(nn::hac::MemoryMappingHandler::MemoryPerm type) const; + const char* getMemMapTypeStr(nn::hac::MemoryMappingHandler::MappingType type) const; +}; \ No newline at end of file diff --git a/programs/nstool/source/UserSettings.cpp b/programs/nstool/source/UserSettings.cpp index e1e2675..9ac9dc2 100644 --- a/programs/nstool/source/UserSettings.cpp +++ b/programs/nstool/source/UserSettings.cpp @@ -87,6 +87,9 @@ void UserSettings::showHelp() printf(" --listapi Print SDK API List.\n"); printf(" --listsym Print Code Symbols.\n"); printf(" --insttype Specify instruction type [64bit|32bit] (64bit is assumed).\n"); + printf("\n INI (Initial Process List Blob)\n"); + printf(" %s [--kipdir ] \n", BIN_NAME); + printf(" --kipdir Extract embedded KIPs to directory.\n"); printf("\n ASET (Homebrew Asset Blob)\n"); printf(" %s [--listfs] [--icon --nacp --fsdir ] \n", BIN_NAME); printf(" --listfs Print filesystem in embedded RomFS partition.\n"); @@ -185,6 +188,11 @@ const sOptional& UserSettings::getNcaPart3Path() const return mNcaPart3Path; } +const sOptional& UserSettings::getKipExtractPath() const +{ + return mKipExtractPath; +} + const sOptional& UserSettings::getAssetIconPath() const { return mAssetIconPath; @@ -368,6 +376,12 @@ void UserSettings::populateCmdArgs(const std::vector& arg_list, sCm cmd_args.inst_type = arg_list[i + 1]; } + else if (arg_list[i] == "--kipdir") + { + if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); + cmd_args.kip_extract_path = arg_list[i + 1]; + } + else if (arg_list[i] == "--icon") { if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); @@ -546,6 +560,8 @@ void UserSettings::populateUserSettings(sCmdArgs& args) mNcaPart2Path = args.part2_path; mNcaPart3Path = args.part3_path; + mKipExtractPath = args.kip_extract_path; + // determine the architecture type for NSO/NRO if (args.inst_type.isSet) mInstructionType = getInstructionTypeFromString(*args.inst_type); diff --git a/programs/nstool/source/UserSettings.h b/programs/nstool/source/UserSettings.h index 33143b8..6e69aeb 100644 --- a/programs/nstool/source/UserSettings.h +++ b/programs/nstool/source/UserSettings.h @@ -41,6 +41,7 @@ public: const sOptional& getNcaPart1Path() const; const sOptional& getNcaPart2Path() const; const sOptional& getNcaPart3Path() const; + const sOptional& getKipExtractPath() const; const sOptional& getAssetIconPath() const; const sOptional& getAssetNacpPath() const; const fnd::List>& getCertificateChain() const; @@ -78,6 +79,7 @@ private: sOptional part1_path; sOptional part2_path; sOptional part3_path; + sOptional kip_extract_path; sOptional list_api; sOptional list_sym; sOptional inst_type; @@ -103,6 +105,8 @@ private: sOptional mNcaPart2Path; sOptional mNcaPart3Path; + sOptional mKipExtractPath; + sOptional mAssetIconPath; sOptional mAssetNacpPath; diff --git a/programs/nstool/source/main.cpp b/programs/nstool/source/main.cpp index 9141874..a12867b 100644 --- a/programs/nstool/source/main.cpp +++ b/programs/nstool/source/main.cpp @@ -12,6 +12,8 @@ #include "NsoProcess.h" #include "NroProcess.h" #include "NacpProcess.h" +#include "IniProcess.h" +#include "KipProcess.h" #include "PkiCertProcess.h" #include "EsTikProcess.h" #include "AssetProcess.h" @@ -40,96 +42,96 @@ int main(int argc, char** argv) if (user_set.getFileType() == FILE_GC) { - GameCardProcess xci; + GameCardProcess obj; - xci.setInputFile(inputFile); + obj.setInputFile(inputFile); - xci.setKeyCfg(user_set.getKeyCfg()); - xci.setCliOutputMode(user_set.getCliOutputMode()); - xci.setVerifyMode(user_set.isVerifyFile()); + obj.setKeyCfg(user_set.getKeyCfg()); + obj.setCliOutputMode(user_set.getCliOutputMode()); + obj.setVerifyMode(user_set.isVerifyFile()); if (user_set.getXciUpdatePath().isSet) - xci.setPartitionForExtract(nn::hac::gc::kUpdatePartitionStr, user_set.getXciUpdatePath().var); + obj.setPartitionForExtract(nn::hac::gc::kUpdatePartitionStr, user_set.getXciUpdatePath().var); if (user_set.getXciLogoPath().isSet) - xci.setPartitionForExtract(nn::hac::gc::kLogoPartitionStr, user_set.getXciLogoPath().var); + obj.setPartitionForExtract(nn::hac::gc::kLogoPartitionStr, user_set.getXciLogoPath().var); if (user_set.getXciNormalPath().isSet) - xci.setPartitionForExtract(nn::hac::gc::kNormalPartitionStr, user_set.getXciNormalPath().var); + obj.setPartitionForExtract(nn::hac::gc::kNormalPartitionStr, user_set.getXciNormalPath().var); if (user_set.getXciSecurePath().isSet) - xci.setPartitionForExtract(nn::hac::gc::kSecurePartitionStr, user_set.getXciSecurePath().var); - xci.setListFs(user_set.isListFs()); + obj.setPartitionForExtract(nn::hac::gc::kSecurePartitionStr, user_set.getXciSecurePath().var); + obj.setListFs(user_set.isListFs()); - xci.process(); + obj.process(); } else if (user_set.getFileType() == FILE_PARTITIONFS || user_set.getFileType() == FILE_NSP) { - PfsProcess pfs; + PfsProcess obj; - pfs.setInputFile(inputFile); - pfs.setCliOutputMode(user_set.getCliOutputMode()); - pfs.setVerifyMode(user_set.isVerifyFile()); + obj.setInputFile(inputFile); + obj.setCliOutputMode(user_set.getCliOutputMode()); + obj.setVerifyMode(user_set.isVerifyFile()); if (user_set.getFsPath().isSet) - pfs.setExtractPath(user_set.getFsPath().var); - pfs.setListFs(user_set.isListFs()); + obj.setExtractPath(user_set.getFsPath().var); + obj.setListFs(user_set.isListFs()); - pfs.process(); + obj.process(); } else if (user_set.getFileType() == FILE_ROMFS) { - RomfsProcess romfs; + RomfsProcess obj; - romfs.setInputFile(inputFile); - romfs.setCliOutputMode(user_set.getCliOutputMode()); - romfs.setVerifyMode(user_set.isVerifyFile()); + obj.setInputFile(inputFile); + obj.setCliOutputMode(user_set.getCliOutputMode()); + obj.setVerifyMode(user_set.isVerifyFile()); if (user_set.getFsPath().isSet) - romfs.setExtractPath(user_set.getFsPath().var); - romfs.setListFs(user_set.isListFs()); + obj.setExtractPath(user_set.getFsPath().var); + obj.setListFs(user_set.isListFs()); - romfs.process(); + obj.process(); } else if (user_set.getFileType() == FILE_NCA) { - NcaProcess nca; + NcaProcess obj; - nca.setInputFile(inputFile); - nca.setKeyCfg(user_set.getKeyCfg()); - nca.setCliOutputMode(user_set.getCliOutputMode()); - nca.setVerifyMode(user_set.isVerifyFile()); + obj.setInputFile(inputFile); + obj.setKeyCfg(user_set.getKeyCfg()); + obj.setCliOutputMode(user_set.getCliOutputMode()); + obj.setVerifyMode(user_set.isVerifyFile()); if (user_set.getNcaPart0Path().isSet) - nca.setPartition0ExtractPath(user_set.getNcaPart0Path().var); + obj.setPartition0ExtractPath(user_set.getNcaPart0Path().var); if (user_set.getNcaPart1Path().isSet) - nca.setPartition1ExtractPath(user_set.getNcaPart1Path().var); + obj.setPartition1ExtractPath(user_set.getNcaPart1Path().var); if (user_set.getNcaPart2Path().isSet) - nca.setPartition2ExtractPath(user_set.getNcaPart2Path().var); + obj.setPartition2ExtractPath(user_set.getNcaPart2Path().var); if (user_set.getNcaPart3Path().isSet) - nca.setPartition3ExtractPath(user_set.getNcaPart3Path().var); - nca.setListFs(user_set.isListFs()); + obj.setPartition3ExtractPath(user_set.getNcaPart3Path().var); + obj.setListFs(user_set.isListFs()); - nca.process(); + obj.process(); } else if (user_set.getFileType() == FILE_META) { - MetaProcess npdm; + MetaProcess obj; - npdm.setInputFile(inputFile); - npdm.setKeyCfg(user_set.getKeyCfg()); - npdm.setCliOutputMode(user_set.getCliOutputMode()); - npdm.setVerifyMode(user_set.isVerifyFile()); + obj.setInputFile(inputFile); + obj.setKeyCfg(user_set.getKeyCfg()); + obj.setCliOutputMode(user_set.getCliOutputMode()); + obj.setVerifyMode(user_set.isVerifyFile()); - npdm.process(); + obj.process(); } else if (user_set.getFileType() == FILE_CNMT) { - CnmtProcess cnmt; + CnmtProcess obj; - cnmt.setInputFile(inputFile); - cnmt.setCliOutputMode(user_set.getCliOutputMode()); - cnmt.setVerifyMode(user_set.isVerifyFile()); + obj.setInputFile(inputFile); + obj.setCliOutputMode(user_set.getCliOutputMode()); + obj.setVerifyMode(user_set.isVerifyFile()); - cnmt.process(); + obj.process(); } else if (user_set.getFileType() == FILE_NSO) { @@ -170,36 +172,59 @@ int main(int argc, char** argv) } else if (user_set.getFileType() == FILE_NACP) { - NacpProcess nacp; + NacpProcess obj; - nacp.setInputFile(inputFile); - nacp.setCliOutputMode(user_set.getCliOutputMode()); - nacp.setVerifyMode(user_set.isVerifyFile()); + obj.setInputFile(inputFile); + obj.setCliOutputMode(user_set.getCliOutputMode()); + obj.setVerifyMode(user_set.isVerifyFile()); - nacp.process(); + obj.process(); + } + else if (user_set.getFileType() == FILE_INI) + { + IniProcess obj; + + obj.setInputFile(inputFile); + obj.setCliOutputMode(user_set.getCliOutputMode()); + obj.setVerifyMode(user_set.isVerifyFile()); + + if (user_set.getKipExtractPath().isSet) + obj.setKipExtractPath(user_set.getKipExtractPath().var); + + obj.process(); + } + else if (user_set.getFileType() == FILE_KIP) + { + KipProcess obj; + + obj.setInputFile(inputFile); + obj.setCliOutputMode(user_set.getCliOutputMode()); + obj.setVerifyMode(user_set.isVerifyFile()); + + obj.process(); } else if (user_set.getFileType() == FILE_PKI_CERT) { - PkiCertProcess cert; + PkiCertProcess obj; - cert.setInputFile(inputFile); - cert.setKeyCfg(user_set.getKeyCfg()); - cert.setCliOutputMode(user_set.getCliOutputMode()); - cert.setVerifyMode(user_set.isVerifyFile()); + obj.setInputFile(inputFile); + obj.setKeyCfg(user_set.getKeyCfg()); + obj.setCliOutputMode(user_set.getCliOutputMode()); + obj.setVerifyMode(user_set.isVerifyFile()); - cert.process(); + obj.process(); } else if (user_set.getFileType() == FILE_ES_TIK) { - EsTikProcess tik; + EsTikProcess obj; - tik.setInputFile(inputFile); - tik.setKeyCfg(user_set.getKeyCfg()); - tik.setCertificateChain(user_set.getCertificateChain()); - tik.setCliOutputMode(user_set.getCliOutputMode()); - tik.setVerifyMode(user_set.isVerifyFile()); + obj.setInputFile(inputFile); + obj.setKeyCfg(user_set.getKeyCfg()); + obj.setCertificateChain(user_set.getCertificateChain()); + obj.setCliOutputMode(user_set.getCliOutputMode()); + obj.setVerifyMode(user_set.isVerifyFile()); - tik.process(); + obj.process(); } else if (user_set.getFileType() == FILE_HB_ASSET) { @@ -220,6 +245,10 @@ int main(int argc, char** argv) obj.process(); } + else + { + throw fnd::Exception("main", "Unhandled file type"); + } } catch (const fnd::Exception& e) { printf("\n\n%s\n", e.what()); From 4499dd06a0cab1409ad9d3b34d1235a7105e78f5 Mon Sep 17 00:00:00 2001 From: jakcron Date: Tue, 6 Nov 2018 12:20:30 +0800 Subject: [PATCH 10/11] [libhac|nstool] Update VS Project Files. --- lib/libhac/libhac.vcxproj | 6 ++++++ lib/libhac/libhac.vcxproj.filters | 18 ++++++++++++++++++ programs/nstool/nstool.vcxproj | 8 ++++++-- programs/nstool/nstool.vcxproj.filters | 24 ++++++++++++++++++------ 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/lib/libhac/libhac.vcxproj b/lib/libhac/libhac.vcxproj index 483f783..4a89383 100644 --- a/lib/libhac/libhac.vcxproj +++ b/lib/libhac/libhac.vcxproj @@ -41,7 +41,9 @@ + + @@ -61,10 +63,12 @@ + + @@ -108,10 +112,12 @@ + + diff --git a/lib/libhac/libhac.vcxproj.filters b/lib/libhac/libhac.vcxproj.filters index 39c36cb..ab4e0f4 100644 --- a/lib/libhac/libhac.vcxproj.filters +++ b/lib/libhac/libhac.vcxproj.filters @@ -36,9 +36,15 @@ Header Files\define + + Header Files\define + Header Files\define + + Header Files\define + Header Files\define @@ -132,6 +138,9 @@ Header Files + + Header Files + Header Files @@ -144,6 +153,9 @@ Header Files + + Header Files + Header Files @@ -269,6 +281,9 @@ Source Files + + Source Files + Source Files @@ -281,6 +296,9 @@ Source Files + + Source Files + Source Files diff --git a/programs/nstool/nstool.vcxproj b/programs/nstool/nstool.vcxproj index ed9eff4..78c2ecc 100644 --- a/programs/nstool/nstool.vcxproj +++ b/programs/nstool/nstool.vcxproj @@ -183,7 +183,10 @@ + + + @@ -197,14 +200,16 @@ - + + + @@ -218,7 +223,6 @@ - diff --git a/programs/nstool/nstool.vcxproj.filters b/programs/nstool/nstool.vcxproj.filters index 7febb7a..243a78b 100644 --- a/programs/nstool/nstool.vcxproj.filters +++ b/programs/nstool/nstool.vcxproj.filters @@ -34,9 +34,18 @@ Header Files + + Header Files + + + Header Files + Header Files + + Header Files + Header Files @@ -76,9 +85,6 @@ Header Files - - Header Files - @@ -93,9 +99,18 @@ Source Files + + Source Files + + + Source Files + Source Files + + Source Files + Source Files @@ -135,8 +150,5 @@ Source Files - - Source Files - \ No newline at end of file From b5de79235a13ecfb4edaf49e89a2a04bf5cef6ad Mon Sep 17 00:00:00 2001 From: jakcron Date: Tue, 6 Nov 2018 14:08:17 +0800 Subject: [PATCH 11/11] [nstool] Update readme. --- programs/nstool/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/programs/nstool/README.md b/programs/nstool/README.md index 2c1618e..4b46e3a 100644 --- a/programs/nstool/README.md +++ b/programs/nstool/README.md @@ -10,6 +10,8 @@ General purpose reading/extraction tool for Nintendo Switch file formats. * Content Metadata (.cnmt) * Nintendo Software Object (.nso) * Nintendo Relocatable Software Object (.nro) +* Kernel Initial Process List (.ini) +* Kernel Initial Process (.kip) * Nintendo Application Control Property (.nacp) * ES Ticket (v2 only) (.tik) * PKI Certificate (.cert) @@ -21,7 +23,7 @@ Usage: nstool [options... ] General Options: -d, --dev Use devkit keyset. -k, --keyset Specify keyset file. - -t, --type Specify input file type. [xci, pfs, romfs, nca, meta, cnmt, nso, nro, nacp, aset, cert, tik] + -t, --type Specify input file type. [xci, pfs, romfs, nca, meta, cnmt, nso, nro, ini, kip, nacp, aset, cert, tik] -y, --verify Verify file. Output Options: @@ -60,6 +62,10 @@ Usage: nstool [options... ] --listsym Print Code Symbols. --insttype Specify instruction type [64bit|32bit] (64bit is assumed). + INI (Initial Process List Blob) + nstool [--kipdir ] + --kipdir Extract embedded KIPs to directory. + ASET (Homebrew Asset Blob) nstool [--listfs] [--icon --nacp --fsdir ] --listfs Print filesystem in embedded RomFS partition.