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