gecko-dev/dom/plugins/ipc/FunctionHook.h

184 строки
5.5 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef dom_plugins_ipc_functionhook_h
#define dom_plugins_ipc_functionhook_h 1
#include "IpdlTuple.h"
#include "base/process.h"
#if defined(XP_WIN)
#include "nsWindowsDllInterceptor.h"
#endif
namespace mozilla {
namespace plugins {
// "PluginHooks" logging helpers
extern mozilla::LazyLogModule sPluginHooksLog;
#define HOOK_LOG(lvl, msg) MOZ_LOG(mozilla::plugins::sPluginHooksLog, lvl, msg);
inline const char *SuccessMsg(bool aVal) { return aVal ? "succeeded" : "failed"; }
class FunctionHook;
class FunctionHookArray;
class FunctionHook
{
public:
virtual ~FunctionHook() {}
virtual FunctionHookId FunctionId() const = 0;
/**
* Register to hook the function represented by this class.
* Returns false if we should have hooked but didn't.
*/
virtual bool Register(int aQuirks) = 0;
/**
* Run the original function with parameters stored in a tuple.
* This is only supported on server-side and for auto-brokered methods.
*/
virtual bool RunOriginalFunction(base::ProcessId aClientId,
const IPC::IpdlTuple &aInTuple,
IPC::IpdlTuple *aOutTuple) const = 0;
/**
* Hook the Win32 methods needed by the plugin process.
*/
static void HookFunctions(int aQuirks);
static FunctionHookArray* GetHooks();
#if defined(XP_WIN)
/**
* Special handler for hooking some kernel32.dll methods that we use to
* disable Flash protected mode.
*/
static void HookProtectedMode();
/**
* Get the WindowsDllInterceptor for the given module. Creates a cache of
* WindowsDllInterceptors by name.
*/
static WindowsDllInterceptor* GetDllInterceptorFor(const char* aModuleName);
/**
* Must be called to clear the cache created by calls to GetDllInterceptorFor.
*/
static void ClearDllInterceptorCache();
#endif // defined(XP_WIN)
private:
static StaticAutoPtr<FunctionHookArray> sFunctionHooks;
static void AddFunctionHooks(FunctionHookArray& aHooks);
};
// The FunctionHookArray deletes its FunctionHook objects when freed.
class FunctionHookArray : public nsTArray<FunctionHook*> {
public:
~FunctionHookArray()
{
for (uint32_t idx = 0; idx < Length(); ++idx) {
FunctionHook* elt = ElementAt(idx);
MOZ_ASSERT(elt);
delete elt;
}
}
};
// Type of function that returns true if a function should be hooked according to quirks.
typedef bool(ShouldHookFunc)(int aQuirks);
template<FunctionHookId functionId, typename FunctionType>
class BasicFunctionHook : public FunctionHook
{
public:
BasicFunctionHook(const char* aModuleName,
const char* aFunctionName, FunctionType* aOldFunction,
FunctionType* aNewFunction) :
mOldFunction(aOldFunction), mIsHooked(false), mModuleName(aModuleName),
mFunctionName(aFunctionName), mNewFunction(aNewFunction)
{
MOZ_ASSERT(mOldFunction);
MOZ_ASSERT(mNewFunction);
}
/**
* Hooks the function if we haven't already and if ShouldHook() says to.
*/
bool Register(int aQuirks) override;
/**
* Can be specialized to perform "extra" operations when running the
* function on the server side.
*/
bool RunOriginalFunction(base::ProcessId aClientId,
const IPC::IpdlTuple &aInTuple,
IPC::IpdlTuple *aOutTuple) const override { return false; }
FunctionHookId FunctionId() const override { return functionId; }
FunctionType* OriginalFunction() const { return mOldFunction; }
protected:
// Once the function is hooked, this field will take the value of a pointer to
// a function that performs the old behavior. Before that, it is a pointer to
// the original function.
FunctionType* mOldFunction;
// True if we have already hooked the function.
bool mIsHooked;
// The name of the module containing the function to hook. E.g. "user32.dll".
const nsCString mModuleName;
// The name of the function in the module.
const nsCString mFunctionName;
// The function that we should replace functionName with. The signature of
// newFunction must match that of functionName.
FunctionType* const mNewFunction;
static ShouldHookFunc* const mShouldHook;
};
// Default behavior is to hook every registered function.
extern bool AlwaysHook(int);
template<FunctionHookId functionId, typename FunctionType>
ShouldHookFunc* const BasicFunctionHook<functionId, FunctionType>::mShouldHook = AlwaysHook;
template <FunctionHookId functionId, typename FunctionType>
bool
BasicFunctionHook<functionId, FunctionType>::Register(int aQuirks)
{
MOZ_RELEASE_ASSERT(XRE_IsPluginProcess());
// If we have already hooked or if quirks tell us not to then don't hook.
if (mIsHooked || !mShouldHook(aQuirks)) {
return true;
}
#if defined(XP_WIN)
WindowsDllInterceptor* dllInterceptor =
FunctionHook::GetDllInterceptorFor(mModuleName.Data());
if (!dllInterceptor) {
return false;
}
mIsHooked =
dllInterceptor->AddHook(mFunctionName.Data(), reinterpret_cast<intptr_t>(mNewFunction),
reinterpret_cast<void**>(&mOldFunction));
#endif
HOOK_LOG(LogLevel::Debug,
("Registering to intercept function '%s' : '%s'", mFunctionName.Data(),
SuccessMsg(mIsHooked)));
return mIsHooked;
}
}
}
#endif // dom_plugins_ipc_functionhook_h