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"
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
{
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
{
30 MachOFeatureExtractor();
31 ~MachOFeatureExtractor();
33 // Tests if the stream references a Mach-O image by examinig its magic
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
);
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()),
57 buffer_
.reserve(1024 * 1024);
60 MachOFeatureExtractor::~MachOFeatureExtractor() {}
62 bool MachOFeatureExtractor::IsMachO(ReadStream
* stream
) {
64 return stream
->ReadType
<uint32_t>(&magic
) &&
65 MachOImageReader::IsMachOMagicValue(magic
);
68 bool MachOFeatureExtractor::ExtractFeatures(
70 ClientDownloadRequest_ArchivedBinary
* result
) {
71 uint8_t digest
[crypto::kSHA256Length
];
72 if (!HashAndCopyStream(stream
, digest
))
75 if (!bfe_
->ExtractImageFeaturesFromData(
76 &buffer_
[0], buffer_
.size(), 0,
77 result
->mutable_image_headers(),
78 result
->mutable_signature()->mutable_signed_data())) {
82 result
->set_length(buffer_
.size());
83 result
->mutable_digests()->set_sha256(digest
, sizeof(digest
));
88 bool MachOFeatureExtractor::HashAndCopyStream(
89 ReadStream
* stream
, uint8_t digest
[crypto::kSHA256Length
]) {
90 if (stream
->Seek(0, SEEK_SET
) != 0)
94 scoped_ptr
<crypto::SecureHash
> sha256(
95 crypto::SecureHash::Create(crypto::SecureHash::SHA256
));
98 const size_t kBufferSize
= 2048;
100 size_t buffer_offset
= buffer_
.size();
102 buffer_
.resize(buffer_
.size() + kBufferSize
);
103 if (!stream
->Read(&buffer_
[buffer_offset
], kBufferSize
, &bytes_read
))
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
);
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())
127 while (iterator
.Next()) {
128 scoped_ptr
<ReadStream
> stream
= iterator
.GetReadStream();
129 if (!stream
|| !feature_extractor
.IsMachO(stream
.get()))
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;
141 results
->archived_binary
.RemoveLast();
145 results
->success
= true;
149 } // namespace safe_browsing