1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/agent/asan/iat_patcher.h"
16 :
17 : #include <vector>
18 :
19 : #include "base/files/file_path.h"
20 : #include "base/win/pe_image.h"
21 : #include "gtest/gtest.h"
22 : #include "syzygy/core/unittest_util.h"
23 :
24 : namespace agent {
25 : namespace asan {
26 :
27 : namespace {
28 :
29 : class IATPatcherTest : public testing::Test {
30 : public:
31 : using ImportTable = std::vector<FunctionPointer>;
32 :
33 E : IATPatcherTest() : test_dll_(nullptr) {
34 E : }
35 :
36 E : void SetUp() override {
37 : base::FilePath path =
38 E : testing::GetExeRelativePath(L"test_dll.dll");
39 E : test_dll_ = ::LoadLibrary(path.value().c_str());
40 E : ASSERT_NE(nullptr, test_dll_);
41 E : }
42 :
43 E : void TearDown() override {
44 E : if (test_dll_ != nullptr) {
45 E : ::FreeLibrary(test_dll_);
46 E : test_dll_ = nullptr;
47 : }
48 E : }
49 :
50 E : ImportTable GetIAT(HMODULE module) {
51 E : base::win::PEImage image(module);
52 E : ImportTable ret;
53 :
54 E : image.EnumAllImports(OnImport, &ret);
55 :
56 E : return ret;
57 E : }
58 :
59 E : DWORD GetIATPageProtection(HMODULE module) {
60 E : base::win::PEImage image(module);
61 :
62 : const void* iat =
63 E : image.GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_IAT);
64 :
65 E : MEMORY_BASIC_INFORMATION memory_info {};
66 E : EXPECT_TRUE(::VirtualQuery(iat, &memory_info, sizeof(memory_info)));
67 :
68 E : return memory_info.Protect;
69 E : }
70 :
71 : protected:
72 : static bool OnImport(const base::win::PEImage &image, LPCSTR module,
73 : DWORD ordinal, LPCSTR name, DWORD hint,
74 E : PIMAGE_THUNK_DATA iat, PVOID cookie) {
75 E : ImportTable* imports = reinterpret_cast<ImportTable*>(cookie);
76 E : imports->push_back(reinterpret_cast<FunctionPointer>(iat->u1.Function));
77 :
78 E : return true;
79 E : }
80 :
81 : HMODULE test_dll_;
82 : };
83 :
84 E : static void PatchDestination() {
85 E : }
86 :
87 : } // namespace
88 :
89 E : TEST_F(IATPatcherTest, PatchIATForModule) {
90 : // Capture the IAT of the test module before patching.
91 E : ImportTable iat_before = GetIAT(test_dll_);
92 E : DWORD prot_before = GetIATPageProtection(test_dll_);
93 :
94 : const DWORD kWritableMask =
95 : PAGE_READWRITE | PAGE_WRITECOPY |
96 E : PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
97 :
98 : // We expect the IAT not to be writable.
99 E : ASSERT_EQ(0, prot_before & kWritableMask);
100 :
101 : // None of the imports should point to the dummy destination.
102 E : for (auto fn : iat_before)
103 E : ASSERT_TRUE(PatchDestination != fn);
104 :
105 : // Construct a patch map to patch the named export_dll imports to a dummy
106 : // function.
107 E : IATPatchMap patches;
108 E : patches["function1"] = PatchDestination;
109 E : patches["function3"] = PatchDestination;
110 :
111 : // Patch'er up!
112 E : ASSERT_TRUE(PatchIATForModule(test_dll_, patches));
113 :
114 : // Make sure the IAT page protections have been reset.
115 E : ASSERT_EQ(prot_before, GetIATPageProtection(test_dll_));
116 :
117 : // Capture the IAT of the test module after patching and verify that the
118 : // expected number of functions got redirected to the dummy destination.
119 E : ImportTable iat_after = GetIAT(test_dll_);
120 E : size_t patched = 0;
121 E : for (auto func : iat_after) {
122 E : if (func == &PatchDestination)
123 E : ++patched;
124 E : }
125 :
126 E : ASSERT_EQ(2, patched);
127 E : }
128 :
129 : } // namespace asan
130 : } // namespace agent
|