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 bool ExtractImageHeadersImpl(
24 const base::MemoryMappedFile
& file
,
25 BinaryFeatureExtractor::ExtractHeadersOption options
,
26 ClientDownloadRequest_ImageHeaders
* image_headers
) {
27 PeImageReader pe_image
;
28 if (!pe_image
.Initialize(file
.data(), file
.length()))
32 ClientDownloadRequest_PEImageHeaders
* pe_headers
=
33 image_headers
->mutable_pe_headers();
34 pe_headers
->set_dos_header(pe_image
.GetDosHeader(), sizeof(IMAGE_DOS_HEADER
));
35 pe_headers
->set_file_header(pe_image
.GetCoffFileHeader(),
36 sizeof(IMAGE_FILE_HEADER
));
37 size_t optional_header_size
= 0;
38 const uint8_t* optional_header_data
=
39 pe_image
.GetOptionalHeaderData(&optional_header_size
);
40 if (pe_image
.GetWordSize() == PeImageReader::WORD_SIZE_32
) {
41 pe_headers
->set_optional_headers32(optional_header_data
,
42 optional_header_size
);
44 pe_headers
->set_optional_headers64(optional_header_data
,
45 optional_header_size
);
47 const size_t number_of_sections
= pe_image
.GetNumberOfSections();
48 for (size_t i
= 0; i
!= number_of_sections
; ++i
) {
49 pe_headers
->add_section_header(pe_image
.GetSectionHeaderAt(i
),
50 sizeof(IMAGE_SECTION_HEADER
));
52 if (!(options
& BinaryFeatureExtractor::kOmitExports
)) {
53 size_t export_size
= 0;
54 const uint8_t* export_section
= pe_image
.GetExportSection(&export_size
);
56 pe_headers
->set_export_section_data(export_section
, export_size
);
58 size_t number_of_debug_entries
= pe_image
.GetNumberOfDebugEntries();
59 for (size_t i
= 0; i
!= number_of_debug_entries
; ++i
) {
60 const uint8_t* raw_data
= NULL
;
61 size_t raw_data_size
= 0;
62 const IMAGE_DEBUG_DIRECTORY
* directory_entry
=
63 pe_image
.GetDebugEntry(i
, &raw_data
, &raw_data_size
);
64 if (directory_entry
) {
65 ClientDownloadRequest_PEImageHeaders_DebugData
* debug_data
=
66 pe_headers
->add_debug_data();
67 debug_data
->set_directory_entry(directory_entry
,
68 sizeof(*directory_entry
));
70 debug_data
->set_raw_data(raw_data
, raw_data_size
);
79 BinaryFeatureExtractor::BinaryFeatureExtractor() {}
81 BinaryFeatureExtractor::~BinaryFeatureExtractor() {}
83 void BinaryFeatureExtractor::CheckSignature(
84 const base::FilePath
& file_path
,
85 ClientDownloadRequest_SignatureInfo
* signature_info
) {
86 DVLOG(2) << "Checking signature for " << file_path
.value();
88 WINTRUST_FILE_INFO file_info
= {0};
89 file_info
.cbStruct
= sizeof(file_info
);
90 file_info
.pcwszFilePath
= file_path
.value().c_str();
91 file_info
.hFile
= NULL
;
92 file_info
.pgKnownSubject
= NULL
;
94 WINTRUST_DATA wintrust_data
= {0};
95 wintrust_data
.cbStruct
= sizeof(wintrust_data
);
96 wintrust_data
.pPolicyCallbackData
= NULL
;
97 wintrust_data
.pSIPClientData
= NULL
;
98 wintrust_data
.dwUIChoice
= WTD_UI_NONE
;
99 wintrust_data
.fdwRevocationChecks
= WTD_REVOKE_NONE
;
100 wintrust_data
.dwUnionChoice
= WTD_CHOICE_FILE
;
101 wintrust_data
.pFile
= &file_info
;
102 wintrust_data
.dwStateAction
= WTD_STATEACTION_VERIFY
;
103 wintrust_data
.hWVTStateData
= NULL
;
104 wintrust_data
.pwszURLReference
= NULL
;
105 // Disallow revocation checks over the network.
106 wintrust_data
.dwProvFlags
= WTD_CACHE_ONLY_URL_RETRIEVAL
;
107 wintrust_data
.dwUIContext
= WTD_UICONTEXT_EXECUTE
;
109 // The WINTRUST_ACTION_GENERIC_VERIFY_V2 policy verifies that the certificate
110 // chains up to a trusted root CA, and that it has appropriate permission to
112 GUID policy_guid
= WINTRUST_ACTION_GENERIC_VERIFY_V2
;
114 LONG result
= WinVerifyTrust(static_cast<HWND
>(INVALID_HANDLE_VALUE
),
118 CRYPT_PROVIDER_DATA
* prov_data
= WTHelperProvDataFromStateData(
119 wintrust_data
.hWVTStateData
);
121 if (prov_data
->csSigners
> 0) {
122 signature_info
->set_trusted(result
== ERROR_SUCCESS
);
124 for (DWORD i
= 0; i
< prov_data
->csSigners
; ++i
) {
125 const CERT_CHAIN_CONTEXT
* cert_chain_context
=
126 prov_data
->pasSigners
[i
].pChainContext
;
127 if (!cert_chain_context
)
129 for (DWORD j
= 0; j
< cert_chain_context
->cChain
; ++j
) {
130 CERT_SIMPLE_CHAIN
* simple_chain
= cert_chain_context
->rgpChain
[j
];
131 ClientDownloadRequest_CertificateChain
* chain
=
132 signature_info
->add_certificate_chain();
135 for (DWORD k
= 0; k
< simple_chain
->cElement
; ++k
) {
136 CERT_CHAIN_ELEMENT
* element
= simple_chain
->rgpElement
[k
];
137 chain
->add_element()->set_certificate(
138 element
->pCertContext
->pbCertEncoded
,
139 element
->pCertContext
->cbCertEncoded
);
144 // Free the provider data.
145 wintrust_data
.dwStateAction
= WTD_STATEACTION_CLOSE
;
146 WinVerifyTrust(static_cast<HWND
>(INVALID_HANDLE_VALUE
),
147 &policy_guid
, &wintrust_data
);
151 bool BinaryFeatureExtractor::ExtractImageHeaders(
152 const base::FilePath
& file_path
,
153 ExtractHeadersOption options
,
154 ClientDownloadRequest_ImageHeaders
* image_headers
) {
155 base::MemoryMappedFile mapped_file
;
156 if (!mapped_file
.Initialize(file_path
))
158 return ExtractImageHeadersImpl(mapped_file
, options
, image_headers
);
161 bool BinaryFeatureExtractor::ExtractImageHeadersFromFile(
163 ExtractHeadersOption options
,
164 ClientDownloadRequest_ImageHeaders
* image_headers
) {
165 base::MemoryMappedFile mapped_file
;
166 if (!mapped_file
.Initialize(file
.Pass()))
168 return ExtractImageHeadersImpl(mapped_file
, options
, image_headers
);
171 } // namespace safe_browsing