[nstool] Add dynamic symbol processing to NsoProcess.

This commit is contained in:
jakcron 2018-06-02 20:16:19 +08:00
parent caeea8f119
commit 36d7d7a5bf
7 changed files with 93 additions and 16 deletions

View file

@ -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" />

View file

@ -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" />

View file

@ -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);
} }
@ -272,6 +277,8 @@ void NsoProcess::displayHeader()
} }
void NsoProcess::displayRoApiList() void NsoProcess::displayRoApiList()
{
if (mApiList.size() > 0 || mDynSymbolList.getDynamicSymbolList().getSize() > 0)
{ {
printf("[NSO RO Segment]\n"); printf("[NSO RO Segment]\n");
if (mApiList.size() > 0) if (mApiList.size() > 0)
@ -282,4 +289,14 @@ void NsoProcess::displayRoApiList()
printf(" %s\n", mApiList[i].c_str()); 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());
}
}
}
} }

View file

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

View file

@ -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;
}

View file

@ -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);
}; };

View file

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