OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/browser/safe_browsing/environment_data_collection_win.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/base_paths.h" | |
10 #include "base/files/file_path.h" | |
11 #include "base/path_service.h" | |
12 #include "base/scoped_native_library.h" | |
13 #include "base/strings/utf_string_conversions.h" | |
14 #include "base/test/test_reg_util_win.h" | |
15 #include "base/win/registry.h" | |
16 #include "chrome/browser/safe_browsing/module_integrity_unittest_util_win.h" | |
17 #include "chrome/browser/safe_browsing/module_integrity_verifier_win.h" | |
18 #include "chrome/browser/safe_browsing/path_sanitizer.h" | |
19 #include "chrome/common/safe_browsing/csd.pb.h" | |
20 #include "chrome_elf/chrome_elf_constants.h" | |
21 #include "net/base/winsock_init.h" | |
22 #include "testing/gtest/include/gtest/gtest.h" | |
23 | |
24 namespace { | |
25 | |
26 const wchar_t test_dll[] = L"test_name.dll"; | |
27 | |
28 // Helper function that returns true if a dll with filename |dll_name| is | |
29 // found in |process_report|. | |
30 bool ProcessReportContainsDll( | |
31 const safe_browsing::ClientIncidentReport_EnvironmentData_Process& | |
32 process_report, | |
33 const base::FilePath& dll_name) { | |
34 for (int i = 0; i < process_report.dll_size(); ++i) { | |
35 base::FilePath current_dll = | |
36 base::FilePath::FromUTF8Unsafe(process_report.dll(i).path()); | |
37 | |
38 if (current_dll.BaseName() == dll_name) | |
39 return true; | |
40 } | |
41 | |
42 return false; | |
43 } | |
44 | |
45 // Look through dll entries and check for the presence of the LSP feature for | |
46 // |dll|. | |
47 bool DllEntryContainsLspFeature( | |
48 const safe_browsing::ClientIncidentReport_EnvironmentData_Process& | |
49 process_report, | |
50 const std::string& dll) { | |
51 for (int i = 0; i < process_report.dll_size(); ++i) { | |
52 if (process_report.dll(i).path() == dll) { | |
53 // Verify each feature of |dll|. | |
54 for (int j = 0; j < process_report.dll(i).feature_size(); ++j) { | |
55 if (process_report.dll(i).feature(j) == | |
56 safe_browsing::ClientIncidentReport_EnvironmentData_Process_Dll:: | |
57 LSP) | |
58 // LSP feature found. | |
59 return true; | |
60 } | |
61 } | |
62 } | |
63 | |
64 return false; | |
65 } | |
66 | |
67 } // namespace | |
68 | |
69 TEST(SafeBrowsingEnvironmentDataCollectionWinTest, CollectDlls) { | |
70 // This test will check if the CollectDlls method works by loading | |
71 // a dll and then checking if we can find it within the process report. | |
72 // Pick msvidc32.dll as it is present from WinXP to Win8 and yet rarely used. | |
73 // msvidc32.dll exists in both 32 and 64 bit versions. | |
74 base::FilePath msvdc32_dll(L"msvidc32.dll"); | |
75 | |
76 safe_browsing::ClientIncidentReport_EnvironmentData_Process process_report; | |
77 safe_browsing::CollectDlls(&process_report); | |
78 | |
79 ASSERT_FALSE(ProcessReportContainsDll(process_report, msvdc32_dll)); | |
80 | |
81 // Redo the same verification after loading a new dll. | |
82 base::ScopedNativeLibrary library(msvdc32_dll); | |
83 | |
84 process_report.clear_dll(); | |
85 safe_browsing::CollectDlls(&process_report); | |
86 | |
87 ASSERT_TRUE(ProcessReportContainsDll(process_report, msvdc32_dll)); | |
88 } | |
89 | |
90 TEST(SafeBrowsingEnvironmentDataCollectionWinTest, RecordLspFeature) { | |
91 net::EnsureWinsockInit(); | |
92 | |
93 // Populate our incident report with loaded modules. | |
94 safe_browsing::ClientIncidentReport_EnvironmentData_Process process_report; | |
95 safe_browsing::CollectDlls(&process_report); | |
96 | |
97 // We'll test RecordLspFeatures against a real dll registered as a LSP. All | |
98 // dll paths are expected to be lowercase in the process report. | |
99 std::string lsp = "c:\\windows\\system32\\mswsock.dll"; | |
100 int base_address = 0x77770000; | |
101 int length = 0x180000; | |
102 | |
103 safe_browsing::RecordLspFeature(&process_report); | |
104 | |
105 // Return successfully if LSP feature is found. | |
106 if (DllEntryContainsLspFeature(process_report, lsp)) | |
107 return; | |
108 | |
109 // |lsp| was not already loaded into the current process. Manually add it | |
110 // to the process report so that it will get marked as a LSP. | |
111 safe_browsing::ClientIncidentReport_EnvironmentData_Process_Dll* dll = | |
112 process_report.add_dll(); | |
113 dll->set_path(lsp); | |
114 dll->set_base_address(base_address); | |
115 dll->set_length(length); | |
116 | |
117 safe_browsing::RecordLspFeature(&process_report); | |
118 | |
119 // Return successfully if LSP feature is found. | |
120 if (DllEntryContainsLspFeature(process_report, lsp)) | |
121 return; | |
122 | |
123 FAIL() << "No LSP feature found for " << lsp; | |
124 } | |
125 | |
126 TEST(SafeBrowsingEnvironmentDataCollectionWinTest, CollectDllBlacklistData) { | |
127 // Ensure that CollectDllBlacklistData correctly adds the set of sanitized dll | |
128 // names currently stored in the registry to the report. | |
129 registry_util::RegistryOverrideManager override_manager; | |
130 override_manager.OverrideRegistry(HKEY_CURRENT_USER, L"safe_browsing_test"); | |
131 | |
132 base::win::RegKey blacklist_registry_key(HKEY_CURRENT_USER, | |
133 blacklist::kRegistryFinchListPath, | |
134 KEY_QUERY_VALUE | KEY_SET_VALUE); | |
135 | |
136 // Check that with an empty registry the blacklisted dlls field is left empty. | |
137 safe_browsing::ClientIncidentReport_EnvironmentData_Process process_report; | |
138 safe_browsing::CollectDllBlacklistData(&process_report); | |
139 EXPECT_EQ(0, process_report.blacklisted_dll_size()); | |
140 | |
141 // Check that after adding exactly one dll to the registry it appears in the | |
142 // process report. | |
143 blacklist_registry_key.WriteValue(test_dll, test_dll); | |
144 safe_browsing::CollectDllBlacklistData(&process_report); | |
145 ASSERT_EQ(1, process_report.blacklisted_dll_size()); | |
146 | |
147 base::string16 process_report_dll = | |
148 base::UTF8ToWide(process_report.blacklisted_dll(0)); | |
149 EXPECT_EQ(base::string16(test_dll), process_report_dll); | |
150 | |
151 // Check that if the registry contains the full path to a dll it is properly | |
152 // sanitized before being reported. | |
153 blacklist_registry_key.DeleteValue(test_dll); | |
154 process_report.clear_blacklisted_dll(); | |
155 | |
156 base::FilePath path; | |
157 ASSERT_TRUE(PathService::Get(base::DIR_HOME, &path)); | |
158 base::string16 input_path = | |
159 path.Append(FILE_PATH_LITERAL("test_path.dll")).value(); | |
160 | |
161 std::string path_expected = base::FilePath(FILE_PATH_LITERAL("~")) | |
162 .Append(FILE_PATH_LITERAL("test_path.dll")) | |
163 .AsUTF8Unsafe(); | |
164 | |
165 blacklist_registry_key.WriteValue(input_path.c_str(), input_path.c_str()); | |
166 safe_browsing::CollectDllBlacklistData(&process_report); | |
167 | |
168 ASSERT_EQ(1, process_report.blacklisted_dll_size()); | |
169 std::string process_report_path = process_report.blacklisted_dll(0); | |
170 EXPECT_EQ(path_expected, process_report_path); | |
171 } | |
172 | |
173 TEST(SafeBrowsingEnvironmentDataCollectionWinTest, VerifyLoadedModules) { | |
174 // Load the test modules. | |
175 std::vector<base::ScopedNativeLibrary> test_dlls( | |
176 safe_browsing::kTestDllNamesCount); | |
177 for (size_t i = 0; i < safe_browsing::kTestDllNamesCount; ++i) { | |
178 test_dlls[i].Reset(LoadNativeLibrary( | |
179 base::FilePath(safe_browsing::kTestDllNames[i]), NULL)); | |
180 } | |
181 | |
182 // Edit the first byte of the function exported by the first module. | |
183 HMODULE module_handle = GetModuleHandle(safe_browsing::kTestDllNames[0]); | |
184 EXPECT_NE(reinterpret_cast<HANDLE>(NULL), module_handle); | |
185 uint8_t* export_addr = reinterpret_cast<uint8_t*>( | |
186 GetProcAddress(module_handle, safe_browsing::kTestExportName)); | |
187 EXPECT_NE(reinterpret_cast<uint8_t*>(NULL), export_addr); | |
188 | |
189 uint8_t new_val = (*export_addr) + 1; | |
190 SIZE_T bytes_written = 0; | |
191 WriteProcessMemory(GetCurrentProcess(), | |
192 export_addr, | |
193 reinterpret_cast<void*>(&new_val), | |
194 1, | |
195 &bytes_written); | |
196 EXPECT_EQ(1, bytes_written); | |
197 | |
198 safe_browsing::ClientIncidentReport_EnvironmentData_Process process_report; | |
199 safe_browsing::CollectModuleVerificationData( | |
200 safe_browsing::kTestDllNames, | |
201 safe_browsing::kTestDllNamesCount, | |
202 &process_report); | |
203 | |
204 // CollectModuleVerificationData should return the single modified module and | |
205 // its modified export. The other module, being unmodified, is omitted from | |
206 // the returned list of modules. | |
207 EXPECT_EQ(1, process_report.module_state_size()); | |
208 | |
209 EXPECT_EQ(base::WideToUTF8(std::wstring(safe_browsing::kTestDllNames[0])), | |
210 process_report.module_state(0).name()); | |
211 EXPECT_EQ( | |
212 safe_browsing::ClientIncidentReport_EnvironmentData_Process_ModuleState:: | |
213 MODULE_STATE_MODIFIED, | |
214 process_report.module_state(0).modified_state()); | |
215 EXPECT_EQ(1, process_report.module_state(0).modified_export_size()); | |
216 EXPECT_EQ(std::string(safe_browsing::kTestExportName), | |
217 process_report.module_state(0).modified_export(0)); | |
218 } | |
OLD | NEW |