1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This file contains unit tests for PEImage.
6 #include <algorithm>
7
8 #include "base/files/file_path.h"
9 #include "base/path_service.h"
10 #include "base/scoped_native_library.h"
11 #include "base/win/pe_image.h"
12 #include "build/build_config.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace base {
16 namespace win {
17
18 namespace {
19
20 // Just counts the number of invocations.
ImportsCallback(const PEImage & image,LPCSTR module,DWORD ordinal,LPCSTR name,DWORD hint,PIMAGE_THUNK_DATA iat,PVOID cookie)21 bool ImportsCallback(const PEImage& image,
22 LPCSTR module,
23 DWORD ordinal,
24 LPCSTR name,
25 DWORD hint,
26 PIMAGE_THUNK_DATA iat,
27 PVOID cookie) {
28 int* count = reinterpret_cast<int*>(cookie);
29 (*count)++;
30 return true;
31 }
32
33 // Just counts the number of invocations.
SectionsCallback(const PEImage & image,PIMAGE_SECTION_HEADER header,PVOID section_start,DWORD section_size,PVOID cookie)34 bool SectionsCallback(const PEImage& image,
35 PIMAGE_SECTION_HEADER header,
36 PVOID section_start,
37 DWORD section_size,
38 PVOID cookie) {
39 int* count = reinterpret_cast<int*>(cookie);
40 (*count)++;
41 return true;
42 }
43
44 // Just counts the number of invocations.
RelocsCallback(const PEImage & image,WORD type,PVOID address,PVOID cookie)45 bool RelocsCallback(const PEImage& image,
46 WORD type,
47 PVOID address,
48 PVOID cookie) {
49 int* count = reinterpret_cast<int*>(cookie);
50 (*count)++;
51 return true;
52 }
53
54 // Just counts the number of invocations.
ImportChunksCallback(const PEImage & image,LPCSTR module,PIMAGE_THUNK_DATA name_table,PIMAGE_THUNK_DATA iat,PVOID cookie)55 bool ImportChunksCallback(const PEImage& image,
56 LPCSTR module,
57 PIMAGE_THUNK_DATA name_table,
58 PIMAGE_THUNK_DATA iat,
59 PVOID cookie) {
60 int* count = reinterpret_cast<int*>(cookie);
61 (*count)++;
62 return true;
63 }
64
65 // Just counts the number of invocations.
DelayImportChunksCallback(const PEImage & image,PImgDelayDescr delay_descriptor,LPCSTR module,PIMAGE_THUNK_DATA name_table,PIMAGE_THUNK_DATA iat,PVOID cookie)66 bool DelayImportChunksCallback(const PEImage& image,
67 PImgDelayDescr delay_descriptor,
68 LPCSTR module,
69 PIMAGE_THUNK_DATA name_table,
70 PIMAGE_THUNK_DATA iat,
71 PVOID cookie) {
72 int* count = reinterpret_cast<int*>(cookie);
73 (*count)++;
74 return true;
75 }
76
77 // Just counts the number of invocations.
ExportsCallback(const PEImage & image,DWORD ordinal,DWORD hint,LPCSTR name,PVOID function,LPCSTR forward,PVOID cookie)78 bool ExportsCallback(const PEImage& image,
79 DWORD ordinal,
80 DWORD hint,
81 LPCSTR name,
82 PVOID function,
83 LPCSTR forward,
84 PVOID cookie) {
85 int* count = reinterpret_cast<int*>(cookie);
86 (*count)++;
87 return true;
88 }
89
GetPEImageTestPath()90 base::FilePath GetPEImageTestPath() {
91 base::FilePath pe_image_test_path;
92 EXPECT_TRUE(PathService::Get(DIR_TEST_DATA, &pe_image_test_path));
93 pe_image_test_path = pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image"));
94 #if defined(ARCH_CPU_ARM64)
95 pe_image_test_path =
96 pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_arm64.dll"));
97 #elif defined(ARCH_CPU_X86_64)
98 pe_image_test_path =
99 pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_64.dll"));
100 #elif defined(ARCH_CPU_X86)
101 pe_image_test_path =
102 pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_32.dll"));
103 #else
104 #error This platform is not supported.
105 #endif
106 return pe_image_test_path;
107 }
108
109 } // namespace
110
111 // Tests that we are able to enumerate stuff from a PE file, and that
112 // the actual number of items found matches an expected value.
TEST(PEImageTest,EnumeratesPE)113 TEST(PEImageTest, EnumeratesPE) {
114 base::FilePath pe_image_test_path = GetPEImageTestPath();
115
116 #if defined(ARCH_CPU_ARM64)
117 const int kSections = 7;
118 const int kImportsDlls = 3;
119 const int kDelayDlls = 2;
120 const int kExports = 3;
121 const int kImports = 72;
122 const int kDelayImports = 2;
123 const int kRelocs = 740;
124 #elif defined(ARCH_CPU_64_BITS)
125 const int kSections = 6;
126 const int kImportsDlls = 2;
127 const int kDelayDlls = 2;
128 const int kExports = 3;
129 const int kImports = 70;
130 const int kDelayImports = 2;
131 const int kRelocs = 976;
132 #else
133 const int kSections = 5;
134 const int kImportsDlls = 2;
135 const int kDelayDlls = 2;
136 const int kExports = 3;
137 const int kImports = 66;
138 const int kDelayImports = 2;
139 const int kRelocs = 2114;
140 #endif
141
142 ScopedNativeLibrary module(pe_image_test_path);
143 ASSERT_TRUE(module.is_valid());
144
145 PEImage pe(module.get());
146 int count = 0;
147 EXPECT_TRUE(pe.VerifyMagic());
148
149 pe.EnumSections(SectionsCallback, &count);
150 EXPECT_EQ(kSections, count);
151
152 count = 0;
153 pe.EnumImportChunks(ImportChunksCallback, &count, nullptr);
154 EXPECT_EQ(kImportsDlls, count);
155
156 count = 0;
157 pe.EnumDelayImportChunks(DelayImportChunksCallback, &count, nullptr);
158 EXPECT_EQ(kDelayDlls, count);
159
160 count = 0;
161 pe.EnumExports(ExportsCallback, &count);
162 EXPECT_EQ(kExports, count);
163
164 count = 0;
165 pe.EnumAllImports(ImportsCallback, &count, nullptr);
166 EXPECT_EQ(kImports, count);
167
168 count = 0;
169 pe.EnumAllDelayImports(ImportsCallback, &count, nullptr);
170 EXPECT_EQ(kDelayImports, count);
171
172 count = 0;
173 pe.EnumRelocs(RelocsCallback, &count);
174 EXPECT_EQ(kRelocs, count);
175 }
176
177 // Tests that we are able to enumerate stuff from a PE file, and that
178 // the actual number of items found matches an expected value.
TEST(PEImageTest,EnumeratesPEWithTargetModule)179 TEST(PEImageTest, EnumeratesPEWithTargetModule) {
180 base::FilePath pe_image_test_path = GetPEImageTestPath();
181 const char kTargetModuleStatic[] = "user32.dll";
182 const char kTargetModuleDelay[] = "cfgmgr32.dll";
183
184 const int kImportsDlls = 1;
185 const int kDelayDlls = 1;
186 const int kExports = 3;
187 const int kImports = 2;
188 const int kDelayImports = 1;
189 #if defined(ARCH_CPU_ARM64)
190 const int kSections = 7;
191 const int kRelocs = 740;
192 #elif defined(ARCH_CPU_64_BITS)
193 const int kSections = 6;
194 const int kRelocs = 976;
195 #else
196 const int kSections = 5;
197 const int kRelocs = 2114;
198 #endif
199
200 ScopedNativeLibrary module(pe_image_test_path);
201 ASSERT_TRUE(module.is_valid());
202
203 PEImage pe(module.get());
204 int count = 0;
205 EXPECT_TRUE(pe.VerifyMagic());
206
207 pe.EnumSections(SectionsCallback, &count);
208 EXPECT_EQ(kSections, count);
209
210 count = 0;
211 pe.EnumImportChunks(ImportChunksCallback, &count, kTargetModuleStatic);
212 EXPECT_EQ(kImportsDlls, count);
213
214 count = 0;
215 pe.EnumDelayImportChunks(DelayImportChunksCallback, &count,
216 kTargetModuleDelay);
217 EXPECT_EQ(kDelayDlls, count);
218
219 count = 0;
220 pe.EnumExports(ExportsCallback, &count);
221 EXPECT_EQ(kExports, count);
222
223 count = 0;
224 pe.EnumAllImports(ImportsCallback, &count, kTargetModuleStatic);
225 EXPECT_EQ(kImports, count);
226
227 count = 0;
228 pe.EnumAllDelayImports(ImportsCallback, &count, kTargetModuleDelay);
229 EXPECT_EQ(kDelayImports, count);
230
231 count = 0;
232 pe.EnumRelocs(RelocsCallback, &count);
233 EXPECT_EQ(kRelocs, count);
234 }
235
236 // Tests that we can locate an specific exported symbol, by name and by ordinal.
TEST(PEImageTest,RetrievesExports)237 TEST(PEImageTest, RetrievesExports) {
238 ScopedNativeLibrary module(FilePath(FILE_PATH_LITERAL("advapi32.dll")));
239 ASSERT_TRUE(module.is_valid());
240
241 PEImage pe(module.get());
242 WORD ordinal;
243
244 EXPECT_TRUE(pe.GetProcOrdinal("RegEnumKeyExW", &ordinal));
245
246 FARPROC address1 = pe.GetProcAddress("RegEnumKeyExW");
247 FARPROC address2 = pe.GetProcAddress(reinterpret_cast<char*>(ordinal));
248 EXPECT_TRUE(address1 != nullptr);
249 EXPECT_TRUE(address2 != nullptr);
250 EXPECT_TRUE(address1 == address2);
251 }
252
253 // Tests that we can locate a forwarded export.
TEST(PEImageTest,ForwardedExport)254 TEST(PEImageTest, ForwardedExport) {
255 base::FilePath pe_image_test_path = GetPEImageTestPath();
256
257 ScopedNativeLibrary module(pe_image_test_path);
258
259 ASSERT_TRUE(module.is_valid());
260
261 PEImage pe(module.get());
262
263 FARPROC addr = pe.GetProcAddress("FwdExport");
264 EXPECT_EQ(FARPROC(-1), addr);
265
266 PDWORD export_entry = pe.GetExportEntry("FwdExport");
267 EXPECT_NE(nullptr, export_entry);
268 PVOID fwd_addr = pe.RVAToAddr(*export_entry);
269 const char expected_fwd[] = "KERNEL32.CreateFileA";
270 EXPECT_STREQ(expected_fwd, reinterpret_cast<char*>(fwd_addr));
271 }
272
273 // Test that we can get debug id out of a module.
TEST(PEImageTest,GetDebugId)274 TEST(PEImageTest, GetDebugId) {
275 static constexpr char kPdbFileName[] = "advapi32.pdb";
276 ScopedNativeLibrary module(FilePath(FILE_PATH_LITERAL("advapi32.dll")));
277 ASSERT_TRUE(module.is_valid());
278
279 PEImage pe(module.get());
280 GUID guid = {0};
281 DWORD age = 0;
282 LPCSTR pdb_file = nullptr;
283 size_t pdb_file_length = 0;
284 EXPECT_TRUE(pe.GetDebugId(&guid, &age, &pdb_file, &pdb_file_length));
285 EXPECT_EQ(pdb_file_length, strlen(kPdbFileName));
286 EXPECT_STREQ(pdb_file, kPdbFileName);
287
288 // Should be valid to call without parameters.
289 EXPECT_TRUE(pe.GetDebugId(nullptr, nullptr, nullptr, nullptr));
290
291 GUID empty_guid = {0};
292 EXPECT_TRUE(!IsEqualGUID(empty_guid, guid));
293 EXPECT_NE(0U, age);
294 }
295
296 } // namespace win
297 } // namespace base
298