xref: /aosp_15_r20/external/cronet/base/win/pe_image_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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