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