2020-02-26 09:04:18 +00:00
|
|
|
#include "KipProcess.h"
|
|
|
|
|
2018-11-05 13:11:08 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <iomanip>
|
2020-02-26 09:04:18 +00:00
|
|
|
|
2018-11-05 13:11:08 +00:00
|
|
|
#include <fnd/SimpleTextOutput.h>
|
|
|
|
#include <fnd/OffsetAdjustedIFile.h>
|
|
|
|
#include <fnd/Vec.h>
|
2020-02-26 09:04:18 +00:00
|
|
|
|
|
|
|
#include <nn/hac/KernelCapabilityUtil.h>
|
2018-11-05 13:11:08 +00:00
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
nstool::KipProcess::KipProcess():
|
2018-11-05 13:11:08 +00:00
|
|
|
mFile(),
|
2021-09-28 11:15:54 +00:00
|
|
|
mCliOutputMode(true, false, false, false),
|
2018-11-05 13:11:08 +00:00
|
|
|
mVerify(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::KipProcess::process()
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
|
|
|
importHeader();
|
|
|
|
//importCodeSegments();
|
2021-09-28 11:15:54 +00:00
|
|
|
if (mCliOutputMode.show_basic_info)
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
|
|
|
displayHeader();
|
|
|
|
displayKernelCap(mHdr.getKernelCapabilities());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::KipProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
|
|
|
mFile = file;
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::KipProcess::setCliOutputMode(CliOutputMode type)
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
|
|
|
mCliOutputMode = type;
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::KipProcess::setVerifyMode(bool verify)
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
|
|
|
mVerify = verify;
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::KipProcess::importHeader()
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
2021-09-28 11:15:54 +00:00
|
|
|
tc::ByteData scratch;
|
2018-11-05 13:11:08 +00:00
|
|
|
|
|
|
|
if (*mFile == nullptr)
|
|
|
|
{
|
2021-09-28 11:15:54 +00:00
|
|
|
throw tc::Exception(kModuleName, "No file reader set.");
|
2018-11-05 13:11:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((*mFile)->size() < sizeof(nn::hac::sKipHeader))
|
|
|
|
{
|
2021-09-28 11:15:54 +00:00
|
|
|
throw tc::Exception(kModuleName, "Corrupt KIP: file too small");
|
2018-11-05 13:11:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
scratch.alloc(sizeof(nn::hac::sKipHeader));
|
|
|
|
(*mFile)->read(scratch.data(), 0, scratch.size());
|
|
|
|
|
|
|
|
mHdr.fromBytes(scratch.data(), scratch.size());
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::KipProcess::importCodeSegments()
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
|
|
|
#ifdef _KIP_COMPRESSION_IMPLEMENTED
|
2021-09-28 11:15:54 +00:00
|
|
|
tc::ByteData scratch;
|
2018-11-05 13:11:08 +00:00
|
|
|
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())
|
|
|
|
{
|
2021-09-28 11:15:54 +00:00
|
|
|
throw tc::Exception(kModuleName, "KIP text segment failed to decompress");
|
2018-11-05 13:11:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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())
|
|
|
|
{
|
2021-09-28 11:15:54 +00:00
|
|
|
throw tc::Exception(kModuleName, "KIP ro segment failed to decompress");
|
2018-11-05 13:11:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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())
|
|
|
|
{
|
2021-09-28 11:15:54 +00:00
|
|
|
throw tc::Exception(kModuleName, "KIP data segment failed to decompress");
|
2018-11-05 13:11:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::KipProcess::displayHeader()
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
|
|
|
std::cout << "[KIP Header]" << std::endl;
|
|
|
|
std::cout << " Meta:" << std::endl;
|
2020-03-14 07:25:33 +00:00
|
|
|
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 << " Version: v" << std::dec << mHdr.getVersion() << std::endl;
|
|
|
|
std::cout << " Is64BitInstruction: " << std::boolalpha << mHdr.getIs64BitInstructionFlag() << std::endl;
|
|
|
|
std::cout << " Is64BitAddressSpace: " << std::boolalpha << mHdr.getIs64BitAddressSpaceFlag() << std::endl;
|
|
|
|
std::cout << " UseSecureMemory: " << std::boolalpha << mHdr.getUseSecureMemoryFlag() << std::endl;
|
2018-11-05 13:11:08 +00:00
|
|
|
std::cout << " Program Sections:" << std::endl;
|
|
|
|
std::cout << " .text:" << std::endl;
|
2021-09-28 11:15:54 +00:00
|
|
|
if (mCliOutputMode.show_layout)
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
|
|
|
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;
|
2021-09-28 11:15:54 +00:00
|
|
|
if (mCliOutputMode.show_layout)
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
|
|
|
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;
|
2021-09-28 11:15:54 +00:00
|
|
|
if (mCliOutputMode.show_layout)
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl& kern)
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
|
|
|
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())
|
|
|
|
{
|
2020-03-15 08:00:03 +00:00
|
|
|
auto syscall_ids = kern.getSystemCalls().getSystemCallIds();
|
2018-11-05 13:11:08 +00:00
|
|
|
std::cout << " SystemCalls:" << std::endl;
|
2020-03-15 08:00:03 +00:00
|
|
|
std::vector<std::string> syscall_names;
|
|
|
|
for (size_t syscall_id = 0; syscall_id < syscall_ids.size(); syscall_id++)
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
2020-03-15 08:00:03 +00:00
|
|
|
if (syscall_ids.test(syscall_id))
|
|
|
|
syscall_names.push_back(nn::hac::KernelCapabilityUtil::getSystemCallIdAsString(nn::hac::kc::SystemCallId(syscall_id)));
|
2018-11-05 13:11:08 +00:00
|
|
|
}
|
2020-03-15 08:00:03 +00:00
|
|
|
fnd::SimpleTextOutput::dumpStringList(syscall_names, 60, 4);
|
2018-11-05 13:11:08 +00:00
|
|
|
}
|
|
|
|
if (kern.getMemoryMaps().isSet())
|
|
|
|
{
|
2021-09-28 11:15:54 +00:00
|
|
|
std::vector<nn::hac::MemoryMappingHandler::sMemoryMapping> maps = kern.getMemoryMaps().getMemoryMaps();
|
|
|
|
std::vector<nn::hac::MemoryMappingHandler::sMemoryMapping> ioMaps = kern.getMemoryMaps().getIoMemoryMaps();
|
2018-11-05 13:11:08 +00:00
|
|
|
|
|
|
|
std::cout << " MemoryMaps:" << std::endl;
|
|
|
|
for (size_t i = 0; i < maps.size(); i++)
|
|
|
|
{
|
2020-03-15 08:00:03 +00:00
|
|
|
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=" << nn::hac::KernelCapabilityUtil::getMemoryPermissionAsString(maps[i].perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMappingTypeAsString(maps[i].type) << ")" << std::endl;
|
2018-11-05 13:11:08 +00:00
|
|
|
}
|
|
|
|
//std::cout << " IoMaps:" << std::endl;
|
|
|
|
for (size_t i = 0; i < ioMaps.size(); i++)
|
|
|
|
{
|
2020-03-15 08:00:03 +00:00
|
|
|
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=" << nn::hac::KernelCapabilityUtil::getMemoryPermissionAsString(ioMaps[i].perm) << ") (type=" << nn::hac::KernelCapabilityUtil::getMappingTypeAsString(ioMaps[i].type) << ")" << std::endl;
|
2018-11-05 13:11:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (kern.getInterupts().isSet())
|
|
|
|
{
|
2021-09-28 11:15:54 +00:00
|
|
|
std::vector<uint16_t> interupts = kern.getInterupts().getInteruptList();
|
2018-11-05 13:11:08 +00:00
|
|
|
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())
|
|
|
|
{
|
2020-03-17 11:12:44 +00:00
|
|
|
std::cout << " ProgramType: " << nn::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()) << " (" << std::dec << (uint32_t)kern.getMiscParams().getProgramType() << ")" << std::endl;
|
2018-11-05 13:11:08 +00:00
|
|
|
}
|
|
|
|
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())
|
|
|
|
{
|
2020-03-15 08:00:03 +00:00
|
|
|
auto misc_flags = kern.getMiscFlags().getMiscFlags();
|
2018-11-05 13:11:08 +00:00
|
|
|
std::cout << " Misc Flags:" << std::endl;
|
2020-03-15 08:00:03 +00:00
|
|
|
std::vector<std::string> misc_flags_names;
|
|
|
|
for (size_t misc_flags_bit = 0; misc_flags_bit < misc_flags.size(); misc_flags_bit++)
|
2018-11-05 13:11:08 +00:00
|
|
|
{
|
2020-03-15 08:00:03 +00:00
|
|
|
if (misc_flags.test(misc_flags_bit))
|
|
|
|
misc_flags_names.push_back(nn::hac::KernelCapabilityUtil::getMiscFlagsBitAsString(nn::hac::kc::MiscFlagsBit(misc_flags_bit)));
|
2018-11-05 13:11:08 +00:00
|
|
|
}
|
2020-03-15 08:00:03 +00:00
|
|
|
fnd::SimpleTextOutput::dumpStringList(misc_flags_names, 60, 4);
|
2018-11-05 13:11:08 +00:00
|
|
|
}
|
|
|
|
}
|