sm-ext-dhooks2/vhook.h

376 lines
9.3 KiB
C
Raw Normal View History

2013-08-16 05:53:38 +02:00
#ifndef _INCLUDE_VHOOK_H_
#define _INCLUDE_VHOOK_H_
#include "extension.h"
#include <sourcehook.h>
2013-08-19 17:07:25 +02:00
#include <macro-assembler-x86.h>
enum MRESReturn
{
MRES_ChangedHandled = -2, // Use changed values and return MRES_Handled
MRES_ChangedOverride, // Use changed values and return MRES_Override
MRES_Ignored, // plugin didn't take any action
MRES_Handled, // plugin did something, but real function should still be called
MRES_Override, // call real function, but use my return value
MRES_Supercede // skip real function; use my return value
};
2013-08-16 05:53:38 +02:00
enum ObjectValueType
{
ObjectValueType_Int = 0,
ObjectValueType_Bool,
ObjectValueType_Ehandle,
ObjectValueType_Float,
ObjectValueType_CBaseEntityPtr,
ObjectValueType_IntPtr,
ObjectValueType_BoolPtr,
ObjectValueType_EhandlePtr,
ObjectValueType_FloatPtr,
ObjectValueType_Vector,
ObjectValueType_VectorPtr,
ObjectValueType_CharPtr,
ObjectValueType_String
};
2013-08-16 05:53:38 +02:00
enum HookParamType
{
HookParamType_Unknown,
HookParamType_Int,
HookParamType_Bool,
HookParamType_Float,
HookParamType_String,
HookParamType_StringPtr,
HookParamType_CharPtr,
HookParamType_VectorPtr,
HookParamType_CBaseEntity,
HookParamType_ObjectPtr,
2013-08-21 02:18:50 +02:00
HookParamType_Edict,
HookParamType_Object
2013-08-16 05:53:38 +02:00
};
2013-08-19 17:07:25 +02:00
2013-08-16 05:53:38 +02:00
enum ReturnType
{
ReturnType_Unknown,
ReturnType_Void,
ReturnType_Int,
ReturnType_Bool,
ReturnType_Float,
ReturnType_String,
ReturnType_StringPtr,
ReturnType_CharPtr,
ReturnType_Vector,
ReturnType_VectorPtr,
ReturnType_CBaseEntity,
ReturnType_Edict
};
2013-08-19 17:07:25 +02:00
enum ThisPointerType
{
ThisPointer_Ignore,
ThisPointer_CBaseEntity,
ThisPointer_Address
};
enum HookType
{
HookType_Entity,
HookType_GameRules,
HookType_Raw
};
struct ParamInfo
2013-08-16 05:53:38 +02:00
{
HookParamType type;
size_t size;
unsigned int flag;
2013-08-19 17:07:25 +02:00
SourceHook::PassInfo::PassType pass_type;
};
2013-08-20 04:33:44 +02:00
class HookReturnStruct
2013-08-19 17:07:25 +02:00
{
2013-08-20 04:33:44 +02:00
public:
~HookReturnStruct()
{
if(this->type != ReturnType_CharPtr && this->type != ReturnType_Vector && this->type != ReturnType_VectorPtr)
{
free(this->newResult);
}
else if(this->isChanged)
{
if(this->type == ReturnType_CharPtr)
{
delete *(char **)this->newResult;
}
else if(this->type == ReturnType_Vector || this->type == ReturnType_VectorPtr)
{
delete *(Vector **)this->newResult;
}
}
if(this->type == ReturnType_Vector || this->type == ReturnType_VectorPtr)
{
delete *(Vector **)this->orgResult;
}
else if(this->type != ReturnType_String && this->type != ReturnType_Int && this->type != ReturnType_Bool && this->type != ReturnType_Float)
{
free(*(void **)this->orgResult);
}
2013-08-21 04:21:29 +02:00
free(this->orgResult);
2013-08-20 04:33:44 +02:00
}
public:
2013-08-19 17:07:25 +02:00
ReturnType type;
bool isChanged;
void *orgResult;
void *newResult;
2013-08-16 05:53:38 +02:00
};
class DHooksInfo
{
public:
2013-08-19 17:07:25 +02:00
CUtlVector<ParamInfo> params;
2013-08-16 05:53:38 +02:00
int offset;
2013-08-19 17:07:25 +02:00
unsigned int returnFlag;
ReturnType returnType;
bool post;
IPluginFunction *plugin_callback;
int entity;
ThisPointerType thisType;
HookType hookType;
2013-08-16 05:53:38 +02:00
};
class DHooksCallback : public SourceHook::ISHDelegate, public DHooksInfo
{
public:
virtual bool IsEqual(ISHDelegate *pOtherDeleg){return false;};
2013-08-19 17:07:25 +02:00
virtual void DeleteThis()
{
*(void ***)this = this->oldvtable;
g_pSM->GetScriptingEngine()->FreePageMemory(this->newvtable[2]);
delete this->newvtable;
delete this;
};
virtual void Call() {};
public:
void **newvtable;
void **oldvtable;
2013-08-16 05:53:38 +02:00
};
2013-08-19 17:07:25 +02:00
#ifndef __linux__
void *Callback(DHooksCallback *dg, void **stack, size_t *argsizep);
float Callback_float(DHooksCallback *dg, void **stack, size_t *argsizep);
Vector *Callback_vector(DHooksCallback *dg, void **stack, size_t *argsizep);
2013-08-19 17:07:25 +02:00
#else
void *Callback(DHooksCallback *dg, void **stack);
float Callback_float(DHooksCallback *dg, void **stack);
2013-08-29 04:58:42 +02:00
Vector *Callback_vector(DHooksCallback *dg, void **stack);
2013-08-29 21:18:43 +02:00
string_t *Callback_stringt(DHooksCallback *dg, void **stack);
2013-08-19 17:07:25 +02:00
#endif
bool SetupHookManager(ISmmAPI *ismm);
void CleanupHooks(IPluginContext *pContext);
size_t GetParamTypeSize(HookParamType type);
SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type);
#ifdef __linux__
static void *GenerateThunk(ReturnType type)
{
MacroAssemblerX86 masm;
2013-08-29 04:58:42 +02:00
static const size_t kStackNeeded = (2) * 4; // 2 args max
static const size_t kReserve = ke::Align(kStackNeeded+8, 16)-8;
2013-08-19 17:07:25 +02:00
masm.push(ebp);
masm.movl(ebp, esp);
2013-08-29 04:58:42 +02:00
masm.subl(esp, kReserve);
2013-08-29 21:18:43 +02:00
if(type != ReturnType_String && type != ReturnType_Vector)
{
masm.lea(eax, Operand(ebp, 12)); // grab the incoming caller argument vector
masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
masm.movl(eax, Operand(ebp, 8)); // grab the |this|
masm.movl(Operand(esp, 0 * 4), eax); // set |this| as the 1st argument*/
}
else
{
masm.lea(eax, Operand(ebp, 8)); // grab the incoming caller argument vector
masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
masm.movl(eax, Operand(ebp, 12)); // grab the |this|
masm.movl(Operand(esp, 0 * 4), eax); // set |this| as the 1st argument*/
}
if(type == ReturnType_Float)
2013-08-29 04:58:42 +02:00
{
2013-08-19 17:07:25 +02:00
masm.call(ExternalAddress((void *)Callback_float));
2013-08-29 04:58:42 +02:00
}
else if(type == ReturnType_Vector)
{
masm.call(ExternalAddress((void *)Callback_vector));
}
2013-08-29 21:18:43 +02:00
else if(type == ReturnType_String)
{
masm.call(ExternalAddress((void *)Callback_stringt));
}
else
2013-08-29 04:58:42 +02:00
{
2013-08-19 17:07:25 +02:00
masm.call(ExternalAddress((void *)Callback));
2013-08-29 04:58:42 +02:00
}
masm.addl(esp, kReserve);
masm.pop(ebp); // restore ebp
2013-08-19 17:07:25 +02:00
masm.ret();
2013-08-29 04:58:42 +02:00
2013-08-19 17:07:25 +02:00
void *base = g_pSM->GetScriptingEngine()->AllocatePageMemory(masm.length());
masm.emitToExecutableMemory(base);
return base;
}
#else
// HUGE THANKS TO BAILOPAN (dvander)!
2013-08-19 17:07:25 +02:00
static void *GenerateThunk(ReturnType type)
{
MacroAssemblerX86 masm;
static const size_t kStackNeeded = (3 + 1) * 4; // 3 args max, 1 locals max
static const size_t kReserve = ke::Align(kStackNeeded+8, 16)-8;
2013-08-19 17:07:25 +02:00
masm.push(ebp);
masm.movl(ebp, esp);
masm.subl(esp, kReserve);
masm.lea(eax, Operand(esp, 3 * 4)); // ptr to 2nd var after argument space
masm.movl(Operand(esp, 2 * 4), eax); // set the ptr as the third argument
masm.lea(eax, Operand(ebp, 8)); // grab the incoming caller argument vector
masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
masm.movl(Operand(esp, 0 * 4), ecx); // set |this| as the 1st argument
if(type == ReturnType_Float)
{
masm.call(ExternalAddress(Callback_float));
}
else if(type == ReturnType_Vector)
{
masm.call(ExternalAddress(Callback_vector));
}
else
{
2013-08-19 17:07:25 +02:00
masm.call(ExternalAddress(Callback));
}
masm.movl(ecx, Operand(esp, 3*4));
masm.addl(esp, kReserve);
2013-08-19 17:07:25 +02:00
masm.pop(ebp); // restore ebp
masm.pop(edx); // grab return address in edx
masm.addl(esp, ecx); // remove arguments
masm.jmp(edx); // return to caller
void *base = g_pSM->GetScriptingEngine()->AllocatePageMemory(masm.length());
masm.emitToExecutableMemory(base);
return base;
}
#endif
static DHooksCallback *MakeHandler(ReturnType type)
{
DHooksCallback *dg = new DHooksCallback();
dg->returnType = type;
dg->oldvtable = *(void ***)dg;
dg->newvtable = new void *[3];
dg->newvtable[0] = dg->oldvtable[0];
dg->newvtable[1] = dg->oldvtable[1];
dg->newvtable[2] = GenerateThunk(type);
*(void ***)dg = dg->newvtable;
return dg;
}
class HookParamsStruct
2013-08-16 05:53:38 +02:00
{
public:
2013-08-19 17:07:25 +02:00
HookParamsStruct()
{
this->orgParams = NULL;
this->newParams = NULL;
this->dg = NULL;
2013-08-20 04:33:44 +02:00
this->isChanged = NULL;
2013-08-19 17:07:25 +02:00
}
~HookParamsStruct()
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
if(this->orgParams != NULL)
{
2013-08-20 04:33:44 +02:00
free(this->orgParams);
}
if(this->isChanged != NULL)
{
free(this->isChanged);
2013-08-19 17:07:25 +02:00
}
if(this->newParams != NULL)
{
2013-08-20 04:33:44 +02:00
for(int i = dg->params.Count() - 1; i >= 0 ; i--)
{
if(this->newParams[i] == NULL)
continue;
if(dg->params.Element(i).type == HookParamType_VectorPtr)
{
delete (Vector *)this->newParams[i];
}
else if(dg->params.Element(i).type == HookParamType_CharPtr)
{
delete (char *)this->newParams[i];
}
else if(dg->params.Element(i).type == HookParamType_Float)
{
delete (float *)this->newParams[i];
}
2013-08-20 04:33:44 +02:00
}
free(this->newParams);
2013-08-19 17:07:25 +02:00
}
}
public:
void **orgParams;
void **newParams;
2013-08-20 04:33:44 +02:00
bool *isChanged;
2013-08-19 17:07:25 +02:00
DHooksCallback *dg;
};
class HookSetup
{
public:
HookSetup(ReturnType returnType, unsigned int returnFlag, HookType hookType, ThisPointerType thisType, int offset, IPluginFunction *callback)
{
this->returnType = returnType;
this->returnFlag = returnFlag;
this->hookType = hookType;
this->thisType = thisType;
this->offset = offset;
this->callback = callback;
2013-08-16 05:53:38 +02:00
};
2013-08-19 17:07:25 +02:00
~HookSetup(){};
public:
unsigned int returnFlag;
ReturnType returnType;
HookType hookType;
ThisPointerType thisType;
CUtlVector<ParamInfo> params;
int offset;
IPluginFunction *callback;
};
class DHooksManager
{
public:
DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, bool post);
2013-08-16 05:53:38 +02:00
~DHooksManager()
{
2013-08-19 17:07:25 +02:00
if(this->hookid)
2013-08-16 05:53:38 +02:00
{
2013-08-19 17:07:25 +02:00
g_SHPtr->RemoveHookByID(this->hookid);
if(this->remove_callback)
{
this->remove_callback->PushCell(this->hookid);
this->remove_callback->Execute(NULL);
}
2013-08-16 05:53:38 +02:00
}
}
2013-08-19 17:07:25 +02:00
public:
intptr_t addr;
2013-08-16 05:53:38 +02:00
int hookid;
2013-08-19 17:07:25 +02:00
DHooksCallback *callback;
IPluginFunction *remove_callback;
2013-08-16 05:53:38 +02:00
};
2013-08-20 04:33:44 +02:00
size_t GetStackArgsSize(DHooksCallback *dg);
2013-08-16 05:53:38 +02:00
extern IBinTools *g_pBinTools;
2013-08-19 17:07:25 +02:00
extern HandleType_t g_HookParamsHandle;
extern HandleType_t g_HookReturnHandle;
2013-08-20 04:33:44 +02:00
#endif