mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2025-12-09 03:18:29 +00:00
Completly redone templates, added "vfnptrs"
--HG-- extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%4042
This commit is contained in:
parent
9bb40ae639
commit
bb2cb311ad
@ -20,7 +20,7 @@
|
|||||||
#define SH_GLOB_PLUGPTR g_PLID
|
#define SH_GLOB_PLUGPTR g_PLID
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SH_ASSERT(x) if (!(x)) __asm { int 3 }
|
#define SH_ASSERT(x, info) if (!(x)) __asm { int 3 }
|
||||||
|
|
||||||
// System
|
// System
|
||||||
#define SH_SYS_WIN32 1
|
#define SH_SYS_WIN32 1
|
||||||
@ -54,6 +54,8 @@
|
|||||||
#include "sh_memfuncinfo.h"
|
#include "sh_memfuncinfo.h"
|
||||||
#include "sh_memory.h"
|
#include "sh_memory.h"
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
// Good old metamod!
|
// Good old metamod!
|
||||||
@ -73,6 +75,13 @@ namespace SourceHook
|
|||||||
{
|
{
|
||||||
const int STRBUF_LEN=8192; // In bytes, for "vafmt" functions
|
const int STRBUF_LEN=8192; // In bytes, for "vafmt" functions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An empty class. No inheritance used. Used for original-function-call hacks
|
||||||
|
*/
|
||||||
|
class EmptyClass
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A plugin typedef
|
* @brief A plugin typedef
|
||||||
*
|
*
|
||||||
@ -136,66 +145,61 @@ namespace SourceHook
|
|||||||
*/
|
*/
|
||||||
struct HookManagerInfo
|
struct HookManagerInfo
|
||||||
{
|
{
|
||||||
struct Iface
|
struct VfnPtr
|
||||||
{
|
{
|
||||||
struct Hook
|
struct Iface
|
||||||
{
|
{
|
||||||
ISHDelegate *handler; //!< Pointer to the handler
|
struct Hook
|
||||||
bool paused; //!< If true, the hook should not be executed
|
{
|
||||||
Plugin plug; //!< The owner plugin
|
ISHDelegate *handler; //!< Pointer to the handler
|
||||||
|
bool paused; //!< If true, the hook should not be executed
|
||||||
|
Plugin plug; //!< The owner plugin
|
||||||
|
};
|
||||||
|
void *ptr; //!< Pointer to the interface instance
|
||||||
|
std::list<Hook> hooks_pre; //!< A list of pre-hooks
|
||||||
|
std::list<Hook> hooks_post; //!< A list of post-hooks
|
||||||
|
bool operator ==(void *other) const
|
||||||
|
{
|
||||||
|
return ptr == other;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
void *callclass; //!< Stores a call class for this interface
|
|
||||||
void *ptr; //!< Pointer to the interface instance
|
void *vfnptr; //!< Pointer to the function
|
||||||
void *orig_entry; //!< The original vtable entry
|
void *orig_entry; //!< The original vtable entry
|
||||||
std::list<Hook> hooks_pre; //!< A list of pre-hooks
|
|
||||||
std::list<Hook> hooks_post; //!< A list of post-hooks
|
typedef std::list<Iface> IfaceList;
|
||||||
bool operator ==(void *other) const
|
typedef IfaceList::iterator IfaceListIter;
|
||||||
|
IfaceList ifaces;
|
||||||
|
|
||||||
|
bool operator ==(void *other)
|
||||||
{
|
{
|
||||||
return ptr == other;
|
return vfnptr == other;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Plugin plug; //!< The owner plugin
|
Plugin plug; //!< The owner plugin
|
||||||
const char *proto; //!< The prototype of the function the hook manager is responsible for
|
const char *proto; //!< The prototype of the function the hook manager is responsible for
|
||||||
int vtbl_idx; //!< The vtable index
|
int vtbl_idx; //!< The vtable index
|
||||||
int vtbl_offs; //!< The vtable offset
|
int vtbl_offs; //!< The vtable offset
|
||||||
int thisptr_offs; //!< The this-pointer-adjuster
|
|
||||||
HookManagerPubFunc func; //!< The interface to the hook manager
|
HookManagerPubFunc func; //!< The interface to the hook manager
|
||||||
|
|
||||||
int hookfunc_vtbl_idx; //!< the vtable index of the hookfunc
|
void *hookfunc_vfnptr; //!< Pointer to the hookfunc impl
|
||||||
int hookfunc_vtbl_offs; //!< the vtable offset of the hookfunc
|
|
||||||
void *hookfunc_inst; //!< Instance of the class the hookfunc is in
|
|
||||||
|
|
||||||
std::list<Iface> ifaces; //!< List of hooked interfaces
|
typedef std::list<VfnPtr> VfnPtrList;
|
||||||
|
typedef VfnPtrList::iterator VfnPtrListIter;
|
||||||
|
VfnPtrList vfnptrs; //!< List of hooked interfaces
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
typedef std::vector<void*> OrigFuncs;
|
||||||
* @brief Structure describing a callclass
|
typedef std::map<int, OrigFuncs> OrigVTables;
|
||||||
*/
|
|
||||||
struct CallClass
|
template<class B> struct CallClass
|
||||||
{
|
{
|
||||||
struct VTable
|
B *ptr;
|
||||||
{
|
OrigVTables vt;
|
||||||
void *ptr;
|
|
||||||
int actsize;
|
|
||||||
std::list<int> patches; //!< Already patched entries
|
|
||||||
bool operator ==(void *other) const
|
|
||||||
{
|
|
||||||
return ptr == other;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
void *iface; //!< The iface pointer this callclass belongs to
|
|
||||||
size_t size; //!< The size of the callclass
|
|
||||||
void *ptr; //!< The actual "object"
|
|
||||||
typedef std::list<VTable> VTableList;
|
|
||||||
VTableList vtables; //!< Already known vtables
|
|
||||||
int refcounter; //!< How many times it was requested
|
|
||||||
|
|
||||||
bool operator ==(void *other) const
|
|
||||||
{
|
|
||||||
return ptr == other;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef CallClass<void> GenericCallClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The main SourceHook interface
|
* @brief The main SourceHook interface
|
||||||
*/
|
*/
|
||||||
@ -214,7 +218,7 @@ namespace SourceHook
|
|||||||
* @param handler A pointer to a FastDelegate containing the hook handler
|
* @param handler A pointer to a FastDelegate containing the hook handler
|
||||||
* @param post Set to true if you want a post handler
|
* @param post Set to true if you want a post handler
|
||||||
*/
|
*/
|
||||||
virtual bool AddHook(Plugin plug, void *iface, int ifacesize, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
|
virtual bool AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Removes a hook.
|
* @brief Removes a hook.
|
||||||
@ -227,7 +231,7 @@ namespace SourceHook
|
|||||||
* @param handler A pointer to a FastDelegate containing the hook handler
|
* @param handler A pointer to a FastDelegate containing the hook handler
|
||||||
* @param post Set to true if you want a post handler
|
* @param post Set to true if you want a post handler
|
||||||
*/
|
*/
|
||||||
virtual bool RemoveHook(Plugin plug, void *iface, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
|
virtual bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks whether a plugin has (a) hook manager(s) that is/are currently used by other plugins
|
* @brief Checks whether a plugin has (a) hook manager(s) that is/are currently used by other plugins
|
||||||
@ -242,14 +246,14 @@ namespace SourceHook
|
|||||||
* @param iface The interface pointer
|
* @param iface The interface pointer
|
||||||
* @param size Size of the class
|
* @param size Size of the class
|
||||||
*/
|
*/
|
||||||
virtual void *GetCallClass(void *iface, size_t size) = 0;
|
virtual GenericCallClass *GetCallClass(void *iface) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Release a callclass
|
* @brief Release a callclass
|
||||||
*
|
*
|
||||||
* @param ptr Pointer to the callclass
|
* @param ptr Pointer to the callclass
|
||||||
*/
|
*/
|
||||||
virtual void ReleaseCallClass(void *ptr) = 0;
|
virtual void ReleaseCallClass(GenericCallClass *ptr) = 0;
|
||||||
|
|
||||||
virtual void SetRes(META_RES res) = 0; //!< Sets the meta result
|
virtual void SetRes(META_RES res) = 0; //!< Sets the meta result
|
||||||
virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the previously called handler
|
virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the previously called handler
|
||||||
@ -284,11 +288,16 @@ namespace SourceHook
|
|||||||
/**
|
/**
|
||||||
* @brief Get/generate callclass for an interface pointer
|
* @brief Get/generate callclass for an interface pointer
|
||||||
*
|
*
|
||||||
* @param ifacetype The type of the interface
|
|
||||||
* @param ifaceptr The interface pointer
|
* @param ifaceptr The interface pointer
|
||||||
*/
|
*/
|
||||||
#define SH_GET_CALLCLASS(ifacetype, ifaceptr) reinterpret_cast<ifacetype*>(SH_GLOB_SHPTR->GetCallClass(ifaceptr, sizeof(ifacetype)))
|
template<class ifacetype>
|
||||||
#define SH_RELEASE_CALLCLASS(ptr) SH_GLOB_SHPTR->ReleaseCallClass(reinterpret_cast<void*>(ptr))
|
inline SourceHook::CallClass<ifacetype> *SH_GET_CALLCLASS(ifacetype *ptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<SourceHook::CallClass<ifacetype>*>(
|
||||||
|
SH_GLOB_SHPTR->GetCallClass(reinterpret_cast<void*>(ptr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SH_RELEASE_CALLCLASS(ptr) SH_GLOB_SHPTR->ReleaseCallClass(reinterpret_cast<SourceHook::GenericCallClass*>(ptr))
|
||||||
|
|
||||||
#define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
|
#define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
|
||||||
SourceHook::SH_FHAdd##ifacetype##ifacefunc((void*)ifaceptr, post, handler)
|
SourceHook::SH_FHAdd##ifacetype##ifacefunc((void*)ifaceptr, post, handler)
|
||||||
@ -307,6 +316,18 @@ namespace SourceHook
|
|||||||
#define SH_NOATTRIB
|
#define SH_NOATTRIB
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if SH_COMP == SH_COMP_MSVC
|
||||||
|
# define SH_SETUP_MFP(mfp) \
|
||||||
|
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry;
|
||||||
|
#elif SH_COMP == SH_COMP_GCC
|
||||||
|
# define SH_SETUP_MFP(mfp) \
|
||||||
|
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry; \
|
||||||
|
reinterpret_cast<void**>(&mfp)[1] = 0;
|
||||||
|
#else
|
||||||
|
# error Not supported yet.
|
||||||
|
#endif
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
#define SH_FHCls(ift, iff, ov) FHCls_##ift##iff##ov
|
#define SH_FHCls(ift, iff, ov) FHCls_##ift##iff##ov
|
||||||
|
|
||||||
@ -320,13 +341,10 @@ namespace SourceHook
|
|||||||
GetFuncInfo(funcptr, mfi); \
|
GetFuncInfo(funcptr, mfi); \
|
||||||
param->vtbl_idx = mfi.vtblindex; \
|
param->vtbl_idx = mfi.vtblindex; \
|
||||||
param->vtbl_offs = mfi.vtbloffs; \
|
param->vtbl_offs = mfi.vtbloffs; \
|
||||||
param->thisptr_offs = mfi.thisptroffs; \
|
\
|
||||||
if (param->thisptr_offs < 0) \
|
|
||||||
return 2; /*No virtual inheritance supported*/ \
|
|
||||||
GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \
|
GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \
|
||||||
param->hookfunc_vtbl_idx = mfi.vtblindex; \
|
param->hookfunc_vfnptr = \
|
||||||
param->hookfunc_vtbl_offs = mfi.vtbloffs; \
|
reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]; \
|
||||||
param->hookfunc_inst = (void*)&ms_Inst; \
|
|
||||||
return 0; \
|
return 0; \
|
||||||
} \
|
} \
|
||||||
else if (action == HA_Register) \
|
else if (action == HA_Register) \
|
||||||
@ -353,7 +371,7 @@ namespace SourceHook
|
|||||||
static const char *ms_Proto; \
|
static const char *ms_Proto; \
|
||||||
SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
|
SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
|
||||||
|
|
||||||
#define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto) \
|
#define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto, funcptr) \
|
||||||
}; \
|
}; \
|
||||||
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
|
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
|
||||||
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \
|
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \
|
||||||
@ -361,42 +379,67 @@ namespace SourceHook
|
|||||||
bool SH_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
|
bool SH_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
|
||||||
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
|
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
|
||||||
{ \
|
{ \
|
||||||
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, sizeof(ifacetype), \
|
MemFuncInfo mfi; \
|
||||||
|
GetFuncInfo(funcptr, mfi); \
|
||||||
|
if (mfi.thisptroffs < 0) \
|
||||||
|
return false; /* No virtual inheritance supported */ \
|
||||||
|
\
|
||||||
|
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, mfi.thisptroffs, \
|
||||||
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
|
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
|
||||||
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
|
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
|
||||||
} \
|
} \
|
||||||
bool SH_FHRemove##ifacetype##ifacefunc(void *iface, bool post, \
|
bool SH_FHRemove##ifacetype##ifacefunc(void *iface, bool post, \
|
||||||
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
|
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
|
||||||
{ \
|
{ \
|
||||||
|
MemFuncInfo mfi; \
|
||||||
|
GetFuncInfo(funcptr, mfi); \
|
||||||
|
if (mfi.thisptroffs < 0) \
|
||||||
|
return false; /* No virtual inheritance supported */ \
|
||||||
|
\
|
||||||
CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD> tmp(handler); \
|
CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD> tmp(handler); \
|
||||||
return SH_GLOB_SHPTR->RemoveHook(SH_GLOB_PLUGPTR, iface, \
|
return SH_GLOB_SHPTR->RemoveHook(SH_GLOB_PLUGPTR, iface, mfi.thisptroffs, \
|
||||||
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, &tmp, post); \
|
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, &tmp, post); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SH_SETUPCALLS(rettype) \
|
#define SH_SETUPCALLS(rettype, paramtypes, params) \
|
||||||
/* 1) Find the iface ptr */ \
|
/* 1) Find the vfnptr */ \
|
||||||
/* 1.1) Adjust to original this pointer */ \
|
void *ourvfnptr = reinterpret_cast<void*>( \
|
||||||
void *origthis = this - ms_HI->thisptr_offs; \
|
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \
|
||||||
std::list<HookManagerInfo::Iface>::iterator ifaceiter = std::find(ms_HI->ifaces.begin(), \
|
\
|
||||||
ms_HI->ifaces.end(), origthis); \
|
HookManagerInfo::VfnPtrListIter vfptriter = std::find(ms_HI->vfnptrs.begin(), \
|
||||||
SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \
|
ms_HI->vfnptrs.end(), ourvfnptr); \
|
||||||
HookManagerInfo::Iface &ci = *ifaceiter; \
|
if (vfptriter == ms_HI->vfnptrs.end()) \
|
||||||
|
{ \
|
||||||
|
/* Bleh? Should be impossible! */ \
|
||||||
|
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
|
||||||
|
} \
|
||||||
|
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
|
||||||
|
/* 2) Find the iface */ \
|
||||||
|
HookManagerInfo::VfnPtr::IfaceListIter ifiter = std::find(vfnptr.ifaces.begin(), vfnptr.ifaces.end(), this); \
|
||||||
|
if (ifiter == vfnptr.ifaces.end()) \
|
||||||
|
{ \
|
||||||
|
/* The iface info was not found. Redirect the call to the original function. */ \
|
||||||
|
rettype (EmptyClass::*mfp)paramtypes; \
|
||||||
|
SH_SETUP_MFP(mfp); \
|
||||||
|
return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
|
||||||
|
} \
|
||||||
|
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
|
||||||
/* 2) Declare some vars and set it up */ \
|
/* 2) Declare some vars and set it up */ \
|
||||||
std::list<HookManagerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
|
std::list<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \
|
||||||
std::list<HookManagerInfo::Iface::Hook> &postlist = ci.hooks_post; \
|
std::list<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \
|
||||||
rettype orig_ret, override_ret, plugin_ret; \
|
rettype orig_ret, override_ret, plugin_ret; \
|
||||||
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
|
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
|
||||||
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
|
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
|
||||||
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
|
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
|
||||||
status = MRES_IGNORED; \
|
status = MRES_IGNORED; \
|
||||||
SH_GLOB_SHPTR->SetIfacePtr(ci.ptr); \
|
SH_GLOB_SHPTR->SetIfacePtr(this); \
|
||||||
SH_GLOB_SHPTR->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \
|
SH_GLOB_SHPTR->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \
|
||||||
SH_GLOB_SHPTR->SetOverrideRet(NULL);
|
SH_GLOB_SHPTR->SetOverrideRet(NULL);
|
||||||
|
|
||||||
#define SH_CALL_HOOKS(post, params) \
|
#define SH_CALL_HOOKS(post, params) \
|
||||||
prev_res = MRES_IGNORED; \
|
prev_res = MRES_IGNORED; \
|
||||||
for (std::list<HookManagerInfo::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
|
for (std::list<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
|
||||||
{ \
|
{ \
|
||||||
if (hiter->paused) continue; \
|
if (hiter->paused) continue; \
|
||||||
cur_res = MRES_IGNORED; \
|
cur_res = MRES_IGNORED; \
|
||||||
@ -411,44 +454,64 @@ namespace SourceHook
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SH_CALL_ORIG(ifacetype, ifacefunc, params) \
|
#define SH_CALL_ORIG(ifacetype, ifacefunc, rettype, paramtypes, params) \
|
||||||
if (status != MRES_SUPERCEDE) \
|
if (status != MRES_SUPERCEDE) \
|
||||||
orig_ret = reinterpret_cast<ifacetype*>(ci.callclass)->ifacefunc params; \
|
{ \
|
||||||
|
rettype (EmptyClass::*mfp)paramtypes; \
|
||||||
|
SH_SETUP_MFP(mfp); \
|
||||||
|
orig_ret = (reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \
|
||||||
|
} \
|
||||||
else \
|
else \
|
||||||
orig_ret = override_ret;
|
orig_ret = override_ret;
|
||||||
|
|
||||||
#define SH_RETURN() \
|
#define SH_RETURN() \
|
||||||
return status >= MRES_OVERRIDE ? override_ret : orig_ret;
|
return status >= MRES_OVERRIDE ? override_ret : orig_ret;
|
||||||
|
|
||||||
#define SH_HANDLEFUNC(ifacetype, ifacefunc, params, rettype) \
|
#define SH_HANDLEFUNC(ifacetype, ifacefunc, paramtypes, params, rettype) \
|
||||||
SH_SETUPCALLS(rettype) \
|
SH_SETUPCALLS(rettype, paramtypes, params) \
|
||||||
SH_CALL_HOOKS(pre, params) \
|
SH_CALL_HOOKS(pre, params) \
|
||||||
SH_CALL_ORIG(ifacetype, ifacefunc, params) \
|
SH_CALL_ORIG(ifacetype, ifacefunc, rettype, paramtypes, params) \
|
||||||
SH_CALL_HOOKS(post, params) \
|
SH_CALL_HOOKS(post, params) \
|
||||||
SH_RETURN()
|
SH_RETURN()
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
#define SH_SETUPCALLS_void() \
|
#define SH_SETUPCALLS_void(paramtypes, params) \
|
||||||
/* 1) Find the iface ptr */ \
|
/* 1) Find the vfnptr */ \
|
||||||
/* 1.1) Adjust to original this pointer */ \
|
void *ourvfnptr = reinterpret_cast<void*>( \
|
||||||
void *origthis = this - ms_HI->thisptr_offs; \
|
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \
|
||||||
std::list<HookManagerInfo::Iface>::iterator ifaceiter = std::find(ms_HI->ifaces.begin(), \
|
\
|
||||||
ms_HI->ifaces.end(), origthis); \
|
HookManagerInfo::VfnPtrListIter vfptriter = std::find(ms_HI->vfnptrs.begin(), \
|
||||||
SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \
|
ms_HI->vfnptrs.end(), ourvfnptr); \
|
||||||
HookManagerInfo::Iface &ci = *ifaceiter; \
|
if (vfptriter == ms_HI->vfnptrs.end()) \
|
||||||
|
{ \
|
||||||
|
/* Bleh? Should be impossible! */ \
|
||||||
|
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
|
||||||
|
} \
|
||||||
|
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
|
||||||
|
/* 2) Find the iface */ \
|
||||||
|
HookManagerInfo::VfnPtr::IfaceListIter ifiter = std::find(vfnptr.ifaces.begin(), vfnptr.ifaces.end(), this); \
|
||||||
|
if (ifiter == vfnptr.ifaces.end()) \
|
||||||
|
{ \
|
||||||
|
/* The iface info was not found. Redirect the call to the original function. */ \
|
||||||
|
void (EmptyClass::*mfp)paramtypes; \
|
||||||
|
SH_SETUP_MFP(mfp); \
|
||||||
|
(reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
|
||||||
/* 2) Declare some vars and set it up */ \
|
/* 2) Declare some vars and set it up */ \
|
||||||
std::list<HookManagerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
|
std::list<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \
|
||||||
std::list<HookManagerInfo::Iface::Hook> &postlist = ci.hooks_post; \
|
std::list<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \
|
||||||
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
|
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
|
||||||
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
|
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
|
||||||
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
|
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
|
||||||
status = MRES_IGNORED; \
|
status = MRES_IGNORED; \
|
||||||
SH_GLOB_SHPTR->SetIfacePtr(ci.ptr); \
|
SH_GLOB_SHPTR->SetIfacePtr(this); \
|
||||||
SH_GLOB_SHPTR->SetOverrideRet(NULL);
|
SH_GLOB_SHPTR->SetOverrideRet(NULL);
|
||||||
|
|
||||||
#define SH_CALL_HOOKS_void(post, params) \
|
#define SH_CALL_HOOKS_void(post, params) \
|
||||||
prev_res = MRES_IGNORED; \
|
prev_res = MRES_IGNORED; \
|
||||||
for (std::list<HookManagerInfo::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
|
for (std::list<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
|
||||||
{ \
|
{ \
|
||||||
if (hiter->paused) continue; \
|
if (hiter->paused) continue; \
|
||||||
cur_res = MRES_IGNORED; \
|
cur_res = MRES_IGNORED; \
|
||||||
@ -458,54 +521,60 @@ namespace SourceHook
|
|||||||
status = cur_res; \
|
status = cur_res; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SH_CALL_ORIG_void(ifacetype, ifacefunc, params) \
|
#define SH_CALL_ORIG_void(ifacetype, ifacefunc, paramtypes, params) \
|
||||||
if (status != MRES_SUPERCEDE) \
|
if (status != MRES_SUPERCEDE) \
|
||||||
reinterpret_cast<ifacetype*>(ci.callclass)->ifacefunc params;
|
{ \
|
||||||
|
void (EmptyClass::*mfp)paramtypes; \
|
||||||
|
SH_SETUP_MFP(mfp); \
|
||||||
|
(reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \
|
||||||
|
}
|
||||||
|
|
||||||
#define SH_RETURN_void()
|
#define SH_RETURN_void()
|
||||||
|
|
||||||
#define SH_HANDLEFUNC_void(ifacetype, ifacefunc, params) \
|
#define SH_HANDLEFUNC_void(ifacetype, ifacefunc, paramtypes, params) \
|
||||||
SH_SETUPCALLS_void() \
|
SH_SETUPCALLS_void(paramtypes, params) \
|
||||||
SH_CALL_HOOKS_void(pre, params) \
|
SH_CALL_HOOKS_void(pre, params) \
|
||||||
SH_CALL_ORIG_void(ifacetype, ifacefunc, params) \
|
SH_CALL_ORIG_void(ifacetype, ifacefunc, paramtypes, params) \
|
||||||
SH_CALL_HOOKS_void(post, params) \
|
SH_CALL_HOOKS_void(post, params) \
|
||||||
SH_RETURN_void()
|
SH_RETURN_void()
|
||||||
|
|
||||||
|
|
||||||
// Special vafmt handlers
|
// Special vafmt handlers
|
||||||
#define SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, params_orig, params_plug, rettype) \
|
#define SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, paramtypes, params_orig, params_plug, rettype) \
|
||||||
SH_SETUPCALLS(rettype) \
|
SH_SETUPCALLS(rettype, paramtypes, params_orig) \
|
||||||
SH_CALL_HOOKS(pre, params_plug) \
|
SH_CALL_HOOKS(pre, params_plug) \
|
||||||
SH_CALL_ORIG(ifacetype, ifacefunc, params_orig) \
|
SH_CALL_ORIG(ifacetype, ifacefunc, rettype, paramtypes, params_orig) \
|
||||||
SH_CALL_HOOKS(post, params_plug) \
|
SH_CALL_HOOKS(post, params_plug) \
|
||||||
SH_RETURN()
|
SH_RETURN()
|
||||||
|
|
||||||
#define SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, params_orig, params_plug) \
|
#define SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, paramtypes, params_orig, params_plug) \
|
||||||
SH_SETUPCALLS_void() \
|
SH_SETUPCALLS_void(paramtypes, params_orig) \
|
||||||
SH_CALL_HOOKS_void(pre, params_plug) \
|
SH_CALL_HOOKS_void(pre, params_plug) \
|
||||||
SH_CALL_ORIG_void(ifacetype, ifacefunc, params_orig) \
|
SH_CALL_ORIG_void(ifacetype, ifacefunc, paramtypes, params_orig) \
|
||||||
SH_CALL_HOOKS_void(post, params_plug) \
|
SH_CALL_HOOKS_void(post, params_plug) \
|
||||||
SH_RETURN_void()
|
SH_RETURN_void()
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@VARARGS@
|
@VARARGS@
|
||||||
// *********
|
// ********* Support for @$@ arguments *********
|
||||||
#define SH_DECL_HOOK@$@(ifacetype, ifacefunc, attr, overload, rettype@, param%%@) \
|
#define SH_DECL_HOOK@$@(ifacetype, ifacefunc, attr, overload, rettype@, param%%@) \
|
||||||
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(@param%%|, @)> \
|
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(@param%%|, @)> \
|
||||||
(&ifacetype::ifacefunc))) \
|
(&ifacetype::ifacefunc))) \
|
||||||
typedef fastdelegate::FastDelegate@$@<@param%%|, @@, @rettype> FD; \
|
typedef fastdelegate::FastDelegate@$@<@param%%|, @@, @rettype> FD; \
|
||||||
virtual rettype Func(@param%% p%%|, @) attr \
|
virtual rettype Func(@param%% p%%|, @) attr \
|
||||||
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (@p%%|, @), rettype); } \
|
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (@param%%|, @), (@p%%|, @), rettype); } \
|
||||||
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype @"|" #param%%| @)
|
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype @"|" #param%%| @, \
|
||||||
|
(static_cast<rettype (ifacetype::*)(@param%%|, @)>(&ifacetype::ifacefunc)))
|
||||||
|
|
||||||
#define SH_DECL_HOOK@$@_void(ifacetype, ifacefunc, attr, overload@, param%%@) \
|
#define SH_DECL_HOOK@$@_void(ifacetype, ifacefunc, attr, overload@, param%%@) \
|
||||||
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(@param%%|, @)> \
|
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(@param%%|, @)> \
|
||||||
(&ifacetype::ifacefunc))) \
|
(&ifacetype::ifacefunc))) \
|
||||||
typedef fastdelegate::FastDelegate@$@<@param%%|, @> FD; \
|
typedef fastdelegate::FastDelegate@$@<@param%%|, @> FD; \
|
||||||
virtual void Func(@param%% p%%|, @) attr \
|
virtual void Func(@param%% p%%|, @) attr \
|
||||||
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (@p%%|, @)); } \
|
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (@param%%|, @), (@p%%|, @)); } \
|
||||||
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr @"|" #param%%| @)
|
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr @"|" #param%%| @, \
|
||||||
|
(static_cast<void (ifacetype::*)(@param%%|, @)>(&ifacetype::ifacefunc)))
|
||||||
|
|
||||||
#define SH_DECL_HOOK@$@_vafmt(ifacetype, ifacefunc, attr, overload, rettype@, param%%@) \
|
#define SH_DECL_HOOK@$@_vafmt(ifacetype, ifacefunc, attr, overload, rettype@, param%%@) \
|
||||||
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(@param%%|, @@, @const char *, ...)> \
|
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(@param%%|, @@, @const char *, ...)> \
|
||||||
@ -518,9 +587,10 @@ namespace SourceHook
|
|||||||
va_start(ap, fmt); \
|
va_start(ap, fmt); \
|
||||||
vsnprintf(buf, sizeof(buf), fmt, ap); \
|
vsnprintf(buf, sizeof(buf), fmt, ap); \
|
||||||
va_end(ap); \
|
va_end(ap); \
|
||||||
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (@p%%|, @@, @"%s", buf), (@p%%|, @@, @buf), rettype); \
|
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (@param%%|, @@, @...), (@p%%|, @@, @"%s", buf), (@p%%|, @@, @buf), rettype); \
|
||||||
} \
|
} \
|
||||||
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype @"|" #param%%| @ "|const char*|...")
|
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype @"|" #param%%| @ "|const char*|...", \
|
||||||
|
(static_cast<rettype (ifacetype::*)(@param%%|, @@, @const char *, ...)>(&ifacetype::ifacefunc)))
|
||||||
|
|
||||||
#define SH_DECL_HOOK@$@_void_vafmt(ifacetype, ifacefunc, attr, overload, rettype@, param%%@) \
|
#define SH_DECL_HOOK@$@_void_vafmt(ifacetype, ifacefunc, attr, overload, rettype@, param%%@) \
|
||||||
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(@param%%|, @@, @const char *, ...)> \
|
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(@param%%|, @@, @const char *, ...)> \
|
||||||
@ -533,22 +603,70 @@ namespace SourceHook
|
|||||||
va_start(ap, fmt); \
|
va_start(ap, fmt); \
|
||||||
vsnprintf(buf, sizeof(buf), fmt, ap); \
|
vsnprintf(buf, sizeof(buf), fmt, ap); \
|
||||||
va_end(ap); \
|
va_end(ap); \
|
||||||
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (@p%%|, @@, @"%s", buf), (@p%%|, @@, @buf)); \
|
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (@param%%|, @@, @...), (@p%%|, @@, @"%s", buf), (@p%%|, @@, @buf)); \
|
||||||
} \
|
} \
|
||||||
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr @"|" #param%%| @ "|const char*|...")
|
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr @"|" #param%%| @ "|const char*|...", \
|
||||||
|
(static_cast<void (ifacetype::*)(@param%%|, @@, @const char *, ...)>(&ifacetype::ifacefunc)))
|
||||||
|
|
||||||
@ENDARGS@
|
@ENDARGS@
|
||||||
|
|
||||||
/*
|
|
||||||
#define SH_DECL_HOOK1(ifacetype, ifacefunc, attr, overload, rettype, param1) \
|
|
||||||
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload) \
|
|
||||||
typedef fastdelegate::FastDelegate1<param1, rettype> FD; \
|
|
||||||
virtual rettype Func(param1 p1) \
|
|
||||||
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (p1), rettype); } \
|
|
||||||
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1)
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// SH_CALL
|
||||||
|
|
||||||
|
|
||||||
|
#define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
|
||||||
|
{ \
|
||||||
|
MemFuncInfo mfi; \
|
||||||
|
MFI_Impl<sizeof(m_MFP)>::GetFuncInfo(m_MFP, mfi); \
|
||||||
|
OrigVTables::const_iterator iter = m_CC->vt.find(mfi.vtbloffs); \
|
||||||
|
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->second.size() || iter->second[mfi.vtblindex] == NULL) \
|
||||||
|
return (m_CC->ptr->*m_MFP)call; \
|
||||||
|
\
|
||||||
|
/* It's hooked. Call the original function. */ \
|
||||||
|
union \
|
||||||
|
{ \
|
||||||
|
RetType(EmptyClass::*mfpnew)prms; \
|
||||||
|
void *addr; \
|
||||||
|
} u; \
|
||||||
|
u.addr = iter->second[mfi.vtblindex]; \
|
||||||
|
\
|
||||||
|
return (reinterpret_cast<EmptyClass*>(m_CC->ptr)->*u.mfpnew)call; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace SourceHook
|
||||||
|
{
|
||||||
|
template<class CCType, class RetType, class MFPType> class ExecutableClass
|
||||||
|
{
|
||||||
|
CCType *m_CC;
|
||||||
|
MFPType m_MFP;
|
||||||
|
public:
|
||||||
|
ExecutableClass(CCType *cc, MFPType mfp) : m_CC(cc), m_MFP(mfp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@VARARGS@
|
||||||
|
// Support for @$@ arguments
|
||||||
|
template<@class Param%%|, @> RetType operator()(@Param%% p%%|, @) const
|
||||||
|
SH_MAKE_EXECUTABLECLASS_OB((@p%%@), (@Param%%@))
|
||||||
|
|
||||||
|
@ENDARGS@
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@VARARGS@
|
||||||
|
// Support for @$@ arguments
|
||||||
|
template <class X, class Y, class RetType@, @@class Param%%|, @>
|
||||||
|
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, RetType (X::*)(@Param%%|, @)>
|
||||||
|
SH_CALL(SourceHook::CallClass<Y> *ptr, RetType(X::*mfp)(@Param%%|, @))
|
||||||
|
{
|
||||||
|
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, RetType (X::*)(@Param%%|, @)>(ptr, mfp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ENDARGS@
|
||||||
|
|
||||||
|
#undef SH_MAKE_EXECUTABLECLASS_BODY
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
// The pope is dead. -> :(
|
// The pope is dead. -> :(
|
||||||
@ -16,93 +16,38 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "sourcehook_impl.h"
|
#include "sourcehook_impl.h"
|
||||||
|
|
||||||
#if SH_SYS == SH_SYS_WIN32
|
|
||||||
# include <windows.h>
|
|
||||||
#elif SH_SYS == SH_SYS_LINUX
|
|
||||||
# include <sys/mman.h>
|
|
||||||
# include <limits.h>
|
|
||||||
# include <unistd.h>
|
|
||||||
# ifndef PAGESIZE
|
|
||||||
# define PAGESIZE 4096
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if SH_RUNTIME_CODEGEN == 1
|
|
||||||
# if SH_COMP == SH_COMP_GCC
|
|
||||||
# define SH_CCC_CODESIZE 15
|
|
||||||
// :TODO:
|
|
||||||
//void SH_CCC_MakeGate(void *origthisptr, unsigned char* &ptr, void *origvtable, int i)
|
|
||||||
//{
|
|
||||||
//}
|
|
||||||
# elif SH_COMP == SH_COMP_MSVC
|
|
||||||
# define SH_CCC_CODESIZE 19
|
|
||||||
void SH_CCC_MakeGate(void *origthisptr, void *ccthisptr, unsigned char* ptr, void *origfunc)
|
|
||||||
{
|
|
||||||
// --Subtract old this pointer to get the offset
|
|
||||||
// 00417EDF 81 E9 A1 7B 33 01 sub ecx,1337BA1h
|
|
||||||
*ptr++ = 0x81;
|
|
||||||
*ptr++ = 0xE9;
|
|
||||||
*reinterpret_cast<void**>(ptr) = ccthisptr;
|
|
||||||
ptr += sizeof(void*);
|
|
||||||
// --Add it to the new this pointer
|
|
||||||
// 00417EE5 81 C1 37 13 37 13 add ecx,13371337h
|
|
||||||
*ptr++ = 0x81;
|
|
||||||
*ptr++ = 0xC1;
|
|
||||||
*reinterpret_cast<void**>(ptr) = origthisptr;
|
|
||||||
ptr += sizeof(void*);
|
|
||||||
// --Prepare address
|
|
||||||
// 00417EEB B8 EF BE AD DE mov eax,0DEADBEEFh
|
|
||||||
*ptr++ = 0xB8;
|
|
||||||
*reinterpret_cast<void**>(ptr) = origfunc;
|
|
||||||
ptr += sizeof(void*);
|
|
||||||
// -- Do actual jump
|
|
||||||
// 00417EF0 FF E0 jmp eax
|
|
||||||
*ptr++ = 0xFF;
|
|
||||||
*ptr++ = 0xE0;
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
namespace SourceHook
|
namespace SourceHook
|
||||||
{
|
{
|
||||||
CSourceHookImpl::CSourceHookImpl()
|
CSourceHookImpl::CSourceHookImpl()
|
||||||
{
|
{
|
||||||
// Get page size
|
|
||||||
#if SH_SYS == SH_SYS_WIN32
|
|
||||||
SYSTEM_INFO sysinfo;
|
|
||||||
GetSystemInfo(&sysinfo);
|
|
||||||
m_PageSize = sysinfo.dwPageSize;
|
|
||||||
#elif SH_SYS == SH_SYS_LINUX
|
|
||||||
m_PageSize = PAGESIZE;
|
|
||||||
#else
|
|
||||||
# error Unsupported system
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CSourceHookImpl::~CSourceHookImpl()
|
CSourceHookImpl::~CSourceHookImpl()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSourceHookImpl::IsPluginInUse(Plugin plug)
|
bool CSourceHookImpl::IsPluginInUse(Plugin plug)
|
||||||
{
|
{
|
||||||
// Iterate through all hook managers which are in this plugin
|
// Iterate through all hook managers which are in this plugin
|
||||||
// Iterate through their hooks
|
// Iterate through their vfnptrs, ifaces, hooks
|
||||||
// If a hook from an other plugin is found, return true
|
// If a hook from an other plugin is found, return true
|
||||||
// Return false otherwise
|
// Return false otherwise
|
||||||
#define TMP_CHECK_LIST(name) \
|
#define TMP_CHECK_LIST(name) \
|
||||||
for (iter3 = iter2->name.begin(); iter3 != iter2->name.end(); ++iter3) \
|
for (hook_iter = iface_iter->name.begin(); hook_iter != iface_iter->name.end(); ++hook_iter) \
|
||||||
if (iter3->plug == plug) \
|
if (hook_iter->plug == plug) \
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for (HookManInfoList::iterator iter = m_HookMans.begin(); iter != m_HookMans.end(); ++iter)
|
for (HookManInfoList::iterator hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter)
|
||||||
{
|
{
|
||||||
if (iter->plug == plug && !iter->ifaces.empty())
|
if (hmil_iter->plug != plug)
|
||||||
|
continue;
|
||||||
|
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->vfnptrs.begin();
|
||||||
|
vfnptr_iter != hmil_iter->vfnptrs.end(); ++vfnptr_iter)
|
||||||
{
|
{
|
||||||
for (std::list<HookManagerInfo::Iface>::iterator iter2 = iter->ifaces.begin(); iter2 != iter->ifaces.end(); ++iter2)
|
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin();
|
||||||
|
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter)
|
||||||
{
|
{
|
||||||
std::list<HookManagerInfo::Iface::Hook>::iterator iter3;
|
std::list<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hook_iter;
|
||||||
TMP_CHECK_LIST(hooks_pre);
|
TMP_CHECK_LIST(hooks_pre);
|
||||||
TMP_CHECK_LIST(hooks_post);
|
TMP_CHECK_LIST(hooks_post);
|
||||||
}
|
}
|
||||||
@ -116,24 +61,29 @@ namespace SourceHook
|
|||||||
{
|
{
|
||||||
// 1) Manually remove all hooks by this plugin
|
// 1) Manually remove all hooks by this plugin
|
||||||
std::list<RemoveHookInfo> hookstoremove;
|
std::list<RemoveHookInfo> hookstoremove;
|
||||||
|
#define TMP_CHECK_LIST(name, ispost) \
|
||||||
for (HookManInfoList::iterator iter = m_HookMans.begin(); iter != m_HookMans.end(); ++iter)
|
for (hook_iter = iface_iter->name.begin(); hook_iter != iface_iter->name.end(); ++hook_iter) \
|
||||||
|
if (hook_iter->plug == plug) \
|
||||||
|
hookstoremove.push_back(RemoveHookInfo(hook_iter->plug, iface_iter->ptr, \
|
||||||
|
hmil_iter->func, hook_iter->handler, ispost))
|
||||||
|
for (HookManInfoList::iterator hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter)
|
||||||
{
|
{
|
||||||
for (std::list<HookManagerInfo::Iface>::iterator iter2 = iter->ifaces.begin(); iter2 != iter->ifaces.end();
|
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->vfnptrs.begin();
|
||||||
++iter2)
|
vfnptr_iter != hmil_iter->vfnptrs.end(); ++vfnptr_iter)
|
||||||
{
|
{
|
||||||
for (std::list<HookManagerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_pre.begin(); iter3 != iter2->hooks_pre.end(); ++iter3)
|
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin();
|
||||||
if (iter3->plug == plug)
|
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter)
|
||||||
hookstoremove.push_back(RemoveHookInfo(iter3->plug, iter2->ptr, iter->func, iter3->handler, false));
|
{
|
||||||
|
std::list<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hook_iter;
|
||||||
for (std::list<HookManagerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_post.begin(); iter3 != iter2->hooks_post.end(); ++iter3)
|
TMP_CHECK_LIST(hooks_pre, false);
|
||||||
if (iter3->plug == plug)
|
TMP_CHECK_LIST(hooks_post, true);
|
||||||
hookstoremove.push_back(RemoveHookInfo(iter3->plug, iter2->ptr, iter->func, iter3->handler, true));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#undef TMP_CHECK_LIST
|
||||||
|
|
||||||
for (std::list<RemoveHookInfo>::iterator rmiter = hookstoremove.begin(); rmiter != hookstoremove.end(); ++rmiter)
|
for (std::list<RemoveHookInfo>::iterator rmiter = hookstoremove.begin(); rmiter != hookstoremove.end(); ++rmiter)
|
||||||
RemoveHook(rmiter->plug, rmiter->iface, rmiter->hpf, rmiter->handler, rmiter->post);
|
RemoveHook(*rmiter);
|
||||||
|
|
||||||
// 2) Other plugins may use hook managers in this plugin.
|
// 2) Other plugins may use hook managers in this plugin.
|
||||||
// Get a list of hook managers that are in this plugin and are used by other plugins
|
// Get a list of hook managers that are in this plugin and are used by other plugins
|
||||||
@ -141,16 +91,16 @@ namespace SourceHook
|
|||||||
|
|
||||||
HookManInfoList tmphookmans;
|
HookManInfoList tmphookmans;
|
||||||
bool erase = false;
|
bool erase = false;
|
||||||
for (HookManInfoList::iterator iter = m_HookMans.begin(); iter != m_HookMans.end();
|
for (HookManInfoList::iterator hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end();
|
||||||
erase ? iter=m_HookMans.erase(iter) : ++iter)
|
erase ? hmil_iter=m_HookMans.erase(hmil_iter) : ++hmil_iter)
|
||||||
{
|
{
|
||||||
if (iter->plug == plug)
|
if (hmil_iter->plug == plug)
|
||||||
{
|
{
|
||||||
if (!iter->ifaces.empty())
|
if (!hmil_iter->vfnptrs.empty())
|
||||||
{
|
{
|
||||||
// All hooks by this plugin are already removed
|
// All hooks by this plugin are already removed
|
||||||
// So if there is an iface, it has to be used by an other plugin
|
// So if there is a vfnptr, it has to be used by an other plugin
|
||||||
tmphookmans.push_back(*iter);
|
tmphookmans.push_back(*hmil_iter);
|
||||||
}
|
}
|
||||||
erase = true;
|
erase = true;
|
||||||
}
|
}
|
||||||
@ -159,29 +109,28 @@ namespace SourceHook
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For each hook manager:
|
// For each hook manager:
|
||||||
for (HookManInfoList::iterator iter = tmphookmans.begin(); iter != tmphookmans.end(); ++iter)
|
for (HookManInfoList::iterator hmil_iter = tmphookmans.begin(); hmil_iter != tmphookmans.end(); ++hmil_iter)
|
||||||
{
|
{
|
||||||
// Find a suitable hook manager in an other plugin
|
// Find a suitable hook manager in an other plugin
|
||||||
HookManInfoList::iterator newHookMan = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
|
HookManInfoList::iterator newHookMan = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
|
||||||
iter->proto, iter->vtbl_offs, iter->vtbl_idx, iter->thisptr_offs);
|
hmil_iter->proto, hmil_iter->vtbl_offs, hmil_iter->vtbl_idx);
|
||||||
if (newHookMan == m_HookMans.end())
|
|
||||||
{
|
|
||||||
// This should _never_ happen.
|
|
||||||
// If there is a hook from an other plugin, the plugin must have provided a hook manager as well.
|
|
||||||
SH_ASSERT(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddHook should make sure that every plugin only has _one_ hook manager for _one_ proto/vi/vo/thisptroffs
|
// This should _never_ happen.
|
||||||
SH_ASSERT(newHookMan->plug != plug);
|
// If there is a hook from an other plugin, the plugin must have provided a hook manager as well.
|
||||||
|
SH_ASSERT(newHookMan != m_HookMans.end(),
|
||||||
|
"Could not find a suitable hook manager in an other plugin!");
|
||||||
|
|
||||||
// The first hooker should be always used - so the new hook manager has to be empty
|
// AddHook should make sure that every plugin only has _one_ hook manager for _one_ proto/vi/vo
|
||||||
SH_ASSERT(newHookMan->ifaces.empty());
|
SH_ASSERT(newHookMan->plug != plug, "New hook manager from same plugin!");
|
||||||
|
|
||||||
// Move the ifaces from the old hook manager to the new one
|
// The first hook manager should be always used - so the new hook manager has to be empty
|
||||||
newHookMan->ifaces = iter->ifaces;
|
SH_ASSERT(newHookMan->vfnptrs.empty(), "New hook manager not empty!");
|
||||||
|
|
||||||
|
// Move the vfnptrs from the old hook manager to the new one
|
||||||
|
newHookMan->vfnptrs = hmil_iter->vfnptrs;
|
||||||
|
|
||||||
// Unregister the old one, register the new one
|
// Unregister the old one, register the new one
|
||||||
iter->func(HA_Unregister, NULL);
|
hmil_iter->func(HA_Unregister, NULL);
|
||||||
newHookMan->func(HA_Register, &(*newHookMan));
|
newHookMan->func(HA_Register, &(*newHookMan));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,43 +138,49 @@ namespace SourceHook
|
|||||||
void CSourceHookImpl::CompleteShutdown()
|
void CSourceHookImpl::CompleteShutdown()
|
||||||
{
|
{
|
||||||
std::list<RemoveHookInfo> hookstoremove;
|
std::list<RemoveHookInfo> hookstoremove;
|
||||||
|
#define TMP_CHECK_LIST(name, ispost) \
|
||||||
for (HookManInfoList::iterator iter = m_HookMans.begin(); iter != m_HookMans.end(); ++iter)
|
for (hook_iter = iface_iter->name.begin(); hook_iter != iface_iter->name.end(); ++hook_iter) \
|
||||||
|
hookstoremove.push_back(RemoveHookInfo(hook_iter->plug, iface_iter->ptr, \
|
||||||
|
hmil_iter->func, hook_iter->handler, ispost))
|
||||||
|
for (HookManInfoList::iterator hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter)
|
||||||
{
|
{
|
||||||
for (std::list<HookManagerInfo::Iface>::iterator iter2 = iter->ifaces.begin(); iter2 != iter->ifaces.end();
|
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->vfnptrs.begin();
|
||||||
++iter2)
|
vfnptr_iter != hmil_iter->vfnptrs.end(); ++vfnptr_iter)
|
||||||
{
|
{
|
||||||
for (std::list<HookManagerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_pre.begin(); iter3 != iter2->hooks_pre.end(); ++iter3)
|
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin();
|
||||||
hookstoremove.push_back(RemoveHookInfo(iter3->plug, iter2->ptr, iter->func, iter3->handler, false));
|
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter)
|
||||||
|
{
|
||||||
for (std::list<HookManagerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_post.begin(); iter3 != iter2->hooks_post.end(); ++iter3)
|
std::list<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hook_iter;
|
||||||
hookstoremove.push_back(RemoveHookInfo(iter3->plug, iter2->ptr, iter->func, iter3->handler, true));
|
TMP_CHECK_LIST(hooks_pre, false);
|
||||||
|
TMP_CHECK_LIST(hooks_post, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#undef TMP_CHECK_LIST
|
||||||
|
|
||||||
for (std::list<RemoveHookInfo>::iterator rmiter = hookstoremove.begin(); rmiter != hookstoremove.end(); ++rmiter)
|
for (std::list<RemoveHookInfo>::iterator rmiter = hookstoremove.begin(); rmiter != hookstoremove.end(); ++rmiter)
|
||||||
RemoveHook(rmiter->plug, rmiter->iface, rmiter->hpf, rmiter->handler, rmiter->post);
|
RemoveHook(*rmiter);
|
||||||
|
|
||||||
m_HookMans.clear();
|
m_HookMans.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSourceHookImpl::AddHook(Plugin plug, void *iface, int ifacesize, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post)
|
bool CSourceHookImpl::AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post)
|
||||||
{
|
{
|
||||||
|
void *adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface) + thisptr_offs);
|
||||||
// 1) Get info about the hook manager
|
// 1) Get info about the hook manager
|
||||||
HookManagerInfo tmp;
|
HookManagerInfo tmp;
|
||||||
if (myHookMan(HA_GetInfo, &tmp) != 0)
|
if (myHookMan(HA_GetInfo, &tmp) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Add the proposed hook manager to the _end_ of the list if the plugin doesn't have a hook manager with this proto/vo/vi registered
|
// Add the proposed hook manager to the _end_ of the list if the plugin doesn't have a hook manager with this proto/vo/vi registered
|
||||||
HookManInfoList::iterator hookmaniter;
|
HookManInfoList::iterator hkmi_iter;
|
||||||
for (hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
|
for (hkmi_iter = m_HookMans.begin(); hkmi_iter != m_HookMans.end(); ++hkmi_iter)
|
||||||
{
|
{
|
||||||
if (hookmaniter->plug == plug && strcmp(hookmaniter->proto, tmp.proto) == 0 &&
|
if (hkmi_iter->plug == plug && strcmp(hkmi_iter->proto, tmp.proto) == 0 &&
|
||||||
hookmaniter->vtbl_offs == tmp.vtbl_offs && hookmaniter->vtbl_idx == tmp.vtbl_idx &&
|
hkmi_iter->vtbl_offs == tmp.vtbl_offs && hkmi_iter->vtbl_idx == tmp.vtbl_idx)
|
||||||
hookmaniter->thisptr_offs == tmp.thisptr_offs)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (hookmaniter == m_HookMans.end())
|
if (hkmi_iter == m_HookMans.end())
|
||||||
{
|
{
|
||||||
// No such hook manager from this plugin yet, add it!
|
// No such hook manager from this plugin yet, add it!
|
||||||
tmp.func = myHookMan;
|
tmp.func = myHookMan;
|
||||||
@ -234,47 +189,70 @@ namespace SourceHook
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Then, search for a suitable hook manager (from the beginning)
|
// Then, search for a suitable hook manager (from the beginning)
|
||||||
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(), tmp.proto, tmp.vtbl_offs, tmp.vtbl_idx, tmp.thisptr_offs);
|
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(), tmp.proto, tmp.vtbl_offs, tmp.vtbl_idx);
|
||||||
SH_ASSERT(hookman != m_HookMans.end());
|
SH_ASSERT(hookman != m_HookMans.end(), "No hookman found - but if there was none, we've just added one!");
|
||||||
|
|
||||||
// Tell it to store the pointer if it's not already active
|
// Tell it to store the pointer if it's not already active
|
||||||
if (hookman->ifaces.empty())
|
if (hookman->vfnptrs.empty())
|
||||||
hookman->func(HA_Register, &(*hookman));
|
hookman->func(HA_Register, &(*hookman));
|
||||||
|
|
||||||
std::list<HookManagerInfo::Iface>::iterator ifsiter = std::find(hookman->ifaces.begin(), hookman->ifaces.end(), iface);
|
void **cur_vtptr = *reinterpret_cast<void***>(
|
||||||
|
reinterpret_cast<char*>(adjustediface) + tmp.vtbl_offs);
|
||||||
|
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.vtbl_idx);
|
||||||
|
|
||||||
if (ifsiter == hookman->ifaces.end())
|
HookManagerInfo::VfnPtrListIter vfnptr_iter = std::find(
|
||||||
|
hookman->vfnptrs.begin(), hookman->vfnptrs.end(), cur_vfnptr);
|
||||||
|
|
||||||
|
if (vfnptr_iter == hookman->vfnptrs.end())
|
||||||
{
|
{
|
||||||
HookManagerInfo::Iface ifs;
|
// Add a new one
|
||||||
ifs.ptr = iface;
|
HookManagerInfo::VfnPtr vfp;
|
||||||
ifs.callclass = GetCallClass(iface, ifacesize);
|
vfp.vfnptr = cur_vfnptr;
|
||||||
void *vtableptr = *reinterpret_cast<void**>(reinterpret_cast<char*>(iface) + hookman->vtbl_offs);
|
vfp.orig_entry = *reinterpret_cast<void**>(cur_vfnptr);
|
||||||
SetMemAccess(vtableptr, sizeof(void*) * hookman->vtbl_idx, SH_MEM_READ | SH_MEM_WRITE);
|
hookman->vfnptrs.push_back(vfp);
|
||||||
ifs.orig_entry = (*reinterpret_cast<void***>(reinterpret_cast<char*>(iface) + hookman->vtbl_offs))[hookman->vtbl_idx];
|
|
||||||
(*reinterpret_cast<void***>(reinterpret_cast<char*>(iface) + hookman->vtbl_offs))[hookman->vtbl_idx] =
|
// Alter vtable entry
|
||||||
(*reinterpret_cast<void***>(reinterpret_cast<char*>(hookman->hookfunc_inst) + hookman->hookfunc_vtbl_offs))[hookman->hookfunc_vtbl_idx];
|
SetMemAccess(cur_vtptr, sizeof(void*) * tmp.vtbl_idx, SH_MEM_READ | SH_MEM_WRITE);
|
||||||
hookman->ifaces.push_back(ifs);
|
*reinterpret_cast<void**>(cur_vfnptr) = *reinterpret_cast<void**>(hookman->hookfunc_vfnptr);
|
||||||
ifsiter = hookman->ifaces.end();
|
|
||||||
--ifsiter;
|
// Make vfnptr_iter point to the new element
|
||||||
|
vfnptr_iter = hookman->vfnptrs.end();
|
||||||
|
--vfnptr_iter;
|
||||||
}
|
}
|
||||||
HookManagerInfo::Iface::Hook hookinfo;
|
|
||||||
|
HookManagerInfo::VfnPtr::IfaceListIter iface_iter = std::find(
|
||||||
|
vfnptr_iter->ifaces.begin(), vfnptr_iter->ifaces.end(), adjustediface);
|
||||||
|
if (iface_iter == vfnptr_iter->ifaces.end())
|
||||||
|
{
|
||||||
|
// Add a new one
|
||||||
|
HookManagerInfo::VfnPtr::Iface ifs;
|
||||||
|
ifs.ptr = adjustediface;
|
||||||
|
vfnptr_iter->ifaces.push_back(ifs);
|
||||||
|
|
||||||
|
// Make iface_iter point to the new element
|
||||||
|
iface_iter = vfnptr_iter->ifaces.end();
|
||||||
|
--iface_iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the hook
|
||||||
|
HookManagerInfo::VfnPtr::Iface::Hook hookinfo;
|
||||||
hookinfo.handler = handler;
|
hookinfo.handler = handler;
|
||||||
hookinfo.plug = plug;
|
hookinfo.plug = plug;
|
||||||
hookinfo.paused = false;
|
hookinfo.paused = false;
|
||||||
if (post)
|
if (post)
|
||||||
ifsiter->hooks_post.push_back(hookinfo);
|
iface_iter->hooks_post.push_back(hookinfo);
|
||||||
else
|
else
|
||||||
ifsiter->hooks_pre.push_back(hookinfo);
|
iface_iter->hooks_pre.push_back(hookinfo);
|
||||||
|
|
||||||
|
|
||||||
// Now that it is done, check whether we have to update any callclasses
|
// Now that it is done, check whether we have to update any callclasses
|
||||||
for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter)
|
for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter)
|
||||||
{
|
{
|
||||||
if (cciter->iface == iface)
|
if (cciter->cc.ptr == iface)
|
||||||
{
|
{
|
||||||
ApplyCallClassPatch(*cciter, tmp.vtbl_offs, tmp.vtbl_idx, ifsiter->orig_entry);
|
ApplyCallClassPatch(*cciter, tmp.vtbl_offs, tmp.vtbl_idx, vfnptr_iter->orig_entry);
|
||||||
|
|
||||||
// We can assume that there is no more callclass with the same iface
|
// We can assume that there is no more callclass for the same iface
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,7 +260,18 @@ namespace SourceHook
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSourceHookImpl::RemoveHook(Plugin plug, void *iface, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post)
|
bool CSourceHookImpl::RemoveHook(RemoveHookInfo info)
|
||||||
|
{
|
||||||
|
return RemoveHook(info.plug, info.iface, info.hookman, info.handler, info.post);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSourceHookImpl::RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post)
|
||||||
|
{
|
||||||
|
return RemoveHook(plug, reinterpret_cast<void*>(reinterpret_cast<char*>(iface)+thisptr_offs),
|
||||||
|
myHookMan, handler, post);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSourceHookImpl::RemoveHook(Plugin plug, void *adjustediface, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post)
|
||||||
{
|
{
|
||||||
HookManagerInfo tmp;
|
HookManagerInfo tmp;
|
||||||
if (myHookMan(HA_GetInfo, &tmp) != 0)
|
if (myHookMan(HA_GetInfo, &tmp) != 0)
|
||||||
@ -290,196 +279,110 @@ namespace SourceHook
|
|||||||
|
|
||||||
// Find the hook manager and the hook
|
// Find the hook manager and the hook
|
||||||
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
|
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
|
||||||
tmp.proto, tmp.vtbl_offs, tmp.vtbl_idx, tmp.thisptr_offs);
|
tmp.proto, tmp.vtbl_offs, tmp.vtbl_idx);
|
||||||
if (hookman == m_HookMans.end())
|
if (hookman == m_HookMans.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (std::list<HookManagerInfo::Iface>::iterator ifaceiter = hookman->ifaces.begin(); ifaceiter != hookman->ifaces.end(); ++ifaceiter)
|
void **cur_vtptr = *reinterpret_cast<void***>(
|
||||||
|
reinterpret_cast<char*>(adjustediface) + tmp.vtbl_offs);
|
||||||
|
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.vtbl_idx);
|
||||||
|
|
||||||
|
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->vfnptrs.begin();
|
||||||
|
vfnptr_iter != hookman->vfnptrs.end(); ++vfnptr_iter)
|
||||||
{
|
{
|
||||||
if (ifaceiter->ptr == iface)
|
if (vfnptr_iter->vfnptr == cur_vfnptr)
|
||||||
{
|
{
|
||||||
std::list<HookManagerInfo::Iface::Hook> &hooks = post ? ifaceiter->hooks_post : ifaceiter->hooks_pre;
|
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin();
|
||||||
bool erase;
|
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter)
|
||||||
for (std::list<HookManagerInfo::Iface::Hook>::iterator hookiter = hooks.begin();
|
|
||||||
hookiter != hooks.end(); erase ? hookiter = hooks.erase(hookiter) : ++hookiter)
|
|
||||||
{
|
{
|
||||||
erase = hookiter->plug == plug && hookiter->handler->IsEqual(handler);
|
std::list<HookManagerInfo::VfnPtr::Iface::Hook> &hooks =
|
||||||
if (erase)
|
post ? iface_iter->hooks_post : iface_iter->hooks_pre;
|
||||||
hookiter->handler->DeleteThis(); // Make the _plugin_ delete the handler object
|
|
||||||
|
bool erase;
|
||||||
|
for (std::list<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = hooks.begin();
|
||||||
|
hookiter != hooks.end(); erase ? hookiter = hooks.erase(hookiter) : ++hookiter)
|
||||||
|
{
|
||||||
|
erase = hookiter->plug == plug && hookiter->handler->IsEqual(handler);
|
||||||
|
if (erase)
|
||||||
|
hookiter->handler->DeleteThis(); // Make the _plugin_ delete the handler object
|
||||||
|
}
|
||||||
|
if (iface_iter->hooks_post.empty() && iface_iter->hooks_pre.empty())
|
||||||
|
{
|
||||||
|
vfnptr_iter->ifaces.erase(iface_iter);
|
||||||
|
if (vfnptr_iter->ifaces.empty())
|
||||||
|
{
|
||||||
|
// Deactivate the hook
|
||||||
|
*reinterpret_cast<void**>(vfnptr_iter->vfnptr) = vfnptr_iter->orig_entry;
|
||||||
|
|
||||||
|
hookman->vfnptrs.erase(vfnptr_iter);
|
||||||
|
|
||||||
|
if (hookman->vfnptrs.empty())
|
||||||
|
{
|
||||||
|
// Unregister the hook manager
|
||||||
|
hookman->func(HA_Unregister, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ifaceiter->hooks_post.empty() && ifaceiter->hooks_pre.empty())
|
|
||||||
{
|
|
||||||
// Deactivate the hook
|
|
||||||
(*reinterpret_cast<void***>(reinterpret_cast<char*>(ifaceiter->ptr) +
|
|
||||||
hookman->vtbl_offs))[hookman->vtbl_idx]= ifaceiter->orig_entry;
|
|
||||||
|
|
||||||
// Release the callclass
|
|
||||||
ReleaseCallClass(ifaceiter->callclass);
|
|
||||||
|
|
||||||
// Remove the iface info
|
|
||||||
hookman->ifaces.erase(ifaceiter);
|
|
||||||
|
|
||||||
if (hookman->ifaces.empty())
|
|
||||||
hookman->func(HA_Unregister, NULL);
|
|
||||||
}
|
|
||||||
// :TODO: Better return value? Or none?
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *CSourceHookImpl::GetCallClass(void *iface, size_t size)
|
GenericCallClass *CSourceHookImpl::GetCallClass(void *iface)
|
||||||
{
|
{
|
||||||
for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter)
|
for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter)
|
||||||
{
|
{
|
||||||
if (cciter->iface == iface)
|
if (cciter->cc.ptr == iface)
|
||||||
{
|
{
|
||||||
++cciter->refcounter;
|
++cciter->refcounter;
|
||||||
return cciter->ptr;
|
return &cciter->cc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The layout of callclasses is:
|
CallClassInfo tmp;
|
||||||
// Copy of the class; vtable entries pointing to gates
|
|
||||||
// Pointer to the corresponding CallClass object
|
|
||||||
// Copy of the class; vtable entries pointing to original functions
|
|
||||||
|
|
||||||
CallClass tmp;
|
|
||||||
char *ptr = new char[size * 2 + sizeof(void*)];
|
|
||||||
tmp.ptr = reinterpret_cast<void*>(ptr);
|
|
||||||
memcpy(reinterpret_cast<void*>(ptr), iface, size);
|
|
||||||
memcpy(reinterpret_cast<void*>(ptr + size + sizeof(void*)), iface, size);
|
|
||||||
tmp.iface = iface;
|
|
||||||
tmp.size = size;
|
|
||||||
tmp.refcounter = 1;
|
tmp.refcounter = 1;
|
||||||
|
tmp.cc.ptr = iface;
|
||||||
|
|
||||||
// Go through _all_ hooks and apply any needed patches
|
|
||||||
for (HookManInfoList::iterator hookman = m_HookMans.begin(); hookman != m_HookMans.end(); ++hookman)
|
for (HookManInfoList::iterator hookman = m_HookMans.begin(); hookman != m_HookMans.end(); ++hookman)
|
||||||
{
|
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->vfnptrs.begin();
|
||||||
for (std::list<HookManagerInfo::Iface>::iterator ifaceiter = hookman->ifaces.begin(); ifaceiter != hookman->ifaces.end(); ++ifaceiter)
|
vfnptr_iter != hookman->vfnptrs.end(); ++vfnptr_iter)
|
||||||
{
|
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin();
|
||||||
if (ifaceiter->ptr == iface)
|
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter)
|
||||||
{
|
if (iface_iter->ptr == iface)
|
||||||
if (!ApplyCallClassPatch(tmp, hookman->vtbl_offs, hookman->vtbl_idx, ifaceiter->orig_entry))
|
ApplyCallClassPatch(tmp, hookman->vtbl_offs, hookman->vtbl_idx,
|
||||||
{
|
vfnptr_iter->orig_entry);
|
||||||
FreeCallClass(tmp);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_CallClasses.push_back(tmp);
|
m_CallClasses.push_back(tmp);
|
||||||
// The object has to be followed by the pointer to the vtable info object
|
return &m_CallClasses.back().cc;
|
||||||
*reinterpret_cast<void**>(ptr + size) = &m_CallClasses.back();
|
|
||||||
return tmp.ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSourceHookImpl::ReleaseCallClass(void *ptr)
|
void CSourceHookImpl::ReleaseCallClass(GenericCallClass *ptr)
|
||||||
{
|
{
|
||||||
Impl_CallClassList::iterator iter = std::find(m_CallClasses.begin(), m_CallClasses.end(), ptr);
|
Impl_CallClassList::iterator iter = std::find(m_CallClasses.begin(), m_CallClasses.end(), ptr);
|
||||||
if (iter == m_CallClasses.end())
|
if (iter == m_CallClasses.end())
|
||||||
return;
|
return;
|
||||||
--iter->refcounter;
|
--iter->refcounter;
|
||||||
if (iter->refcounter < 1)
|
if (iter->refcounter < 1)
|
||||||
{
|
|
||||||
FreeCallClass(*iter);
|
|
||||||
m_CallClasses.erase(iter);
|
m_CallClasses.erase(iter);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSourceHookImpl::FreeCallClass(CallClass &cc)
|
void CSourceHookImpl::ApplyCallClassPatch(CallClassInfo &cc, int vtbl_offs, int vtbl_idx, void *orig_entry)
|
||||||
{
|
{
|
||||||
for (CallClass::VTableList::iterator vtbliter = cc.vtables.begin(); vtbliter != cc.vtables.end(); ++vtbliter)
|
OrigFuncs &tmpvec = cc.cc.vt[vtbl_offs];
|
||||||
{
|
if (tmpvec.size() <= (size_t)vtbl_idx)
|
||||||
#if SH_RUNTIME_CODEGEN == 1
|
tmpvec.resize(vtbl_idx+1);
|
||||||
// Delete generated callgates
|
tmpvec[vtbl_idx] = orig_entry;
|
||||||
for (std::list<int>::iterator cgiter = vtbliter->patches.begin(); cgiter != vtbliter->patches.end(); ++cgiter)
|
|
||||||
{
|
|
||||||
char *cgptr = reinterpret_cast<char**>(vtbliter->ptr)[*cgiter];
|
|
||||||
delete [] cgptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
delete [] reinterpret_cast<char*>(vtbliter->ptr);
|
|
||||||
}
|
|
||||||
delete [] reinterpret_cast<char*>(cc.ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSourceHookImpl::ApplyCallClassPatch(CallClass &cc, int vtbl_offs, int vtbl_idx, void *orig_entry)
|
|
||||||
{
|
|
||||||
char *ptr = reinterpret_cast<char*>(cc.ptr);
|
|
||||||
void *vtable = *reinterpret_cast<void**>(ptr + vtbl_offs);
|
|
||||||
|
|
||||||
// Check whether we already know that vtable
|
|
||||||
CallClass::VTableList::iterator vtbliter = std::find(cc.vtables.begin(),
|
|
||||||
cc.vtables.end(), reinterpret_cast<void*>(vtable));
|
|
||||||
int actvtablesize=MAX_VTABLE_LEN;
|
|
||||||
if (vtbliter == cc.vtables.end())
|
|
||||||
{
|
|
||||||
CallClass::VTable newvtableinfo;
|
|
||||||
int pagesnum = (MAX_VTABLE_LEN % m_PageSize == 0) ? MAX_VTABLE_LEN / m_PageSize : MAX_VTABLE_LEN / m_PageSize + 1;
|
|
||||||
// Set all pages in the range to readwrite
|
|
||||||
// :TODO: Fix this!
|
|
||||||
char *pagebegin = reinterpret_cast<char*>(vtable) - (reinterpret_cast<int>(vtable) % m_PageSize);
|
|
||||||
for (int ipage = 0; ipage < pagesnum; ++ipage)
|
|
||||||
{
|
|
||||||
if (!SetMemAccess(reinterpret_cast<void*>(pagebegin + ipage * m_PageSize), 1,
|
|
||||||
SH_MEM_READ | SH_MEM_WRITE))
|
|
||||||
{
|
|
||||||
// We can't go here anymore
|
|
||||||
actvtablesize = static_cast<int>((pagebegin + ipage * m_PageSize) - reinterpret_cast<char*>(vtable));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (actvtablesize < 1)
|
|
||||||
{
|
|
||||||
// We can't access the vtable -> Quit
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Create a new vtable
|
|
||||||
newvtableinfo.ptr = reinterpret_cast<void*>(new char[actvtablesize]);
|
|
||||||
// Fill it with the information from the old vtable
|
|
||||||
memcpy(newvtableinfo.ptr, vtable, actvtablesize);
|
|
||||||
newvtableinfo.actsize = actvtablesize;
|
|
||||||
// Set the pointer in the object and add it to the list of already known vtables
|
|
||||||
*reinterpret_cast<void**>(ptr + vtbl_offs) = newvtableinfo.ptr;
|
|
||||||
cc.vtables.push_back(newvtableinfo);
|
|
||||||
|
|
||||||
vtbliter = cc.vtables.end();
|
|
||||||
--vtbliter;
|
|
||||||
// :TODO: When not codegen, patch the other vtable?
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether we already have this patch
|
|
||||||
if (std::find(vtbliter->patches.begin(), vtbliter->patches.end(), vtbl_idx) == vtbliter->patches.end())
|
|
||||||
{
|
|
||||||
// No -> apply it
|
|
||||||
|
|
||||||
// Get a call gate
|
|
||||||
void *callgate = NULL;
|
|
||||||
#if SH_RUNTIME_CODEGEN == 1
|
|
||||||
unsigned char *cggen = new unsigned char[SH_CCC_CODESIZE];
|
|
||||||
//SH_CCC_MakeGate(cc.iface, cc.ptr, cggen, orig_entry);
|
|
||||||
callgate = (void*)cggen;
|
|
||||||
SetMemAccess(callgate, SH_CCC_CODESIZE, SH_MEM_READ | SH_MEM_WRITE | SH_MEM_EXEC);
|
|
||||||
#else
|
|
||||||
// :TODO:
|
|
||||||
#error Not supported yet!
|
|
||||||
#endif
|
|
||||||
vtbliter->patches.push_back(vtbl_idx);
|
|
||||||
reinterpret_cast<void**>(vtbliter->ptr)[vtbl_idx] = callgate;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CSourceHookImpl::HookManInfoList::iterator CSourceHookImpl::FindHookMan(HookManInfoList::iterator begin,
|
CSourceHookImpl::HookManInfoList::iterator CSourceHookImpl::FindHookMan(HookManInfoList::iterator begin,
|
||||||
HookManInfoList::iterator end, const char *proto, int vtblofs, int vtblidx, int thisptrofs)
|
HookManInfoList::iterator end, const char *proto, int vtblofs, int vtblidx)
|
||||||
{
|
{
|
||||||
for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
|
for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
|
||||||
{
|
{
|
||||||
if (strcmp(hookmaniter->proto, proto) == 0 && hookmaniter->vtbl_offs == vtblofs && hookmaniter->vtbl_idx == vtblidx &&
|
if (strcmp(hookmaniter->proto, proto) == 0 && hookmaniter->vtbl_offs == vtblofs &&
|
||||||
hookmaniter->thisptr_offs == thisptrofs)
|
hookmaniter->vtbl_idx == vtblidx)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return hookmaniter;
|
return hookmaniter;
|
||||||
@ -489,38 +392,42 @@ namespace SourceHook
|
|||||||
{
|
{
|
||||||
// Go through all hook managers, all interfaces, and set the status of all hooks of this plugin to paused
|
// Go through all hook managers, all interfaces, and set the status of all hooks of this plugin to paused
|
||||||
for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
|
for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
|
||||||
for (std::list<HookManagerInfo::Iface>::iterator ifaceiter = hookmaniter->ifaces.begin();
|
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hookmaniter->vfnptrs.begin();
|
||||||
ifaceiter != hookmaniter->ifaces.end(); ++ifaceiter)
|
vfnptr_iter != hookmaniter->vfnptrs.end(); ++vfnptr_iter)
|
||||||
{
|
for (HookManagerInfo::VfnPtr::IfaceListIter ifaceiter = vfnptr_iter->ifaces.begin();
|
||||||
for (std::list<HookManagerInfo::Iface::Hook>::iterator hookiter = ifaceiter->hooks_pre.begin();
|
ifaceiter != vfnptr_iter->ifaces.end(); ++ifaceiter)
|
||||||
hookiter != ifaceiter->hooks_pre.end(); ++hookiter)
|
{
|
||||||
if (plug == hookiter->plug)
|
for (std::list<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = ifaceiter->hooks_pre.begin();
|
||||||
hookiter->paused = true;
|
hookiter != ifaceiter->hooks_pre.end(); ++hookiter)
|
||||||
|
if (plug == hookiter->plug)
|
||||||
|
hookiter->paused = true;
|
||||||
|
|
||||||
for (std::list<HookManagerInfo::Iface::Hook>::iterator hookiter = ifaceiter->hooks_post.begin();
|
for (std::list<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = ifaceiter->hooks_post.begin();
|
||||||
hookiter != ifaceiter->hooks_post.end(); ++hookiter)
|
hookiter != ifaceiter->hooks_post.end(); ++hookiter)
|
||||||
if (plug == hookiter->plug)
|
if (plug == hookiter->plug)
|
||||||
hookiter->paused = true;
|
hookiter->paused = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSourceHookImpl::UnpausePlugin(Plugin plug)
|
void CSourceHookImpl::UnpausePlugin(Plugin plug)
|
||||||
{
|
{
|
||||||
// Go through all hook managers, all interfaces, and set the status of all hooks of this plugin to normal
|
// Go through all hook managers, all interfaces, and set the status of all hooks of this plugin to paused
|
||||||
for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
|
for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
|
||||||
for (std::list<HookManagerInfo::Iface>::iterator ifaceiter = hookmaniter->ifaces.begin();
|
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hookmaniter->vfnptrs.begin();
|
||||||
ifaceiter != hookmaniter->ifaces.end(); ++ifaceiter)
|
vfnptr_iter != hookmaniter->vfnptrs.end(); ++vfnptr_iter)
|
||||||
{
|
for (HookManagerInfo::VfnPtr::IfaceListIter ifaceiter = vfnptr_iter->ifaces.begin();
|
||||||
for (std::list<HookManagerInfo::Iface::Hook>::iterator hookiter = ifaceiter->hooks_pre.begin();
|
ifaceiter != vfnptr_iter->ifaces.end(); ++ifaceiter)
|
||||||
hookiter != ifaceiter->hooks_pre.end(); ++hookiter)
|
{
|
||||||
if (plug == hookiter->plug)
|
for (std::list<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = ifaceiter->hooks_pre.begin();
|
||||||
hookiter->paused = false;
|
hookiter != ifaceiter->hooks_pre.end(); ++hookiter)
|
||||||
|
if (plug == hookiter->plug)
|
||||||
|
hookiter->paused = false;
|
||||||
|
|
||||||
for (std::list<HookManagerInfo::Iface::Hook>::iterator hookiter = ifaceiter->hooks_post.begin();
|
for (std::list<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = ifaceiter->hooks_post.begin();
|
||||||
hookiter != ifaceiter->hooks_post.end(); ++hookiter)
|
hookiter != ifaceiter->hooks_post.end(); ++hookiter)
|
||||||
if (plug == hookiter->plug)
|
if (plug == hookiter->plug)
|
||||||
hookiter->paused = false;
|
hookiter->paused = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSourceHookImpl::SetRes(META_RES res)
|
void CSourceHookImpl::SetRes(META_RES res)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -28,14 +28,15 @@ namespace SourceHook
|
|||||||
*/
|
*/
|
||||||
struct RemoveHookInfo
|
struct RemoveHookInfo
|
||||||
{
|
{
|
||||||
RemoveHookInfo(Plugin p, void *i, HookManagerPubFunc h, ISHDelegate *hd, bool ps)
|
RemoveHookInfo(Plugin pplug, void *piface, HookManagerPubFunc phookman,
|
||||||
: plug(p), iface(i), hpf(h), handler(hd), post(ps)
|
ISHDelegate *phandler, bool ppost)
|
||||||
|
: plug(pplug), iface(piface), hookman(phookman), handler(phandler), post(ppost)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Plugin plug;
|
Plugin plug;
|
||||||
void *iface;
|
void *iface;
|
||||||
HookManagerPubFunc hpf;
|
HookManagerPubFunc hookman;
|
||||||
ISHDelegate *handler;
|
ISHDelegate *handler;
|
||||||
bool post;
|
bool post;
|
||||||
};
|
};
|
||||||
@ -45,27 +46,30 @@ namespace SourceHook
|
|||||||
*/
|
*/
|
||||||
typedef std::list<HookManagerInfo> HookManInfoList;
|
typedef std::list<HookManagerInfo> HookManInfoList;
|
||||||
|
|
||||||
|
struct CallClassInfo
|
||||||
|
{
|
||||||
|
GenericCallClass cc;
|
||||||
|
int refcounter;
|
||||||
|
bool operator==(void *other)
|
||||||
|
{
|
||||||
|
return cc.ptr == other;
|
||||||
|
}
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* @brief A list of Impl_CallClass structures
|
* @brief A list of CallClass structures
|
||||||
*/
|
*/
|
||||||
typedef std::list<CallClass> Impl_CallClassList;
|
typedef std::list<CallClassInfo> Impl_CallClassList;
|
||||||
|
|
||||||
Impl_CallClassList m_CallClasses; //!< A list of already generated callclasses
|
Impl_CallClassList m_CallClasses; //!< A list of already generated callclasses
|
||||||
HookManInfoList m_HookMans; //!< A list of hook managers
|
HookManInfoList m_HookMans; //!< A list of hook managers
|
||||||
|
|
||||||
int m_PageSize; //!< Stores the system's page size
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Finds a hook manager for a function based on a text-prototype, a vtable offset and a vtable index
|
* @brief Finds a hook manager for a function based on a text-prototype, a vtable offset and a vtable index
|
||||||
*/
|
*/
|
||||||
HookManInfoList::iterator FindHookMan(HookManInfoList::iterator begin, HookManInfoList::iterator end,
|
HookManInfoList::iterator FindHookMan(HookManInfoList::iterator begin, HookManInfoList::iterator end,
|
||||||
const char *proto, int vtblofs, int vtblidx, int thisptrofs);
|
const char *proto, int vtblofs, int vtblidx);
|
||||||
|
|
||||||
void FreeCallClass(CallClass &cc);
|
void ApplyCallClassPatch(CallClassInfo &cc, int vtbl_offs, int vtbl_idx, void *orig_entry);
|
||||||
bool ApplyCallClassPatch(CallClass &cc, int vtbl_offs, int vtbl_idx, void *orig_entry);
|
|
||||||
|
|
||||||
static const int MAX_VTABLE_LEN = 4096; //!< Maximal vtable length in bytes
|
|
||||||
|
|
||||||
META_RES m_Status, m_PrevRes, m_CurRes;
|
META_RES m_Status, m_PrevRes, m_CurRes;
|
||||||
const void *m_OrigRet;
|
const void *m_OrigRet;
|
||||||
@ -97,7 +101,7 @@ namespace SourceHook
|
|||||||
* @param handler A pointer to a FastDelegate containing the hook handler
|
* @param handler A pointer to a FastDelegate containing the hook handler
|
||||||
* @param post Set to true if you want a post handler
|
* @param post Set to true if you want a post handler
|
||||||
*/
|
*/
|
||||||
bool AddHook(Plugin plug, void *iface, int ifacesize, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post);
|
bool AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Removes a hook.
|
* @brief Removes a hook.
|
||||||
@ -106,12 +110,35 @@ namespace SourceHook
|
|||||||
*
|
*
|
||||||
* @param plug The unique identifier of the plugin that calls this function
|
* @param plug The unique identifier of the plugin that calls this function
|
||||||
* @param iface The interface pointer
|
* @param iface The interface pointer
|
||||||
|
* @param thisptr_offs This pointer adjuster
|
||||||
|
* @param myHookMan A hook manager function that should be capable of handling the function
|
||||||
|
* @param handler A pointer to a FastDelegate containing the hook handler
|
||||||
|
* @param post Set to true if you want a post handler
|
||||||
|
*/
|
||||||
|
bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a hook.
|
||||||
|
*
|
||||||
|
* @return True if the function succeeded, false otherwise
|
||||||
|
*
|
||||||
|
* @param plug The unique identifier of the plugin that calls this function
|
||||||
|
* @param iface Already adjusted interface pointer
|
||||||
* @param myHookMan A hook manager function that should be capable of handling the function
|
* @param myHookMan A hook manager function that should be capable of handling the function
|
||||||
* @param handler A pointer to a FastDelegate containing the hook handler
|
* @param handler A pointer to a FastDelegate containing the hook handler
|
||||||
* @param post Set to true if you want a post handler
|
* @param post Set to true if you want a post handler
|
||||||
*/
|
*/
|
||||||
bool RemoveHook(Plugin plug, void *iface, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post);
|
bool RemoveHook(Plugin plug, void *iface, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a hook.
|
||||||
|
*
|
||||||
|
* @ return True if the function succeeded, false otherwise
|
||||||
|
*
|
||||||
|
* @param info A RemoveHookInfo structure, describing the hook
|
||||||
|
*/
|
||||||
|
bool RemoveHook(RemoveHookInfo info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks whether a plugin has (a) hook manager(s) that is/are currently used by other plugins
|
* @brief Checks whether a plugin has (a) hook manager(s) that is/are currently used by other plugins
|
||||||
*
|
*
|
||||||
@ -138,14 +165,14 @@ namespace SourceHook
|
|||||||
*
|
*
|
||||||
* @param iface The interface pointer
|
* @param iface The interface pointer
|
||||||
*/
|
*/
|
||||||
void *GetCallClass(void *iface, size_t size);
|
GenericCallClass *GetCallClass(void *iface);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Release a callclass
|
* @brief Release a callclass
|
||||||
*
|
*
|
||||||
* @param ptr Pointer to the callclass
|
* @param ptr Pointer to the callclass
|
||||||
*/
|
*/
|
||||||
virtual void ReleaseCallClass(void *ptr);
|
virtual void ReleaseCallClass(GenericCallClass *ptr);
|
||||||
|
|
||||||
virtual void SetRes(META_RES res); //!< Sets the meta result
|
virtual void SetRes(META_RES res); //!< Sets the meta result
|
||||||
virtual META_RES GetPrevRes(); //!< Gets the meta result of the previously called handler
|
virtual META_RES GetPrevRes(); //!< Gets the meta result of the previously called handler
|
||||||
|
|||||||
@ -402,93 +402,93 @@ bool Test_F16_int_post_handler(int x)
|
|||||||
RETURN_META_VALUE(MRES_OVERRIDE, !META_RESULT_ORIG_RET(bool));
|
RETURN_META_VALUE(MRES_OVERRIDE, !META_RESULT_ORIG_RET(bool));
|
||||||
}
|
}
|
||||||
|
|
||||||
// I haven't checked the second F16 function yet
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
// Get an instance and call the functions using the pointer
|
// Get an instance and call the functions using the pointer
|
||||||
// (otherwise the compiler optimizes away the vtable lookup)
|
// (otherwise the compiler optimizes away the vtable lookup)
|
||||||
Test zLOL;
|
Test zLOL;
|
||||||
|
Test zLOL2;
|
||||||
Test *zLOL_Ptr = &zLOL;
|
Test *zLOL_Ptr = &zLOL;
|
||||||
|
Test *zLOL2_Ptr = &zLOL2;
|
||||||
g_SHPtr = &g_SHImpl;
|
g_SHPtr = &g_SHImpl;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
Test *cc = SH_GET_CALLCLASS(Test, zLOL_Ptr);
|
SourceHook::CallClass<Test> *cc = SH_GET_CALLCLASS(zLOL_Ptr);
|
||||||
|
|
||||||
printf("TEST1.1: Calling F299\n");
|
printf("TEST1.1: Calling F299\n");
|
||||||
zLOL_Ptr->F299();
|
zLOL_Ptr->F299();
|
||||||
printf("TEST1.2: Calling F299 through cc\n");
|
printf("TEST1.2: Calling F299 through cc\n");
|
||||||
cc->F299();
|
SH_CALL(cc, &Test::F299)();
|
||||||
printf("TEST1.3: Hooking it\n");
|
printf("TEST1.3: Hooking it\n");
|
||||||
SH_ADD_HOOK_STATICFUNC(Test, F299, zLOL_Ptr, Test_F299_pre_handler, false);
|
SH_ADD_HOOK_STATICFUNC(Test, F299, zLOL_Ptr, Test_F299_pre_handler, false);
|
||||||
|
zLOL2_Ptr->F299();
|
||||||
printf("TEST1.4: Calling F299\n");
|
printf("TEST1.4: Calling F299\n");
|
||||||
zLOL_Ptr->F299();
|
zLOL_Ptr->F299();
|
||||||
printf("TEST1.5: Calling F299 through cc\n");
|
printf("TEST1.5: Calling F299 through cc\n");
|
||||||
cc->F299();
|
SH_CALL(cc, &Test::F299)();
|
||||||
printf("TEST1.6: Adding one more pre and one post hook\n");
|
printf("TEST1.6: Adding one more pre and one post hook\n");
|
||||||
SH_ADD_HOOK_STATICFUNC(Test, F299, zLOL_Ptr, Test_F299_pre_handler2, false);
|
SH_ADD_HOOK_STATICFUNC(Test, F299, zLOL_Ptr, Test_F299_pre_handler2, false);
|
||||||
SH_ADD_HOOK_STATICFUNC(Test, F299, zLOL_Ptr, Test_F299_post_handler, true);
|
SH_ADD_HOOK_STATICFUNC(Test, F299, zLOL_Ptr, Test_F299_post_handler, true);
|
||||||
printf("TEST1.7: Calling F299\n");
|
printf("TEST1.7: Calling F299\n");
|
||||||
zLOL_Ptr->F299();
|
zLOL_Ptr->F299();
|
||||||
printf("TEST1.8: Calling F299 through cc\n");
|
printf("TEST1.8: Calling F299 through cc\n");
|
||||||
cc->F299();
|
SH_CALL(cc, &Test::F299)();
|
||||||
printf("TEST1.9: Removing pre hooks\n");
|
printf("TEST1.9: Removing pre hooks\n");
|
||||||
SH_REMOVE_HOOK_STATICFUNC(Test, F299, zLOL_Ptr, Test_F299_pre_handler, false);
|
SH_REMOVE_HOOK_STATICFUNC(Test, F299, zLOL_Ptr, Test_F299_pre_handler, false);
|
||||||
SH_REMOVE_HOOK_STATICFUNC(Test, F299, zLOL_Ptr, Test_F299_pre_handler2, false);
|
SH_REMOVE_HOOK_STATICFUNC(Test, F299, zLOL_Ptr, Test_F299_pre_handler2, false);
|
||||||
printf("TEST1.10: Calling F299\n");
|
printf("TEST1.10: Calling F299\n");
|
||||||
zLOL_Ptr->F299();
|
zLOL_Ptr->F299();
|
||||||
printf("TEST1.11: Calling F299 through cc\n");
|
printf("TEST1.11: Calling F299 through cc\n");
|
||||||
cc->F299();
|
SH_CALL(cc, &Test::F299)();
|
||||||
printf("TEST1.12: Removing post hook\n");
|
printf("TEST1.12: Removing post hook\n");
|
||||||
SH_REMOVE_HOOK_STATICFUNC(Test, F299, zLOL_Ptr, Test_F299_post_handler, true);
|
SH_REMOVE_HOOK_STATICFUNC(Test, F299, zLOL_Ptr, Test_F299_post_handler, true);
|
||||||
printf("TEST1.13: Calling F299\n");
|
printf("TEST1.13: Calling F299\n");
|
||||||
zLOL_Ptr->F299();
|
zLOL_Ptr->F299();
|
||||||
printf("TEST1.14: Calling F299 through cc\n");
|
printf("TEST1.14: Calling F299 through cc\n");
|
||||||
cc->F299();
|
SH_CALL(cc, &Test::F299)();
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
printf("\n\n*************************************************\n\n");
|
printf("\n\n*************************************************\n\n");
|
||||||
printf("TEST2.1: Calling F16(155)\n");
|
printf("TEST2.1: Calling F16(155)\n");
|
||||||
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
||||||
printf("TEST2.2: Calling F16(155) through CC\n");
|
printf("TEST2.2: Calling F16(155) through CC\n");
|
||||||
printf("Returned: %d\n", cc->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", SH_CALL(cc, static_cast<bool(Test::*)(int)>(&Test::F16))(155) ? 1 : 0);
|
||||||
printf("TEST2.3: Hooking it\n");
|
printf("TEST2.3: Hooking it\n");
|
||||||
SH_ADD_HOOK_STATICFUNC(Test, F16, zLOL_Ptr, Test_F16_int_pre_handler, false);
|
SH_ADD_HOOK_STATICFUNC(Test, F16, zLOL_Ptr, Test_F16_int_pre_handler, false);
|
||||||
printf("TEST2.4: Calling F16(155)\n");
|
printf("TEST2.4: Calling F16(155)\n");
|
||||||
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
||||||
printf("TEST2.5: Calling F16(155) through CC\n");
|
printf("TEST2.5: Calling F16(155) through CC\n");
|
||||||
printf("Returned: %d\n", cc->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", SH_CALL(cc, static_cast<bool(Test::*)(int)>(&Test::F16))(155) ? 1 : 0);
|
||||||
printf("TEST2.6: Adding post hook\n");
|
printf("TEST2.6: Adding post hook\n");
|
||||||
SH_ADD_HOOK_STATICFUNC(Test, F16, zLOL_Ptr, Test_F16_int_post_handler, true);
|
SH_ADD_HOOK_STATICFUNC(Test, F16, zLOL_Ptr, Test_F16_int_post_handler, true);
|
||||||
printf("TEST2.7: Calling F16(155)\n");
|
printf("TEST2.7: Calling F16(155)\n");
|
||||||
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
||||||
printf("TEST2.8: Calling F16(155) through CC\n");
|
printf("TEST2.8: Calling F16(155) through CC\n");
|
||||||
printf("Returned: %d\n", cc->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", SH_CALL(cc, static_cast<bool(Test::*)(int)>(&Test::F16))(155) ? 1 : 0);
|
||||||
printf("TEST2.9: Removing pre hook\n");
|
|
||||||
printf("TEST2.XX.1: Pausing the plugin\n");
|
printf("TEST2.XX.1: Pausing the plugin\n");
|
||||||
g_SHImpl.PausePlugin(g_PLID);
|
g_SHImpl.PausePlugin(g_PLID);
|
||||||
printf("TEST2.XX.2: Calling F16(155)\n");
|
printf("TEST2.XX.2: Calling F16(155)\n");
|
||||||
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
||||||
printf("TEST2.XX.3: Calling F16(155) through CC\n");
|
printf("TEST2.XX.3: Calling F16(155) through CC\n");
|
||||||
printf("Returned: %d\n", cc->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", SH_CALL(cc, static_cast<bool(Test::*)(int)>(&Test::F16))(155) ? 1 : 0);
|
||||||
printf("TEST2.XX.4: Unpausing the plugin\n");
|
printf("TEST2.XX.4: Unpausing the plugin\n");
|
||||||
g_SHImpl.UnpausePlugin(g_PLID);
|
g_SHImpl.UnpausePlugin(g_PLID);
|
||||||
printf("TEST2.XX.5: Calling F16(155)\n");
|
printf("TEST2.XX.5: Calling F16(155)\n");
|
||||||
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
||||||
printf("TEST2.XX.6: Calling F16(155) through CC\n");
|
printf("TEST2.XX.6: Calling F16(155) through CC\n");
|
||||||
printf("Returned: %d\n", cc->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", SH_CALL(cc, static_cast<bool(Test::*)(int)>(&Test::F16))(155) ? 1 : 0);
|
||||||
printf("TEST2.9: Removing pre hook\n");
|
printf("TEST2.9: Removing pre hook\n");
|
||||||
SH_REMOVE_HOOK_STATICFUNC(Test, F16, zLOL_Ptr, Test_F16_int_pre_handler, false);
|
SH_REMOVE_HOOK_STATICFUNC(Test, F16, zLOL_Ptr, Test_F16_int_pre_handler, false);
|
||||||
printf("TEST2.10: Calling F16(155)\n");
|
printf("TEST2.10: Calling F16(155)\n");
|
||||||
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
||||||
printf("TEST2.11: Calling F16(155) through CC\n");
|
printf("TEST2.11: Calling F16(155) through CC\n");
|
||||||
printf("Returned: %d\n", cc->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", SH_CALL(cc, static_cast<bool(Test::*)(int)>(&Test::F16))(155) ? 1 : 0);
|
||||||
printf("TEST2.12: Removing post hook\n");
|
printf("TEST2.12: Removing post hook\n");
|
||||||
SH_REMOVE_HOOK_STATICFUNC(Test, F16, zLOL_Ptr, Test_F16_int_post_handler, true);
|
SH_REMOVE_HOOK_STATICFUNC(Test, F16, zLOL_Ptr, Test_F16_int_post_handler, true);
|
||||||
printf("TEST2.10: Calling F16(155)\n");
|
printf("TEST2.10: Calling F16(155)\n");
|
||||||
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", zLOL_Ptr->F16(155) ? 1 : 0);
|
||||||
printf("TEST2.11: Calling F16(155) through CC\n");
|
printf("TEST2.11: Calling F16(155) through CC\n");
|
||||||
printf("Returned: %d\n", cc->F16(155) ? 1 : 0);
|
printf("Returned: %d\n", SH_CALL(cc, static_cast<bool(Test::*)(int)>(&Test::F16))(155) ? 1 : 0);
|
||||||
|
|
||||||
SH_RELEASE_CALLCLASS(cc);
|
SH_RELEASE_CALLCLASS(cc);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user