| Index: chrome_frame/vtable_patch_manager.cc
|
| ===================================================================
|
| --- chrome_frame/vtable_patch_manager.cc (revision 0)
|
| +++ chrome_frame/vtable_patch_manager.cc (revision 0)
|
| @@ -0,0 +1,82 @@
|
| +// Copyright (c) 2009 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 "chrome_frame/vtable_patch_manager.h"
|
| +
|
| +#include "base/logging.h"
|
| +
|
| +#include "chrome_frame/function_stub.h"
|
| +
|
| +namespace vtable_patch {
|
| +
|
| +// Convenient definition of a VTABLE
|
| +typedef PROC* Vtable;
|
| +
|
| +// Returns a pointer to the VTable of a COM interface.
|
| +// @param unknown [in] The pointer of the COM interface.
|
| +inline Vtable GetIFVTable(void* unknown) {
|
| + return reinterpret_cast<Vtable>(*reinterpret_cast<void**>(unknown));
|
| +}
|
| +
|
| +HRESULT PatchInterfaceMethods(void* unknown, MethodPatchInfo* patches) {
|
| + // Do some sanity checking of the input arguments.
|
| + if (NULL == unknown || NULL == patches) {
|
| + NOTREACHED();
|
| + return E_INVALIDARG;
|
| + }
|
| +
|
| + Vtable vtable = GetIFVTable(unknown);
|
| + DCHECK(vtable);
|
| +
|
| + for (MethodPatchInfo* it = patches; it->index_ != -1; ++it) {
|
| + PROC original_fn = vtable[it->index_];
|
| + FunctionStub* stub = FunctionStub::FromCode(original_fn);
|
| + if (stub != NULL) {
|
| + DLOG(ERROR) << "attempt to patch a function that's already patched";
|
| + DCHECK(stub->absolute_target() ==
|
| + reinterpret_cast<uintptr_t>(it->method_)) <<
|
| + "patching the same method multiple times with different hooks?";
|
| + continue;
|
| + }
|
| +
|
| + stub = FunctionStub::Create(reinterpret_cast<uintptr_t>(original_fn),
|
| + it->method_);
|
| + if (!stub) {
|
| + NOTREACHED();
|
| + return E_OUTOFMEMORY;
|
| + } else {
|
| + DWORD protect = 0;
|
| + if (::VirtualProtect(&vtable[it->index_], sizeof(PROC),
|
| + PAGE_EXECUTE_READWRITE, &protect)) {
|
| + it->stub_ = stub; // save the stub
|
| + vtable[it->index_] = stub->code();
|
| + ::VirtualProtect(&vtable[it->index_], sizeof(PROC), protect,
|
| + &protect);
|
| + } else {
|
| + NOTREACHED();
|
| + }
|
| + }
|
| + }
|
| +
|
| + return S_OK;
|
| +}
|
| +
|
| +HRESULT UnpatchInterfaceMethods(MethodPatchInfo* patches) {
|
| + for (MethodPatchInfo* it = patches; it->index_ != -1; ++it) {
|
| + if (it->stub_) {
|
| + DCHECK(it->stub_->absolute_target() ==
|
| + reinterpret_cast<uintptr_t>(it->method_));
|
| + // Modify the stub to just jump directly to the original function.
|
| + it->stub_->BypassStub(reinterpret_cast<void*>(it->stub_->argument()));
|
| + it->stub_ = NULL;
|
| + // Leave the stub in memory so that we won't break any possible chains.
|
| + } else {
|
| + DLOG(WARNING) << "attempt to unpatch a function that wasn't patched";
|
| + }
|
| + }
|
| +
|
| + return S_OK;
|
| +}
|
| +
|
| +} // namespace vtable_patch
|
|
|