mirror of
https://github.com/jakcron/nstool
synced 2024-11-26 23:49:36 +00:00
[nstool] Add dynamic symbol processing to NsoProcess.
This commit is contained in:
parent
caeea8f119
commit
36d7d7a5bf
7 changed files with 93 additions and 16 deletions
|
@ -168,6 +168,7 @@
|
||||||
<ClInclude Include="source\AesCtrWrappedIFile.h" />
|
<ClInclude Include="source\AesCtrWrappedIFile.h" />
|
||||||
<ClInclude Include="source\CnmtProcess.h" />
|
<ClInclude Include="source\CnmtProcess.h" />
|
||||||
<ClInclude Include="source\CopiedIFile.h" />
|
<ClInclude Include="source\CopiedIFile.h" />
|
||||||
|
<ClInclude Include="source\DynamicSymbolParser.h" />
|
||||||
<ClInclude Include="source\HashTreeMeta.h" />
|
<ClInclude Include="source\HashTreeMeta.h" />
|
||||||
<ClInclude Include="source\HashTreeWrappedIFile.h" />
|
<ClInclude Include="source\HashTreeWrappedIFile.h" />
|
||||||
<ClInclude Include="source\NcaProcess.h" />
|
<ClInclude Include="source\NcaProcess.h" />
|
||||||
|
@ -184,6 +185,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="source\AesCtrWrappedIFile.cpp" />
|
<ClCompile Include="source\AesCtrWrappedIFile.cpp" />
|
||||||
<ClCompile Include="source\CnmtProcess.cpp" />
|
<ClCompile Include="source\CnmtProcess.cpp" />
|
||||||
|
<ClCompile Include="source\DynamicSymbolParser.cpp" />
|
||||||
<ClCompile Include="source\HashTreeMeta.cpp" />
|
<ClCompile Include="source\HashTreeMeta.cpp" />
|
||||||
<ClCompile Include="source\HashTreeWrappedIFile.cpp" />
|
<ClCompile Include="source\HashTreeWrappedIFile.cpp" />
|
||||||
<ClCompile Include="source\main.cpp" />
|
<ClCompile Include="source\main.cpp" />
|
||||||
|
|
|
@ -60,6 +60,9 @@
|
||||||
<ClInclude Include="source\NsoProcess.h">
|
<ClInclude Include="source\NsoProcess.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\DynamicSymbolParser.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="source\main.cpp">
|
<ClCompile Include="source\main.cpp">
|
||||||
|
@ -101,6 +104,9 @@
|
||||||
<ClCompile Include="source\NsoProcess.cpp">
|
<ClCompile Include="source\NsoProcess.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\DynamicSymbolParser.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="makefile" />
|
<None Include="makefile" />
|
||||||
|
|
|
@ -5,17 +5,12 @@
|
||||||
#include "OffsetAdjustedIFile.h"
|
#include "OffsetAdjustedIFile.h"
|
||||||
#include "NsoProcess.h"
|
#include "NsoProcess.h"
|
||||||
|
|
||||||
inline const char* getBoolStr(bool isTrue)
|
|
||||||
{
|
|
||||||
return isTrue? "TRUE" : "FALSE";
|
|
||||||
}
|
|
||||||
|
|
||||||
NsoProcess::NsoProcess():
|
NsoProcess::NsoProcess():
|
||||||
mReader(nullptr),
|
mReader(nullptr),
|
||||||
mCliOutputType(OUTPUT_NORMAL),
|
mCliOutputType(OUTPUT_NORMAL),
|
||||||
mVerify(false)
|
mVerify(false)
|
||||||
{
|
{
|
||||||
|
mArchType.isSet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NsoProcess::~NsoProcess()
|
NsoProcess::~NsoProcess()
|
||||||
|
@ -59,6 +54,11 @@ void NsoProcess::setVerifyMode(bool verify)
|
||||||
mVerify = verify;
|
mVerify = verify;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NsoProcess::setArchType(nx::npdm::InstructionType type)
|
||||||
|
{
|
||||||
|
mArchType = type;
|
||||||
|
}
|
||||||
|
|
||||||
const nx::NsoHeader& NsoProcess::getNsoHeader() const
|
const nx::NsoHeader& NsoProcess::getNsoHeader() const
|
||||||
{
|
{
|
||||||
return mHdr;
|
return mHdr;
|
||||||
|
@ -192,7 +192,7 @@ void NsoProcess::importApiList()
|
||||||
std::stringstream list_stream(std::string((char*)mRoBlob.getBytes() + mHdr.getRoEmbeddedInfo().offset, mHdr.getRoEmbeddedInfo().size));
|
std::stringstream list_stream(std::string((char*)mRoBlob.getBytes() + mHdr.getRoEmbeddedInfo().offset, mHdr.getRoEmbeddedInfo().size));
|
||||||
std::string api;
|
std::string api;
|
||||||
|
|
||||||
while(std::getline(list_stream, api, '+'))
|
while(std::getline(list_stream, api, (char)0x00))
|
||||||
{
|
{
|
||||||
mApiList.push_back(api);
|
mApiList.push_back(api);
|
||||||
}
|
}
|
||||||
|
@ -201,6 +201,11 @@ void NsoProcess::importApiList()
|
||||||
{
|
{
|
||||||
mApiList.clear();
|
mApiList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mHdr.getRoDynSymInfo().size > 0 && mArchType.isSet == true)
|
||||||
|
{
|
||||||
|
mDynSymbolList.parseData(mRoBlob.getBytes() + mHdr.getRoDynSymInfo().offset, mHdr.getRoDynSymInfo().size, mRoBlob.getBytes() + mHdr.getRoDynStrInfo().offset, mHdr.getRoDynStrInfo().size, *mArchType == nx::npdm::INSTR_64BIT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NsoProcess::displayHeader()
|
void NsoProcess::displayHeader()
|
||||||
|
@ -246,13 +251,13 @@ void NsoProcess::displayHeader()
|
||||||
if (mCliOutputType >= OUTPUT_VERBOSE)
|
if (mCliOutputType >= OUTPUT_VERBOSE)
|
||||||
{
|
{
|
||||||
printf(" .api_info:\n");
|
printf(" .api_info:\n");
|
||||||
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset + mHdr.getRoEmbeddedInfo().offset);
|
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().offset);
|
||||||
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size);
|
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size);
|
||||||
printf(" .dynstr:\n");
|
printf(" .dynstr:\n");
|
||||||
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset + mHdr.getRoDynStrInfo().offset);
|
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().offset);
|
||||||
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size);
|
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size);
|
||||||
printf(" .dynsym:\n");
|
printf(" .dynsym:\n");
|
||||||
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset + mHdr.getRoDynSymInfo().offset);
|
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().offset);
|
||||||
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size);
|
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,13 +278,25 @@ void NsoProcess::displayHeader()
|
||||||
|
|
||||||
void NsoProcess::displayRoApiList()
|
void NsoProcess::displayRoApiList()
|
||||||
{
|
{
|
||||||
printf("[NSO RO Segment]\n");
|
if (mApiList.size() > 0 || mDynSymbolList.getDynamicSymbolList().getSize() > 0)
|
||||||
if (mApiList.size() > 0)
|
|
||||||
{
|
{
|
||||||
printf(" API List:\n");
|
printf("[NSO RO Segment]\n");
|
||||||
for (size_t i = 0; i < mApiList.size(); i++)
|
if (mApiList.size() > 0)
|
||||||
{
|
{
|
||||||
printf(" %s\n", mApiList[i].c_str());
|
printf(" API List:\n");
|
||||||
|
for (size_t i = 0; i < mApiList.size(); i++)
|
||||||
|
{
|
||||||
|
printf(" %s\n", mApiList[i].c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mDynSymbolList.getDynamicSymbolList().getSize() > 0)
|
||||||
|
{
|
||||||
|
printf(" Undefined Symbol List:\n");
|
||||||
|
for (size_t i = 0; i < mDynSymbolList.getDynamicSymbolList().getSize(); i++)
|
||||||
|
{
|
||||||
|
if (mDynSymbolList.getDynamicSymbolList()[i].shn_index == nx::dynsym::SHN_UNDEF && (mDynSymbolList.getDynamicSymbolList()[i].symbol_type == nx::dynsym::STT_FUNC || mDynSymbolList.getDynamicSymbolList()[i].symbol_type == nx::dynsym::STT_NOTYPE))
|
||||||
|
printf(" %s\n", mDynSymbolList.getDynamicSymbolList()[i].name.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
#include <nx/NsoHeader.h>
|
#include <nx/NsoHeader.h>
|
||||||
|
|
||||||
#include "nstool.h"
|
#include "nstool.h"
|
||||||
|
#include "DynamicSymbolParser.h"
|
||||||
|
|
||||||
class NsoProcess
|
class NsoProcess
|
||||||
{
|
{
|
||||||
|
@ -19,6 +20,8 @@ public:
|
||||||
void setCliOutputMode(CliOutputType type);
|
void setCliOutputMode(CliOutputType type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
void setArchType(nx::npdm::InstructionType type);
|
||||||
|
|
||||||
// processed data
|
// processed data
|
||||||
const nx::NsoHeader& getNsoHeader() const;
|
const nx::NsoHeader& getNsoHeader() const;
|
||||||
const fnd::MemoryBlob& getTextBlob() const;
|
const fnd::MemoryBlob& getTextBlob() const;
|
||||||
|
@ -32,10 +35,12 @@ private:
|
||||||
fnd::IFile* mReader;
|
fnd::IFile* mReader;
|
||||||
CliOutputType mCliOutputType;
|
CliOutputType mCliOutputType;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
sOptional<nx::npdm::InstructionType> mArchType;
|
||||||
|
|
||||||
nx::NsoHeader mHdr;
|
nx::NsoHeader mHdr;
|
||||||
fnd::MemoryBlob mTextBlob, mRoBlob, mDataBlob;
|
fnd::MemoryBlob mTextBlob, mRoBlob, mDataBlob;
|
||||||
std::vector<std::string> mApiList;
|
std::vector<std::string> mApiList;
|
||||||
|
DynamicSymbolParser mDynSymbolList;
|
||||||
|
|
||||||
void importHeader();
|
void importHeader();
|
||||||
void importCodeSegments();
|
void importCodeSegments();
|
||||||
|
|
|
@ -62,6 +62,10 @@ void UserSettings::showHelp()
|
||||||
printf(" --part1 Extract \"partition 1\" to directory \n");
|
printf(" --part1 Extract \"partition 1\" to directory \n");
|
||||||
printf(" --part2 Extract \"partition 2\" to directory \n");
|
printf(" --part2 Extract \"partition 2\" to directory \n");
|
||||||
printf(" --part3 Extract \"partition 3\" to directory \n");
|
printf(" --part3 Extract \"partition 3\" to directory \n");
|
||||||
|
printf("\n NSO (Nintendo Software Object)\n");
|
||||||
|
printf(" nstool [--arch <architecture>] <.nso>\n");
|
||||||
|
printf(" --arch Specify code architecture [32bit, 64bit]\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string UserSettings::getInputPath() const
|
const std::string UserSettings::getInputPath() const
|
||||||
|
@ -94,6 +98,11 @@ bool UserSettings::isListFs() const
|
||||||
return mListFs;
|
return mListFs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sOptional<nx::npdm::InstructionType>& UserSettings::getArchType() const
|
||||||
|
{
|
||||||
|
return mArchType;
|
||||||
|
}
|
||||||
|
|
||||||
const sOptional<std::string>& UserSettings::getUpdatePath() const
|
const sOptional<std::string>& UserSettings::getUpdatePath() const
|
||||||
{
|
{
|
||||||
return mUpdatePath;
|
return mUpdatePath;
|
||||||
|
@ -269,6 +278,12 @@ void UserSettings::populateCmdArgs(int argc, char** argv, sCmdArgs& cmd_args)
|
||||||
cmd_args.part3_path = args[i+1];
|
cmd_args.part3_path = args[i+1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (args[i] == "--arch")
|
||||||
|
{
|
||||||
|
if (!hasParamter) throw fnd::Exception(kModuleName, args[i] + " requries a parameter.");
|
||||||
|
cmd_args.arch_type = args[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, args[i] + " is not recognised.");
|
throw fnd::Exception(kModuleName, args[i] + " is not recognised.");
|
||||||
|
@ -524,6 +539,12 @@ void UserSettings::populateUserSettings(sCmdArgs& args)
|
||||||
mPart2Path = args.part2_path;
|
mPart2Path = args.part2_path;
|
||||||
mPart3Path = args.part3_path;
|
mPart3Path = args.part3_path;
|
||||||
|
|
||||||
|
// determine the architecture type for NSO
|
||||||
|
if (args.arch_type.isSet)
|
||||||
|
mArchType = getInstructionTypeFromString(*args.arch_type);
|
||||||
|
else
|
||||||
|
mArchType.isSet = false;
|
||||||
|
|
||||||
// determine output path
|
// determine output path
|
||||||
if (args.verbose_output.isSet)
|
if (args.verbose_output.isSet)
|
||||||
mOutputType = OUTPUT_VERBOSE;
|
mOutputType = OUTPUT_VERBOSE;
|
||||||
|
@ -649,3 +670,19 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path)
|
||||||
|
|
||||||
return file_type;
|
return file_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nx::npdm::InstructionType UserSettings::getInstructionTypeFromString(const std::string & type_str)
|
||||||
|
{
|
||||||
|
std::string str = type_str;
|
||||||
|
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||||
|
|
||||||
|
nx::npdm::InstructionType type;
|
||||||
|
if (str == "32bit")
|
||||||
|
type = nx::npdm::INSTR_32BIT;
|
||||||
|
else if (str == "64bit")
|
||||||
|
type = nx::npdm::INSTR_64BIT;
|
||||||
|
else
|
||||||
|
throw fnd::Exception(kModuleName, "Unsupported architecture type: " + str);
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
|
#include <nx/npdm.h>
|
||||||
#include "nstool.h"
|
#include "nstool.h"
|
||||||
|
|
||||||
class UserSettings
|
class UserSettings
|
||||||
|
@ -20,6 +21,7 @@ public:
|
||||||
|
|
||||||
// specialised toggles
|
// specialised toggles
|
||||||
bool isListFs() const;
|
bool isListFs() const;
|
||||||
|
const sOptional<nx::npdm::InstructionType>& getArchType() const;
|
||||||
|
|
||||||
// specialised paths
|
// specialised paths
|
||||||
const sOptional<std::string>& getUpdatePath() const;
|
const sOptional<std::string>& getUpdatePath() const;
|
||||||
|
@ -54,6 +56,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> arch_type;
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
|
@ -75,6 +78,7 @@ private:
|
||||||
part1_path.isSet = false;
|
part1_path.isSet = false;
|
||||||
part2_path.isSet = false;
|
part2_path.isSet = false;
|
||||||
part3_path.isSet = false;
|
part3_path.isSet = false;
|
||||||
|
arch_type.isSet = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -95,10 +99,13 @@ private:
|
||||||
sOptional<std::string> mPart2Path;
|
sOptional<std::string> mPart2Path;
|
||||||
sOptional<std::string> mPart3Path;
|
sOptional<std::string> mPart3Path;
|
||||||
|
|
||||||
|
sOptional<nx::npdm::InstructionType> mArchType;
|
||||||
|
|
||||||
void populateCmdArgs(int argc, char** argv, sCmdArgs& cmd_args);
|
void populateCmdArgs(int argc, char** argv, sCmdArgs& cmd_args);
|
||||||
void populateKeyset(sCmdArgs& args);
|
void populateKeyset(sCmdArgs& args);
|
||||||
void populateUserSettings(sCmdArgs& args);
|
void populateUserSettings(sCmdArgs& args);
|
||||||
void decodeHexStringToBytes(const std::string& name, const std::string& str, byte_t* out, size_t out_len);
|
void decodeHexStringToBytes(const std::string& name, const std::string& str, byte_t* out, size_t out_len);
|
||||||
FileType getFileTypeFromString(const std::string& type_str);
|
FileType getFileTypeFromString(const std::string& type_str);
|
||||||
FileType determineFileTypeFromFile(const std::string& path);
|
FileType determineFileTypeFromFile(const std::string& path);
|
||||||
|
nx::npdm::InstructionType getInstructionTypeFromString(const std::string& type_str);
|
||||||
};
|
};
|
|
@ -118,6 +118,9 @@ int main(int argc, char** argv)
|
||||||
nso.setCliOutputMode(user_set.getCliOutputType());
|
nso.setCliOutputMode(user_set.getCliOutputType());
|
||||||
nso.setVerifyMode(user_set.isVerifyFile());
|
nso.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
|
if (user_set.getArchType().isSet)
|
||||||
|
nso.setArchType(user_set.getArchType().var);
|
||||||
|
|
||||||
nso.process();
|
nso.process();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue