Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / utility / safe_browsing / mac / dmg_analyzer.cc
blob953f26903c7ca163543de3c1afede2bfe2b607e9
1 // Copyright 2015 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/utility/safe_browsing/mac/dmg_analyzer.h"
7 #include <vector>
9 #include "base/macros.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/common/safe_browsing/binary_feature_extractor.h"
13 #include "chrome/common/safe_browsing/csd.pb.h"
14 #include "chrome/common/safe_browsing/mach_o_image_reader_mac.h"
15 #include "chrome/utility/safe_browsing/mac/dmg_iterator.h"
16 #include "chrome/utility/safe_browsing/mac/read_stream.h"
17 #include "crypto/secure_hash.h"
18 #include "crypto/sha2.h"
20 namespace safe_browsing {
21 namespace dmg {
23 namespace {
25 // MachOFeatureExtractor examines files to determine if they are Mach-O, and,
26 // if so, it uses the BinaryFeatureExtractor to obtain information about the
27 // image. In addition, this class will compute the SHA256 hash of the file.
28 class MachOFeatureExtractor {
29 public:
30 MachOFeatureExtractor();
31 ~MachOFeatureExtractor();
33 // Tests if the stream references a Mach-O image by examinig its magic
34 // number.
35 bool IsMachO(ReadStream* stream);
37 // Computes the hash of the data in |stream| and extracts the Mach-O
38 // features from the data. Returns true if successful, or false on error or
39 // if the file was not Mach-O.
40 bool ExtractFeatures(ReadStream* stream,
41 ClientDownloadRequest_ArchivedBinary* result);
43 private:
44 // Reads the entire stream and updates the hash.
45 bool HashAndCopyStream(ReadStream* stream,
46 uint8_t digest[crypto::kSHA256Length]);
48 scoped_refptr<BinaryFeatureExtractor> bfe_;
49 std::vector<uint8_t> buffer_; // Buffer that contains read stream data.
51 DISALLOW_COPY_AND_ASSIGN(MachOFeatureExtractor);
54 MachOFeatureExtractor::MachOFeatureExtractor()
55 : bfe_(new BinaryFeatureExtractor()),
56 buffer_() {
57 buffer_.reserve(1024 * 1024);
60 MachOFeatureExtractor::~MachOFeatureExtractor() {}
62 bool MachOFeatureExtractor::IsMachO(ReadStream* stream) {
63 uint32_t magic = 0;
64 return stream->ReadType<uint32_t>(&magic) &&
65 MachOImageReader::IsMachOMagicValue(magic);
68 bool MachOFeatureExtractor::ExtractFeatures(
69 ReadStream* stream,
70 ClientDownloadRequest_ArchivedBinary* result) {
71 uint8_t digest[crypto::kSHA256Length];
72 if (!HashAndCopyStream(stream, digest))
73 return false;
75 if (!bfe_->ExtractImageFeaturesFromData(
76 &buffer_[0], buffer_.size(), 0,
77 result->mutable_image_headers(),
78 result->mutable_signature()->mutable_signed_data())) {
79 return false;
82 result->set_length(buffer_.size());
83 result->mutable_digests()->set_sha256(digest, sizeof(digest));
85 return true;
88 bool MachOFeatureExtractor::HashAndCopyStream(
89 ReadStream* stream, uint8_t digest[crypto::kSHA256Length]) {
90 if (stream->Seek(0, SEEK_SET) != 0)
91 return false;
93 buffer_.clear();
94 scoped_ptr<crypto::SecureHash> sha256(
95 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
97 size_t bytes_read;
98 const size_t kBufferSize = 2048;
99 do {
100 size_t buffer_offset = buffer_.size();
102 buffer_.resize(buffer_.size() + kBufferSize);
103 if (!stream->Read(&buffer_[buffer_offset], kBufferSize, &bytes_read))
104 return false;
106 buffer_.resize(buffer_offset + bytes_read);
107 sha256->Update(&buffer_[buffer_offset], bytes_read);
108 } while (bytes_read > 0);
110 sha256->Finish(digest, crypto::kSHA256Length);
112 return true;
115 } // namespace
117 void AnalyzeDMGFile(base::File dmg_file,
118 safe_browsing::zip_analyzer::Results* results) {
119 MachOFeatureExtractor feature_extractor;
120 results->success = false;
122 FileReadStream read_stream(dmg_file.GetPlatformFile());
123 DMGIterator iterator(&read_stream);
124 if (!iterator.Open())
125 return;
127 while (iterator.Next()) {
128 scoped_ptr<ReadStream> stream = iterator.GetReadStream();
129 if (!stream || !feature_extractor.IsMachO(stream.get()))
130 continue;
132 ClientDownloadRequest_ArchivedBinary* binary =
133 results->archived_binary.Add();
134 binary->set_file_basename(base::UTF16ToUTF8(iterator.GetPath()));
136 if (feature_extractor.ExtractFeatures(stream.get(), binary)) {
137 binary->set_download_type(
138 ClientDownloadRequest_DownloadType_MAC_EXECUTABLE);
139 results->has_executable = true;
140 } else {
141 results->archived_binary.RemoveLast();
145 results->success = true;
148 } // namespace dmg
149 } // namespace safe_browsing