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/module_integrity_verifier.h" | |
6 | |
7 #include "base/files/file_path.h" | |
8 #include "base/files/memory_mapped_file.h" | |
9 #include "base/native_library.h" | |
10 #include "base/path_service.h" | |
11 #include "base/scoped_native_library.h" | |
12 #include "base/win/pe_image.h" | |
13 #include "testing/gtest/include/gtest/gtest.h" | |
14 | |
15 namespace safe_browsing { | |
16 | |
17 const wchar_t kTestDllName[] = L"verifier_test_dll.dll"; | |
grt (UTC plus 2)
2014/07/31 17:03:34
put in unnamed namespace
krstnmnlsn
2014/08/04 15:18:16
Right.
| |
18 | |
19 class SafeBrowsingModuleVerifierTest : public testing::Test { | |
20 protected: | |
21 SafeBrowsingModuleVerifierTest() {} | |
grt (UTC plus 2)
2014/07/31 17:03:34
may as well remove these
krstnmnlsn
2014/08/04 15:18:15
Done.
| |
22 virtual ~SafeBrowsingModuleVerifierTest() {} | |
23 | |
24 base::ScopedNativeLibrary mem_dll_handle_; | |
25 base::MemoryMappedFile disk_dll_handle_; | |
26 scoped_ptr<base::win::PEImageAsData> disk_peimage_ptr_; | |
27 scoped_ptr<base::win::PEImage> mem_peimage_ptr_; | |
28 | |
29 void SetUpTestDllAndPEImages() { | |
30 LoadModule(); | |
31 HMODULE mem_handle; | |
32 HMODULE disk_handle; | |
33 GetMemModuleHandle(&mem_handle); | |
34 GetDiskModuleHandle(&disk_handle); | |
35 | |
36 disk_peimage_ptr_.reset(new base::win::PEImageAsData(disk_handle)); | |
37 ASSERT_TRUE(disk_peimage_ptr_->VerifyMagic()); | |
38 mem_peimage_ptr_.reset(new base::win::PEImage(mem_handle)); | |
39 ASSERT_TRUE(mem_peimage_ptr_->VerifyMagic()); | |
40 } | |
41 | |
42 void LoadModule() { | |
43 base::FilePath current_dir; | |
44 ASSERT_TRUE(PathService::Get(base::DIR_EXE, ¤t_dir)); | |
grt (UTC plus 2)
2014/07/31 17:03:34
is this needed? doesn't the loader check the exe's
krstnmnlsn
2014/08/04 15:18:15
Yep, seems like I don't need it.
| |
45 mem_dll_handle_.Reset( | |
46 LoadNativeLibrary(current_dir.Append(kTestDllName), NULL)); | |
47 ASSERT_TRUE(mem_dll_handle_.is_valid()); | |
48 } | |
49 | |
50 void GetMemModuleHandle(HMODULE* mem_handle) { | |
51 *mem_handle = GetModuleHandle(kTestDllName); | |
52 ASSERT_TRUE(NULL != *mem_handle); | |
grt (UTC plus 2)
2014/07/31 17:03:34
as clumsy as it is:
ASSERT_NE(static_cast<HMOD
krstnmnlsn
2014/08/04 15:18:15
Done.
| |
53 } | |
54 | |
55 void GetDiskModuleHandle(HMODULE* disk_handle) { | |
56 // Use the module handle to find the it on disk, then load as a file. | |
57 HMODULE module_handle = GetModuleHandle(kTestDllName); | |
58 ASSERT_TRUE(NULL != module_handle); | |
grt (UTC plus 2)
2014/07/31 17:03:34
ASSERT_NE(static_cast<HMODULE>(NULL), module_handl
krstnmnlsn
2014/08/04 15:18:15
Done.
| |
59 | |
60 WCHAR module_path[MAX_PATH] = {}; | |
61 DWORD length = | |
62 GetModuleFileName(module_handle, module_path, arraysize(module_path)); | |
63 ASSERT_NE(length, arraysize(module_path)); | |
grt (UTC plus 2)
2014/07/31 17:03:34
swap args. reason: the expected value comes first
krstnmnlsn
2014/08/04 15:18:15
Done.
| |
64 | |
65 ASSERT_TRUE(disk_dll_handle_.Initialize(base::FilePath(module_path))); | |
66 *disk_handle = | |
67 reinterpret_cast<HMODULE>(const_cast<uint8*>(disk_dll_handle_.data())); | |
68 } | |
69 | |
70 private: | |
grt (UTC plus 2)
2014/07/31 17:03:34
not needed for tests
krstnmnlsn
2014/08/04 15:18:15
Done.
| |
71 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingModuleVerifierTest); | |
72 }; | |
73 | |
74 TEST_F(SafeBrowsingModuleVerifierTest, CountBytesDiffInPtr) { | |
75 // Construct test pointers and try with CountBytesDiffInPtr. | |
76 // The first Bytes differ. | |
77 uintptr_t num_a = 0xFF; | |
78 uintptr_t num_b = 0x00; | |
79 | |
80 // Any inbetween Bytes are identical. | |
81 int num_bytes_to_add = sizeof(num_a) - 2; | |
82 for (int i = 0; i < num_bytes_to_add; ++i) { | |
83 num_a <<= 8; | |
84 num_b <<= 8; | |
85 num_a += 0xFF; | |
86 num_b += 0xFF; | |
87 } | |
88 | |
89 // The last Bytes differ. | |
90 num_a <<= 8; | |
91 num_b <<= 8; | |
92 num_a += 0x0F; | |
93 num_b += 0xFF; | |
94 | |
95 EXPECT_EQ(2, CountBytesDiffInPtr(num_a, num_b)); | |
96 EXPECT_EQ(2, CountBytesDiffInPtr(num_b, num_a)); | |
97 EXPECT_EQ(0, CountBytesDiffInPtr(num_a, num_a)); | |
98 } | |
99 | |
100 TEST_F(SafeBrowsingModuleVerifierTest, VerifyModuleUnmodified) { | |
101 // Call VerifyModule before the module has been loaded, should fail. | |
102 EXPECT_EQ(MODULE_STATE_UNKNOWN, VerifyModule(kTestDllName)); | |
103 | |
104 // On loading, the module should be identical (up to relocations) in memory as | |
105 // on disk. | |
106 SetUpTestDllAndPEImages(); | |
107 EXPECT_EQ(MODULE_STATE_UNMODIFIED, VerifyModule(kTestDllName)); | |
108 } | |
109 | |
110 TEST_F(SafeBrowsingModuleVerifierTest, VerifyModuleModified) { | |
111 // Confirm the module is identical in memory as on disk before we begin. | |
112 SetUpTestDllAndPEImages(); | |
113 EXPECT_EQ(MODULE_STATE_UNMODIFIED, VerifyModule(kTestDllName)); | |
114 | |
115 uint8_t* mem_code_addr = NULL; | |
116 uint8_t* disk_code_addr = NULL; | |
117 uint32_t code_size = 0; | |
118 EXPECT_TRUE(GetCodeAddrsAndSize(*mem_peimage_ptr_, | |
119 *disk_peimage_ptr_, | |
120 &mem_code_addr, | |
121 &disk_code_addr, | |
122 &code_size)); | |
123 | |
124 // Edit the first byte of the code section of the module. | |
125 uint8_t new_val = (*mem_code_addr) + 1; | |
126 SIZE_T bytes_written = 0; | |
127 WriteProcessMemory(GetCurrentProcess(), | |
128 mem_code_addr, | |
129 reinterpret_cast<void*>(&new_val), | |
130 1, | |
131 &bytes_written); | |
132 EXPECT_EQ(1, bytes_written); | |
133 | |
134 // VerifyModule should detect the change. | |
135 EXPECT_EQ(MODULE_STATE_MODIFIED, VerifyModule(kTestDllName)); | |
136 } | |
137 | |
138 } // namespace safe_browsing | |
OLD | NEW |