// Copyright 2017 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 "base/win/com_init_check_hook.h" #include #include #include #include "base/test/gtest_util.h" #include "base/win/com_init_util.h" #include "base/win/patch_util.h" #include "base/win/scoped_com_initializer.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { namespace win { using Microsoft::WRL::ComPtr; TEST(ComInitCheckHook, AssertNotInitialized) { ComInitCheckHook com_check_hook; AssertComApartmentType(ComApartmentType::NONE); ComPtr shell_link; #if defined(COM_INIT_CHECK_HOOK_ENABLED) EXPECT_DCHECK_DEATH(::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&shell_link))); #else EXPECT_EQ(CO_E_NOTINITIALIZED, ::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&shell_link))); #endif } TEST(ComInitCheckHook, HookRemoval) { AssertComApartmentType(ComApartmentType::NONE); { ComInitCheckHook com_check_hook; } ComPtr shell_link; EXPECT_EQ(CO_E_NOTINITIALIZED, ::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&shell_link))); } TEST(ComInitCheckHook, NoAssertComInitialized) { ComInitCheckHook com_check_hook; ScopedCOMInitializer com_initializer; ComPtr shell_link; EXPECT_TRUE(SUCCEEDED(::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&shell_link)))); } TEST(ComInitCheckHook, MultipleHooks) { ComInitCheckHook com_check_hook_1; ComInitCheckHook com_check_hook_2; AssertComApartmentType(ComApartmentType::NONE); ComPtr shell_link; #if defined(COM_INIT_CHECK_HOOK_ENABLED) EXPECT_DCHECK_DEATH(::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&shell_link))); #else EXPECT_EQ(CO_E_NOTINITIALIZED, ::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&shell_link))); #endif } TEST(ComInitCheckHook, UnexpectedHook) { #if defined(COM_INIT_CHECK_HOOK_ENABLED) HMODULE ole32_library = ::LoadLibrary(L"ole32.dll"); ASSERT_TRUE(ole32_library); uint32_t co_create_instance_padded_address = reinterpret_cast( GetProcAddress(ole32_library, "CoCreateInstance")) - 5; const unsigned char* co_create_instance_bytes = reinterpret_cast(co_create_instance_padded_address); const unsigned char original_byte = co_create_instance_bytes[0]; const unsigned char unexpected_byte = 0xdb; ASSERT_EQ(static_cast(NO_ERROR), internal::ModifyCode( reinterpret_cast(co_create_instance_padded_address), reinterpret_cast(&unexpected_byte), sizeof(unexpected_byte))); EXPECT_DCHECK_DEATH({ ComInitCheckHook com_check_hook; }); // If this call fails, really bad things are going to happen to other tests // so CHECK here. CHECK_EQ(static_cast(NO_ERROR), internal::ModifyCode( reinterpret_cast(co_create_instance_padded_address), reinterpret_cast(&original_byte), sizeof(original_byte))); ::FreeLibrary(ole32_library); ole32_library = nullptr; #endif } TEST(ComInitCheckHook, ExternallyHooked) { #if defined(COM_INIT_CHECK_HOOK_ENABLED) HMODULE ole32_library = ::LoadLibrary(L"ole32.dll"); ASSERT_TRUE(ole32_library); uint32_t co_create_instance_address = reinterpret_cast( GetProcAddress(ole32_library, "CoCreateInstance")); const unsigned char* co_create_instance_bytes = reinterpret_cast(co_create_instance_address); const unsigned char original_byte = co_create_instance_bytes[0]; const unsigned char jmp_byte = 0xe9; ASSERT_EQ(static_cast(NO_ERROR), internal::ModifyCode( reinterpret_cast(co_create_instance_address), reinterpret_cast(&jmp_byte), sizeof(jmp_byte))); // Externally patched instances should crash so we catch these cases on bots. EXPECT_DCHECK_DEATH({ ComInitCheckHook com_check_hook; }); // If this call fails, really bad things are going to happen to other tests // so CHECK here. CHECK_EQ( static_cast(NO_ERROR), internal::ModifyCode(reinterpret_cast(co_create_instance_address), reinterpret_cast(&original_byte), sizeof(original_byte))); ::FreeLibrary(ole32_library); ole32_library = nullptr; #endif } TEST(ComInitCheckHook, UnexpectedChangeDuringHook) { #if defined(COM_INIT_CHECK_HOOK_ENABLED) HMODULE ole32_library = ::LoadLibrary(L"ole32.dll"); ASSERT_TRUE(ole32_library); uint32_t co_create_instance_padded_address = reinterpret_cast( GetProcAddress(ole32_library, "CoCreateInstance")) - 5; const unsigned char* co_create_instance_bytes = reinterpret_cast(co_create_instance_padded_address); const unsigned char original_byte = co_create_instance_bytes[0]; const unsigned char unexpected_byte = 0xdb; ASSERT_EQ(static_cast(NO_ERROR), internal::ModifyCode( reinterpret_cast(co_create_instance_padded_address), reinterpret_cast(&unexpected_byte), sizeof(unexpected_byte))); EXPECT_DCHECK_DEATH({ ComInitCheckHook com_check_hook; internal::ModifyCode( reinterpret_cast(co_create_instance_padded_address), reinterpret_cast(&unexpected_byte), sizeof(unexpected_byte)); }); // If this call fails, really bad things are going to happen to other tests // so CHECK here. CHECK_EQ(static_cast(NO_ERROR), internal::ModifyCode( reinterpret_cast(co_create_instance_padded_address), reinterpret_cast(&original_byte), sizeof(original_byte))); ::FreeLibrary(ole32_library); ole32_library = nullptr; #endif } } // namespace win } // namespace base