[nstool] Add initial support for INI/KIP.

This commit is contained in:
jakcron 2018-11-05 21:11:08 +08:00
parent 735ace1749
commit 1458e267d5
7 changed files with 1142 additions and 65 deletions

View file

@ -0,0 +1,170 @@
#include <iostream>
#include <iomanip>
#include <fnd/io.h>
#include <fnd/SimpleFile.h>
#include <fnd/SimpleTextOutput.h>
#include <fnd/OffsetAdjustedIFile.h>
#include <fnd/Vec.h>
#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<fnd::IFile>& 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<byte_t> 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<byte_t> 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<byte_t> 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;
}

View file

@ -0,0 +1,47 @@
#pragma once
#include <vector>
#include <string>
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <fnd/List.h>
#include <fnd/SharedPtr.h>
#include <nn/hac/IniHeader.h>
#include <nn/hac/KernelInitialProcessHeader.h>
#include "common.h"
class IniProcess
{
public:
IniProcess();
void process();
void setInputFile(const fnd::SharedPtr<fnd::IFile>& 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<fnd::IFile> mFile;
CliOutputMode mCliOutputMode;
bool mVerify;
bool mDoExtractKip;
std::string mKipExtractPath;
nn::hac::IniHeader mHdr;
fnd::List<fnd::SharedPtr<fnd::IFile>> mKipList;
void importHeader();
void importKipList();
void displayHeader();
void displayKipList();
void extractKipList();
size_t getKipSizeFromHeader(const nn::hac::KernelInitialProcessHeader& hdr) const;
};

View file

@ -0,0 +1,767 @@
#include <iostream>
#include <iomanip>
#include <fnd/SimpleTextOutput.h>
#include <fnd/OffsetAdjustedIFile.h>
#include <fnd/Vec.h>
#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<fnd::IFile>& file)
{
mFile = file;
}
void KipProcess::setCliOutputMode(CliOutputMode type)
{
mCliOutputMode = type;
}
void KipProcess::setVerifyMode(bool verify)
{
mVerify = verify;
}
void KipProcess::importHeader()
{
fnd::Vec<byte_t> 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<byte_t> 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<uint8_t> 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<nn::hac::MemoryMappingHandler::sMemoryMapping> maps = kern.getMemoryMaps().getMemoryMaps();
fnd::List<nn::hac::MemoryMappingHandler::sMemoryMapping> 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<uint16_t> 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<nn::hac::MiscFlagsHandler::Flags> 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;
}

View file

@ -0,0 +1,44 @@
#pragma once
#include <vector>
#include <string>
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <fnd/SharedPtr.h>
#include <nn/hac/KernelInitialProcessHeader.h>
#include "common.h"
class KipProcess
{
public:
KipProcess();
void process();
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
private:
const std::string kModuleName = "KipProcess";
fnd::SharedPtr<fnd::IFile> mFile;
CliOutputMode mCliOutputMode;
bool mVerify;
nn::hac::KernelInitialProcessHeader mHdr;
fnd::Vec<byte_t> 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;
};

View file

@ -87,6 +87,9 @@ void UserSettings::showHelp()
printf(" --listapi Print SDK API List.\n"); printf(" --listapi Print SDK API List.\n");
printf(" --listsym Print Code Symbols.\n"); printf(" --listsym Print Code Symbols.\n");
printf(" --insttype Specify instruction type [64bit|32bit] (64bit is assumed).\n"); printf(" --insttype Specify instruction type [64bit|32bit] (64bit is assumed).\n");
printf("\n INI (Initial Process List Blob)\n");
printf(" %s [--kipdir <dir>] <file>\n", BIN_NAME);
printf(" --kipdir Extract embedded KIPs to directory.\n");
printf("\n ASET (Homebrew Asset Blob)\n"); printf("\n ASET (Homebrew Asset Blob)\n");
printf(" %s [--listfs] [--icon <file> --nacp <file> --fsdir <dir>] <file>\n", BIN_NAME); printf(" %s [--listfs] [--icon <file> --nacp <file> --fsdir <dir>] <file>\n", BIN_NAME);
printf(" --listfs Print filesystem in embedded RomFS partition.\n"); printf(" --listfs Print filesystem in embedded RomFS partition.\n");
@ -185,6 +188,11 @@ const sOptional<std::string>& UserSettings::getNcaPart3Path() const
return mNcaPart3Path; return mNcaPart3Path;
} }
const sOptional<std::string>& UserSettings::getKipExtractPath() const
{
return mKipExtractPath;
}
const sOptional<std::string>& UserSettings::getAssetIconPath() const const sOptional<std::string>& UserSettings::getAssetIconPath() const
{ {
return mAssetIconPath; return mAssetIconPath;
@ -368,6 +376,12 @@ void UserSettings::populateCmdArgs(const std::vector<std::string>& arg_list, sCm
cmd_args.inst_type = arg_list[i + 1]; 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") else if (arg_list[i] == "--icon")
{ {
if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter."); 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; mNcaPart2Path = args.part2_path;
mNcaPart3Path = args.part3_path; mNcaPart3Path = args.part3_path;
mKipExtractPath = args.kip_extract_path;
// determine the architecture type for NSO/NRO // determine the architecture type for NSO/NRO
if (args.inst_type.isSet) if (args.inst_type.isSet)
mInstructionType = getInstructionTypeFromString(*args.inst_type); mInstructionType = getInstructionTypeFromString(*args.inst_type);

View file

@ -41,6 +41,7 @@ public:
const sOptional<std::string>& getNcaPart1Path() const; const sOptional<std::string>& getNcaPart1Path() const;
const sOptional<std::string>& getNcaPart2Path() const; const sOptional<std::string>& getNcaPart2Path() const;
const sOptional<std::string>& getNcaPart3Path() const; const sOptional<std::string>& getNcaPart3Path() const;
const sOptional<std::string>& getKipExtractPath() const;
const sOptional<std::string>& getAssetIconPath() const; const sOptional<std::string>& getAssetIconPath() const;
const sOptional<std::string>& getAssetNacpPath() const; const sOptional<std::string>& getAssetNacpPath() const;
const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& getCertificateChain() const; const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& getCertificateChain() const;
@ -78,6 +79,7 @@ private:
sOptional<std::string> part1_path; sOptional<std::string> part1_path;
sOptional<std::string> part2_path; sOptional<std::string> part2_path;
sOptional<std::string> part3_path; sOptional<std::string> part3_path;
sOptional<std::string> kip_extract_path;
sOptional<bool> list_api; sOptional<bool> list_api;
sOptional<bool> list_sym; sOptional<bool> list_sym;
sOptional<std::string> inst_type; sOptional<std::string> inst_type;
@ -103,6 +105,8 @@ private:
sOptional<std::string> mNcaPart2Path; sOptional<std::string> mNcaPart2Path;
sOptional<std::string> mNcaPart3Path; sOptional<std::string> mNcaPart3Path;
sOptional<std::string> mKipExtractPath;
sOptional<std::string> mAssetIconPath; sOptional<std::string> mAssetIconPath;
sOptional<std::string> mAssetNacpPath; sOptional<std::string> mAssetNacpPath;

View file

@ -12,6 +12,8 @@
#include "NsoProcess.h" #include "NsoProcess.h"
#include "NroProcess.h" #include "NroProcess.h"
#include "NacpProcess.h" #include "NacpProcess.h"
#include "IniProcess.h"
#include "KipProcess.h"
#include "PkiCertProcess.h" #include "PkiCertProcess.h"
#include "EsTikProcess.h" #include "EsTikProcess.h"
#include "AssetProcess.h" #include "AssetProcess.h"
@ -40,96 +42,96 @@ int main(int argc, char** argv)
if (user_set.getFileType() == FILE_GC) if (user_set.getFileType() == FILE_GC)
{ {
GameCardProcess xci; GameCardProcess obj;
xci.setInputFile(inputFile); obj.setInputFile(inputFile);
xci.setKeyCfg(user_set.getKeyCfg()); obj.setKeyCfg(user_set.getKeyCfg());
xci.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
xci.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(user_set.isVerifyFile());
if (user_set.getXciUpdatePath().isSet) 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) 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) 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) if (user_set.getXciSecurePath().isSet)
xci.setPartitionForExtract(nn::hac::gc::kSecurePartitionStr, user_set.getXciSecurePath().var); obj.setPartitionForExtract(nn::hac::gc::kSecurePartitionStr, user_set.getXciSecurePath().var);
xci.setListFs(user_set.isListFs()); obj.setListFs(user_set.isListFs());
xci.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_PARTITIONFS || user_set.getFileType() == FILE_NSP) else if (user_set.getFileType() == FILE_PARTITIONFS || user_set.getFileType() == FILE_NSP)
{ {
PfsProcess pfs; PfsProcess obj;
pfs.setInputFile(inputFile); obj.setInputFile(inputFile);
pfs.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
pfs.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(user_set.isVerifyFile());
if (user_set.getFsPath().isSet) if (user_set.getFsPath().isSet)
pfs.setExtractPath(user_set.getFsPath().var); obj.setExtractPath(user_set.getFsPath().var);
pfs.setListFs(user_set.isListFs()); obj.setListFs(user_set.isListFs());
pfs.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_ROMFS) else if (user_set.getFileType() == FILE_ROMFS)
{ {
RomfsProcess romfs; RomfsProcess obj;
romfs.setInputFile(inputFile); obj.setInputFile(inputFile);
romfs.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
romfs.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(user_set.isVerifyFile());
if (user_set.getFsPath().isSet) if (user_set.getFsPath().isSet)
romfs.setExtractPath(user_set.getFsPath().var); obj.setExtractPath(user_set.getFsPath().var);
romfs.setListFs(user_set.isListFs()); obj.setListFs(user_set.isListFs());
romfs.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_NCA) else if (user_set.getFileType() == FILE_NCA)
{ {
NcaProcess nca; NcaProcess obj;
nca.setInputFile(inputFile); obj.setInputFile(inputFile);
nca.setKeyCfg(user_set.getKeyCfg()); obj.setKeyCfg(user_set.getKeyCfg());
nca.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
nca.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(user_set.isVerifyFile());
if (user_set.getNcaPart0Path().isSet) if (user_set.getNcaPart0Path().isSet)
nca.setPartition0ExtractPath(user_set.getNcaPart0Path().var); obj.setPartition0ExtractPath(user_set.getNcaPart0Path().var);
if (user_set.getNcaPart1Path().isSet) if (user_set.getNcaPart1Path().isSet)
nca.setPartition1ExtractPath(user_set.getNcaPart1Path().var); obj.setPartition1ExtractPath(user_set.getNcaPart1Path().var);
if (user_set.getNcaPart2Path().isSet) if (user_set.getNcaPart2Path().isSet)
nca.setPartition2ExtractPath(user_set.getNcaPart2Path().var); obj.setPartition2ExtractPath(user_set.getNcaPart2Path().var);
if (user_set.getNcaPart3Path().isSet) if (user_set.getNcaPart3Path().isSet)
nca.setPartition3ExtractPath(user_set.getNcaPart3Path().var); obj.setPartition3ExtractPath(user_set.getNcaPart3Path().var);
nca.setListFs(user_set.isListFs()); obj.setListFs(user_set.isListFs());
nca.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_META) else if (user_set.getFileType() == FILE_META)
{ {
MetaProcess npdm; MetaProcess obj;
npdm.setInputFile(inputFile); obj.setInputFile(inputFile);
npdm.setKeyCfg(user_set.getKeyCfg()); obj.setKeyCfg(user_set.getKeyCfg());
npdm.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
npdm.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(user_set.isVerifyFile());
npdm.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_CNMT) else if (user_set.getFileType() == FILE_CNMT)
{ {
CnmtProcess cnmt; CnmtProcess obj;
cnmt.setInputFile(inputFile); obj.setInputFile(inputFile);
cnmt.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
cnmt.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(user_set.isVerifyFile());
cnmt.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_NSO) else if (user_set.getFileType() == FILE_NSO)
{ {
@ -170,36 +172,59 @@ int main(int argc, char** argv)
} }
else if (user_set.getFileType() == FILE_NACP) else if (user_set.getFileType() == FILE_NACP)
{ {
NacpProcess nacp; NacpProcess obj;
nacp.setInputFile(inputFile); obj.setInputFile(inputFile);
nacp.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
nacp.setVerifyMode(user_set.isVerifyFile()); 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) else if (user_set.getFileType() == FILE_PKI_CERT)
{ {
PkiCertProcess cert; PkiCertProcess obj;
cert.setInputFile(inputFile); obj.setInputFile(inputFile);
cert.setKeyCfg(user_set.getKeyCfg()); obj.setKeyCfg(user_set.getKeyCfg());
cert.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
cert.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(user_set.isVerifyFile());
cert.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_ES_TIK) else if (user_set.getFileType() == FILE_ES_TIK)
{ {
EsTikProcess tik; EsTikProcess obj;
tik.setInputFile(inputFile); obj.setInputFile(inputFile);
tik.setKeyCfg(user_set.getKeyCfg()); obj.setKeyCfg(user_set.getKeyCfg());
tik.setCertificateChain(user_set.getCertificateChain()); obj.setCertificateChain(user_set.getCertificateChain());
tik.setCliOutputMode(user_set.getCliOutputMode()); obj.setCliOutputMode(user_set.getCliOutputMode());
tik.setVerifyMode(user_set.isVerifyFile()); obj.setVerifyMode(user_set.isVerifyFile());
tik.process(); obj.process();
} }
else if (user_set.getFileType() == FILE_HB_ASSET) else if (user_set.getFileType() == FILE_HB_ASSET)
{ {
@ -220,6 +245,10 @@ int main(int argc, char** argv)
obj.process(); obj.process();
} }
else
{
throw fnd::Exception("main", "Unhandled file type");
}
} }
catch (const fnd::Exception& e) { catch (const fnd::Exception& e) {
printf("\n\n%s\n", e.what()); printf("\n\n%s\n", e.what());