зеркало из https://github.com/mozilla/gecko-dev.git
184 строки
5.5 KiB
C++
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
|