1 // Copyright 2018 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.
4
5 #include "chrome/chrome_cleaner/scanner/matcher_util.h"
6
7 #include <shlobj.h>
8
9 #include <memory>
10 #include <string>
11
12 #include "base/command_line.h"
13 #include "base/path_service.h"
14 #include "base/stl_util.h"
15 #include "base/strings/strcat.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/test/scoped_path_override.h"
18 #include "base/test/test_reg_util_win.h"
19 #include "base/win/registry.h"
20 #include "chrome/chrome_cleaner/os/file_path_sanitization.h"
21 #include "chrome/chrome_cleaner/scanner/signature_matcher.h"
22 #include "chrome/chrome_cleaner/test/resources/grit/test_resources.h"
23 #include "chrome/chrome_cleaner/test/test_file_util.h"
24 #include "chrome/chrome_cleaner/test/test_pup_data.h"
25 #include "chrome/chrome_cleaner/test/test_signature_matcher.h"
26 #include "chrome/chrome_cleaner/test/test_task_scheduler.h"
27 #include "chrome/chrome_cleaner/test/test_util.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29
30 namespace chrome_cleaner {
31
32 namespace {
33
34 constexpr wchar_t kFileName1[] = L"File1";
35 constexpr wchar_t kFileName2[] = L"File2";
36 constexpr wchar_t kFileName3[] = L"File3";
37 constexpr wchar_t kFileName4[] = L"File4";
38
39 constexpr char kFileContent1[] = "This is the file content.";
40 constexpr char kFileContent2[] = "Hi!";
41 constexpr char kFileContent3[] = "Hello World!";
42 constexpr char kFileContent4[] = "Ha!";
43
44 constexpr char kFileContent[] = "This is the file content.";
45
46 const char* const kKnownContentDigests[] = {
47 "00D2BB3E285BA62224888A9AD874AC2787D4CF681F30A2FD8EE2873859ECE1DC",
48 // Hash for content: |kFileContent|.
49 "BD283E41A3672B6BDAA574F8BD7176F8BCA95BD81383CDE32AA6D78B1DB0E371",
50 };
51
52 constexpr wchar_t kKnownOriginalFilename[] = L"uws.exe";
53 constexpr wchar_t kUnknownOriginalFilename[] = L"knowngood.exe";
54 const wchar_t* const kKnownOriginalFilenames[] = {
55 L"dummy entry",
56 L"uws.exe",
57 L"zombie uws.exe",
58 };
59
60 constexpr wchar_t kKnownCompanyName[] = L"uws vendor inc";
61 constexpr wchar_t kUnknownCompanyName[] = L"paradise";
62 const wchar_t* const kKnownCompanyNames[] = {
63 L"dummy entry",
64 L"uws vendor inc",
65 L"ACME",
66 };
67
68 constexpr FileDigestInfo kFileContentDigestInfos[] = {
69 {"02544E052F29BBA79C81243EC63B43B6CD85B185461928E65BFF501346C62A75", 33},
70 {"04614470DDF4939091F5EC4A13C92A9EAAACF07CA5C3F713E792E2D21CD24075", 21},
71 // Hash for content: |kFileContent2|.
72 {"82E0B92772BC0DA59AAB0B9231AA006FB37B4F99EC3E853C5A62786A1C7215BD", 4},
73 {"9000000000000000000000000000000000000000000000000000000000000009", 4},
74 {"94F7BDF53CDFDE7AA5E5C90BCDA6793B7377CE39E2591ABC758EBAE8072A275C", 12},
75 // Hash for content: |kFileContent1|.
76 {"BD283E41A3672B6BDAA574F8BD7176F8BCA95BD81383CDE32AA6D78B1DB0E371", 26},
77 };
78
79 // Messages are logged to a vector for testing.
80 class LoggingTest : public testing::Test {
81 public:
82 LoggingOverride logger_;
83 };
84
85 } // namespace
86
TEST(MatcherUtilTest,IsKnownFileByDigest)87 TEST(MatcherUtilTest, IsKnownFileByDigest) {
88 base::ScopedTempDir temp_dir;
89 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
90 base::FilePath file_path1(temp_dir.GetPath().Append(kFileName1));
91 base::FilePath file_path2(temp_dir.GetPath().Append(kFileName2));
92 base::FilePath file_path3(temp_dir.GetPath().Append(kFileName3));
93
94 CreateFileWithContent(file_path1, kFileContent, sizeof(kFileContent));
95 CreateFileWithRepeatedContent(file_path2, kFileContent, sizeof(kFileContent),
96 2);
97
98 std::unique_ptr<SignatureMatcher> signature_matcher =
99 std::make_unique<SignatureMatcher>();
100 ASSERT_TRUE(signature_matcher);
101
102 // Hash: BD283E41A3672B6BDAA574F8BD7176F8BCA95BD81383CDE32AA6D78B1DB0E371.
103 EXPECT_TRUE(IsKnownFileByDigest(file_path1, signature_matcher.get(),
104 kKnownContentDigests,
105 base::size(kKnownContentDigests)));
106 // Hash: not present.
107 EXPECT_FALSE(IsKnownFileByDigest(file_path2, signature_matcher.get(),
108 kKnownContentDigests,
109 base::size(kKnownContentDigests)));
110 // The file doesn't exist.
111 EXPECT_FALSE(IsKnownFileByDigest(file_path3, signature_matcher.get(),
112 kKnownContentDigests,
113 base::size(kKnownContentDigests)));
114 }
115
TEST(MatcherUtilTest,IsKnownFileByDigestInfo)116 TEST(MatcherUtilTest, IsKnownFileByDigestInfo) {
117 base::ScopedTempDir temp_dir;
118 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
119 base::FilePath file_path1(temp_dir.GetPath().Append(kFileName1));
120 base::FilePath file_path2(temp_dir.GetPath().Append(kFileName2));
121 base::FilePath file_path3(temp_dir.GetPath().Append(kFileName3));
122 base::FilePath file_path4(temp_dir.GetPath().Append(kFileName4));
123
124 CreateFileWithContent(file_path1, kFileContent1, sizeof(kFileContent1));
125 CreateFileWithContent(file_path2, kFileContent2, sizeof(kFileContent2));
126 CreateFileWithContent(file_path3, kFileContent3, sizeof(kFileContent3));
127
128 std::unique_ptr<SignatureMatcher> signature_matcher =
129 std::make_unique<SignatureMatcher>();
130
131 // Search BD283E41A3672B6BDAA574F8BD7176F8BCA95BD81383CDE32AA6D78B1DB0E371.
132 EXPECT_TRUE(IsKnownFileByDigestInfo(file_path1, signature_matcher.get(),
133 kFileContentDigestInfos,
134 base::size(kFileContentDigestInfos)));
135 // Search 82E0B92772BC0DA59AAB0B9231AA006FB37B4F99EC3E853C5A62786A1C7215BD.
136 EXPECT_TRUE(IsKnownFileByDigestInfo(file_path2, signature_matcher.get(),
137 kFileContentDigestInfos,
138 base::size(kFileContentDigestInfos)));
139
140 // Replace the content of file_path2 with a content of the same size, it
141 // must no longer match.
142 ASSERT_EQ(sizeof(kFileContent2), sizeof(kFileContent4));
143 CreateFileWithContent(file_path2, kFileContent4, sizeof(kFileContent4));
144 EXPECT_FALSE(IsKnownFileByDigestInfo(file_path2, signature_matcher.get(),
145 kFileContentDigestInfos,
146 base::size(kFileContentDigestInfos)));
147
148 // The digest of |file_path3| is not in the array.
149 EXPECT_FALSE(IsKnownFileByDigestInfo(file_path3, signature_matcher.get(),
150 kFileContentDigestInfos,
151 base::size(kFileContentDigestInfos)));
152 // The |file_path4| doesn't exist.
153 EXPECT_FALSE(IsKnownFileByDigestInfo(file_path4, signature_matcher.get(),
154 kFileContentDigestInfos,
155 base::size(kFileContentDigestInfos)));
156 }
157
TEST(MatcherUtilTest,IsKnownFileByOriginalFilename)158 TEST(MatcherUtilTest, IsKnownFileByOriginalFilename) {
159 base::ScopedTempDir temp_dir;
160 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
161
162 TestSignatureMatcher signature_matcher;
163
164 const base::FilePath normalized_temp_dir_path =
165 NormalizePath(temp_dir.GetPath());
166
167 // A non-existing file should not be recognized.
168 base::FilePath nonexistent_file_path(
169 normalized_temp_dir_path.Append(kFileName1));
170 EXPECT_FALSE(IsKnownFileByOriginalFilename(
171 nonexistent_file_path, &signature_matcher, kKnownOriginalFilenames,
172 base::size(kKnownOriginalFilenames)));
173
174 // An existing file without version information should not be recognized.
175 base::FilePath file_path2(normalized_temp_dir_path.Append(kFileName2));
176 CreateFileWithContent(file_path2, kFileContent, sizeof(kFileContent));
177 EXPECT_FALSE(IsKnownFileByOriginalFilename(
178 file_path2, &signature_matcher, kKnownOriginalFilenames,
179 base::size(kKnownOriginalFilenames)));
180
181 // A file with version information but not in the array should not be
182 // recognized.
183 base::FilePath file_path3(normalized_temp_dir_path.Append(kFileName3));
184
185 VersionInformation goodware_information = {};
186 goodware_information.original_filename = kUnknownOriginalFilename;
187 signature_matcher.MatchVersionInformation(file_path3, goodware_information);
188
189 CreateFileWithContent(file_path3, kFileContent, sizeof(kFileContent));
190 EXPECT_FALSE(IsKnownFileByOriginalFilename(
191 file_path3, &signature_matcher, kKnownOriginalFilenames,
192 base::size(kKnownOriginalFilenames)));
193
194 // A file with version information present in the array should be recognized.
195 base::FilePath file_path4(normalized_temp_dir_path.Append(kFileName4));
196
197 VersionInformation badware_information = {};
198 badware_information.original_filename = kKnownOriginalFilename;
199 signature_matcher.MatchVersionInformation(file_path4, badware_information);
200
201 CreateFileWithContent(file_path4, kFileContent, sizeof(kFileContent));
202 EXPECT_TRUE(IsKnownFileByOriginalFilename(
203 file_path4, &signature_matcher, kKnownOriginalFilenames,
204 base::size(kKnownOriginalFilenames)));
205 }
206
TEST(MatcherUtilTest,IsKnownFileByCompanyName)207 TEST(MatcherUtilTest, IsKnownFileByCompanyName) {
208 base::ScopedTempDir temp_dir;
209 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
210
211 const base::FilePath normalized_temp_dir_path =
212 NormalizePath(temp_dir.GetPath());
213
214 TestSignatureMatcher signature_matcher;
215
216 // A non-existing file should not be recognized.
217 base::FilePath nonexistent_file_path(
218 normalized_temp_dir_path.Append(kFileName1));
219 EXPECT_FALSE(IsKnownFileByCompanyName(nonexistent_file_path,
220 &signature_matcher, kKnownCompanyNames,
221 base::size(kKnownCompanyNames)));
222
223 // An existing file without version information should not be recognized.
224 base::FilePath file_path2(normalized_temp_dir_path.Append(kFileName2));
225 CreateFileWithContent(file_path2, kFileContent, sizeof(kFileContent));
226 EXPECT_FALSE(IsKnownFileByCompanyName(file_path2, &signature_matcher,
227 kKnownCompanyNames,
228 base::size(kKnownCompanyNames)));
229
230 // A file with version information but not in the array should not be
231 // recognized.
232 base::FilePath file_path3(normalized_temp_dir_path.Append(kFileName3));
233
234 VersionInformation goodware_information = {};
235 goodware_information.company_name = kUnknownCompanyName;
236 signature_matcher.MatchVersionInformation(file_path3, goodware_information);
237
238 CreateFileWithContent(file_path3, kFileContent, sizeof(kFileContent));
239 EXPECT_FALSE(IsKnownFileByCompanyName(file_path3, &signature_matcher,
240 kKnownCompanyNames,
241 base::size(kKnownCompanyNames)));
242
243 // A file with version information present in the array should be recognized.
244 base::FilePath file_path4(normalized_temp_dir_path.Append(kFileName4));
245
246 VersionInformation badware_information = {};
247 badware_information.company_name = kKnownCompanyName;
248 signature_matcher.MatchVersionInformation(file_path4, badware_information);
249
250 CreateFileWithContent(file_path4, kFileContent, sizeof(kFileContent));
251 EXPECT_TRUE(IsKnownFileByCompanyName(file_path4, &signature_matcher,
252 kKnownCompanyNames,
253 base::size(kKnownCompanyNames)));
254 }
255
256 } // namespace chrome_cleaner
257