|  | // Copyright 2016 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. | 
|  |  | 
|  | #include <windows.h> | 
|  |  | 
|  | #include "chrome_elf/hook_util/hook_util.h" | 
|  | // Compile in this test DLL, so that it's in the IAT. | 
|  | #include "chrome_elf/hook_util/test/hook_util_test_dll.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // IATHook test constants. | 
|  | const char kIATTestDllName[] = "hook_util_test_dll.dll"; | 
|  | const char kIATExportedApiFunction[] = "ExportedApi"; | 
|  |  | 
|  | // IATHook function, which does nothing. | 
|  | void IATHookedExportedApi() { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Shady third-party IATHook function, which also does nothing, but different | 
|  | // chunk of code/address. | 
|  | void IATHookedExportedApiTwo() { | 
|  | printf("Something to make this function different!\n"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | class HookTest : public testing::Test { | 
|  | protected: | 
|  | HookTest() {} | 
|  | }; | 
|  |  | 
|  | //------------------------------------------------------------------------------ | 
|  | // IATHook tests | 
|  | //------------------------------------------------------------------------------ | 
|  |  | 
|  | TEST_F(HookTest, IATHook) { | 
|  | // Sanity test with no hook. | 
|  | ASSERT_EQ(0, ExportedApiCallCount()); | 
|  | ExportedApi(); | 
|  | ExportedApi(); | 
|  | ASSERT_EQ(2, ExportedApiCallCount()); | 
|  |  | 
|  | // Apply IAT hook. | 
|  | elf_hook::IATHook iat_hook; | 
|  | if (iat_hook.Hook(::GetModuleHandle(nullptr), kIATTestDllName, | 
|  | kIATExportedApiFunction, | 
|  | IATHookedExportedApi) != NO_ERROR) { | 
|  | ADD_FAILURE(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Make sure hooking twice with the same object fails. | 
|  | if (iat_hook.Hook(::GetModuleHandle(nullptr), kIATTestDllName, | 
|  | kIATExportedApiFunction, | 
|  | IATHookedExportedApi) != ERROR_SHARING_VIOLATION) | 
|  | ADD_FAILURE(); | 
|  |  | 
|  | // Call count should not change with hook. | 
|  | ExportedApi(); | 
|  | ExportedApi(); | 
|  | ExportedApi(); | 
|  | EXPECT_EQ(2, ExportedApiCallCount()); | 
|  |  | 
|  | // Remove hook. | 
|  | if (iat_hook.Unhook() != NO_ERROR) | 
|  | ADD_FAILURE(); | 
|  |  | 
|  | // Sanity test things are back to normal. | 
|  | ExportedApi(); | 
|  | EXPECT_EQ(3, ExportedApiCallCount()); | 
|  |  | 
|  | // Double unhook should fail. | 
|  | if (iat_hook.Unhook() != ERROR_INVALID_PARAMETER) | 
|  | ADD_FAILURE(); | 
|  |  | 
|  | // Try hooking a non-existent function. | 
|  | if (iat_hook.Hook(::GetModuleHandle(nullptr), kIATTestDllName, "FooBarred", | 
|  | IATHookedExportedApi) != ERROR_PROC_NOT_FOUND) | 
|  | ADD_FAILURE(); | 
|  |  | 
|  | // Test the case where someone else hooks our hook!  Unhook() should leave it. | 
|  | if (iat_hook.Hook(::GetModuleHandle(nullptr), kIATTestDllName, | 
|  | kIATExportedApiFunction, | 
|  | IATHookedExportedApi) != NO_ERROR) { | 
|  | ADD_FAILURE(); | 
|  | return; | 
|  | } | 
|  | elf_hook::IATHook shady_third_party_iat_hook; | 
|  | if (shady_third_party_iat_hook.Hook(::GetModuleHandle(nullptr), | 
|  | kIATTestDllName, kIATExportedApiFunction, | 
|  | IATHookedExportedApiTwo) != NO_ERROR) | 
|  | ADD_FAILURE(); | 
|  | if (iat_hook.Unhook() != ERROR_INVALID_FUNCTION) | 
|  | ADD_FAILURE(); | 
|  | if (shady_third_party_iat_hook.Unhook() != NO_ERROR) | 
|  | ADD_FAILURE(); | 
|  | // NOTE: the first hook was left in and couldn't be cleaned up. | 
|  | } | 
|  |  | 
|  | }  // namespace |