1 #include "pe_classifier.h"
2 #include "borland/borland_types.h"
3 #include "borland/borland_version.h"
4 
5 namespace REDasm {
6 
PEClassifier()7 PEClassifier::PEClassifier(): m_classification(PEClassifications::Unclassified), m_bits(0) { }
signatures() const8 const std::unordered_set<std::string> &PEClassifier::signatures() const { return m_signatures; }
9 
checkVisualBasic() const10 size_t PEClassifier::checkVisualBasic() const
11 {
12     if((m_classification == PEClassifications::VisualBasic_5) || (m_classification == PEClassifications::VisualBasic_6))
13         return m_classification;
14 
15     return PEClassifications::Unclassified;
16 }
17 
checkDotNet() const18 size_t PEClassifier::checkDotNet() const
19 {
20     if((m_classification == PEClassifications::DotNet_1) || (m_classification == PEClassifications::DotNet))
21         return m_classification;
22 
23     return PEClassifications::Unclassified;
24 }
25 
checkVisualStudio() const26 size_t PEClassifier::checkVisualStudio() const
27 {
28     if((m_classification >= PEClassifications::VisualStudio) && (m_classification <= PEClassifications::VisualStudio_2017))
29         return m_classification;
30 
31     return PEClassifications::Unclassified;
32 }
33 
checkBorland() const34 size_t PEClassifier::checkBorland() const
35 {
36     if((m_classification == PEClassifications::BorlandDelphi) || (m_classification == PEClassifications::BorlandCpp))
37         return m_classification;
38 
39     return PEClassifications::Unclassified;
40 }
41 
checkDelphi() const42 size_t PEClassifier::checkDelphi() const
43 {
44     if((m_classification >= PEClassifications::BorlandDelphi) && (m_classification <= PEClassifications::BorlandDelphi_XE2_6))
45         return m_classification;
46 
47     return PEClassifications::Unclassified;
48 }
49 
bits() const50 size_t PEClassifier::bits() const { return m_bits; }
setBits(size_t bits)51 void PEClassifier::setBits(size_t bits) { m_bits = bits; }
52 
classifyVisualStudio()53 void PEClassifier::classifyVisualStudio()
54 {
55     if(this->isClassified())
56         return;
57 
58     m_classification = PEClassifications::VisualStudio;
59 }
60 
classifyDotNet(ImageCorHeader * corheader)61 void PEClassifier::classifyDotNet(ImageCorHeader *corheader)
62 {
63     if(!corheader || (corheader->cb < sizeof(ImageCorHeader)))
64         return;
65 
66     if(corheader->MajorRuntimeVersion == 1)
67         m_classification = PEClassifications::DotNet_1;
68     else
69         m_classification = PEClassifications::DotNet;
70 }
71 
classifyImport(const std::string & library)72 void PEClassifier::classifyImport(const std::string& library)
73 {
74     if(REDasm::startsWith(library, "msvbvm50"))
75         m_classification = PEClassifications::VisualBasic_5;
76     else if(REDasm::startsWith(library, "msvbvm60"))
77         m_classification = PEClassifications::VisualBasic_6;
78 
79     if((this->checkVisualBasic() || this->isClassified()) && (m_classification != PEClassifications::VisualStudio))
80         return;
81 
82     if(REDasm::startsWith(library, "msvcp50"))
83         m_classification = PEClassifications::VisualStudio_5;
84     else if(REDasm::startsWith(library, "msvcp60") || REDasm::startsWith(library, "msvcrt."))
85         m_classification = PEClassifications::VisualStudio_6;
86     else if(REDasm::startsWith(library, "msvcp70") || REDasm::startsWith(library, "msvcr70"))
87         m_classification = PEClassifications::VisualStudio_2002;
88     else if(REDasm::startsWith(library, "msvcp71") || REDasm::startsWith(library, "msvcr71"))
89         m_classification = PEClassifications::VisualStudio_2003;
90     else if(REDasm::startsWith(library, "msvcp80") || REDasm::startsWith(library, "msvcr80"))
91         m_classification = PEClassifications::VisualStudio_2005;
92     else if(REDasm::startsWith(library, "msvcp90") || REDasm::startsWith(library, "msvcr90"))
93         m_classification = PEClassifications::VisualStudio_2008;
94     else if(REDasm::startsWith(library, "msvcp100") || REDasm::startsWith(library, "msvcr100"))
95         m_classification = PEClassifications::VisualStudio_2010;
96     else if(REDasm::startsWith(library, "msvcp110") || REDasm::startsWith(library, "msvcr110"))
97         m_classification = PEClassifications::VisualStudio_2012;
98     else if(REDasm::startsWith(library, "msvcp120") || REDasm::startsWith(library, "msvcr120"))
99         m_classification = PEClassifications::VisualStudio_2013;
100     else if(REDasm::startsWith(library, "msvcp140") || REDasm::startsWith(library, "vcruntime140"))
101         m_classification = PEClassifications::VisualStudio_2015;
102 }
103 
classifyDelphi(ImageDosHeader * dosheader,const ImageNtHeaders * ntheaders,const PEResources & peresources)104 void PEClassifier::classifyDelphi(ImageDosHeader* dosheader, const ImageNtHeaders* ntheaders, const PEResources &peresources)
105 {
106     PEResources::ResourceItem ri = peresources.find(PEResources::RCDATA);
107 
108     if(!ri.second)
109         return;
110 
111     ri = peresources.find("PACKAGEINFO", ri);
112 
113     if(!ri.second)
114         return;
115 
116     u64 datasize = 0;
117     PackageInfoHeader* packageinfo = peresources.data<PackageInfoHeader>(ri, dosheader, ntheaders, &datasize);
118 
119     if(!packageinfo)
120     {
121         REDasm::problem("Cannot parse 'PACKAGEINFO' header");
122         return;
123     }
124 
125     BorlandVersion borlandver(packageinfo, ri, datasize);
126 
127     if(borlandver.isDelphi())
128     {
129         m_borlandsignature = borlandver.getSignature();
130 
131         if(m_borlandsignature == "delphi3")
132             m_classification = PEClassifications::BorlandDelphi_3;
133         else if(m_borlandsignature == "delphiXE2_6")
134             m_classification = PEClassifications::BorlandDelphi_XE2_6;
135         else if(m_borlandsignature == "delphiXE")
136             m_classification = PEClassifications::BorlandDelphi_XE;
137         else if(m_borlandsignature == "delphi9_10")
138             m_classification = PEClassifications::BorlandDelphi_9_10;
139         else if(m_borlandsignature == "delphi6")
140             m_classification = PEClassifications::BorlandDelphi_6;
141         else if(m_borlandsignature == "delphi6")
142             m_classification = PEClassifications::BorlandDelphi_7;
143         else
144             m_classification = PEClassifications::BorlandDelphi;
145     }
146     else if(borlandver.isCpp())
147         m_classification = PEClassifications::BorlandCpp;
148 }
149 
classify(const ImageNtHeaders * ntheaders)150 void PEClassifier::classify(const ImageNtHeaders *ntheaders)
151 {
152     if(this->checkVisualStudio() || !this->isClassified())
153     {
154         if(ntheaders->OptionalHeaderMagic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
155             this->checkLinkerVersion(ntheaders->OptionalHeader64.MajorLinkerVersion, ntheaders->OptionalHeader64.MinorLinkerVersion);
156         else
157             this->checkLinkerVersion(ntheaders->OptionalHeader32.MajorLinkerVersion, ntheaders->OptionalHeader32.MinorLinkerVersion);
158     }
159 
160     if(this->checkBorland())
161         this->addSignature(m_borlandsignature);
162     else if(m_classification == PEClassifications::VisualStudio_6)
163         this->addSignature("msvc6");
164     else if(m_classification == PEClassifications::VisualStudio_2003)
165         this->addSignature("msvc2003");
166     else if(m_classification == PEClassifications::VisualStudio_2005)
167         this->addSignature("msvc2005");
168     else if(m_classification == PEClassifications::VisualStudio_2008)
169         this->addSignature("msvc2008");
170     else if(m_classification == PEClassifications::VisualStudio_2017)
171         this->addSignature("msvc2017");
172 }
173 
display()174 void PEClassifier::display()
175 {
176     if(m_classification == PEClassifications::VisualBasic_5)
177         REDasm::log("PE Classification: Visual Basic 5");
178     else if(m_classification == PEClassifications::VisualBasic_6)
179         REDasm::log("PE Classification: Visual Basic 6");
180     else if(m_classification == PEClassifications::VisualStudio)
181         REDasm::log("PE Classification: Visual Studio");
182     else if(m_classification == PEClassifications::VisualStudio_4)
183         REDasm::log("PE Classification: Visual Studio 4");
184     else if(m_classification == PEClassifications::VisualStudio_5)
185         REDasm::log("PE Classification: Visual Studio 5");
186     else if(m_classification == PEClassifications::VisualStudio_6)
187         REDasm::log("PE Classification: Visual Studio 6");
188     else if(m_classification == PEClassifications::VisualStudio_2002)
189         REDasm::log("PE Classification: Visual Studio 2002");
190     else if(m_classification == PEClassifications::VisualStudio_2003)
191         REDasm::log("PE Classification: Visual Studio 2003");
192     else if(m_classification == PEClassifications::VisualStudio_2005)
193         REDasm::log("PE Classification: Visual Studio 2005");
194     else if(m_classification == PEClassifications::VisualStudio_2008)
195         REDasm::log("PE Classification: Visual Studio 2008");
196     else if(m_classification == PEClassifications::VisualStudio_2010)
197         REDasm::log("PE Classification: Visual Studio 2010");
198     else if(m_classification == PEClassifications::VisualStudio_2012)
199         REDasm::log("PE Classification: Visual Studio 2012");
200     else if(m_classification == PEClassifications::VisualStudio_2013)
201         REDasm::log("PE Classification: Visual Studio 2013");
202     else if(m_classification == PEClassifications::VisualStudio_2015)
203         REDasm::log("PE Classification: Visual Studio 2015");
204     else if(m_classification == PEClassifications::VisualStudio_2017)
205         REDasm::log("PE Classification: Visual Studio 2017");
206     else if(m_classification == PEClassifications::DotNet_1)
207         REDasm::log("PE Classification: .NET 1.x");
208     else if(m_classification == PEClassifications::DotNet)
209         REDasm::log("PE Classification: .NET >= 2.x");
210     else if(m_classification == PEClassifications::BorlandDelphi)
211         REDasm::log("PE Classification: Borland Delphi");
212     else if(m_classification == PEClassifications::BorlandDelphi_3)
213         REDasm::log("PE Classification: Borland Delphi 3");
214     else if(m_classification == PEClassifications::BorlandDelphi_6)
215         REDasm::log("PE Classification: Borland Delphi 6");
216     else if(m_classification == PEClassifications::BorlandDelphi_7)
217         REDasm::log("PE Classification: Borland Delphi 7");
218     else if(m_classification == PEClassifications::BorlandDelphi_9_10)
219         REDasm::log("PE Classification: Borland Delphi 9/10");
220     else if(m_classification == PEClassifications::BorlandDelphi_XE)
221         REDasm::log("PE Classification: Borland Delphi XE");
222     else if(m_classification == PEClassifications::BorlandDelphi_XE2_6)
223         REDasm::log("PE Classification: Borland Delphi XE 2.6");
224     else if(m_classification == PEClassifications::BorlandCpp)
225         REDasm::log("PE Classification: Borland C++");
226     else
227         REDasm::log("PE Classification: Unclassified");
228 }
229 
isClassified() const230 bool PEClassifier::isClassified() const { return m_classification != PEClassifications::Unclassified;  }
231 
checkLinkerVersion(u8 major,u8 minor)232 void PEClassifier::checkLinkerVersion(u8 major, u8 minor)
233 {
234     if(major == 4)
235         m_classification = PEClassifications::VisualStudio_4;
236     else if(major == 5)
237         m_classification = PEClassifications::VisualStudio_5;
238     else if(major == 6)
239         m_classification = PEClassifications::VisualStudio_6;
240     else if(major == 7)
241     {
242         if(minor < 10)
243             m_classification = PEClassifications::VisualStudio_2002;
244         else
245             m_classification = PEClassifications::VisualStudio_2003;
246     }
247     else if(major == 8)
248         m_classification = PEClassifications::VisualStudio_2005;
249     else if(major == 9)
250         m_classification = PEClassifications::VisualStudio_2008;
251     else if(major == 10)
252         m_classification = PEClassifications::VisualStudio_2010;
253     else if(major == 11)
254         m_classification = PEClassifications::VisualStudio_2012;
255     else if(major == 12)
256         m_classification = PEClassifications::VisualStudio_2013;
257     else if(major == 14)
258     {
259         if(!minor)
260             m_classification = PEClassifications::VisualStudio_2015;
261         else
262             m_classification = PEClassifications::VisualStudio_2017;
263     }
264 }
265 
addSignature(const std::string & s)266 void PEClassifier::addSignature(const std::string &s)
267 {
268     if(s.empty())
269         return;
270 
271     m_signatures.insert(s);
272 }
273 
274 } // namespace REDasm
275