16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 26e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 36e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// found in the LICENSE file. 46e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/safe_browsing/incident_reporting/module_integrity_verifier_win.h" 66e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/files/file_path.h" 86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/files/memory_mapped_file.h" 96e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/native_library.h" 106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/path_service.h" 116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/scoped_native_library.h" 126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/win/pe_image.h" 136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/safe_browsing/incident_reporting/module_integrity_unittest_util_win.h" 146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)namespace safe_browsing { 176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)class SafeBrowsingModuleVerifierWinTest : public testing::Test { 196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) protected: 206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void SetUpTestDllAndPEImages() { 216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) LoadModule(); 226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) HMODULE mem_handle; 236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) GetMemModuleHandle(&mem_handle); 246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) mem_peimage_ptr_.reset(new base::win::PEImage(mem_handle)); 256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ASSERT_TRUE(mem_peimage_ptr_->VerifyMagic()); 266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) LoadDLLAsFile(); 286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) HMODULE disk_handle; 296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) GetDiskModuleHandle(&disk_handle); 306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) disk_peimage_ptr_.reset(new base::win::PEImageAsData(disk_handle)); 316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ASSERT_TRUE(disk_peimage_ptr_->VerifyMagic()); 326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void LoadModule() { 356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) HMODULE mem_dll_handle = 366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) LoadNativeLibrary(base::FilePath(kTestDllNames[0]), NULL); 376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ASSERT_NE(static_cast<HMODULE>(NULL), mem_dll_handle) 386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) << "GLE=" << GetLastError(); 396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) mem_dll_handle_.Reset(mem_dll_handle); 406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ASSERT_TRUE(mem_dll_handle_.is_valid()); 416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void GetMemModuleHandle(HMODULE* mem_handle) { 446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) *mem_handle = GetModuleHandle(kTestDllNames[0]); 456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ASSERT_NE(static_cast<HMODULE>(NULL), *mem_handle); 466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void LoadDLLAsFile() { 496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Use the module handle to find the it on disk, then load as a file. 506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) HMODULE module_handle; 516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) GetMemModuleHandle(&module_handle); 526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) WCHAR module_path[MAX_PATH] = {}; 546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DWORD length = 556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) GetModuleFileName(module_handle, module_path, arraysize(module_path)); 566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ASSERT_NE(arraysize(module_path), length); 576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ASSERT_TRUE(disk_dll_handle_.Initialize(base::FilePath(module_path))); 586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void GetDiskModuleHandle(HMODULE* disk_handle) { 616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) *disk_handle = 626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reinterpret_cast<HMODULE>(const_cast<uint8*>(disk_dll_handle_.data())); 636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Edits the first byte of the single function exported by the test dll. 666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void EditExport() { 676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) HMODULE mem_handle; 686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) GetMemModuleHandle(&mem_handle); 696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t* export_addr = 706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reinterpret_cast<uint8_t*>(GetProcAddress(mem_handle, kTestExportName)); 716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_NE(reinterpret_cast<uint8_t*>(NULL), export_addr); 726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Edit the first byte of the function. 746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t new_val = (*export_addr) + 1; 756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) SIZE_T bytes_written = 0; 766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) WriteProcessMemory(GetCurrentProcess(), 776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) export_addr, 786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reinterpret_cast<void*>(&new_val), 796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1, 806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &bytes_written); 816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ(1, bytes_written); 826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::ScopedNativeLibrary mem_dll_handle_; 856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::MemoryMappedFile disk_dll_handle_; 866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) scoped_ptr<base::win::PEImageAsData> disk_peimage_ptr_; 876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) scoped_ptr<base::win::PEImage> mem_peimage_ptr_; 886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)TEST_F(SafeBrowsingModuleVerifierWinTest, VerifyModuleUnmodified) { 916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::set<std::string> modified_exports; 926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Call VerifyModule before the module has been loaded, should fail. 936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ(MODULE_STATE_UNKNOWN, 946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) VerifyModule(kTestDllNames[0], &modified_exports)); 956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ(0, modified_exports.size()); 966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // On loading, the module should be identical (up to relocations) in memory as 986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // on disk. 996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) SetUpTestDllAndPEImages(); 1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ(MODULE_STATE_UNMODIFIED, 1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) VerifyModule(kTestDllNames[0], &modified_exports)); 1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ(0, modified_exports.size()); 1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)TEST_F(SafeBrowsingModuleVerifierWinTest, VerifyModuleModified) { 1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::set<std::string> modified_exports; 1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Confirm the module is identical in memory as on disk before we begin. 1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) SetUpTestDllAndPEImages(); 1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ(MODULE_STATE_UNMODIFIED, 1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) VerifyModule(kTestDllNames[0], &modified_exports)); 1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t* mem_code_addr = NULL; 1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t* disk_code_addr = NULL; 1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint32_t code_size = 0; 1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_TRUE(GetCodeAddrsAndSize(*mem_peimage_ptr_, 1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) *disk_peimage_ptr_, 1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &mem_code_addr, 1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &disk_code_addr, 1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &code_size)); 1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Edit the first byte of the code section of the module (this may be before 1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // the address of any export). 1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t new_val = (*mem_code_addr) + 1; 1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) SIZE_T bytes_written = 0; 1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) WriteProcessMemory(GetCurrentProcess(), 1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) mem_code_addr, 1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reinterpret_cast<void*>(&new_val), 1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1, 1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &bytes_written); 1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ(1, bytes_written); 1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // VerifyModule should detect the change. 1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ(MODULE_STATE_MODIFIED, 1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) VerifyModule(kTestDllNames[0], &modified_exports)); 1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)TEST_F(SafeBrowsingModuleVerifierWinTest, VerifyModuleExportModified) { 1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::set<std::string> modified_exports; 1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Confirm the module is identical in memory as on disk before we begin. 1406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) SetUpTestDllAndPEImages(); 1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ(MODULE_STATE_UNMODIFIED, 1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) VerifyModule(kTestDllNames[0], &modified_exports)); 1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) modified_exports.clear(); 1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Edit the exported function, VerifyModule should now return the function 1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // name in modified_exports. 1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EditExport(); 1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ(MODULE_STATE_MODIFIED, 1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) VerifyModule(kTestDllNames[0], &modified_exports)); 1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ(1, modified_exports.size()); 1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ(0, std::string(kTestExportName).compare(*modified_exports.begin())); 1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} // namespace safe_browsing 155