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 14 struct FunctionStub; 15 16 // This namespace provides methods to patch VTable methods of COM interfaces. 17 namespace vtable_patch { 18 19 // Internal implementation, exposed only for testing. 20 namespace 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. 25 bool 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 33 struct 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. 46 HRESULT 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. 55 HRESULT 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. 61 class 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