1 #include "dotnet_reader.h"
2 #include "dotnet.h"
3
4 #define IS_STREAM_VALID(s) (s && s->Offset)
5
6 namespace REDasm {
7
DotNetReader(ImageCor20MetaData * cormetadata)8 DotNetReader::DotNetReader(ImageCor20MetaData *cormetadata): m_cormetadata(cormetadata), m_cortablesheader(nullptr)
9 {
10 REDasm::log(".NET Version: " + PeDotNet::getVersion(cormetadata));
11 ImageStreamHeader* streamheader = PeDotNet::getStream(cormetadata, "#~");
12
13 if(!IS_STREAM_VALID(streamheader))
14 return;
15
16 m_cortablesheader = REDasm::relpointer<ImageCor20TablesHeader>(cormetadata, streamheader->Offset);
17 PeDotNet::getTables(m_cortablesheader, m_cortables);
18
19 streamheader = PeDotNet::getStream(cormetadata, "#Strings");
20
21 if(!IS_STREAM_VALID(streamheader))
22 return;
23
24 m_corstrings = REDasm::relpointer<char>(cormetadata, streamheader->Offset);
25 }
26
iterateTypes(const MethodCallback & cbmethods) const27 void DotNetReader::iterateTypes(const MethodCallback& cbmethods) const
28 {
29 const CorTableRows& cortdrows = this->getTableRows(CorMetadataTables::TypeDef);
30 const CorTableRows& cormdrows = this->getTableRows(CorMetadataTables::MethodDef);
31
32 for(auto it = cortdrows.begin(); it != cortdrows.end(); it++)
33 {
34 u32 c = this->getListCount(it, cortdrows, static_cast<u32>(cormdrows.size()), [](const CorTablePtr& cortable) -> u32 {
35 return cortable->typeDef.methodList + 1; // "methodList" is the last index
36 });
37
38 this->iterateMethods(*it, c, cbmethods);
39 }
40 }
41
isValid() const42 bool DotNetReader::isValid() const
43 {
44 ImageStreamHeader* streamheader = PeDotNet::getStream(m_cormetadata, "#~");
45
46 if(!streamheader || !streamheader->Offset)
47 return false;
48
49 return true;
50 }
51
getTableRows(u32 cortable) const52 const CorTableRows &DotNetReader::getTableRows(u32 cortable) const { return m_cortables.items.at(cortable); }
53
buildType(std::string & dest,u32 stringidx) const54 void DotNetReader::buildType(std::string &dest, u32 stringidx) const
55 {
56 std::string s = this->getString(stringidx);
57
58 if(s.front() != '.' && !dest.empty() && (dest.back() != '.'))
59 dest += ".";
60
61 dest += s;
62 }
63
iterateMethods(const CorTablePtr & cortypedef,u32 methodcount,const MethodCallback & cbmethods) const64 void DotNetReader::iterateMethods(const CorTablePtr& cortypedef, u32 methodcount, const MethodCallback& cbmethods) const
65 {
66 std::string tname;
67
68 if(cortypedef->typeDef.typeNamespace)
69 this->buildType(tname, cortypedef->typeDef.typeNamespace);
70
71 this->buildType(tname, cortypedef->typeDef.typeName);
72
73 const CorTableRows& cormdrows = this->getTableRows(CorMetadataTables::MethodDef);
74 auto it = cormdrows.begin();
75 std::advance(it, DOTNET_INDEX(cortypedef->typeDef.methodList));
76
77 for(u32 i = 0; (it != cormdrows.end()) && (i < methodcount); it++, i++)
78 {
79 std::string mname = tname;
80 this->buildType(mname, (*it)->methodDef.name);
81 cbmethods((*it)->methodDef.rva, mname + "()");
82 }
83 }
84
getListCount(CorTableRows::const_iterator rowsit,const CorTableRows & cortablerows,u32 maxrows,const IndexCallback & cbindex) const85 u32 DotNetReader::getListCount(CorTableRows::const_iterator rowsit, const CorTableRows& cortablerows, u32 maxrows, const IndexCallback& cbindex) const
86 {
87 u32 index = cbindex(*rowsit), lastindex = 0;
88 rowsit++;
89
90 if(rowsit != cortablerows.end())
91 lastindex = std::min(maxrows, cbindex(*rowsit));
92 else
93 lastindex = maxrows;
94
95 return lastindex - index;
96 }
97
getString(u32 index) const98 std::string DotNetReader::getString(u32 index) const
99 {
100 if(!index)
101 return "string_null";
102
103 if(!m_corstrings)
104 return "string_" + std::to_string(index);
105
106 return m_corstrings + index;
107 }
108
109 } // namespace REDasm
110