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