| Index: chrome_frame/buggy_bho_handling.cc
|
| ===================================================================
|
| --- chrome_frame/buggy_bho_handling.cc (revision 0)
|
| +++ chrome_frame/buggy_bho_handling.cc (revision 0)
|
| @@ -0,0 +1,199 @@
|
| +// Copyright (c) 2010 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/buggy_bho_handling.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/scoped_comptr_win.h"
|
| +
|
| +#include "chrome_frame/function_stub.h"
|
| +#include "chrome_frame/utils.h"
|
| +#include "chrome_frame/vtable_patch_manager.h"
|
| +
|
| +namespace buggy_bho {
|
| +
|
| +base::ThreadLocalPointer<BuggyBhoTls> BuggyBhoTls::s_bad_object_tls_;
|
| +
|
| +struct ModuleAndVersion {
|
| + const char* module_name_;
|
| + const uint32 major_version_;
|
| + const uint32 minor_version_;
|
| +};
|
| +
|
| +const ModuleAndVersion kBuggyModules[] = {
|
| + { "askbar.dll", 4, 1 }, // troublemaker: 4.1.0.5.
|
| + { "gbieh.dll", 3, 8 }, // troublemaker: 3.8.14.12
|
| + { "gbiehcef.dll", 3, 8 }, // troublemaker: 3.8.11.23
|
| + { "alot.dll", 2, 5 }, // troublemaker: 2.5.12000.509
|
| + { "srchbxex.dll", 1, 2 }, // troublemaker: 1.2.123.0
|
| + { "tbabso.dll", 4, 5 }, // troublemaker: 4.5.156.0
|
| + { "tbabs0.dll.dll", 4, 5 }, // troublemaker: 4.5.156.0
|
| + { "tbbes0.dll", 4, 5 }, // troublemaker: 4.5.153.0
|
| + { "ctbr.dll", 5, 1 }, // troublemaker: 5.1.0.95
|
| +
|
| + // Viruses?
|
| + { "msgsc2.dll", 0xffff, 0xffff }, // troublemaker: 1.2.3000.1
|
| + { "essclis.dll", 0xffff, 0xffff }, // troublemaker: 4.3.1800.2
|
| +};
|
| +
|
| +bool IsBuggyBho(HMODULE mod) {
|
| + DCHECK(mod);
|
| +
|
| + char path[MAX_PATH * 2] = {0};
|
| + ::GetModuleFileNameA(mod, path, arraysize(path));
|
| + const char* file_name = ::PathFindFileNameA(path);
|
| + for (size_t i = 0; i < arraysize(kBuggyModules); ++i) {
|
| + if (lstrcmpiA(file_name, kBuggyModules[i].module_name_) == 0) {
|
| + uint32 version = 0;
|
| + GetModuleVersion(mod, &version, NULL);
|
| + const ModuleAndVersion& buggy = kBuggyModules[i];
|
| + if (HIWORD(version) < buggy.major_version_ ||
|
| + (HIWORD(version) == buggy.major_version_ &&
|
| + LOWORD(version) <= buggy.minor_version_)) {
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +BuggyBhoTls::BuggyBhoTls() : previous_instance_(s_bad_object_tls_.Get()) {
|
| + s_bad_object_tls_.Set(this);
|
| +}
|
| +
|
| +BuggyBhoTls::~BuggyBhoTls() {
|
| + DCHECK(FromCurrentThread() == this);
|
| + s_bad_object_tls_.Set(previous_instance_);
|
| +}
|
| +
|
| +void BuggyBhoTls::AddBuggyObject(IDispatch* obj) {
|
| + bad_objects_.push_back(obj);
|
| +}
|
| +
|
| +bool BuggyBhoTls::IsBuggyObject(IDispatch* obj) const {
|
| + return std::find(bad_objects_.begin(), bad_objects_.end(), obj) !=
|
| + bad_objects_.end();
|
| +}
|
| +
|
| +// static
|
| +BuggyBhoTls* BuggyBhoTls::FromCurrentThread() {
|
| + return s_bad_object_tls_.Get();
|
| +}
|
| +
|
| +// static
|
| +STDMETHODIMP BuggyBhoTls::BuggyBhoInvoke(InvokeFunc original, IDispatch* me,
|
| + DISPID dispid, REFIID riid, LCID lcid,
|
| + WORD flags, DISPPARAMS* params,
|
| + VARIANT* result, EXCEPINFO* ei,
|
| + UINT* err) {
|
| + DLOG(INFO) << __FUNCTION__;
|
| +
|
| + const BuggyBhoTls* tls = BuggyBhoTls::FromCurrentThread();
|
| + if (tls && tls->IsBuggyObject(me)) {
|
| + // Ignore this call and avoid the bug.
|
| + // TODO(tommi): Maybe we should check a specific list of DISPIDs too?
|
| + return S_OK;
|
| + }
|
| +
|
| + return original(me, dispid, riid, lcid, flags, params, result, ei, err);
|
| +}
|
| +
|
| +// static
|
| +HRESULT BuggyBhoTls::PatchInvokeMethod(PROC* invoke) {
|
| + CCritSecLock lock(_pAtlModule->m_csStaticDataInitAndTypeInfo, true);
|
| +
|
| + FunctionStub* stub = FunctionStub::FromCode(*invoke);
|
| + if (stub)
|
| + return S_FALSE;
|
| +
|
| + DWORD flags = 0;
|
| + if (!::VirtualProtect(invoke, sizeof(PROC), PAGE_EXECUTE_READWRITE, &flags))
|
| + return AtlHresultFromLastError();
|
| +
|
| + HRESULT hr = S_OK;
|
| +
|
| + stub = FunctionStub::Create(reinterpret_cast<uintptr_t>(*invoke),
|
| + BuggyBhoInvoke);
|
| + if (!stub) {
|
| + hr = E_OUTOFMEMORY;
|
| + } else {
|
| + if (!vtable_patch::internal::ReplaceFunctionPointer(
|
| + reinterpret_cast<void**>(invoke), stub->code(),
|
| + reinterpret_cast<void*>(stub->argument()))) {
|
| + hr = E_UNEXPECTED;
|
| + FunctionStub::Destroy(stub);
|
| + } else {
|
| + ::FlushInstructionCache(::GetCurrentProcess(), invoke, sizeof(PROC));
|
| + }
|
| + }
|
| +
|
| + ::VirtualProtect(invoke, sizeof(PROC), flags, &flags);
|
| +
|
| + return hr;
|
| +}
|
| +
|
| +// static
|
| +bool BuggyBhoTls::PatchIfBuggy(CONNECTDATA* cd, const IID& diid) {
|
| + DCHECK(cd);
|
| + PROC* methods = *reinterpret_cast<PROC**>(cd->pUnk);
|
| + HMODULE mod = GetModuleFromAddress(methods[0]);
|
| + if (!IsBuggyBho(mod))
|
| + return false;
|
| +
|
| + ScopedComPtr<IDispatch> disp;
|
| + HRESULT hr = cd->pUnk->QueryInterface(diid,
|
| + reinterpret_cast<void**>(disp.Receive()));
|
| + if (FAILED(hr)) // Sometimes only IDispatch QI is supported
|
| + hr = disp.QueryFrom(cd->pUnk);
|
| + DCHECK(SUCCEEDED(hr));
|
| +
|
| + if (SUCCEEDED(hr)) {
|
| + const int kInvokeIndex = 6;
|
| + DCHECK(static_cast<IUnknown*>(disp) == cd->pUnk);
|
| + if (SUCCEEDED(PatchInvokeMethod(&methods[kInvokeIndex]))) {
|
| + BuggyBhoTls* tls = BuggyBhoTls::FromCurrentThread();
|
| + DCHECK(tls);
|
| + if (tls) {
|
| + tls->AddBuggyObject(disp);
|
| + }
|
| + }
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +// static
|
| +HRESULT BuggyBhoTls::PatchBuggyBHOs(IWebBrowser2* browser) {
|
| + DCHECK(browser);
|
| + DCHECK(BuggyBhoTls::FromCurrentThread())
|
| + << "You must first have an instance of BuggyBhoTls on this thread";
|
| +
|
| + ScopedComPtr<IConnectionPointContainer> cpc;
|
| + HRESULT hr = cpc.QueryFrom(browser);
|
| + if (SUCCEEDED(hr)) {
|
| + const GUID sinks[] = { DIID_DWebBrowserEvents2, DIID_DWebBrowserEvents };
|
| + for (size_t i = 0; i < arraysize(sinks); ++i) {
|
| + ScopedComPtr<IConnectionPoint> cp;
|
| + cpc->FindConnectionPoint(sinks[i], cp.Receive());
|
| + if (cp) {
|
| + ScopedComPtr<IEnumConnections> connections;
|
| + cp->EnumConnections(connections.Receive());
|
| + if (connections) {
|
| + CONNECTDATA cd = {0};
|
| + DWORD fetched = 0;
|
| + while (connections->Next(1, &cd, &fetched) == S_OK && fetched) {
|
| + PatchIfBuggy(&cd, sinks[i]);
|
| + cd.pUnk->Release();
|
| + fetched = 0;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + return hr;
|
| +}
|
| +
|
| +} // end namespace buggy_bho
|
|
|
| Property changes on: chrome_frame\buggy_bho_handling.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|