Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(221)

Side by Side Diff: chrome/browser/win/enumerate_modules_model.cc

Issue 2653333002: [win] Create utilities for helping to populate ModuleDatabase. (Closed)
Patch Set: Fix include order. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/win/enumerate_modules_model.h ('k') | chrome/test/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/win/enumerate_modules_model.h" 5 #include "chrome/browser/win/enumerate_modules_model.h"
6 6
7 #include <softpub.h> 7 #include <softpub.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <stdint.h> 9 #include <stdint.h>
10 #include <tlhelp32.h> 10 #include <tlhelp32.h>
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 DWORD return_value = GetLongPathName(short_path.c_str(), long_path_buf, 90 DWORD return_value = GetLongPathName(short_path.c_str(), long_path_buf,
91 MAX_PATH); 91 MAX_PATH);
92 if (return_value != 0 && return_value < MAX_PATH) { 92 if (return_value != 0 && return_value < MAX_PATH) {
93 *long_path = long_path_buf; 93 *long_path = long_path_buf;
94 return true; 94 return true;
95 } 95 }
96 96
97 return false; 97 return false;
98 } 98 }
99 99
100 // Helper for scoped tracking an HCERTSTORE.
101 struct ScopedHCERTSTORETraits {
102 static HCERTSTORE InvalidValue() { return nullptr; }
103 static void Free(HCERTSTORE store) {
104 ::CertCloseStore(store, 0);
105 }
106 };
107 using ScopedHCERTSTORE =
108 base::ScopedGeneric<HCERTSTORE, ScopedHCERTSTORETraits>;
109
110 // Helper for scoped tracking an HCRYPTMSG.
111 struct ScopedHCRYPTMSGTraits {
112 static HCRYPTMSG InvalidValue() { return nullptr; }
113 static void Free(HCRYPTMSG message) {
114 ::CryptMsgClose(message);
115 }
116 };
117 using ScopedHCRYPTMSG =
118 base::ScopedGeneric<HCRYPTMSG, ScopedHCRYPTMSGTraits>;
119
120 // Returns the "Subject" field from the digital signature in the provided
121 // binary, if any is present. Returns an empty string on failure.
122 base::string16 GetSubjectNameInFile(const base::FilePath& filename) {
123 ScopedHCERTSTORE store;
124 ScopedHCRYPTMSG message;
125
126 // Find the crypto message for this filename.
127 {
128 HCERTSTORE temp_store = nullptr;
129 HCRYPTMSG temp_message = nullptr;
130 bool result = !!CryptQueryObject(CERT_QUERY_OBJECT_FILE,
131 filename.value().c_str(),
132 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
133 CERT_QUERY_FORMAT_FLAG_BINARY,
134 0,
135 nullptr,
136 nullptr,
137 nullptr,
138 &temp_store,
139 &temp_message,
140 nullptr);
141 store.reset(temp_store);
142 message.reset(temp_message);
143 if (!result)
144 return base::string16();
145 }
146
147 // Determine the size of the signer info data.
148 DWORD signer_info_size = 0;
149 bool result = !!CryptMsgGetParam(message.get(),
150 CMSG_SIGNER_INFO_PARAM,
151 0,
152 nullptr,
153 &signer_info_size);
154 if (!result)
155 return base::string16();
156
157 // Allocate enough space to hold the signer info.
158 std::unique_ptr<BYTE[]> signer_info_buffer(new BYTE[signer_info_size]);
159 CMSG_SIGNER_INFO* signer_info =
160 reinterpret_cast<CMSG_SIGNER_INFO*>(signer_info_buffer.get());
161
162 // Obtain the signer info.
163 result = !!CryptMsgGetParam(message.get(),
164 CMSG_SIGNER_INFO_PARAM,
165 0,
166 signer_info,
167 &signer_info_size);
168 if (!result)
169 return base::string16();
170
171 // Search for the signer certificate.
172 CERT_INFO CertInfo = {0};
173 PCCERT_CONTEXT cert_context = nullptr;
174 CertInfo.Issuer = signer_info->Issuer;
175 CertInfo.SerialNumber = signer_info->SerialNumber;
176
177 cert_context = CertFindCertificateInStore(
178 store.get(),
179 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
180 0,
181 CERT_FIND_SUBJECT_CERT,
182 &CertInfo,
183 nullptr);
184 if (!cert_context)
185 return base::string16();
186
187 // Determine the size of the Subject name.
188 DWORD subject_name_size = CertGetNameString(
189 cert_context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nullptr, nullptr, 0);
190 if (!subject_name_size)
191 return base::string16();
192
193 base::string16 subject_name;
194 subject_name.resize(subject_name_size);
195
196 // Get subject name.
197 if (!(CertGetNameString(cert_context,
198 CERT_NAME_SIMPLE_DISPLAY_TYPE,
199 0,
200 nullptr,
201 const_cast<LPWSTR>(subject_name.c_str()),
202 subject_name_size))) {
203 return base::string16();
204 }
205
206 return subject_name;
207 }
208
209 // Helper for scoped tracking a catalog admin context.
210 struct CryptCATContextScopedTraits {
211 static PVOID InvalidValue() { return nullptr; }
212 static void Free(PVOID context) {
213 CryptCATAdminReleaseContext(context, 0);
214 }
215 };
216 using ScopedCryptCATContext =
217 base::ScopedGeneric<PVOID, CryptCATContextScopedTraits>;
218
219 // Helper for scoped tracking of a catalog context. A catalog context is only
220 // valid with an associated admin context, so this is effectively a std::pair.
221 // A custom operator!= is required in order for a null |catalog_context| but
222 // non-null |context| to compare equal to the InvalidValue exposed by the
223 // traits class.
224 class CryptCATCatalogContext {
225 public:
226 CryptCATCatalogContext(PVOID context, PVOID catalog_context)
227 : context_(context), catalog_context_(catalog_context) {}
228
229 bool operator!=(const CryptCATCatalogContext& rhs) const {
230 return catalog_context_ != rhs.catalog_context_;
231 }
232
233 PVOID context() const { return context_; }
234 PVOID catalog_context() const { return catalog_context_; }
235
236 private:
237 PVOID context_;
238 PVOID catalog_context_;
239 };
240
241 struct CryptCATCatalogContextScopedTraits {
242 static CryptCATCatalogContext InvalidValue() {
243 return CryptCATCatalogContext(nullptr, nullptr);
244 }
245 static void Free(const CryptCATCatalogContext& c) {
246 CryptCATAdminReleaseCatalogContext(
247 c.context(), c.catalog_context(), 0);
248 }
249 };
250 using ScopedCryptCATCatalogContext = base::ScopedGeneric<
251 CryptCATCatalogContext, CryptCATCatalogContextScopedTraits>;
252
253 // Extracts the subject name and catalog path if the provided file is present in
254 // a catalog file.
255 void GetCatalogCertificateInfo(const base::FilePath& filename,
256 ModuleEnumerator::CertificateInfo* cert_info) {
257 // Get a crypt context for signature verification.
258 ScopedCryptCATContext context;
259 {
260 PVOID raw_context = nullptr;
261 if (!CryptCATAdminAcquireContext(&raw_context, nullptr, 0))
262 return;
263 context.reset(raw_context);
264 }
265
266 // Open the file of interest.
267 base::win::ScopedHandle file_handle(CreateFileW(
268 filename.value().c_str(), GENERIC_READ,
269 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
270 nullptr, OPEN_EXISTING, 0, nullptr));
271 if (!file_handle.IsValid())
272 return;
273
274 // Get the size we need for our hash.
275 DWORD hash_size = 0;
276 CryptCATAdminCalcHashFromFileHandle(
277 file_handle.Get(), &hash_size, nullptr, 0);
278 if (hash_size == 0)
279 return;
280
281 // Calculate the hash. If this fails then bail.
282 std::vector<BYTE> buffer(hash_size);
283 if (!CryptCATAdminCalcHashFromFileHandle(file_handle.Get(), &hash_size,
284 buffer.data(), 0)) {
285 return;
286 }
287
288 // Get catalog for our context.
289 ScopedCryptCATCatalogContext catalog_context(CryptCATCatalogContext(
290 context.get(),
291 CryptCATAdminEnumCatalogFromHash(context.get(), buffer.data(), hash_size,
292 0, nullptr)));
293 if (!catalog_context.is_valid())
294 return;
295
296 // Get the catalog info. This includes the path to the catalog itself, which
297 // contains the signature of interest.
298 CATALOG_INFO catalog_info = {};
299 catalog_info.cbStruct = sizeof(catalog_info);
300 if (!CryptCATCatalogInfoFromContext(
301 catalog_context.get().catalog_context(), &catalog_info, 0)) {
302 return;
303 }
304
305 // Attempt to get the "Subject" field from the signature of the catalog file
306 // itself.
307 base::FilePath catalog_path(catalog_info.wszCatalogFile);
308 base::string16 subject = GetSubjectNameInFile(catalog_path);
309
310 if (subject.empty())
311 return;
312
313 cert_info->type = ModuleEnumerator::CERTIFICATE_IN_CATALOG;
314 cert_info->path = catalog_path;
315 cert_info->subject = subject;
316 }
317
318 // Extracts information about the certificate of the given file, if any is
319 // found.
320 void GetCertificateInfo(const base::FilePath& filename,
321 ModuleEnumerator::CertificateInfo* cert_info) {
322 DCHECK_EQ(ModuleEnumerator::NO_CERTIFICATE, cert_info->type);
323 DCHECK(cert_info->path.empty());
324 DCHECK(cert_info->subject.empty());
325
326 GetCatalogCertificateInfo(filename, cert_info);
327 if (cert_info->type == ModuleEnumerator::CERTIFICATE_IN_CATALOG)
328 return;
329
330 base::string16 subject = GetSubjectNameInFile(filename);
331 if (subject.empty())
332 return;
333
334 cert_info->type = ModuleEnumerator::CERTIFICATE_IN_FILE;
335 cert_info->path = filename;
336 cert_info->subject = subject;
337 }
338
339 } // namespace 100 } // namespace
340 101
341 ModuleEnumerator::CertificateInfo::CertificateInfo() : type(NO_CERTIFICATE) {}
342
343 ModuleEnumerator::Module::Module() { 102 ModuleEnumerator::Module::Module() {
344 } 103 }
345 104
346 ModuleEnumerator::Module::Module(const Module& rhs) = default; 105 ModuleEnumerator::Module::Module(const Module& rhs) = default;
347 106
348 ModuleEnumerator::Module::Module(ModuleType type, 107 ModuleEnumerator::Module::Module(ModuleType type,
349 ModuleStatus status, 108 ModuleStatus status,
350 const base::string16& location, 109 const base::string16& location,
351 const base::string16& name, 110 const base::string16& name,
352 const base::string16& product_name, 111 const base::string16& product_name,
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
702 // catalog counts as a single certificate, as does a file with a baked in 461 // catalog counts as a single certificate, as does a file with a baked in
703 // certificate. 462 // certificate.
704 std::set<base::FilePath> unique_certificates; 463 std::set<base::FilePath> unique_certificates;
705 size_t microsoft_certificates = 0; 464 size_t microsoft_certificates = 0;
706 size_t signed_modules = 0; 465 size_t signed_modules = 0;
707 size_t microsoft_modules = 0; 466 size_t microsoft_modules = 0;
708 size_t catalog_modules = 0; 467 size_t catalog_modules = 0;
709 size_t third_party_loaded = 0; 468 size_t third_party_loaded = 0;
710 size_t third_party_not_loaded = 0; 469 size_t third_party_not_loaded = 0;
711 for (const auto& module : *enumerated_modules_) { 470 for (const auto& module : *enumerated_modules_) {
712 if (module.cert_info.type != ModuleEnumerator::NO_CERTIFICATE) { 471 if (module.cert_info.type != ModuleDatabase::NO_CERTIFICATE) {
713 ++signed_modules; 472 ++signed_modules;
714 473
715 if (module.cert_info.type == ModuleEnumerator::CERTIFICATE_IN_CATALOG) 474 if (module.cert_info.type == ModuleDatabase::CERTIFICATE_IN_CATALOG)
716 ++catalog_modules; 475 ++catalog_modules;
717 476
718 // The first time this certificate is encountered it will be inserted 477 // The first time this certificate is encountered it will be inserted
719 // into the set. 478 // into the set.
720 bool new_certificate = 479 bool new_certificate =
721 unique_certificates.insert(module.cert_info.path).second; 480 unique_certificates.insert(module.cert_info.path).second;
722 481
723 // Check if the signer name begins with "Microsoft ". Signatures are 482 // Check if the signer name begins with "Microsoft ". Signatures are
724 // typically "Microsoft Corporation" or "Microsoft Windows", but others 483 // typically "Microsoft Corporation" or "Microsoft Windows", but others
725 // may exist. 484 // may exist.
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
1011 770
1012 UMA_HISTOGRAM_COUNTS_100("Conflicts.SuspectedBadModules", 771 UMA_HISTOGRAM_COUNTS_100("Conflicts.SuspectedBadModules",
1013 suspected_bad_modules_detected_); 772 suspected_bad_modules_detected_);
1014 UMA_HISTOGRAM_COUNTS_100("Conflicts.ConfirmedBadModules", 773 UMA_HISTOGRAM_COUNTS_100("Conflicts.ConfirmedBadModules",
1015 confirmed_bad_modules_detected_); 774 confirmed_bad_modules_detected_);
1016 775
1017 // Forward the callback to any registered observers. 776 // Forward the callback to any registered observers.
1018 for (Observer& observer : observers_) 777 for (Observer& observer : observers_)
1019 observer.OnScanCompleted(); 778 observer.OnScanCompleted();
1020 } 779 }
OLDNEW
« no previous file with comments | « chrome/browser/win/enumerate_modules_model.h ('k') | chrome/test/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698