1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/common/safe_browsing/binary_feature_extractor.h"
11 #include "base/files/file_path.h"
12 #include "base/files/memory_mapped_file.h"
13 #include "base/logging.h"
14 #include "chrome/common/safe_browsing/csd.pb.h"
15 #include "chrome/common/safe_browsing/pe_image_reader_win.h"
17 #pragma comment(lib, "wintrust.lib")
19 namespace safe_browsing
{
23 // An EnumCertificatesCallback that collects each SignedData blob.
24 bool OnCertificateEntry(uint16_t revision
,
25 uint16_t certificate_type
,
26 const uint8_t* certificate_data
,
27 size_t certificate_data_size
,
29 google::protobuf::RepeatedPtrField
<std::string
>* signed_data
=
30 reinterpret_cast<google::protobuf::RepeatedPtrField
<std::string
>*>(
33 if (revision
== WIN_CERT_REVISION_2_0
&&
34 certificate_type
== WIN_CERT_TYPE_PKCS_SIGNED_DATA
) {
35 signed_data
->Add()->assign(certificate_data
,
36 certificate_data
+ certificate_data_size
);
41 bool ExtractImageFeaturesImpl(
42 const base::MemoryMappedFile
& file
,
43 BinaryFeatureExtractor::ExtractHeadersOption options
,
44 ClientDownloadRequest_ImageHeaders
* image_headers
,
45 google::protobuf::RepeatedPtrField
<std::string
>* signed_data
) {
46 PeImageReader pe_image
;
47 if (!pe_image
.Initialize(file
.data(), file
.length()))
51 ClientDownloadRequest_PEImageHeaders
* pe_headers
=
52 image_headers
->mutable_pe_headers();
53 pe_headers
->set_dos_header(pe_image
.GetDosHeader(), sizeof(IMAGE_DOS_HEADER
));
54 pe_headers
->set_file_header(pe_image
.GetCoffFileHeader(),
55 sizeof(IMAGE_FILE_HEADER
));
56 size_t optional_header_size
= 0;
57 const uint8_t* optional_header_data
=
58 pe_image
.GetOptionalHeaderData(&optional_header_size
);
59 if (pe_image
.GetWordSize() == PeImageReader::WORD_SIZE_32
) {
60 pe_headers
->set_optional_headers32(optional_header_data
,
61 optional_header_size
);
63 pe_headers
->set_optional_headers64(optional_header_data
,
64 optional_header_size
);
66 const size_t number_of_sections
= pe_image
.GetNumberOfSections();
67 for (size_t i
= 0; i
!= number_of_sections
; ++i
) {
68 pe_headers
->add_section_header(pe_image
.GetSectionHeaderAt(i
),
69 sizeof(IMAGE_SECTION_HEADER
));
71 if (!(options
& BinaryFeatureExtractor::kOmitExports
)) {
72 size_t export_size
= 0;
73 const uint8_t* export_section
= pe_image
.GetExportSection(&export_size
);
75 pe_headers
->set_export_section_data(export_section
, export_size
);
77 size_t number_of_debug_entries
= pe_image
.GetNumberOfDebugEntries();
78 for (size_t i
= 0; i
!= number_of_debug_entries
; ++i
) {
79 const uint8_t* raw_data
= NULL
;
80 size_t raw_data_size
= 0;
81 const IMAGE_DEBUG_DIRECTORY
* directory_entry
=
82 pe_image
.GetDebugEntry(i
, &raw_data
, &raw_data_size
);
83 if (directory_entry
) {
84 ClientDownloadRequest_PEImageHeaders_DebugData
* debug_data
=
85 pe_headers
->add_debug_data();
86 debug_data
->set_directory_entry(directory_entry
,
87 sizeof(*directory_entry
));
89 debug_data
->set_raw_data(raw_data
, raw_data_size
);
94 pe_image
.EnumCertificates(&OnCertificateEntry
, signed_data
);
101 BinaryFeatureExtractor::BinaryFeatureExtractor() {}
103 BinaryFeatureExtractor::~BinaryFeatureExtractor() {}
105 void BinaryFeatureExtractor::CheckSignature(
106 const base::FilePath
& file_path
,
107 ClientDownloadRequest_SignatureInfo
* signature_info
) {
108 DVLOG(2) << "Checking signature for " << file_path
.value();
110 WINTRUST_FILE_INFO file_info
= {0};
111 file_info
.cbStruct
= sizeof(file_info
);
112 file_info
.pcwszFilePath
= file_path
.value().c_str();
113 file_info
.hFile
= NULL
;
114 file_info
.pgKnownSubject
= NULL
;
116 WINTRUST_DATA wintrust_data
= {0};
117 wintrust_data
.cbStruct
= sizeof(wintrust_data
);
118 wintrust_data
.pPolicyCallbackData
= NULL
;
119 wintrust_data
.pSIPClientData
= NULL
;
120 wintrust_data
.dwUIChoice
= WTD_UI_NONE
;
121 wintrust_data
.fdwRevocationChecks
= WTD_REVOKE_NONE
;
122 wintrust_data
.dwUnionChoice
= WTD_CHOICE_FILE
;
123 wintrust_data
.pFile
= &file_info
;
124 wintrust_data
.dwStateAction
= WTD_STATEACTION_VERIFY
;
125 wintrust_data
.hWVTStateData
= NULL
;
126 wintrust_data
.pwszURLReference
= NULL
;
127 // Disallow revocation checks over the network.
128 wintrust_data
.dwProvFlags
= WTD_CACHE_ONLY_URL_RETRIEVAL
;
129 wintrust_data
.dwUIContext
= WTD_UICONTEXT_EXECUTE
;
131 // The WINTRUST_ACTION_GENERIC_VERIFY_V2 policy verifies that the certificate
132 // chains up to a trusted root CA, and that it has appropriate permission to
134 GUID policy_guid
= WINTRUST_ACTION_GENERIC_VERIFY_V2
;
136 LONG result
= WinVerifyTrust(static_cast<HWND
>(INVALID_HANDLE_VALUE
),
140 CRYPT_PROVIDER_DATA
* prov_data
= WTHelperProvDataFromStateData(
141 wintrust_data
.hWVTStateData
);
143 if (prov_data
->csSigners
> 0) {
144 signature_info
->set_trusted(result
== ERROR_SUCCESS
);
146 for (DWORD i
= 0; i
< prov_data
->csSigners
; ++i
) {
147 const CERT_CHAIN_CONTEXT
* cert_chain_context
=
148 prov_data
->pasSigners
[i
].pChainContext
;
149 if (!cert_chain_context
)
151 for (DWORD j
= 0; j
< cert_chain_context
->cChain
; ++j
) {
152 CERT_SIMPLE_CHAIN
* simple_chain
= cert_chain_context
->rgpChain
[j
];
153 ClientDownloadRequest_CertificateChain
* chain
=
154 signature_info
->add_certificate_chain();
157 for (DWORD k
= 0; k
< simple_chain
->cElement
; ++k
) {
158 CERT_CHAIN_ELEMENT
* element
= simple_chain
->rgpElement
[k
];
159 chain
->add_element()->set_certificate(
160 element
->pCertContext
->pbCertEncoded
,
161 element
->pCertContext
->cbCertEncoded
);
166 // Free the provider data.
167 wintrust_data
.dwStateAction
= WTD_STATEACTION_CLOSE
;
168 WinVerifyTrust(static_cast<HWND
>(INVALID_HANDLE_VALUE
),
169 &policy_guid
, &wintrust_data
);
173 bool BinaryFeatureExtractor::ExtractImageFeatures(
174 const base::FilePath
& file_path
,
175 ExtractHeadersOption options
,
176 ClientDownloadRequest_ImageHeaders
* image_headers
,
177 google::protobuf::RepeatedPtrField
<std::string
>* signed_data
) {
178 base::MemoryMappedFile mapped_file
;
179 if (!mapped_file
.Initialize(file_path
))
181 return ExtractImageFeaturesImpl(mapped_file
, options
, image_headers
,
185 bool BinaryFeatureExtractor::ExtractImageFeaturesFromFile(
187 ExtractHeadersOption options
,
188 ClientDownloadRequest_ImageHeaders
* image_headers
,
189 google::protobuf::RepeatedPtrField
<std::string
>* signed_data
) {
190 base::MemoryMappedFile mapped_file
;
191 if (!mapped_file
.Initialize(file
.Pass()))
193 return ExtractImageFeaturesImpl(mapped_file
, options
, image_headers
,
197 } // namespace safe_browsing