| // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This file contains unit tests for PEImage. |
| |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "base/win/pe_image.h" |
| #include "base/win/windows_version.h" |
| |
| namespace base { |
| namespace win { |
| |
| // Just counts the number of invocations. |
| bool ExportsCallback(const PEImage &image, |
| DWORD ordinal, |
| DWORD hint, |
| LPCSTR name, |
| PVOID function, |
| LPCSTR forward, |
| PVOID cookie) { |
| int* count = reinterpret_cast<int*>(cookie); |
| (*count)++; |
| return true; |
| } |
| |
| // Just counts the number of invocations. |
| bool ImportsCallback(const PEImage &image, |
| LPCSTR module, |
| DWORD ordinal, |
| LPCSTR name, |
| DWORD hint, |
| PIMAGE_THUNK_DATA iat, |
| PVOID cookie) { |
| int* count = reinterpret_cast<int*>(cookie); |
| (*count)++; |
| return true; |
| } |
| |
| // Just counts the number of invocations. |
| bool SectionsCallback(const PEImage &image, |
| PIMAGE_SECTION_HEADER header, |
| PVOID section_start, |
| DWORD section_size, |
| PVOID cookie) { |
| int* count = reinterpret_cast<int*>(cookie); |
| (*count)++; |
| return true; |
| } |
| |
| // Just counts the number of invocations. |
| bool RelocsCallback(const PEImage &image, |
| WORD type, |
| PVOID address, |
| PVOID cookie) { |
| int* count = reinterpret_cast<int*>(cookie); |
| (*count)++; |
| return true; |
| } |
| |
| // Just counts the number of invocations. |
| bool ImportChunksCallback(const PEImage &image, |
| LPCSTR module, |
| PIMAGE_THUNK_DATA name_table, |
| PIMAGE_THUNK_DATA iat, |
| PVOID cookie) { |
| int* count = reinterpret_cast<int*>(cookie); |
| (*count)++; |
| return true; |
| } |
| |
| // Just counts the number of invocations. |
| bool DelayImportChunksCallback(const PEImage &image, |
| PImgDelayDescr delay_descriptor, |
| LPCSTR module, |
| PIMAGE_THUNK_DATA name_table, |
| PIMAGE_THUNK_DATA iat, |
| PIMAGE_THUNK_DATA bound_iat, |
| PIMAGE_THUNK_DATA unload_iat, |
| PVOID cookie) { |
| int* count = reinterpret_cast<int*>(cookie); |
| (*count)++; |
| return true; |
| } |
| |
| // We'll be using some known values for the tests. |
| enum Value { |
| sections = 0, |
| imports_dlls, |
| delay_dlls, |
| exports, |
| imports, |
| delay_imports, |
| relocs |
| }; |
| |
| // Retrieves the expected value from advapi32.dll based on the OS. |
| int GetExpectedValue(Value value, DWORD os) { |
| const int xp_delay_dlls = 2; |
| const int xp_exports = 675; |
| const int xp_imports = 422; |
| const int xp_delay_imports = 8; |
| const int xp_relocs = 9180; |
| const int vista_delay_dlls = 4; |
| const int vista_exports = 799; |
| const int vista_imports = 476; |
| const int vista_delay_imports = 24; |
| const int vista_relocs = 10188; |
| const int w2k_delay_dlls = 0; |
| const int w2k_exports = 566; |
| const int w2k_imports = 357; |
| const int w2k_delay_imports = 0; |
| const int w2k_relocs = 7388; |
| const int win7_delay_dlls = 7; |
| const int win7_exports = 806; |
| const int win7_imports = 568; |
| const int win7_delay_imports = 71; |
| const int win7_relocs = 7812; |
| |
| // Contains the expected value, for each enumerated property (Value), and the |
| // OS version: [Value][os_version] |
| const int expected[][4] = { |
| {4, 4, 4, 4}, |
| {3, 3, 3, 13}, |
| {w2k_delay_dlls, xp_delay_dlls, vista_delay_dlls, win7_delay_dlls}, |
| {w2k_exports, xp_exports, vista_exports, win7_exports}, |
| {w2k_imports, xp_imports, vista_imports, win7_imports}, |
| {w2k_delay_imports, xp_delay_imports, |
| vista_delay_imports, win7_delay_imports}, |
| {w2k_relocs, xp_relocs, vista_relocs, win7_relocs} |
| }; |
| |
| if (value > relocs) |
| return 0; |
| if (50 == os) |
| os = 0; // 5.0 |
| else if (51 == os || 52 == os) |
| os = 1; |
| else if (os == 60) |
| os = 2; // 6.x |
| else if (os >= 61) |
| os = 3; |
| else |
| return 0; |
| |
| return expected[value][os]; |
| } |
| |
| // Tests that we are able to enumerate stuff from a PE file, and that |
| // the actual number of items found is within the expected range. |
| TEST(PEImageTest, EnumeratesPE) { |
| // Windows Server 2003 is not supported as a test environment for this test. |
| if (base::win::GetVersion() == base::win::VERSION_SERVER_2003) |
| return; |
| HMODULE module = LoadLibrary(L"advapi32.dll"); |
| ASSERT_TRUE(NULL != module); |
| |
| PEImage pe(module); |
| int count = 0; |
| EXPECT_TRUE(pe.VerifyMagic()); |
| |
| DWORD os = pe.GetNTHeaders()->OptionalHeader.MajorOperatingSystemVersion; |
| os = os * 10 + pe.GetNTHeaders()->OptionalHeader.MinorOperatingSystemVersion; |
| |
| pe.EnumSections(SectionsCallback, &count); |
| EXPECT_EQ(GetExpectedValue(sections, os), count); |
| |
| count = 0; |
| pe.EnumImportChunks(ImportChunksCallback, &count); |
| EXPECT_EQ(GetExpectedValue(imports_dlls, os), count); |
| |
| count = 0; |
| pe.EnumDelayImportChunks(DelayImportChunksCallback, &count); |
| EXPECT_EQ(GetExpectedValue(delay_dlls, os), count); |
| |
| count = 0; |
| pe.EnumExports(ExportsCallback, &count); |
| EXPECT_GT(count, GetExpectedValue(exports, os) - 20); |
| EXPECT_LT(count, GetExpectedValue(exports, os) + 100); |
| |
| count = 0; |
| pe.EnumAllImports(ImportsCallback, &count); |
| EXPECT_GT(count, GetExpectedValue(imports, os) - 20); |
| EXPECT_LT(count, GetExpectedValue(imports, os) + 100); |
| |
| count = 0; |
| pe.EnumAllDelayImports(ImportsCallback, &count); |
| EXPECT_GT(count, GetExpectedValue(delay_imports, os) - 2); |
| EXPECT_LT(count, GetExpectedValue(delay_imports, os) + 8); |
| |
| count = 0; |
| pe.EnumRelocs(RelocsCallback, &count); |
| EXPECT_GT(count, GetExpectedValue(relocs, os) - 150); |
| EXPECT_LT(count, GetExpectedValue(relocs, os) + 1500); |
| |
| FreeLibrary(module); |
| } |
| |
| // Tests that we can locate an specific exported symbol, by name and by ordinal. |
| TEST(PEImageTest, RetrievesExports) { |
| HMODULE module = LoadLibrary(L"advapi32.dll"); |
| ASSERT_TRUE(NULL != module); |
| |
| PEImage pe(module); |
| WORD ordinal; |
| |
| EXPECT_TRUE(pe.GetProcOrdinal("RegEnumKeyExW", &ordinal)); |
| |
| FARPROC address1 = pe.GetProcAddress("RegEnumKeyExW"); |
| FARPROC address2 = pe.GetProcAddress(reinterpret_cast<char*>(ordinal)); |
| EXPECT_TRUE(address1 != NULL); |
| EXPECT_TRUE(address2 != NULL); |
| EXPECT_TRUE(address1 == address2); |
| |
| FreeLibrary(module); |
| } |
| |
| } // namespace win |
| } // namespace base |