1// Copyright (c) 2009 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef CHROME_FRAME_VTABLE_PATCH_MANAGER_H_ 6#define CHROME_FRAME_VTABLE_PATCH_MANAGER_H_ 7 8#include <windows.h> 9 10#include <list> 11 12#include "base/synchronization/lock.h" 13 14struct FunctionStub; 15 16// This namespace provides methods to patch VTable methods of COM interfaces. 17namespace vtable_patch { 18 19// Internal implementation, exposed only for testing. 20namespace internal { 21 22// Replaces *entry with new_proc iff *entry is curr_proc. 23// Returns true iff *entry was rewritten. 24// Note: does not crash on access violation. 25bool ReplaceFunctionPointer(void** entry, void* new_proc, void* curr_proc); 26 27} // namespace internal 28 29// This structure represents information about one VTable method. 30// We allocate an array of these structures per VTable that we patch to 31// remember the original method. We also use this structure to actually 32// describe the VTable patch functions 33struct MethodPatchInfo { 34 int index_; 35 PROC method_; 36 FunctionStub* stub_; 37}; 38 39// Patches methods in the passed in COM interface. The indexes of the 40// methods to patch and the actual patch functions are described in the 41// array pointed to by patches. 42// @param[in] unknown The pointer of the COM interface to patch 43// @param[in] patches An array of MethodPatchInfo structures describing 44// the methods to patch and the patch functions. 45// The last entry of patches must have index_ set to -1. 46HRESULT PatchInterfaceMethods(void* unknown, MethodPatchInfo* patches); 47 48// Using the patch info provided in |patches| the function goes through the 49// list of patched methods and modifies thunks so that they no longer point 50// to a hook method but rather go straight through to the original target. 51// The thunk itself is not destroyed to support chaining. 52// @param[in] patches An array of MethodPatchInfo structures describing 53// the methods to patch and the patch functions. 54// The last entry of patches must have index_ set to -1. 55HRESULT UnpatchInterfaceMethods(MethodPatchInfo* patches); 56 57// Disabled as we're not using it atm. 58#if 0 59// Used when dynamically patching zero or more (usually more than 1) 60// implementations of a particular interface. 61class DynamicPatchManager { 62 public: 63 explicit DynamicPatchManager(const MethodPatchInfo* patch_prototype); 64 ~DynamicPatchManager(); 65 66 // Returns S_OK if the object was successfully patched, S_FALSE if it was 67 // already patched or an error value if something bad happened. 68 HRESULT PatchObject(void* unknown); 69 70 bool UnpatchAll(); 71 72 protected: 73 struct PatchedObject { 74 void* vtable_; 75 MethodPatchInfo patch_info_[1]; 76 77 // Used to match PatchedObject instances based on the vtable when 78 // searching through the patch list. 79 bool operator==(const PatchedObject& that) const { 80 return vtable_ == that.vtable_; 81 } 82 }; 83 84 typedef std::list<PatchedObject*> PatchList; 85 const MethodPatchInfo* patch_prototype_; 86 mutable base::Lock patch_list_lock_; 87 PatchList patch_list_; 88}; 89#endif // disable DynamicPatchManager 90 91} // namespace vtable_patch 92 93// Begins the declaration of a VTable patch 94// @param IFName The name of the interface to patch 95#define BEGIN_VTABLE_PATCHES(IFName) \ 96 vtable_patch::MethodPatchInfo IFName##_PatchInfo[] = { 97// Defines a single method patch in a VTable 98// @param index The index of the method to patch 99// @param PatchFunction The patch function 100#define VTABLE_PATCH_ENTRY(index, PatchFunction) {\ 101 index, \ 102 reinterpret_cast<PROC>(PatchFunction), \ 103 NULL, \ 104 }, 105 106#define DCHECK_IS_NOT_PATCHED(IFName) \ 107 for (vtable_patch::MethodPatchInfo* it = IFName##_PatchInfo; \ 108 it->index_ != -1; ++it) { \ 109 DCHECK(it->stub_ == NULL); \ 110 } 111 112#define DCHECK_IS_PATCHED(IFName) \ 113 for (vtable_patch::MethodPatchInfo* it = IFName##_PatchInfo; \ 114 it->index_ != -1; ++it) { \ 115 DCHECK(it->stub_ != NULL); \ 116 } 117 118// Checks if the interface is patched. Note that only the first method 119// is checked and subsequent methods are assumed to have the same state. 120#define IS_PATCHED(IFName) \ 121 (IFName##_PatchInfo[0].stub_ != NULL) 122 123// Ends the declaration of a VTable patch by adding an entry with 124// index set to -1. 125#define END_VTABLE_PATCHES() \ 126 -1, NULL, NULL \ 127 }; 128 129#endif // CHROME_FRAME_VTABLE_PATCH_MANAGER_H_ 130