Merge pull request #26 from jakcron/codesym-development

Refactor NSO/NRO code symbol processing.
This commit is contained in:
Jack 2018-06-21 17:33:00 +08:00 committed by GitHub
commit ee1531d40d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 578 additions and 546 deletions

View file

@ -10,9 +10,11 @@
"/usr/include", "/usr/include",
"${workspaceRoot}", "${workspaceRoot}",
"${workspaceRoot}/lib/libcrypto/include", "${workspaceRoot}/lib/libcrypto/include",
"${workspaceRoot}/lib/libcompress/include",
"${workspaceRoot}/lib/libes/include", "${workspaceRoot}/lib/libes/include",
"${workspaceRoot}/lib/libfnd/include", "${workspaceRoot}/lib/libfnd/include",
"${workspaceRoot}/lib/libnx/include" "${workspaceRoot}/lib/libnx/include",
"${workspaceRoot}/lib/libnx-hb/include"
], ],
"defines": [], "defines": [],
"intelliSenseMode": "clang-x64", "intelliSenseMode": "clang-x64",

View file

@ -3,12 +3,11 @@
namespace nx namespace nx
{ {
namespace dynsym namespace elf
{ {
enum SpecialSectionIndex enum SpecialSectionIndex
{ {
SHN_UNDEF, SHN_UNDEF,
SHN_EXPORT = 1,
SHN_LORESERVE = 0xFF00, SHN_LORESERVE = 0xFF00,
SHN_LOPROC = 0xFF00, SHN_LOPROC = 0xFF00,
SHN_HIPROC = 0xFF1F, SHN_HIPROC = 0xFF1F,
@ -31,10 +30,21 @@ namespace nx
STT_LOPROC, STT_LOPROC,
STT_HIPROC = 0xF STT_HIPROC = 0xF
}; };
enum SymbolBinding
{
STB_LOCAL,
STB_GLOBAL,
STB_WEAK,
STB_LOOS = 10,
STB_HIOS = 12,
STB_LOPROC,
STB_HIPROC = 0xF
};
} }
#pragma pack(push,1) #pragma pack(push,1)
struct sDynSymbol32Bit struct sElfSymbol32Bit
{ {
le_uint32_t name; le_uint32_t name;
le_uint32_t value; le_uint32_t value;
@ -44,7 +54,7 @@ namespace nx
le_uint32_t special_section_index; le_uint32_t special_section_index;
}; };
struct sDynSymbol64Bit struct sElfSymbol64Bit
{ {
le_uint32_t name; le_uint32_t name;
byte_t info; byte_t info;

View file

@ -28,7 +28,7 @@
<ClInclude Include="include\nx\ApplicationControlPropertyUtils.h" /> <ClInclude Include="include\nx\ApplicationControlPropertyUtils.h" />
<ClInclude Include="include\nx\cnmt.h" /> <ClInclude Include="include\nx\cnmt.h" />
<ClInclude Include="include\nx\ContentMetaBinary.h" /> <ClInclude Include="include\nx\ContentMetaBinary.h" />
<ClInclude Include="include\nx\dynamic_symbol.h" /> <ClInclude Include="include\nx\elf.h" />
<ClInclude Include="include\nx\FacBinary.h" /> <ClInclude Include="include\nx\FacBinary.h" />
<ClInclude Include="include\nx\FacHeader.h" /> <ClInclude Include="include\nx\FacHeader.h" />
<ClInclude Include="include\nx\HandleTableSizeEntry.h" /> <ClInclude Include="include\nx\HandleTableSizeEntry.h" />

View file

@ -162,9 +162,6 @@
<ClInclude Include="include\nx\NsoHeader.h"> <ClInclude Include="include\nx\NsoHeader.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="include\nx\dynamic_symbol.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\nx\macro.h"> <ClInclude Include="include\nx\macro.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -186,6 +183,9 @@
<ClInclude Include="include\nx\nacp.h"> <ClInclude Include="include\nx\nacp.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="include\nx\elf.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="makefile" /> <None Include="makefile" />

View file

@ -171,7 +171,7 @@
<ClInclude Include="source\AesCtrWrappedIFile.h" /> <ClInclude Include="source\AesCtrWrappedIFile.h" />
<ClInclude Include="source\AssetProcess.h" /> <ClInclude Include="source\AssetProcess.h" />
<ClInclude Include="source\CnmtProcess.h" /> <ClInclude Include="source\CnmtProcess.h" />
<ClInclude Include="source\DynamicSymbolParser.h" /> <ClInclude Include="source\ElfSymbolParser.h" />
<ClInclude Include="source\HashTreeMeta.h" /> <ClInclude Include="source\HashTreeMeta.h" />
<ClInclude Include="source\HashTreeWrappedIFile.h" /> <ClInclude Include="source\HashTreeWrappedIFile.h" />
<ClInclude Include="source\NacpProcess.h" /> <ClInclude Include="source\NacpProcess.h" />
@ -182,6 +182,7 @@
<ClInclude Include="source\nstool.h" /> <ClInclude Include="source\nstool.h" />
<ClInclude Include="source\OffsetAdjustedIFile.h" /> <ClInclude Include="source\OffsetAdjustedIFile.h" />
<ClInclude Include="source\PfsProcess.h" /> <ClInclude Include="source\PfsProcess.h" />
<ClInclude Include="source\RoMetadataProcess.h" />
<ClInclude Include="source\RomfsProcess.h" /> <ClInclude Include="source\RomfsProcess.h" />
<ClInclude Include="source\SdkApiString.h" /> <ClInclude Include="source\SdkApiString.h" />
<ClInclude Include="source\UserSettings.h" /> <ClInclude Include="source\UserSettings.h" />
@ -192,7 +193,7 @@
<ClCompile Include="source\AesCtrWrappedIFile.cpp" /> <ClCompile Include="source\AesCtrWrappedIFile.cpp" />
<ClCompile Include="source\AssetProcess.cpp" /> <ClCompile Include="source\AssetProcess.cpp" />
<ClCompile Include="source\CnmtProcess.cpp" /> <ClCompile Include="source\CnmtProcess.cpp" />
<ClCompile Include="source\DynamicSymbolParser.cpp" /> <ClCompile Include="source\ElfSymbolParser.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" />
@ -203,6 +204,7 @@
<ClCompile Include="source\NsoProcess.cpp" /> <ClCompile Include="source\NsoProcess.cpp" />
<ClCompile Include="source\OffsetAdjustedIFile.cpp" /> <ClCompile Include="source\OffsetAdjustedIFile.cpp" />
<ClCompile Include="source\PfsProcess.cpp" /> <ClCompile Include="source\PfsProcess.cpp" />
<ClCompile Include="source\RoMetadataProcess.cpp" />
<ClCompile Include="source\RomfsProcess.cpp" /> <ClCompile Include="source\RomfsProcess.cpp" />
<ClCompile Include="source\SdkApiString.cpp" /> <ClCompile Include="source\SdkApiString.cpp" />
<ClCompile Include="source\UserSettings.cpp" /> <ClCompile Include="source\UserSettings.cpp" />

View file

@ -57,9 +57,6 @@
<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>
<ClInclude Include="source\AssetProcess.h"> <ClInclude Include="source\AssetProcess.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -72,6 +69,12 @@
<ClInclude Include="source\NacpProcess.h"> <ClInclude Include="source\NacpProcess.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="source\ElfSymbolParser.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="source\RoMetadataProcess.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="source\main.cpp"> <ClCompile Include="source\main.cpp">
@ -113,9 +116,6 @@
<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>
<ClCompile Include="source\AssetProcess.cpp"> <ClCompile Include="source\AssetProcess.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -128,6 +128,12 @@
<ClCompile Include="source\NacpProcess.cpp"> <ClCompile Include="source\NacpProcess.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="source\ElfSymbolParser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="source\RoMetadataProcess.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="makefile" /> <None Include="makefile" />

View file

@ -1,70 +0,0 @@
#include "DynamicSymbolParser.h"
DynamicSymbolParser::DynamicSymbolParser()
{
mDynSymbolList.clear();
}
bool DynamicSymbolParser::operator==(const DynamicSymbolParser& other) const
{
return isEqual(other);
}
bool DynamicSymbolParser::operator!=(const DynamicSymbolParser& other) const
{
return !isEqual(other);
}
void DynamicSymbolParser::operator=(const DynamicSymbolParser& other)
{
copyFrom(other);
}
void DynamicSymbolParser::parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit)
{
//printf("DynamicSymbolParser::parseData()");
size_t dynSymSize = is64Bit ? sizeof(nx::sDynSymbol64Bit) : sizeof(nx::sDynSymbol32Bit);
sDynSymbol symbol;
for (size_t i = 0; i < dyn_sym_size; i += dynSymSize)
{
//printf("pos %x\n", i);
uint32_t name_pos;
if (is64Bit)
{
name_pos = ((nx::sDynSymbol64Bit*)(dyn_sym + i))->name.get();
symbol.shn_index = (nx::dynsym::SpecialSectionIndex)((nx::sDynSymbol64Bit*)(dyn_sym + i))->special_section_index.get();
symbol.symbol_type = (nx::dynsym::SymbolType)((((nx::sDynSymbol64Bit*)(dyn_sym + i))->info) & nx::dynsym::STT_HIPROC);
}
else
{
name_pos = ((nx::sDynSymbol64Bit*)(dyn_sym + i))->name.get();
symbol.shn_index = (nx::dynsym::SpecialSectionIndex)((nx::sDynSymbol32Bit*)(dyn_sym + i))->special_section_index.get();
symbol.symbol_type = (nx::dynsym::SymbolType)((((nx::sDynSymbol32Bit*)(dyn_sym + i))->info.get()) & nx::dynsym::STT_HIPROC);
}
for (; dyn_str[name_pos] == 0x00 && name_pos < dyn_str_size; name_pos++);
//printf("name_pos = 0x%x\n", name_pos);
symbol.name = std::string((char*)&dyn_str[name_pos]);
mDynSymbolList.addElement(symbol);
}
//printf("DynamicSymbolParser::parseData() end\n");
}
const fnd::List<DynamicSymbolParser::sDynSymbol>& DynamicSymbolParser::getDynamicSymbolList() const
{
return mDynSymbolList;
}
bool DynamicSymbolParser::isEqual(const DynamicSymbolParser& other) const
{
return mDynSymbolList == other.mDynSymbolList;
}
void DynamicSymbolParser::copyFrom(const DynamicSymbolParser& other)
{
mDynSymbolList = other.mDynSymbolList;
}

View file

@ -1,49 +0,0 @@
#pragma once
#include <string>
#include <fnd/List.h>
#include <nx/dynamic_symbol.h>
class DynamicSymbolParser
{
public:
struct sDynSymbol
{
nx::dynsym::SpecialSectionIndex shn_index;
nx::dynsym::SymbolType symbol_type;
std::string name;
void operator=(const sDynSymbol& other)
{
shn_index = other.shn_index;
symbol_type = other.symbol_type;
name = other.name;
}
bool operator==(const sDynSymbol& other) const
{
return (shn_index == other.shn_index && symbol_type == other.symbol_type && name == other.name);
}
bool operator!=(const sDynSymbol& other) const
{
return !(*this == other);
}
};
DynamicSymbolParser();
bool operator==(const DynamicSymbolParser& other) const;
bool operator!=(const DynamicSymbolParser& other) const;
void operator=(const DynamicSymbolParser& other);
void parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit);
const fnd::List<sDynSymbol>& getDynamicSymbolList() const;
private:
// data
fnd::List<sDynSymbol> mDynSymbolList;
bool isEqual(const DynamicSymbolParser& other) const;
void copyFrom(const DynamicSymbolParser& other);
};

View file

@ -0,0 +1,72 @@
#include "ElfSymbolParser.h"
ElfSymbolParser::ElfSymbolParser()
{
mSymbolList.clear();
}
bool ElfSymbolParser::operator==(const ElfSymbolParser& other) const
{
return isEqual(other);
}
bool ElfSymbolParser::operator!=(const ElfSymbolParser& other) const
{
return !isEqual(other);
}
void ElfSymbolParser::operator=(const ElfSymbolParser& other)
{
copyFrom(other);
}
void ElfSymbolParser::parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit)
{
//printf("ElfSymbolParser::parseData()");
size_t dynSymSize = is64Bit ? sizeof(nx::sElfSymbol64Bit) : sizeof(nx::sElfSymbol32Bit);
sElfSymbol symbol;
for (size_t i = 0; i < dyn_sym_size; i += dynSymSize)
{
//printf("pos %x\n", i);
uint32_t name_pos;
if (is64Bit)
{
name_pos = ((nx::sElfSymbol64Bit*)(dyn_sym + i))->name.get();
symbol.shn_index = (nx::elf::SpecialSectionIndex)((nx::sElfSymbol64Bit*)(dyn_sym + i))->special_section_index.get();
symbol.symbol_type = (nx::elf::SymbolType)((((nx::sElfSymbol64Bit*)(dyn_sym + i))->info) & nx::elf::STT_HIPROC);
symbol.symbol_binding = (nx::elf::SymbolBinding)(((((nx::sElfSymbol64Bit*)(dyn_sym + i))->info) >> 4) & nx::elf::STB_HIPROC);
}
else
{
name_pos = ((nx::sElfSymbol64Bit*)(dyn_sym + i))->name.get();
symbol.shn_index = (nx::elf::SpecialSectionIndex)((nx::sElfSymbol32Bit*)(dyn_sym + i))->special_section_index.get();
symbol.symbol_type = (nx::elf::SymbolType)((((nx::sElfSymbol32Bit*)(dyn_sym + i))->info.get()) & nx::elf::STT_HIPROC);
symbol.symbol_binding = (nx::elf::SymbolBinding)(((((nx::sElfSymbol32Bit*)(dyn_sym + i))->info.get()) >> 4) & nx::elf::STB_HIPROC);
}
for (; dyn_str[name_pos] == 0x00 && name_pos < dyn_str_size; name_pos++);
//printf("name_pos = 0x%x\n", name_pos);
symbol.name = std::string((char*)&dyn_str[name_pos]);
mSymbolList.addElement(symbol);
}
//printf("ElfSymbolParser::parseData() end\n");
}
const fnd::List<ElfSymbolParser::sElfSymbol>& ElfSymbolParser::getSymbolList() const
{
return mSymbolList;
}
bool ElfSymbolParser::isEqual(const ElfSymbolParser& other) const
{
return mSymbolList == other.mSymbolList;
}
void ElfSymbolParser::copyFrom(const ElfSymbolParser& other)
{
mSymbolList = other.mSymbolList;
}

View file

@ -0,0 +1,51 @@
#pragma once
#include <string>
#include <fnd/List.h>
#include <nx/elf.h>
class ElfSymbolParser
{
public:
struct sElfSymbol
{
nx::elf::SpecialSectionIndex shn_index;
nx::elf::SymbolType symbol_type;
nx::elf::SymbolBinding symbol_binding;
std::string name;
void operator=(const sElfSymbol& other)
{
shn_index = other.shn_index;
symbol_type = other.symbol_type;
symbol_binding = other.symbol_binding;
name = other.name;
}
bool operator==(const sElfSymbol& other) const
{
return (shn_index == other.shn_index && symbol_type == other.symbol_type && symbol_binding == other.symbol_binding && name == other.name);
}
bool operator!=(const sElfSymbol& other) const
{
return !(*this == other);
}
};
ElfSymbolParser();
bool operator==(const ElfSymbolParser& other) const;
bool operator!=(const ElfSymbolParser& other) const;
void operator=(const ElfSymbolParser& other);
void parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit);
const fnd::List<sElfSymbol>& getSymbolList() const;
private:
// data
fnd::List<sElfSymbol> mSymbolList;
bool isEqual(const ElfSymbolParser& other) const;
void copyFrom(const ElfSymbolParser& other);
};

View file

@ -1,4 +1,3 @@
#include <sstream>
#include <fnd/SimpleTextOutput.h> #include <fnd/SimpleTextOutput.h>
#include <fnd/MemoryBlob.h> #include <fnd/MemoryBlob.h>
#include <compress/lz4.h> #include <compress/lz4.h>
@ -10,10 +9,7 @@ NroProcess::NroProcess():
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false), mVerify(false)
mInstructionType(nx::npdm::INSTR_64BIT),
mListApi(false),
mListSymbols(false)
{ {
} }
@ -34,12 +30,12 @@ void NroProcess::process()
importHeader(); importHeader();
importCodeSegments(); importCodeSegments();
importApiList();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{
displayHeader(); displayHeader();
displayRoMetaData();
} processRoMeta();
if (mIsHomebrewNro) if (mIsHomebrewNro)
mAssetProc.process(); mAssetProc.process();
} }
@ -62,17 +58,17 @@ void NroProcess::setVerifyMode(bool verify)
void NroProcess::setInstructionType(nx::npdm::InstructionType type) void NroProcess::setInstructionType(nx::npdm::InstructionType type)
{ {
mInstructionType = type; mRoMeta.setInstructionType(type);
} }
void NroProcess::setListApi(bool listApi) void NroProcess::setListApi(bool listApi)
{ {
mListApi = listApi; mRoMeta.setListApi(listApi);
} }
void NroProcess::setListSymbols(bool listSymbols) void NroProcess::setListSymbols(bool listSymbols)
{ {
mListSymbols = listSymbols; mRoMeta.setListSymbols(listSymbols);
} }
void NroProcess::setAssetListFs(bool list) void NroProcess::setAssetListFs(bool list)
@ -108,8 +104,8 @@ void NroProcess::importHeader()
mHdr.importBinary(scratch.getBytes(), scratch.getSize()); mHdr.importBinary(scratch.getBytes(), scratch.getSize());
// setup homebrew extension
nx::sNroHeader* raw_hdr = (nx::sNroHeader*)scratch.getBytes(); nx::sNroHeader* raw_hdr = (nx::sNroHeader*)scratch.getBytes();
if (((le_uint64_t*)raw_hdr->reserved_0)->get() == nx::nro::kNroHomebrewSig && mFile->size() > mHdr.getNroSize()) if (((le_uint64_t*)raw_hdr->reserved_0)->get() == nx::nro::kNroHomebrewSig && mFile->size() > mHdr.getNroSize())
{ {
mIsHomebrewNro = true; mIsHomebrewNro = true;
@ -119,7 +115,6 @@ void NroProcess::importHeader()
} }
else else
mIsHomebrewNro = false; mIsHomebrewNro = false;
} }
void NroProcess::importCodeSegments() void NroProcess::importCodeSegments()
@ -132,38 +127,6 @@ void NroProcess::importCodeSegments()
mFile->read(mDataBlob.getBytes(), mHdr.getDataInfo().memory_offset, mDataBlob.getSize()); mFile->read(mDataBlob.getBytes(), mHdr.getDataInfo().memory_offset, mDataBlob.getSize());
} }
void NroProcess::importApiList()
{
struct sLayout { size_t offset; size_t size; } api_info, dyn_str, dyn_sym;
api_info.offset = mHdr.getRoEmbeddedInfo().memory_offset;
api_info.size = mHdr.getRoEmbeddedInfo().size;
dyn_str.offset = mHdr.getRoDynStrInfo().memory_offset;
dyn_str.size = mHdr.getRoDynStrInfo().size;
dyn_sym.offset = mHdr.getRoDynSymInfo().memory_offset;
dyn_sym.size = mHdr.getRoDynSymInfo().size;
if (api_info.size > 0)
{
std::stringstream list_stream(std::string((char*)mRoBlob.getBytes() + api_info.offset, api_info.size));
std::string api;
while(std::getline(list_stream, api, (char)0x00))
{
mApiList.push_back(api);
}
}
else
{
mApiList.clear();
}
if (dyn_sym.size > 0)
{
mDynSymbolList.parseData(mRoBlob.getBytes() + dyn_sym.offset, dyn_sym.size, mRoBlob.getBytes() + dyn_str.offset, dyn_str.size, mInstructionType == nx::npdm::INSTR_64BIT);
}
}
void NroProcess::displayHeader() void NroProcess::displayHeader()
{ {
#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
@ -203,125 +166,16 @@ void NroProcess::displayHeader()
#undef _HEXDUMP_L #undef _HEXDUMP_L
} }
void NroProcess::displayRoMetaData() void NroProcess::processRoMeta()
{ {
if (mApiList.size() > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) if (mRoBlob.getSize())
{ {
printf("[SDK API List]\n"); // setup ro metadata
for (size_t i = 0; i < mApiList.size(); i++) mRoMeta.setApiInfo(mHdr.getRoEmbeddedInfo().memory_offset, mHdr.getRoEmbeddedInfo().size);
{ mRoMeta.setDynSym(mHdr.getRoDynSymInfo().memory_offset, mHdr.getRoDynSymInfo().size);
printf(" API %d:\n", (int)i); mRoMeta.setDynStr(mHdr.getRoDynStrInfo().memory_offset, mHdr.getRoDynStrInfo().size);
printf(" Type: %s\n", getApiTypeStr(mApiList[i].getApiType())); mRoMeta.setRoBinary(mRoBlob);
printf(" Vender: %s\n", mApiList[i].getVenderName().c_str()); mRoMeta.setCliOutputMode(mCliOutputMode);
printf(" Module: %s\n", mApiList[i].getModuleName().c_str()); mRoMeta.process();
}
} }
if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
{
printf("[Symbol List]\n");
for (size_t i = 0; i < mDynSymbolList.getDynamicSymbolList().getSize(); i++)
{
const DynamicSymbolParser::sDynSymbol& symbol = mDynSymbolList.getDynamicSymbolList()[i];
printf(" %s [SHN=%s (%04x)][STT=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type));
}
}
}
const char* NroProcess::getApiTypeStr(SdkApiString::ApiType type) const
{
const char* str;
switch (type)
{
case (SdkApiString::API_MIDDLEWARE):
str = "Middleware";
break;
case (SdkApiString::API_DEBUG):
str = "Debug";
break;
case (SdkApiString::API_PRIVATE):
str = "Private";
break;
case (SdkApiString::API_SDK_VERSION):
str = "SDK Version";
break;
default:
str = "UNKNOWN";
break;
}
return str;
}
const char* NroProcess::getSectionIndexStr(nx::dynsym::SpecialSectionIndex shn_index) const
{
const char* str;
switch (shn_index)
{
case (nx::dynsym::SHN_UNDEF):
str = "UNDEF";
break;
case (nx::dynsym::SHN_EXPORT):
str = "EXPORT";
break;
case (nx::dynsym::SHN_LOPROC):
str = "LOPROC";
break;
case (nx::dynsym::SHN_HIPROC):
str = "HIPROC";
break;
case (nx::dynsym::SHN_LOOS):
str = "LOOS";
break;
case (nx::dynsym::SHN_HIOS):
str = "HIOS";
break;
case (nx::dynsym::SHN_ABS):
str = "ABS";
break;
case (nx::dynsym::SHN_COMMON):
str = "COMMON";
break;
default:
str = "UNKNOWN";
break;
}
return str;
}
const char* NroProcess::getSymbolTypeStr(nx::dynsym::SymbolType symbol_type) const
{
const char* str;
switch (symbol_type)
{
case (nx::dynsym::STT_NOTYPE):
str = "NOTYPE";
break;
case (nx::dynsym::STT_OBJECT):
str = "OBJECT";
break;
case (nx::dynsym::STT_FUNC):
str = "FUNC";
break;
case (nx::dynsym::STT_SECTION):
str = "SECTION";
break;
case (nx::dynsym::STT_FILE):
str = "FILE";
break;
case (nx::dynsym::STT_LOOS):
str = "LOOS";
break;
case (nx::dynsym::STT_HIOS):
str = "HIOS";
break;
case (nx::dynsym::STT_LOPROC):
str = "LOPROC";
break;
case (nx::dynsym::STT_HIPROC):
str = "HIPROC";
break;
default:
str = "UNKNOWN";
break;
}
return str;
} }

View file

@ -8,8 +8,7 @@
#include "AssetProcess.h" #include "AssetProcess.h"
#include "nstool.h" #include "nstool.h"
#include "SdkApiString.h" #include "RoMetadataProcess.h"
#include "DynamicSymbolParser.h"
class NroProcess class NroProcess
{ {
@ -40,24 +39,15 @@ private:
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;
nx::npdm::InstructionType mInstructionType;
bool mListApi;
bool mListSymbols;
nx::NroHeader mHdr; nx::NroHeader mHdr;
fnd::MemoryBlob mTextBlob, mRoBlob, mDataBlob;
RoMetadataProcess mRoMeta;
bool mIsHomebrewNro; bool mIsHomebrewNro;
AssetProcess mAssetProc; AssetProcess mAssetProc;
fnd::MemoryBlob mTextBlob, mRoBlob, mDataBlob;
std::vector<SdkApiString> mApiList;
DynamicSymbolParser mDynSymbolList;
void importHeader(); void importHeader();
void importCodeSegments(); void importCodeSegments();
void importApiList();
void displayHeader(); void displayHeader();
void displayRoMetaData(); void processRoMeta();
const char* getApiTypeStr(SdkApiString::ApiType type) const;
const char* getSectionIndexStr(nx::dynsym::SpecialSectionIndex shn_index) const;
const char* getSymbolTypeStr(nx::dynsym::SymbolType symbol_type) const;
}; };

View file

@ -1,4 +1,3 @@
#include <sstream>
#include <fnd/SimpleTextOutput.h> #include <fnd/SimpleTextOutput.h>
#include <fnd/MemoryBlob.h> #include <fnd/MemoryBlob.h>
#include <compress/lz4.h> #include <compress/lz4.h>
@ -9,10 +8,7 @@ NsoProcess::NsoProcess():
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false), mVerify(false)
mInstructionType(nx::npdm::INSTR_64BIT),
mListApi(false),
mListSymbols(false)
{ {
} }
@ -33,12 +29,10 @@ void NsoProcess::process()
importHeader(); importHeader();
importCodeSegments(); importCodeSegments();
importApiList();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{
displayNsoHeader(); displayNsoHeader();
displayRoMetaData();
} processRoMeta();
} }
void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile) void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile)
@ -59,17 +53,17 @@ void NsoProcess::setVerifyMode(bool verify)
void NsoProcess::setInstructionType(nx::npdm::InstructionType type) void NsoProcess::setInstructionType(nx::npdm::InstructionType type)
{ {
mInstructionType = type; mRoMeta.setInstructionType(type);
} }
void NsoProcess::setListApi(bool listApi) void NsoProcess::setListApi(bool listApi)
{ {
mListApi = listApi; mRoMeta.setListApi(listApi);
} }
void NsoProcess::setListSymbols(bool listSymbols) void NsoProcess::setListSymbols(bool listSymbols)
{ {
mListSymbols = listSymbols; mRoMeta.setListSymbols(listSymbols);
} }
void NsoProcess::importHeader() void NsoProcess::importHeader()
@ -83,7 +77,7 @@ void NsoProcess::importHeader()
scratch.alloc(sizeof(nx::sNsoHeader)); scratch.alloc(sizeof(nx::sNsoHeader));
mFile->read(scratch.getBytes(), 0, scratch.getSize()); mFile->read(scratch.getBytes(), 0, scratch.getSize());
mNsoHdr.importBinary(scratch.getBytes(), scratch.getSize()); mHdr.importBinary(scratch.getBytes(), scratch.getSize());
} }
void NsoProcess::importCodeSegments() void NsoProcess::importCodeSegments()
@ -93,11 +87,11 @@ void NsoProcess::importCodeSegments()
crypto::sha::sSha256Hash calc_hash; crypto::sha::sSha256Hash calc_hash;
// process text segment // process text segment
if (mNsoHdr.getTextSegmentInfo().is_compressed) if (mHdr.getTextSegmentInfo().is_compressed)
{ {
scratch.alloc(mNsoHdr.getTextSegmentInfo().file_layout.size); scratch.alloc(mHdr.getTextSegmentInfo().file_layout.size);
mFile->read(scratch.getBytes(), mNsoHdr.getTextSegmentInfo().file_layout.offset, scratch.getSize()); mFile->read(scratch.getBytes(), mHdr.getTextSegmentInfo().file_layout.offset, scratch.getSize());
mTextBlob.alloc(mNsoHdr.getTextSegmentInfo().memory_layout.size); mTextBlob.alloc(mHdr.getTextSegmentInfo().memory_layout.size);
compress::lz4::decompressData(scratch.getBytes(), (uint32_t)scratch.getSize(), mTextBlob.getBytes(), (uint32_t)mTextBlob.getSize(), decompressed_len); compress::lz4::decompressData(scratch.getBytes(), (uint32_t)scratch.getSize(), mTextBlob.getBytes(), (uint32_t)mTextBlob.getSize(), decompressed_len);
if (decompressed_len != mTextBlob.getSize()) if (decompressed_len != mTextBlob.getSize())
{ {
@ -106,24 +100,24 @@ void NsoProcess::importCodeSegments()
} }
else else
{ {
mTextBlob.alloc(mNsoHdr.getTextSegmentInfo().file_layout.size); mTextBlob.alloc(mHdr.getTextSegmentInfo().file_layout.size);
mFile->read(mTextBlob.getBytes(), mNsoHdr.getTextSegmentInfo().file_layout.offset, mTextBlob.getSize()); mFile->read(mTextBlob.getBytes(), mHdr.getTextSegmentInfo().file_layout.offset, mTextBlob.getSize());
} }
if (mNsoHdr.getTextSegmentInfo().is_hashed) if (mHdr.getTextSegmentInfo().is_hashed)
{ {
crypto::sha::Sha256(mTextBlob.getBytes(), mTextBlob.getSize(), calc_hash.bytes); crypto::sha::Sha256(mTextBlob.getBytes(), mTextBlob.getSize(), calc_hash.bytes);
if (calc_hash != mNsoHdr.getTextSegmentInfo().hash) if (calc_hash != mHdr.getTextSegmentInfo().hash)
{ {
throw fnd::Exception(kModuleName, "NSO text segment failed SHA256 verification"); throw fnd::Exception(kModuleName, "NSO text segment failed SHA256 verification");
} }
} }
// process ro segment // process ro segment
if (mNsoHdr.getRoSegmentInfo().is_compressed) if (mHdr.getRoSegmentInfo().is_compressed)
{ {
scratch.alloc(mNsoHdr.getRoSegmentInfo().file_layout.size); scratch.alloc(mHdr.getRoSegmentInfo().file_layout.size);
mFile->read(scratch.getBytes(), mNsoHdr.getRoSegmentInfo().file_layout.offset, scratch.getSize()); mFile->read(scratch.getBytes(), mHdr.getRoSegmentInfo().file_layout.offset, scratch.getSize());
mRoBlob.alloc(mNsoHdr.getRoSegmentInfo().memory_layout.size); mRoBlob.alloc(mHdr.getRoSegmentInfo().memory_layout.size);
compress::lz4::decompressData(scratch.getBytes(), (uint32_t)scratch.getSize(), mRoBlob.getBytes(), (uint32_t)mRoBlob.getSize(), decompressed_len); compress::lz4::decompressData(scratch.getBytes(), (uint32_t)scratch.getSize(), mRoBlob.getBytes(), (uint32_t)mRoBlob.getSize(), decompressed_len);
if (decompressed_len != mRoBlob.getSize()) if (decompressed_len != mRoBlob.getSize())
{ {
@ -132,24 +126,24 @@ void NsoProcess::importCodeSegments()
} }
else else
{ {
mRoBlob.alloc(mNsoHdr.getRoSegmentInfo().file_layout.size); mRoBlob.alloc(mHdr.getRoSegmentInfo().file_layout.size);
mFile->read(mRoBlob.getBytes(), mNsoHdr.getRoSegmentInfo().file_layout.offset, mRoBlob.getSize()); mFile->read(mRoBlob.getBytes(), mHdr.getRoSegmentInfo().file_layout.offset, mRoBlob.getSize());
} }
if (mNsoHdr.getRoSegmentInfo().is_hashed) if (mHdr.getRoSegmentInfo().is_hashed)
{ {
crypto::sha::Sha256(mRoBlob.getBytes(), mRoBlob.getSize(), calc_hash.bytes); crypto::sha::Sha256(mRoBlob.getBytes(), mRoBlob.getSize(), calc_hash.bytes);
if (calc_hash != mNsoHdr.getRoSegmentInfo().hash) if (calc_hash != mHdr.getRoSegmentInfo().hash)
{ {
throw fnd::Exception(kModuleName, "NSO ro segment failed SHA256 verification"); throw fnd::Exception(kModuleName, "NSO ro segment failed SHA256 verification");
} }
} }
// process data segment // process data segment
if (mNsoHdr.getDataSegmentInfo().is_compressed) if (mHdr.getDataSegmentInfo().is_compressed)
{ {
scratch.alloc(mNsoHdr.getDataSegmentInfo().file_layout.size); scratch.alloc(mHdr.getDataSegmentInfo().file_layout.size);
mFile->read(scratch.getBytes(), mNsoHdr.getDataSegmentInfo().file_layout.offset, scratch.getSize()); mFile->read(scratch.getBytes(), mHdr.getDataSegmentInfo().file_layout.offset, scratch.getSize());
mDataBlob.alloc(mNsoHdr.getDataSegmentInfo().memory_layout.size); mDataBlob.alloc(mHdr.getDataSegmentInfo().memory_layout.size);
compress::lz4::decompressData(scratch.getBytes(), (uint32_t)scratch.getSize(), mDataBlob.getBytes(), (uint32_t)mDataBlob.getSize(), decompressed_len); compress::lz4::decompressData(scratch.getBytes(), (uint32_t)scratch.getSize(), mDataBlob.getBytes(), (uint32_t)mDataBlob.getSize(), decompressed_len);
if (decompressed_len != mDataBlob.getSize()) if (decompressed_len != mDataBlob.getSize())
{ {
@ -158,239 +152,99 @@ void NsoProcess::importCodeSegments()
} }
else else
{ {
mDataBlob.alloc(mNsoHdr.getDataSegmentInfo().file_layout.size); mDataBlob.alloc(mHdr.getDataSegmentInfo().file_layout.size);
mFile->read(mDataBlob.getBytes(), mNsoHdr.getDataSegmentInfo().file_layout.offset, mDataBlob.getSize()); mFile->read(mDataBlob.getBytes(), mHdr.getDataSegmentInfo().file_layout.offset, mDataBlob.getSize());
} }
if (mNsoHdr.getDataSegmentInfo().is_hashed) if (mHdr.getDataSegmentInfo().is_hashed)
{ {
crypto::sha::Sha256(mDataBlob.getBytes(), mDataBlob.getSize(), calc_hash.bytes); crypto::sha::Sha256(mDataBlob.getBytes(), mDataBlob.getSize(), calc_hash.bytes);
if (calc_hash != mNsoHdr.getDataSegmentInfo().hash) if (calc_hash != mHdr.getDataSegmentInfo().hash)
{ {
throw fnd::Exception(kModuleName, "NSO data segment failed SHA256 verification"); throw fnd::Exception(kModuleName, "NSO data segment failed SHA256 verification");
} }
} }
} }
void NsoProcess::importApiList()
{
struct sLayout { size_t offset; size_t size; } api_info, dyn_str, dyn_sym;
api_info.offset = mNsoHdr.getRoEmbeddedInfo().offset;
api_info.size = mNsoHdr.getRoEmbeddedInfo().size;
dyn_str.offset = mNsoHdr.getRoDynStrInfo().offset;
dyn_str.size = mNsoHdr.getRoDynStrInfo().size;
dyn_sym.offset = mNsoHdr.getRoDynSymInfo().offset;
dyn_sym.size = mNsoHdr.getRoDynSymInfo().size;
if (api_info.size > 0)
{
std::stringstream list_stream(std::string((char*)mRoBlob.getBytes() + api_info.offset, api_info.size));
std::string api;
while(std::getline(list_stream, api, (char)0x00))
{
mApiList.push_back(api);
}
}
else
{
mApiList.clear();
}
if (dyn_sym.size > 0)
{
mDynSymbolList.parseData(mRoBlob.getBytes() + dyn_sym.offset, dyn_sym.size, mRoBlob.getBytes() + dyn_str.offset, dyn_str.size, mInstructionType == nx::npdm::INSTR_64BIT);
}
}
void NsoProcess::displayNsoHeader() void NsoProcess::displayNsoHeader()
{ {
#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
printf("[NSO Header]\n"); printf("[NSO Header]\n");
printf(" ModuleId: "); printf(" ModuleId: ");
_HEXDUMP_L(mNsoHdr.getModuleId().data, nx::nso::kModuleIdSize); _HEXDUMP_L(mHdr.getModuleId().data, nx::nso::kModuleIdSize);
printf("\n"); printf("\n");
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
printf(" Program Segments:\n"); {
printf(" .module_name:\n"); printf(" Program Segments:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getModuleNameInfo().offset); printf(" .module_name:\n");
printf(" FileSize: 0x%" PRIx32 "\n", mNsoHdr.getModuleNameInfo().size); printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().offset);
printf(" .text:\n"); printf(" FileSize: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().size);
printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().file_layout.offset); printf(" .text:\n");
printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getTextSegmentInfo().file_layout.size, mNsoHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : ""); printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().file_layout.offset);
printf(" .ro:\n"); printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getTextSegmentInfo().file_layout.size, mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : "");
printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().file_layout.offset); printf(" .ro:\n");
printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getRoSegmentInfo().file_layout.size, mNsoHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : ""); printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().file_layout.offset);
printf(" .data:\n"); printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getRoSegmentInfo().file_layout.size, mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : "");
printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().file_layout.offset); printf(" .data:\n");
printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getDataSegmentInfo().file_layout.size, mNsoHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : ""); printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().file_layout.offset);
printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getDataSegmentInfo().file_layout.size, mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : "");
}
printf(" Program Sections:\n"); printf(" Program Sections:\n");
printf(" .text:\n"); printf(" .text:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().memory_layout.offset); printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().memory_layout.size); printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.size);
if (mNsoHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" Hash: "); printf(" Hash: ");
_HEXDUMP_L(mNsoHdr.getTextSegmentInfo().hash.bytes, 32); _HEXDUMP_L(mHdr.getTextSegmentInfo().hash.bytes, 32);
printf("\n"); printf("\n");
} }
printf(" .ro:\n"); printf(" .ro:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().memory_layout.offset); printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().memory_layout.size); printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.size);
if (mNsoHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" Hash: "); printf(" Hash: ");
_HEXDUMP_L(mNsoHdr.getRoSegmentInfo().hash.bytes, 32); _HEXDUMP_L(mHdr.getRoSegmentInfo().hash.bytes, 32);
printf("\n"); printf("\n");
} }
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" .api_info:\n"); printf(" .api_info:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoEmbeddedInfo().offset); printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoEmbeddedInfo().size); printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size);
printf(" .dynstr:\n"); printf(" .dynstr:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoDynStrInfo().offset); printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoDynStrInfo().size); printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size);
printf(" .dynsym:\n"); printf(" .dynsym:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoDynSymInfo().offset); printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoDynSymInfo().size); printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size);
} }
printf(" .data:\n"); printf(" .data:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().memory_layout.offset); printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().memory_layout.size); printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.size);
if (mNsoHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) if (mHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{ {
printf(" Hash: "); printf(" Hash: ");
_HEXDUMP_L(mNsoHdr.getDataSegmentInfo().hash.bytes, 32); _HEXDUMP_L(mHdr.getDataSegmentInfo().hash.bytes, 32);
printf("\n"); printf("\n");
} }
printf(" .bss:\n"); printf(" .bss:\n");
printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getBssSize()); printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getBssSize());
#undef _HEXDUMP_L #undef _HEXDUMP_L
} }
void NsoProcess::displayRoMetaData() void NsoProcess::processRoMeta()
{ {
if (mApiList.size() > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) if (mRoBlob.getSize())
{ {
printf("[SDK API List]\n"); // setup ro metadata
for (size_t i = 0; i < mApiList.size(); i++) mRoMeta.setApiInfo(mHdr.getRoEmbeddedInfo().offset, mHdr.getRoEmbeddedInfo().size);
{ mRoMeta.setDynSym(mHdr.getRoDynSymInfo().offset, mHdr.getRoDynSymInfo().size);
printf(" API %d:\n", (int)i); mRoMeta.setDynStr(mHdr.getRoDynStrInfo().offset, mHdr.getRoDynStrInfo().size);
printf(" Type: %s\n", getApiTypeStr(mApiList[i].getApiType())); mRoMeta.setRoBinary(mRoBlob);
printf(" Vender: %s\n", mApiList[i].getVenderName().c_str()); mRoMeta.setCliOutputMode(mCliOutputMode);
printf(" Module: %s\n", mApiList[i].getModuleName().c_str()); mRoMeta.process();
}
} }
if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
{
printf("[Symbol List]\n");
for (size_t i = 0; i < mDynSymbolList.getDynamicSymbolList().getSize(); i++)
{
const DynamicSymbolParser::sDynSymbol& symbol = mDynSymbolList.getDynamicSymbolList()[i];
printf(" %s [SHN=%s (%04x)][STT=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type));
}
}
}
const char* NsoProcess::getApiTypeStr(SdkApiString::ApiType type) const
{
const char* str;
switch (type)
{
case (SdkApiString::API_MIDDLEWARE):
str = "Middleware";
break;
case (SdkApiString::API_DEBUG):
str = "Debug";
break;
case (SdkApiString::API_PRIVATE):
str = "Private";
break;
case (SdkApiString::API_SDK_VERSION):
str = "SDK Version";
break;
default:
str = "UNKNOWN";
break;
}
return str;
}
const char* NsoProcess::getSectionIndexStr(nx::dynsym::SpecialSectionIndex shn_index) const
{
const char* str;
switch (shn_index)
{
case (nx::dynsym::SHN_UNDEF):
str = "UNDEF";
break;
case (nx::dynsym::SHN_EXPORT):
str = "EXPORT";
break;
case (nx::dynsym::SHN_LOPROC):
str = "LOPROC";
break;
case (nx::dynsym::SHN_HIPROC):
str = "HIPROC";
break;
case (nx::dynsym::SHN_LOOS):
str = "LOOS";
break;
case (nx::dynsym::SHN_HIOS):
str = "HIOS";
break;
case (nx::dynsym::SHN_ABS):
str = "ABS";
break;
case (nx::dynsym::SHN_COMMON):
str = "COMMON";
break;
default:
str = "UNKNOWN";
break;
}
return str;
}
const char* NsoProcess::getSymbolTypeStr(nx::dynsym::SymbolType symbol_type) const
{
const char* str;
switch (symbol_type)
{
case (nx::dynsym::STT_NOTYPE):
str = "NOTYPE";
break;
case (nx::dynsym::STT_OBJECT):
str = "OBJECT";
break;
case (nx::dynsym::STT_FUNC):
str = "FUNC";
break;
case (nx::dynsym::STT_SECTION):
str = "SECTION";
break;
case (nx::dynsym::STT_FILE):
str = "FILE";
break;
case (nx::dynsym::STT_LOOS):
str = "LOOS";
break;
case (nx::dynsym::STT_HIOS):
str = "HIOS";
break;
case (nx::dynsym::STT_LOPROC):
str = "LOPROC";
break;
case (nx::dynsym::STT_HIPROC):
str = "HIPROC";
break;
default:
str = "UNKNOWN";
break;
}
return str;
} }

View file

@ -7,8 +7,7 @@
#include <nx/NsoHeader.h> #include <nx/NsoHeader.h>
#include "nstool.h" #include "nstool.h"
#include "SdkApiString.h" #include "RoMetadataProcess.h"
#include "DynamicSymbolParser.h"
class NsoProcess class NsoProcess
{ {
@ -37,18 +36,12 @@ private:
bool mListApi; bool mListApi;
bool mListSymbols; bool mListSymbols;
nx::NsoHeader mNsoHdr; nx::NsoHeader mHdr;
fnd::MemoryBlob mTextBlob, mRoBlob, mDataBlob; fnd::MemoryBlob mTextBlob, mRoBlob, mDataBlob;
std::vector<SdkApiString> mApiList; RoMetadataProcess mRoMeta;
DynamicSymbolParser mDynSymbolList;
void importHeader(); void importHeader();
void importCodeSegments(); void importCodeSegments();
void importApiList();
void displayNsoHeader(); void displayNsoHeader();
void displayRoMetaData(); void processRoMeta();
const char* getApiTypeStr(SdkApiString::ApiType type) const;
const char* getSectionIndexStr(nx::dynsym::SpecialSectionIndex shn_index) const;
const char* getSymbolTypeStr(nx::dynsym::SymbolType symbol_type) const;
}; };

View file

@ -0,0 +1,255 @@
#include <sstream>
#include <fnd/types.h>
#include "RoMetadataProcess.h"
RoMetadataProcess::RoMetadataProcess() :
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mInstructionType(nx::npdm::INSTR_64BIT),
mListApi(false),
mListSymbols(false),
mApiInfo(),
mDynSym(),
mDynStr(),
mRoBlob(),
mSdkVerApiList(),
mPublicApiList(),
mDebugApiList(),
mPrivateApiList(),
mSymbolList()
{
}
void RoMetadataProcess::process()
{
if (mRoBlob.getSize() == 0)
{
throw fnd::Exception(kModuleName, "No ro binary set.");
}
importApiList();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
displayRoMetaData();
}
void RoMetadataProcess::setRoBinary(const fnd::MemoryBlob& bin)
{
mRoBlob = bin;
}
void RoMetadataProcess::setApiInfo(size_t offset, size_t size)
{
mApiInfo.offset = offset;
mApiInfo.size = size;
}
void RoMetadataProcess::setDynSym(size_t offset, size_t size)
{
mDynSym.offset = offset;
mDynSym.size = size;
}
void RoMetadataProcess::setDynStr(size_t offset, size_t size)
{
mDynStr.offset = offset;
mDynStr.size = size;
}
void RoMetadataProcess::setCliOutputMode(CliOutputMode type)
{
mCliOutputMode = type;
}
void RoMetadataProcess::setInstructionType(nx::npdm::InstructionType type)
{
mInstructionType = type;
}
void RoMetadataProcess::setListApi(bool listApi)
{
mListApi = listApi;
}
void RoMetadataProcess::setListSymbols(bool listSymbols)
{
mListSymbols = listSymbols;
}
void RoMetadataProcess::importApiList()
{
if (mApiInfo.size > 0)
{
std::stringstream list_stream(std::string((char*)mRoBlob.getBytes() + mApiInfo.offset, mApiInfo.size));
std::string api_str;
while(std::getline(list_stream, api_str, (char)0x00))
{
SdkApiString api(api_str);
if (api.getApiType() == SdkApiString::API_SDK_VERSION)
mSdkVerApiList.push_back(api);
else if (api.getApiType() == SdkApiString::API_MIDDLEWARE)
mPublicApiList.push_back(api);
else if (api.getApiType() == SdkApiString::API_DEBUG)
mDebugApiList.push_back(api);
else if (api.getApiType() == SdkApiString::API_PRIVATE)
mPrivateApiList.push_back(api);
}
}
if (mDynSym.size > 0)
{
mSymbolList.parseData(mRoBlob.getBytes() + mDynSym.offset, mDynSym.size, mRoBlob.getBytes() + mDynStr.offset, mDynStr.size, mInstructionType == nx::npdm::INSTR_64BIT);
}
}
void RoMetadataProcess::displayRoMetaData()
{
size_t api_num = mSdkVerApiList.size() + mPublicApiList.size() + mDebugApiList.size() + mPrivateApiList.size();
if (api_num > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
{
printf("[SDK API List]\n");
if (mSdkVerApiList.size() > 0)
{
printf(" Sdk Revision: %s\n", mSdkVerApiList[0].getModuleName().c_str());
}
if (mPublicApiList.size() > 0)
{
printf(" Public APIs:\n");
for (size_t i = 0; i < mPublicApiList.size(); i++)
{
printf(" %s (vender: %s)\n", mPublicApiList[i].getModuleName().c_str(), mPublicApiList[i].getVenderName().c_str());
}
}
if (mDebugApiList.size() > 0)
{
printf(" Debug APIs:\n");
for (size_t i = 0; i < mDebugApiList.size(); i++)
{
printf(" %s (vender: %s)\n", mDebugApiList[i].getModuleName().c_str(), mDebugApiList[i].getVenderName().c_str());
}
}
if (mPrivateApiList.size() > 0)
{
printf(" Private APIs:\n");
for (size_t i = 0; i < mPrivateApiList.size(); i++)
{
printf(" %s (vender: %s)\n", mPrivateApiList[i].getModuleName().c_str(), mPrivateApiList[i].getVenderName().c_str());
}
}
}
if (mSymbolList.getSymbolList().getSize() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
{
printf("[Symbol List]\n");
for (size_t i = 0; i < mSymbolList.getSymbolList().getSize(); i++)
{
const ElfSymbolParser::sElfSymbol& symbol = mSymbolList.getSymbolList()[i];
printf(" %s [SHN=%s (%04x)][STT=%s][STB=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type), getSymbolBindingStr(symbol.symbol_binding));
}
}
}
const char* RoMetadataProcess::getSectionIndexStr(nx::elf::SpecialSectionIndex shn_index) const
{
const char* str;
switch (shn_index)
{
case (nx::elf::SHN_UNDEF):
str = "UNDEF";
break;
case (nx::elf::SHN_LOPROC):
str = "LOPROC";
break;
case (nx::elf::SHN_HIPROC):
str = "HIPROC";
break;
case (nx::elf::SHN_LOOS):
str = "LOOS";
break;
case (nx::elf::SHN_HIOS):
str = "HIOS";
break;
case (nx::elf::SHN_ABS):
str = "ABS";
break;
case (nx::elf::SHN_COMMON):
str = "COMMON";
break;
default:
str = "UNKNOWN";
break;
}
return str;
}
const char* RoMetadataProcess::getSymbolTypeStr(nx::elf::SymbolType symbol_type) const
{
const char* str;
switch (symbol_type)
{
case (nx::elf::STT_NOTYPE):
str = "NOTYPE";
break;
case (nx::elf::STT_OBJECT):
str = "OBJECT";
break;
case (nx::elf::STT_FUNC):
str = "FUNC";
break;
case (nx::elf::STT_SECTION):
str = "SECTION";
break;
case (nx::elf::STT_FILE):
str = "FILE";
break;
case (nx::elf::STT_LOOS):
str = "LOOS";
break;
case (nx::elf::STT_HIOS):
str = "HIOS";
break;
case (nx::elf::STT_LOPROC):
str = "LOPROC";
break;
case (nx::elf::STT_HIPROC):
str = "HIPROC";
break;
default:
str = "UNKNOWN";
break;
}
return str;
}
const char* RoMetadataProcess::getSymbolBindingStr(nx::elf::SymbolBinding symbol_binding) const
{
const char* str;
switch (symbol_binding)
{
case (nx::elf::STB_LOCAL):
str = "LOCAL";
break;
case (nx::elf::STB_GLOBAL):
str = "GLOBAL";
break;
case (nx::elf::STB_WEAK):
str = "WEAK";
break;
case (nx::elf::STB_LOOS):
str = "LOOS";
break;
case (nx::elf::STB_HIOS):
str = "HIOS";
break;
case (nx::elf::STB_LOPROC):
str = "LOPROC";
break;
case (nx::elf::STB_HIPROC):
str = "HIPROC";
break;
default:
str = "UNKNOWN";
break;
}
return str;
}

View file

@ -0,0 +1,62 @@
#pragma once
#include <vector>
#include <string>
#include <fnd/types.h>
#include <fnd/MemoryBlob.h>
#include <nx/npdm.h>
#include "nstool.h"
#include "SdkApiString.h"
#include "ElfSymbolParser.h"
class RoMetadataProcess
{
public:
RoMetadataProcess();
void process();
void setRoBinary(const fnd::MemoryBlob& bin);
void setApiInfo(size_t offset, size_t size);
void setDynSym(size_t offset, size_t size);
void setDynStr(size_t offset, size_t size);
void setCliOutputMode(CliOutputMode type);
void setInstructionType(nx::npdm::InstructionType type);
void setListApi(bool listApi);
void setListSymbols(bool listSymbols);
private:
const std::string kModuleName = "RoMetadataProcess";
CliOutputMode mCliOutputMode;
nx::npdm::InstructionType mInstructionType;
bool mListApi;
bool mListSymbols;
struct sLayout
{
sLayout() : offset(0), size(0) {}
size_t offset;
size_t size;
};
sLayout mApiInfo;
sLayout mDynSym;
sLayout mDynStr;
fnd::MemoryBlob mRoBlob;
std::vector<SdkApiString> mSdkVerApiList;
std::vector<SdkApiString> mPublicApiList;
std::vector<SdkApiString> mDebugApiList;
std::vector<SdkApiString> mPrivateApiList;
ElfSymbolParser mSymbolList;
void importApiList();
void displayRoMetaData();
const char* getSectionIndexStr(nx::elf::SpecialSectionIndex shn_index) const;
const char* getSymbolTypeStr(nx::elf::SymbolType symbol_type) const;
const char* getSymbolBindingStr(nx::elf::SymbolBinding symbol_binding) const;
};