| // Copyright (c) 2012 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; |
| } |
| |
| // Identifiers for the set of supported expectations. |
| enum ExpectationSet { |
| WIN_2K_SET, |
| WIN_XP_SET, |
| WIN_VISTA_SET, |
| WIN_7_SET, |
| WIN_8_SET, |
| UNSUPPORTED_SET, |
| }; |
| |
| // We'll be using some known values for the tests. |
| enum Value { |
| sections = 0, |
| imports_dlls, |
| delay_dlls, |
| exports, |
| imports, |
| delay_imports, |
| relocs |
| }; |
| |
| ExpectationSet GetExpectationSet(DWORD os) { |
| if (os == 50) |
| return WIN_2K_SET; |
| if (os == 51) |
| return WIN_XP_SET; |
| if (os == 60) |
| return WIN_VISTA_SET; |
| if (os == 61) |
| return WIN_7_SET; |
| if (os >= 62) |
| return WIN_8_SET; |
| return UNSUPPORTED_SET; |
| } |
| |
| // 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; |
| const int win8_delay_dlls = 9; |
| const int win8_exports = 806; |
| const int win8_imports = 568; |
| const int win8_delay_imports = 113; |
| const int win8_relocs = 9478; |
| int win8_sections = 4; |
| int win8_import_dlls = 17; |
| |
| base::win::OSInfo* os_info = base::win::OSInfo::GetInstance(); |
| if (os_info->architecture() == base::win::OSInfo::X86_ARCHITECTURE) { |
| win8_sections = 5; |
| win8_import_dlls = 19; |
| } |
| |
| // Contains the expected value, for each enumerated property (Value), and the |
| // OS version: [Value][os_version] |
| const int expected[][5] = { |
| {4, 4, 4, 4, win8_sections}, |
| {3, 3, 3, 13, win8_import_dlls}, |
| {w2k_delay_dlls, xp_delay_dlls, vista_delay_dlls, win7_delay_dlls, |
| win8_delay_dlls}, |
| {w2k_exports, xp_exports, vista_exports, win7_exports, win8_exports}, |
| {w2k_imports, xp_imports, vista_imports, win7_imports, win8_imports}, |
| {w2k_delay_imports, xp_delay_imports, |
| vista_delay_imports, win7_delay_imports, win8_delay_imports}, |
| {w2k_relocs, xp_relocs, vista_relocs, win7_relocs, win8_relocs} |
| }; |
| COMPILE_ASSERT(arraysize(expected[0]) == UNSUPPORTED_SET, |
| expected_value_set_mismatch); |
| |
| if (value > relocs) |
| return 0; |
| ExpectationSet expected_set = GetExpectationSet(os); |
| if (expected_set >= arraysize(expected)) { |
| // This should never happen. Log a failure if it does. |
| EXPECT_NE(UNSUPPORTED_SET, expected_set); |
| expected_set = WIN_2K_SET; |
| } |
| |
| return expected[value][expected_set]; |
| } |
| |
| // 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) { |
| 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; |
| |
| // Skip this test for unsupported OS versions. |
| if (GetExpectationSet(os) == UNSUPPORTED_SET) |
| return; |
| |
| 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 |