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
3 // found in the LICENSE file.
5 #include "chrome/common/safe_browsing/zip_analyzer.h"
7 #include "base/i18n/streaming_utf8_validator.h"
8 #include "base/logging.h"
9 #include "base/macros.h"
10 #include "chrome/common/safe_browsing/binary_feature_extractor.h"
11 #include "chrome/common/safe_browsing/csd.pb.h"
12 #include "chrome/common/safe_browsing/download_protection_util.h"
13 #include "chrome/common/safe_browsing/zip_analyzer_results.h"
14 #include "crypto/secure_hash.h"
15 #include "crypto/sha2.h"
16 #include "third_party/zlib/google/zip_reader.h"
18 namespace safe_browsing
{
19 namespace zip_analyzer
{
23 // A writer delegate that computes a SHA-256 hash digest over the data while
24 // writing it to a file.
25 class HashingFileWriter
: public zip::FileWriterDelegate
{
27 explicit HashingFileWriter(base::File
* file
);
29 // zip::FileWriterDelegate methods:
30 bool WriteBytes(const char* data
, int num_bytes
) override
;
32 void ComputeDigest(uint8_t* digest
, size_t digest_length
);
35 scoped_ptr
<crypto::SecureHash
> sha256_
;
37 DISALLOW_COPY_AND_ASSIGN(HashingFileWriter
);
40 HashingFileWriter::HashingFileWriter(base::File
* file
)
41 : zip::FileWriterDelegate(file
),
42 sha256_(crypto::SecureHash::Create(crypto::SecureHash::SHA256
)) {
45 bool HashingFileWriter::WriteBytes(const char* data
, int num_bytes
) {
46 if (!zip::FileWriterDelegate::WriteBytes(data
, num_bytes
))
48 sha256_
->Update(data
, num_bytes
);
52 void HashingFileWriter::ComputeDigest(uint8_t* digest
, size_t digest_length
) {
53 sha256_
->Finish(digest
, digest_length
);
56 void AnalyzeContainedFile(
57 const scoped_refptr
<BinaryFeatureExtractor
>& binary_feature_extractor
,
58 const base::FilePath
& file_path
,
59 zip::ZipReader
* reader
,
60 base::File
* temp_file
,
61 ClientDownloadRequest_ArchivedBinary
* archived_binary
) {
62 std::string
file_basename(file_path
.BaseName().AsUTF8Unsafe());
63 if (base::StreamingUtf8Validator::Validate(file_basename
))
64 archived_binary
->set_file_basename(file_basename
);
65 archived_binary
->set_download_type(
66 download_protection_util::GetDownloadType(file_path
));
67 archived_binary
->set_length(reader
->current_entry_info()->original_size());
68 HashingFileWriter
writer(temp_file
);
69 if (reader
->ExtractCurrentEntry(&writer
)) {
70 uint8_t digest
[crypto::kSHA256Length
];
71 writer
.ComputeDigest(&digest
[0], arraysize(digest
));
72 archived_binary
->mutable_digests()->set_sha256(&digest
[0],
74 if (!binary_feature_extractor
->ExtractImageFeaturesFromFile(
75 temp_file
->Duplicate(),
76 BinaryFeatureExtractor::kDefaultOptions
,
77 archived_binary
->mutable_image_headers(),
78 archived_binary
->mutable_signature()->mutable_signed_data())) {
79 archived_binary
->clear_image_headers();
80 archived_binary
->clear_signature();
81 } else if (!archived_binary
->signature().signed_data_size()) {
82 // No SignedData blobs were extracted, so clear the signature field.
83 archived_binary
->clear_signature();
90 void AnalyzeZipFile(base::File zip_file
,
93 scoped_refptr
<BinaryFeatureExtractor
> binary_feature_extractor(
94 new BinaryFeatureExtractor());
95 zip::ZipReader reader
;
96 if (!reader
.OpenFromPlatformFile(zip_file
.GetPlatformFile())) {
97 DVLOG(1) << "Failed to open zip file";
101 bool advanced
= true;
102 for (; reader
.HasMore(); advanced
= reader
.AdvanceToNextEntry()) {
104 DVLOG(1) << "Could not advance to next entry, aborting zip scan.";
107 if (!reader
.OpenCurrentEntryInZip()) {
108 DVLOG(1) << "Failed to open current entry in zip file";
111 const base::FilePath
& file
= reader
.current_entry_info()->file_path();
112 if (download_protection_util::IsBinaryFile(file
)) {
113 // Don't consider an archived archive to be executable, but record
115 if (download_protection_util::IsArchiveFile(file
)) {
116 results
->has_archive
= true;
118 DVLOG(2) << "Downloaded a zipped executable: " << file
.value();
119 results
->has_executable
= true;
120 AnalyzeContainedFile(binary_feature_extractor
, file
, &reader
,
121 &temp_file
, results
->archived_binary
.Add());
124 DVLOG(3) << "Ignoring non-binary file: " << file
.value();
127 results
->success
= true;
130 } // namespace zip_analyzer
131 } // namespace safe_browsing