From 36d7d7a5bf5a04150a0c4683b374bd2c5e0b6dd8 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sat, 2 Jun 2018 20:16:19 +0800 Subject: [PATCH] [nstool] Add dynamic symbol processing to NsoProcess. --- programs/nstool/nstool.vcxproj | 2 ++ programs/nstool/nstool.vcxproj.filters | 6 ++++ programs/nstool/source/NsoProcess.cpp | 47 +++++++++++++++++-------- programs/nstool/source/NsoProcess.h | 5 +++ programs/nstool/source/UserSettings.cpp | 39 +++++++++++++++++++- programs/nstool/source/UserSettings.h | 7 ++++ programs/nstool/source/main.cpp | 3 ++ 7 files changed, 93 insertions(+), 16 deletions(-) diff --git a/programs/nstool/nstool.vcxproj b/programs/nstool/nstool.vcxproj index 7a87ad3..fcd32eb 100644 --- a/programs/nstool/nstool.vcxproj +++ b/programs/nstool/nstool.vcxproj @@ -168,6 +168,7 @@ + @@ -184,6 +185,7 @@ + diff --git a/programs/nstool/nstool.vcxproj.filters b/programs/nstool/nstool.vcxproj.filters index f35bba6..799b7f4 100644 --- a/programs/nstool/nstool.vcxproj.filters +++ b/programs/nstool/nstool.vcxproj.filters @@ -60,6 +60,9 @@ Header Files + + Header Files + @@ -101,6 +104,9 @@ Source Files + + Source Files + diff --git a/programs/nstool/source/NsoProcess.cpp b/programs/nstool/source/NsoProcess.cpp index b7fe4ed..8b080c0 100644 --- a/programs/nstool/source/NsoProcess.cpp +++ b/programs/nstool/source/NsoProcess.cpp @@ -5,17 +5,12 @@ #include "OffsetAdjustedIFile.h" #include "NsoProcess.h" -inline const char* getBoolStr(bool isTrue) -{ - return isTrue? "TRUE" : "FALSE"; -} - NsoProcess::NsoProcess(): mReader(nullptr), mCliOutputType(OUTPUT_NORMAL), mVerify(false) { - + mArchType.isSet = false; } NsoProcess::~NsoProcess() @@ -59,6 +54,11 @@ void NsoProcess::setVerifyMode(bool verify) mVerify = verify; } +void NsoProcess::setArchType(nx::npdm::InstructionType type) +{ + mArchType = type; +} + const nx::NsoHeader& NsoProcess::getNsoHeader() const { 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::string api; - while(std::getline(list_stream, api, '+')) + while(std::getline(list_stream, api, (char)0x00)) { mApiList.push_back(api); } @@ -201,6 +201,11 @@ void NsoProcess::importApiList() { 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() @@ -246,13 +251,13 @@ void NsoProcess::displayHeader() if (mCliOutputType >= OUTPUT_VERBOSE) { 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(" .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(" .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); } @@ -273,13 +278,25 @@ void NsoProcess::displayHeader() void NsoProcess::displayRoApiList() { - printf("[NSO RO Segment]\n"); - if (mApiList.size() > 0) + if (mApiList.size() > 0 || mDynSymbolList.getDynamicSymbolList().getSize() > 0) { - printf(" API List:\n"); - for (size_t i = 0; i < mApiList.size(); i++) + printf("[NSO RO Segment]\n"); + 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()); + } } } } \ No newline at end of file diff --git a/programs/nstool/source/NsoProcess.h b/programs/nstool/source/NsoProcess.h index 6dbc982..a1ab964 100644 --- a/programs/nstool/source/NsoProcess.h +++ b/programs/nstool/source/NsoProcess.h @@ -6,6 +6,7 @@ #include #include "nstool.h" +#include "DynamicSymbolParser.h" class NsoProcess { @@ -19,6 +20,8 @@ public: void setCliOutputMode(CliOutputType type); void setVerifyMode(bool verify); + void setArchType(nx::npdm::InstructionType type); + // processed data const nx::NsoHeader& getNsoHeader() const; const fnd::MemoryBlob& getTextBlob() const; @@ -32,10 +35,12 @@ private: fnd::IFile* mReader; CliOutputType mCliOutputType; bool mVerify; + sOptional mArchType; nx::NsoHeader mHdr; fnd::MemoryBlob mTextBlob, mRoBlob, mDataBlob; std::vector mApiList; + DynamicSymbolParser mDynSymbolList; void importHeader(); void importCodeSegments(); diff --git a/programs/nstool/source/UserSettings.cpp b/programs/nstool/source/UserSettings.cpp index 7fc07e4..977b4ed 100644 --- a/programs/nstool/source/UserSettings.cpp +++ b/programs/nstool/source/UserSettings.cpp @@ -62,6 +62,10 @@ void UserSettings::showHelp() printf(" --part1 Extract \"partition 1\" to directory \n"); printf(" --part2 Extract \"partition 2\" to directory \n"); printf(" --part3 Extract \"partition 3\" to directory \n"); + printf("\n NSO (Nintendo Software Object)\n"); + printf(" nstool [--arch ] <.nso>\n"); + printf(" --arch Specify code architecture [32bit, 64bit]\n"); + } const std::string UserSettings::getInputPath() const @@ -94,6 +98,11 @@ bool UserSettings::isListFs() const return mListFs; } +const sOptional& UserSettings::getArchType() const +{ + return mArchType; +} + const sOptional& UserSettings::getUpdatePath() const { return mUpdatePath; @@ -269,6 +278,12 @@ void UserSettings::populateCmdArgs(int argc, char** argv, sCmdArgs& cmd_args) 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 { throw fnd::Exception(kModuleName, args[i] + " is not recognised."); @@ -524,6 +539,12 @@ void UserSettings::populateUserSettings(sCmdArgs& args) mPart2Path = args.part2_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 if (args.verbose_output.isSet) mOutputType = OUTPUT_VERBOSE; @@ -648,4 +669,20 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path) #undef _QUICK_CAST return file_type; -} \ No newline at end of file +} + +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; +} diff --git a/programs/nstool/source/UserSettings.h b/programs/nstool/source/UserSettings.h index 030d6d5..8d508d8 100644 --- a/programs/nstool/source/UserSettings.h +++ b/programs/nstool/source/UserSettings.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include "nstool.h" class UserSettings @@ -20,6 +21,7 @@ public: // specialised toggles bool isListFs() const; + const sOptional& getArchType() const; // specialised paths const sOptional& getUpdatePath() const; @@ -54,6 +56,7 @@ private: sOptional part1_path; sOptional part2_path; sOptional part3_path; + sOptional arch_type; void clear() { @@ -75,6 +78,7 @@ private: part1_path.isSet = false; part2_path.isSet = false; part3_path.isSet = false; + arch_type.isSet = false; } }; @@ -95,10 +99,13 @@ private: sOptional mPart2Path; sOptional mPart3Path; + sOptional mArchType; + void populateCmdArgs(int argc, char** argv, sCmdArgs& cmd_args); void populateKeyset(sCmdArgs& args); void populateUserSettings(sCmdArgs& args); 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 determineFileTypeFromFile(const std::string& path); + nx::npdm::InstructionType getInstructionTypeFromString(const std::string& type_str); }; \ No newline at end of file diff --git a/programs/nstool/source/main.cpp b/programs/nstool/source/main.cpp index 2dd1ef1..0ef0f57 100644 --- a/programs/nstool/source/main.cpp +++ b/programs/nstool/source/main.cpp @@ -117,6 +117,9 @@ int main(int argc, char** argv) nso.setInputFile(&inputFile, 0, inputFile.size()); nso.setCliOutputMode(user_set.getCliOutputType()); nso.setVerifyMode(user_set.isVerifyFile()); + + if (user_set.getArchType().isSet) + nso.setArchType(user_set.getArchType().var); nso.process(); }