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/incident_reporting/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/incident_reporting/module_integrity_unittest_util_win.h" 17#include "chrome/browser/safe_browsing/incident_reporting/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 24namespace { 25 26const 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|. 30bool 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|. 47bool 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 69TEST(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 90TEST(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 126TEST(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); 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 173TEST(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. Calling 183 // GetModuleHandle so we do not increment the library ref count. 184 HMODULE module_handle = GetModuleHandle(safe_browsing::kTestDllNames[0]); 185 EXPECT_NE(reinterpret_cast<HANDLE>(NULL), module_handle); 186 uint8_t* export_addr = reinterpret_cast<uint8_t*>( 187 GetProcAddress(module_handle, safe_browsing::kTestExportName)); 188 EXPECT_NE(reinterpret_cast<uint8_t*>(NULL), export_addr); 189 190 uint8_t new_val = (*export_addr) + 1; 191 SIZE_T bytes_written = 0; 192 WriteProcessMemory(GetCurrentProcess(), 193 export_addr, 194 reinterpret_cast<void*>(&new_val), 195 1, 196 &bytes_written); 197 EXPECT_EQ(1, bytes_written); 198 199 safe_browsing::ClientIncidentReport_EnvironmentData_Process process_report; 200 safe_browsing::CollectModuleVerificationData( 201 safe_browsing::kTestDllNames, 202 safe_browsing::kTestDllNamesCount, 203 &process_report); 204 205 // CollectModuleVerificationData should return the single modified module and 206 // its modified export. The other module, being unmodified, is omitted from 207 // the returned list of modules. 208 EXPECT_EQ(1, process_report.module_state_size()); 209 210 EXPECT_EQ(base::WideToUTF8(std::wstring(safe_browsing::kTestDllNames[0])), 211 process_report.module_state(0).name()); 212 EXPECT_EQ( 213 safe_browsing::ClientIncidentReport_EnvironmentData_Process_ModuleState:: 214 MODULE_STATE_MODIFIED, 215 process_report.module_state(0).modified_state()); 216 EXPECT_EQ(1, process_report.module_state(0).modified_export_size()); 217 EXPECT_EQ(std::string(safe_browsing::kTestExportName), 218 process_report.module_state(0).modified_export(0)); 219} 220