From 2f38de616ecd3533f93ffae33d6c43f534666e87 Mon Sep 17 00:00:00 2001 From: Dr!fter Date: Mon, 19 Aug 2013 11:07:25 -0400 Subject: [PATCH] Update code add natives and listeners --- Makefile | 7 +- extension.cpp | 137 ++++++----- extension.h | 12 +- listeners.cpp | 61 +++++ listeners.h | 28 +++ msvc10/sdk.vcxproj | 9 +- msvc10/sdk.vcxproj.filters | 14 ++ natives.cpp | 252 ++++++++++++++++++++ natives.h | 12 + sdk/smsdk_config.h | 4 +- vhook.cpp | 455 +++++++++++++++++++++---------------- vhook.h | 215 ++++++++++++++++-- vhook_macros.h | 32 --- 13 files changed, 914 insertions(+), 324 deletions(-) create mode 100644 listeners.cpp create mode 100644 listeners.h create mode 100644 natives.cpp create mode 100644 natives.h diff --git a/Makefile b/Makefile index 8448b18..61e6105 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ ### EDIT THESE PATHS FOR YOUR OWN SETUP ### ########################################### -SMSDK = ../sourcemod-1.5 +SMSDK = ../sourcemod-central HL2SDK_ORIG = ../../../hl2sdk HL2SDK_OB = ../../../hl2sdk-ob HL2SDK_CSS = ../hl2sdk-css @@ -24,7 +24,7 @@ PROJECT = sample #Uncomment for Metamod: Source enabled extension USEMETA = true -OBJECTS = sdk/smsdk_ext.cpp extension.cpp vhook.cpp +OBJECTS = sdk/smsdk_ext.cpp extension.cpp vhook.cpp ../sourcemod-central/public/jit/x86/assembler-x86.cpp ############################################## ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### @@ -109,7 +109,7 @@ else LIB_SUFFIX = .$(LIB_EXT) endif -INCLUDE += -I. -I.. -Isdk -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions +INCLUDE += -I. -I.. -Isdk -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions -I$(SMSDK)/public/jit/x86 -I$(SMSDK)/public/jit ifeq "$(USEMETA)" "true" LINK_HL2 = $(HL2LIB)/tier1_i486.a $(HL2LIB)/$(LIB_PREFIX)vstdlib_srv$(LIB_SUFFIX) $(HL2LIB)/$(LIB_PREFIX)tier0_srv$(LIB_SUFFIX) @@ -205,6 +205,7 @@ $(BIN_DIR)/%.o: %.cpp all: check mkdir -p $(BIN_DIR)/sdk + mkdir -p $(BIN_DIR)/../sourcemod-central/public/jit/x86 if [ "$(USEMETA)" = "true" ]; then \ ln -sf $(HL2LIB)/$(LIB_PREFIX)vstdlib$(LIB_SUFFIX); \ ln -sf $(HL2LIB)/$(LIB_PREFIX)tier0$(LIB_SUFFIX); \ diff --git a/extension.cpp b/extension.cpp index 9be536b..f3d6a7c 100644 --- a/extension.cpp +++ b/extension.cpp @@ -1,41 +1,101 @@ #include "extension.h" #include "vhook.h" +#include "listeners.h" +#include -DHooks g_Sample; /**< Global singleton for extension's main interface */ -SMEXT_LINK(&g_Sample); +DHooks g_DHooksIface; /**< Global singleton for extension's main interface */ +SMEXT_LINK(&g_DHooksIface); IBinTools *g_pBinTools; ISDKHooks *g_pSDKHooks; ISDKTools *g_pSDKTools; +DHooksEntityListener *g_pEntityListener = NULL; -CBitVec m_EntityExists; +bool g_bAllowGamerules = true; + +HandleType_t g_HookSetupHandle = 0; +HandleType_t g_HookParamsHandle = 0; +HandleType_t g_HookReturnHandle = 0; bool DHooks::SDK_OnLoad(char *error, size_t maxlength, bool late) { + HandleError err; + g_HookSetupHandle = handlesys->CreateType("HookSetup", this, 0, NULL, NULL, myself->GetIdentity(), &err); + if(g_HookSetupHandle == 0) + { + snprintf(error, maxlength, "Could not create hook setup handle type (err: %d)", err); + return false; + } + g_HookParamsHandle = handlesys->CreateType("HookParams", this, 0, NULL, NULL, myself->GetIdentity(), &err); + if(g_HookParamsHandle == 0) + { + snprintf(error, maxlength, "Could not create hook params handle type (err: %d)", err); + return false; + } + g_HookReturnHandle = handlesys->CreateType("HookReturn", this, 0, NULL, NULL, myself->GetIdentity(), &err); + if(g_HookReturnHandle == 0) + { + snprintf(error, maxlength, "Could not create hook return handle type (err: %d)", err); + return false; + } + sharesys->AddDependency(myself, "bintools.ext", true, true); sharesys->AddDependency(myself, "sdktools.ext", true, true); sharesys->AddDependency(myself, "sdkhooks.ext", true, true); sharesys->RegisterLibrary(myself, "dhooks"); + plsys->AddPluginsListener(this); + sharesys->AddNatives(myself, g_Natives); return true; } + +void DHooks::OnHandleDestroy(HandleType_t type, void *object) +{ + if(type == g_HookSetupHandle) + { + delete (HookSetup *)object; + } + else if(type == g_HookParamsHandle) + { + delete (HookParamsStruct *)object; + } + else if(type == g_HookReturnHandle) + { + delete (HookReturnStruct *)object; + } +} + void DHooks::SDK_OnAllLoaded() { SM_GET_LATE_IFACE(SDKTOOLS, g_pSDKTools); - if(g_pSDKTools == NULL) - { - smutils->LogError(myself, "SDKTools interface not found. DHookGamerules native disabled."); - } - else if(g_pSDKTools->GetInterfaceVersion() < 2) + + if(g_pSDKTools->GetInterfaceVersion() < 2) { // THIS ISN'T DA LIMBO STICK. LOW IS BAD + g_bAllowGamerules = false; smutils->LogError(myself, "SDKTools interface is outdated. DHookGamerules native disabled."); } + SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools); SM_GET_LATE_IFACE(SDKHOOKS, g_pSDKHooks); - g_pSDKHooks->AddEntityListener(this); + + g_pEntityListener = new DHooksEntityListener(); + g_pSDKHooks->AddEntityListener(g_pEntityListener); } + +void DHooks::SDK_OnUnload() +{ + CleanupHooks(NULL); + if(g_pEntityListener) + { + g_pEntityListener->CleanupListeners(NULL); + g_pSDKHooks->RemoveEntityListener(g_pEntityListener); + delete g_pEntityListener; + } + plsys->RemovePluginsListener(this); +} + bool DHooks::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late) { if(!SetupHookManager(ismm)) @@ -45,61 +105,12 @@ bool DHooks::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, boo } return true; } -DHooksManager *manager1; -DHooksManager *manager2; -#ifndef __linux__ -#define WEAPON_CANUSE 258 -#define SET_MODEL 24 -#else -#define WEAPON_CANUSE 259 -#define SET_MODEL 25 -#endif - -void DHooks::OnEntityCreated(CBaseEntity *pEntity, const char *classname) +void DHooks::OnPluginUnloaded(IPlugin *plugin) { - int entity = gamehelpers->ReferenceToIndex(gamehelpers->EntityToBCompatRef(pEntity)); - - if(entity <= playerhelpers->GetMaxClients() && entity > 0) - { - SourceHook::HookManagerPubFunc hook; - SourceHook::CProtoInfoBuilder protoInfo(SourceHook::ProtoInfo::CallConv_ThisCall); - protoInfo.AddParam(sizeof(CBaseEntity *), SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal, NULL, NULL, NULL, NULL); - protoInfo.SetReturnType(sizeof(bool), SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal, NULL, NULL, NULL, NULL); - hook = g_pHookManager->MakeHookMan(protoInfo, 0, WEAPON_CANUSE); - manager1 = new DHooksManager(); - manager1->callback_bool = new DHooksCallback(); - manager1->callback_bool->paramcount = 1; - manager1->callback_bool->params[0].size = sizeof(CBaseEntity *); - manager1->callback_bool->params[0].type = HookParamType_CBaseEntity; - manager1->callback_bool->params[0].flag = PASSFLAG_BYVAL; - manager1->callback_bool->offset = WEAPON_CANUSE; - manager1->hookid = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, pEntity, 0, hook, manager1->callback_bool, false); - - SourceHook::CProtoInfoBuilder protoInfo2(SourceHook::ProtoInfo::CallConv_ThisCall); - protoInfo2.AddParam(sizeof(char *), SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal, NULL, NULL, NULL, NULL); - protoInfo2.SetReturnType(0, SourceHook::PassInfo::PassType_Unknown, 0, NULL, NULL, NULL, NULL); - hook = g_pHookManager->MakeHookMan(protoInfo2, 0, SET_MODEL); - manager2 = new DHooksManager(); - manager2->callback_void = new DHooksCallback(); - manager2->callback_void->paramcount = 1; - manager2->callback_void->params[0].size = sizeof(char *); - manager2->callback_void->params[0].type = HookParamType_CharPtr; - manager2->callback_void->params[0].flag = PASSFLAG_BYVAL; - manager2->callback_void->offset = SET_MODEL; - manager2->hookid = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, pEntity, 0, hook, manager2->callback_void, false); - - META_CONPRINTF("Hooked entity %i\n", entity); + CleanupHooks(plugin->GetBaseContext()); + if(g_pEntityListener) + { + g_pEntityListener->CleanupListeners(plugin->GetBaseContext()); } } -void DHooks::OnEntityDestroyed(CBaseEntity *pEntity) -{ - int entity = gamehelpers->ReferenceToIndex(gamehelpers->EntityToBCompatRef(pEntity)); - - if(entity <= playerhelpers->GetMaxClients() && entity > 0) - { - META_CONPRINTF("Cleaning\n"); - delete manager1; - delete manager2; - } -} \ No newline at end of file diff --git a/extension.h b/extension.h index 56ed646..4f7936a 100644 --- a/extension.h +++ b/extension.h @@ -48,12 +48,13 @@ * Note: Uncomment one of the pre-defined virtual functions in order to use it. */ -class DHooks : public SDKExtension, public ISMEntityListener +class DHooks : public SDKExtension, public ISMEntityListener, public IPluginsListener, public IHandleTypeDispatch { public: - void OnEntityCreated(CBaseEntity *pEntity, const char *classname); - void OnEntityDestroyed(CBaseEntity *pEntity); - + void OnHandleDestroy(HandleType_t type, void *object); +public: //IPluginsListener + void OnPluginUnloaded(IPlugin *plugin); +public: /** * @brief This is called after the initial loading sequence has been processed. * @@ -67,7 +68,7 @@ public: /** * @brief This is called right before the extension is unloaded. */ - //virtual void SDK_OnUnload(); + virtual void SDK_OnUnload(); /** * @brief This is called once all known extensions have been loaded. @@ -123,4 +124,5 @@ public: #endif }; extern SourceHook::IHookManagerAutoGen *g_pHookManager; +extern sp_nativeinfo_t g_Natives[]; #endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/listeners.cpp b/listeners.cpp new file mode 100644 index 0000000..0d08f07 --- /dev/null +++ b/listeners.cpp @@ -0,0 +1,61 @@ +#include "listeners.h" +#include "vhook.h" + +using namespace SourceHook; + +CUtlVector g_EntityListeners; + +void DHooksEntityListener::CleanupListeners(IPluginContext *pContext) +{ + for(int i = g_EntityListeners.Count() -1; i >= 0; i--) + { + if(pContext == NULL || pContext == g_EntityListeners.Element(i).callback->GetParentContext()) + { + g_EntityListeners.Remove(i); + } + } +} + +void DHooksEntityListener::OnEntityCreated(CBaseEntity *pEntity, const char *classname) +{ + int entity = gamehelpers->EntityToBCompatRef(pEntity); + + for(int i = g_EntityListeners.Count() -1; i >= 0; i--) + { + EntityListener listerner = g_EntityListeners.Element(i); + if(listerner.type == ListenType_Created) + { + IPluginFunction *callback = listerner.callback; + callback->PushCell(entity); + callback->PushString(classname); + callback->Execute(NULL); + } + } +} + +void DHooksEntityListener::OnEntityDestroyed(CBaseEntity *pEntity) +{ + int entity = gamehelpers->EntityToBCompatRef(pEntity); + + for(int i = g_EntityListeners.Count() -1; i >= 0; i--) + { + EntityListener listerner = g_EntityListeners.Element(i); + if(listerner.type == ListenType_Deleted) + { + IPluginFunction *callback = listerner.callback; + callback->PushCell(gamehelpers->EntityToBCompatRef(pEntity)); + callback->Execute(NULL); + } + } + + for(int i = g_pHooks.Count() -1; i >= 0; i--) + { + DHooksManager *manager = g_pHooks.Element(i); + if(manager->callback->entity == entity) + { + META_CONPRINT("Removing 1\n"); + delete manager; + g_pHooks.Remove(i); + } + } +} \ No newline at end of file diff --git a/listeners.h b/listeners.h new file mode 100644 index 0000000..23c3d94 --- /dev/null +++ b/listeners.h @@ -0,0 +1,28 @@ +#ifndef _INCLUDE_FORWARDS_H_ +#define _INCLUDE_FORWARDS_H_ + +#include "extension.h" +#include "vhook.h" + +class DHooksEntityListener : public ISMEntityListener +{ +public: + void OnEntityCreated(CBaseEntity *pEntity, const char *classname); + void OnEntityDestroyed(CBaseEntity *pEntity); + void CleanupListeners(IPluginContext *func); +}; + +enum ListenType +{ + ListenType_Created, + ListenType_Deleted +}; + +struct EntityListener +{ + ListenType type; + IPluginFunction *callback; +}; + +extern CUtlVector g_pHooks; +#endif diff --git a/msvc10/sdk.vcxproj b/msvc10/sdk.vcxproj index e21cdee..1ca0be9 100644 --- a/msvc10/sdk.vcxproj +++ b/msvc10/sdk.vcxproj @@ -599,7 +599,7 @@ /MP /D SE_EPISODEONE=1 /D SE_DARKMESSIAH=2 /D SE_ORANGEBOX=3 /D SE_BLOODYGOODTIME=4 /D SE_EYE=5 /D SE_ORANGEBOXVALVE=6 /D SE_LEFT4DEAD=7 /D SE_LEFT4DEAD2=8 /D SE_ALIENSWARM=9 /D SE_PORTAL2=10 /D SE_CSGO=11 %(AdditionalOptions) Speed - ..;..\sdk;$(HL2SDKOBVALVE)\public;$(HL2SDKOBVALVE)\public\engine;$(HL2SDKOBVALVE)\public\game\server;$(HL2SDKOBVALVE)\public\tier0;$(HL2SDKOBVALVE)\public\tier1;$(MMSOURCE19)\core;$(MMSOURCE19)\core\sourcehook;$(SOURCEMOD)\public;$(SOURCEMOD)\public\sourcepawn;$(SOURCEMOD)\public\extensions;$(HL2SDKOBVALVE)\game\server;$(HL2SDKOBVALVE)\game\shared;%(AdditionalIncludeDirectories) + ..;..\sdk;$(HL2SDKOBVALVE)\public;$(HL2SDKOBVALVE)\public\engine;$(HL2SDKOBVALVE)\public\game\server;$(HL2SDKOBVALVE)\public\tier0;$(HL2SDKOBVALVE)\public\tier1;$(MMSOURCE19)\core;$(MMSOURCE19)\core\sourcehook;$(SMCENTRAL)\public;$(SMCENTRAL)\public\sourcepawn;$(SMCENTRAL)\public\extensions;$(HL2SDKOBVALVE)\game\server;$(HL2SDKOBVALVE)\game\shared;$(SMCENTRAL)\public\jit;$(SMCENTRAL)\public\jit\x86;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SOURCEMOD_BUILD;SOURCE_ENGINE=6;%(PreprocessorDefinitions) MultiThreaded NotSet @@ -610,7 +610,7 @@ $(HL2SDKOBVALVE)\lib\public\tier0.lib;$(HL2SDKOBVALVE)\lib\public\tier1.lib;$(HL2SDKOBVALVE)\lib\public\vstdlib.lib;%(AdditionalDependencies) - $(OutDir)sample.ext.2.css.dll + $(OutDir)dhooks.ext.2.css.dll LIBC;LIBCD;LIBCMTD;%(IgnoreSpecificDefaultLibraries) true Windows @@ -882,12 +882,17 @@ + + + + + diff --git a/msvc10/sdk.vcxproj.filters b/msvc10/sdk.vcxproj.filters index f7a116b..76a653c 100644 --- a/msvc10/sdk.vcxproj.filters +++ b/msvc10/sdk.vcxproj.filters @@ -6,6 +6,11 @@ + + JIT + + + @@ -23,6 +28,12 @@ Headers + + Headers + + + Headers + @@ -31,5 +42,8 @@ {8a0b4570-752f-44d9-b270-ef886743e9ea} + + {9ac7d92a-8a9d-4e7c-b108-09d915244278} + \ No newline at end of file diff --git a/natives.cpp b/natives.cpp new file mode 100644 index 0000000..7e9312f --- /dev/null +++ b/natives.cpp @@ -0,0 +1,252 @@ +#include "natives.h" + +CBaseEntity *UTIL_GetCBaseEntity(int num) +{ + edict_t *pEdict = gamehelpers->EdictOfIndex(num); + if (!pEdict || pEdict->IsFree()) + { + return NULL; + } + IServerUnknown *pUnk; + if ((pUnk=pEdict->GetUnknown()) == NULL) + { + return NULL; + } + + return pUnk->GetBaseEntity(); +} + +//native Handle:DHookCreate(offset, HookType:hooktype, ReturnType:returntype, ThisPointerType:thistype, DHookCallback:callback); +cell_t Native_CreateHook(IPluginContext *pContext, const cell_t *params) +{ + if(!pContext->GetFunctionById(params[5])) + { + return pContext->ThrowNativeError("Failed to retrieve function by id"); + } + + HookSetup *setup = new HookSetup((ReturnType)params[3], PASSFLAG_BYVAL,(HookType)params[2], (ThisPointerType)params[4], params[1], pContext->GetFunctionById(params[5])); + + Handle_t hndl = handlesys->CreateHandle(g_HookSetupHandle, setup, pContext->GetIdentity(), myself->GetIdentity(), NULL); + + if(!hndl) + { + delete setup; + return pContext->ThrowNativeError("Failed to create hook"); + } + + return hndl; +} +//native bool:DHookAddParam(Handle:setup, HookParamType:type); +cell_t Native_AddParam(IPluginContext *pContext, const cell_t *params) +{ + if(params[1] == BAD_HANDLE) + { + return pContext->ThrowNativeError("Invalid Handle %i", BAD_HANDLE); + } + + HandleError err; + HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); + HookSetup *setup; + + if((err = handlesys->ReadHandle(params[1], g_HookSetupHandle, &sec, (void **)&setup)) != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err); + } + ParamInfo info; + + if(params[0] == 3) + { + info.flag = params[3]; + } + else + { + info.flag = PASSFLAG_BYVAL; + } + + info.type = (HookParamType)params[2]; + info.size = GetParamTypeSize(info.type); + info.pass_type = GetParamTypePassType(info.type); + setup->params.AddToTail(info); + + return 1; +} +cell_t Native_HookEntity(IPluginContext *pContext, const cell_t *params) +{ + if(params[1] == BAD_HANDLE) + { + return pContext->ThrowNativeError("Invalid Handle %i", BAD_HANDLE); + } + + HandleError err; + HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); + HookSetup *setup; + + if((err = handlesys->ReadHandle(params[1], g_HookSetupHandle, &sec, (void **)&setup)) != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err); + } + if(setup->hookType != HookType_Entity) + { + return pContext->ThrowNativeError("Hook is not an entity hook"); + } + bool post = params[2] != 0; + + for(int i = g_pHooks.Count() -1; i >= 0; i--) + { + if(g_pHooks.Element(i)->callback->hookType == HookType_Entity && g_pHooks.Element(i)->callback->entity == params[3] && g_pHooks.Element(i)->callback->offset == setup->offset && g_pHooks.Element(i)->callback->post == post && g_pHooks.Element(i)->remove_callback == pContext->GetFunctionById(params[4]) && g_pHooks.Element(i)->callback->plugin_callback == setup->callback) + { + return g_pHooks.Element(i)->hookid; + } + } + CBaseEntity *pEnt = UTIL_GetCBaseEntity(params[3]); + + if(!pEnt) + { + return pContext->ThrowNativeError("Invalid entity passed %i", params[2]); + } + + DHooksManager *manager = new DHooksManager(setup, pEnt, pContext->GetFunctionById(params[4]), post); + + if(!manager->hookid) + { + delete manager; + return 0; + } + + g_pHooks.AddToTail(manager); + + return manager->hookid; +} +/*cell_t Native_HookGamerules(IPluginContext *pContext, const cell_t *params); +cell_t Native_RemoveHookID(IPluginContext *pContext, const cell_t *params);*/ +cell_t Native_GetParam(IPluginContext *pContext, const cell_t *params) +{ + if(params[1] == BAD_HANDLE) + { + return pContext->ThrowNativeError("Invalid Handle %i", BAD_HANDLE); + } + + HandleError err; + HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); + HookParamsStruct *paramStruct; + if((err = handlesys->ReadHandle(params[1], g_HookParamsHandle, &sec, (void **)¶mStruct)) != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err); + } + + if(params[2] > paramStruct->dg->params.Count() || params[2] < 0) + { + return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.Count()); + } + if(params[2] == 0) + { + return paramStruct->dg->params.Count(); + } + + int index = params[2] - 1; + + if(paramStruct->orgParams[index] == NULL && (paramStruct->dg->params.Element(index).type == HookParamType_CBaseEntity || paramStruct->dg->params.Element(index).type == HookParamType_Edict)) + { + return pContext->ThrowNativeError("Trying to get value for null pointer."); + } + + switch(paramStruct->dg->params.Element(index).type) + { + case HookParamType_Int: + return (int)paramStruct->orgParams[index]; + case HookParamType_Bool: + return (cell_t)paramStruct->orgParams[index] != 0; + case HookParamType_CBaseEntity: + return gamehelpers->EntityToBCompatRef((CBaseEntity *)paramStruct->orgParams[index]); + case HookParamType_Edict: + return gamehelpers->IndexOfEdict((edict_t *)paramStruct->orgParams[index]); + case HookParamType_Float: + return sp_ftoc(*(float *)paramStruct->orgParams[index]); + default: + return pContext->ThrowNativeError("Invalid param type (%i) to get", paramStruct->dg->params.Element(index).type); + } + + return 1; +} +cell_t Native_GetReturn(IPluginContext *pContext, const cell_t *params) +{ + return 1; +} +cell_t Native_SetReturn(IPluginContext *pContext, const cell_t *params) +{ + return 1; +} +/*cell_t Native_SetParam(IPluginContext *pContext, const cell_t *params); +cell_t Native_GetParamVector(IPluginContext *pContext, const cell_t *params); +cell_t Native_GetReturnVector(IPluginContext *pContext, const cell_t *params); +cell_t Native_SetReturnVector(IPluginContext *pContext, const cell_t *params); +cell_t Native_SetParamVector(IPluginContext *pContext, const cell_t *params);*/ +cell_t Native_GetParamString(IPluginContext *pContext, const cell_t *params) +{ + if(params[1] == BAD_HANDLE) + { + return pContext->ThrowNativeError("Invalid Handle %i", BAD_HANDLE); + } + + HandleError err; + HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); + HookParamsStruct *paramStruct; + if((err = handlesys->ReadHandle(params[1], g_HookParamsHandle, &sec, (void **)¶mStruct)) != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err); + } + + if(params[2] > paramStruct->dg->params.Count() || params[2] <= 0) + { + return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.Count()); + } + int index = params[2] - 1; + + if(paramStruct->orgParams[index] == NULL) + { + return pContext->ThrowNativeError("Trying to get value for null pointer."); + } + + if(paramStruct->dg->params.Element(index).type == HookParamType_CharPtr) + { + pContext->StringToLocal(params[3], params[4], (const char *)paramStruct->orgParams[index]); + } + + return 1; +} +//cell_t Native_GetReturnString(IPluginContext *pContext, const cell_t *params); +//cell_t Native_SetReturnString(IPluginContext *pContext, const cell_t *params); +cell_t Native_SetParamString(IPluginContext *pContext, const cell_t *params) +{ + return 1; +} + +sp_nativeinfo_t g_Natives[] = +{ + {"DHookCreate", Native_CreateHook}, + {"DHookAddParam", Native_AddParam}, + {"DHookEntity", Native_HookEntity}, + /*{"DHookGamerules", Native_HookGamerules}, + {"DHookRaw", Native_HookRaw}, + {"DHookRemoveHookID", Native_RemoveHookID},*/ + {"DHookGetParam", Native_GetParam}, + {"DHookGetReturn", Native_GetReturn}, + {"DHookSetReturn", Native_SetReturn}, + /*{"DHookSetParam", Native_SetParam}, + {"DHookGetParamVector", Native_GetParamVector}, + {"DHookGetReturnVector", Native_GetReturnVector}, + {"DHookSetReturnVector", Native_SetReturnVector}, + {"DHookSetParamVector", Native_SetParamVector},*/ + {"DHookGetParamString", Native_GetParamString}, + //{"DHookGetReturnString", Native_GetReturnString}, + //{"DHookSetReturnString", Native_SetReturnString}, + {"DHookSetParamString", Native_SetParamString}, + /*{"DHookAddEntityListener", Native_AddEntityListener}, + {"DHookRemoveEntityListener", Native_RemoveEntityListener}, + {"DHookGetParamObjectPtrVar", Native_GetParamObjectPtrVar}, + {"DHookSetParamObjectPtrVar", Native_SetParamObjectPtrVar}, + {"DHookGetParamObjectPtrVarVector", Native_GetParamObjectPtrVarVector}, + {"DHookSetParamObjectPtrVarVector", Native_SetParamObjectPtrVarVector}, + {"DHookIsNullParam", Native_IsNullParam},*/ + {NULL, NULL} +}; \ No newline at end of file diff --git a/natives.h b/natives.h new file mode 100644 index 0000000..8213630 --- /dev/null +++ b/natives.h @@ -0,0 +1,12 @@ +#ifndef _INCLUDE_NATIVES_H_ +#define _INCLUDE_NATIVES_H_ + +#include "extension.h" +#include "vhook.h" + +extern bool g_bAllowGamerules; +extern HandleType_t g_HookSetupHandle; +extern HandleType_t g_HookParamsHandle; +extern HandleType_t g_HookReturnHandle; +extern CUtlVector g_pHooks; +#endif diff --git a/sdk/smsdk_config.h b/sdk/smsdk_config.h index dd2419f..42e1e4a 100644 --- a/sdk/smsdk_config.h +++ b/sdk/smsdk_config.h @@ -60,7 +60,7 @@ /** Enable interfaces you want to use here by uncommenting lines */ //#define SMEXT_ENABLE_FORWARDSYS -//#define SMEXT_ENABLE_HANDLESYS +#define SMEXT_ENABLE_HANDLESYS #define SMEXT_ENABLE_PLAYERHELPERS //#define SMEXT_ENABLE_DBMANAGER #define SMEXT_ENABLE_GAMECONF @@ -71,7 +71,7 @@ //#define SMEXT_ENABLE_LIBSYS //#define SMEXT_ENABLE_MENUS //#define SMEXT_ENABLE_ADTFACTORY -//#define SMEXT_ENABLE_PLUGINSYS +#define SMEXT_ENABLE_PLUGINSYS //#define SMEXT_ENABLE_ADMINSYS //#define SMEXT_ENABLE_TEXTPARSERS //#define SMEXT_ENABLE_USERMSGS diff --git a/vhook.cpp b/vhook.cpp index 8336b3a..1c4a91c 100644 --- a/vhook.cpp +++ b/vhook.cpp @@ -1,8 +1,71 @@ #include "vhook.h" -#include "vhook_macros.h" SourceHook::IHookManagerAutoGen *g_pHookManager = NULL; +CUtlVector g_pHooks; + +using namespace SourceHook; + +DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, bool post) +{ + this->callback = MakeHandler(setup->returnType); + this->hookid = 0; + this->remove_callback = remove_callback; + this->callback->offset = setup->offset; + this->callback->plugin_callback = setup->callback; + this->callback->returnFlag = setup->returnFlag; + this->callback->thisType = setup->thisType; + this->callback->post = post; + this->callback->hookType = setup->hookType; + this->callback->params = setup->params; + + if(this->callback->hookType == HookType_Entity) + { + this->callback->entity = gamehelpers->EntityToBCompatRef((CBaseEntity *)iface); + } + else + { + this->callback->entity = -1; + } + + CProtoInfoBuilder protoInfo(ProtoInfo::CallConv_ThisCall); + + for(int i = this->callback->params.Count() -1; i >= 0; i--) + { + protoInfo.AddParam(this->callback->params.Element(i).size, this->callback->params.Element(i).pass_type, this->callback->params.Element(i).flag, NULL, NULL, NULL, NULL); + } + + if(this->callback->returnType == ReturnType_Void) + { + protoInfo.SetReturnType(0, SourceHook::PassInfo::PassType_Unknown, 0, NULL, NULL, NULL, NULL); + } + else if(this->callback->returnType == ReturnType_Float) + { + protoInfo.SetReturnType(sizeof(float), SourceHook::PassInfo::PassType_Float, 0, NULL, NULL, NULL, NULL); + } + else + { + protoInfo.SetReturnType(sizeof(void *), SourceHook::PassInfo::PassType_Basic, 0, NULL, NULL, NULL, NULL); + } + HookManagerPubFunc hook = g_pHookManager->MakeHookMan(protoInfo, 0, this->callback->offset); + + this->hookid = g_SHPtr->AddHook(g_PLID,ISourceHook::Hook_Normal, iface, 0, hook, this->callback, this->callback->post); +} + +void CleanupHooks(IPluginContext *pContext) +{ + for(int i = g_pHooks.Count() -1; i >= 0; i--) + { + DHooksManager *manager = g_pHooks.Element(i); + + if(pContext == NULL || pContext == manager->callback->plugin_callback->GetParentContext()) + { + delete manager; + g_pHooks.Remove(i); + } + } +} + bool SetupHookManager(ISmmAPI *ismm) { g_pHookManager = static_cast(ismm->MetaFactory(MMIFACE_SH_HOOKMANAUTOGEN, NULL, NULL)); @@ -10,210 +73,208 @@ bool SetupHookManager(ISmmAPI *ismm) return g_pHookManager != NULL; } -void CallFunction_Void(DHooksCallback *info, unsigned long stack, void *iface) +size_t GetParamTypeSize(HookParamType type) { - PassInfo *paramInfo = NULL; - ICallWrapper *call; - size_t size = 0; - - if(info->paramcount > 0) + return sizeof(void *); +} +SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type) +{ + switch(type) { - paramInfo = (PassInfo *)malloc(sizeof(PassInfo) * info->paramcount); - for(int i = 0; i < info->paramcount; i++) + case HookParamType_Float: + return SourceHook::PassInfo::PassType::PassType_Float; + default: + return SourceHook::PassInfo::PassType::PassType_Basic; + } +} +size_t GetStackArgsSize(DHooksCallback *dg) +{ + size_t res = 0; + for(int i = dg->params.Count() - 1; i >= 0; i--) + { + res += dg->params.Element(i).size; + } + return res; +} +HookParamsStruct *GetParamStruct(DHooksCallback *dg, void **argStack, size_t argStackSize) +{ + HookParamsStruct *res = new HookParamsStruct(); + res->dg = dg; + res->orgParams = (void **)malloc(argStackSize); + res->newParams = (void **)malloc(argStackSize); + memcpy(res->orgParams, argStack, argStackSize); + for(int i = 0; i < dg->params.Count(); i++) + { + res->newParams[i] = NULL; + } + return res; +} +HookReturnStruct *GetReturnStruct(DHooksCallback *dg, const void *result) +{ + HookReturnStruct *res = new HookReturnStruct(); + res->isChanged = false; + res->type = dg->returnType; + res->orgResult = &result; + res->newResult = 0; + + return res; +} +cell_t GetThisPtr(void *iface, ThisPointerType type) +{ + if(ThisPointer_CBaseEntity) + { + return gamehelpers->EntityToBCompatRef((CBaseEntity *)iface); + } + + return (cell_t)iface; +} +#ifndef __linux__ +void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep) +{ + HookReturnStruct *returnStruct = NULL; + HookParamsStruct *paramStruct = NULL; + Handle_t rHndl; + Handle_t pHndl; + + *argsizep = GetStackArgsSize(dg); + + if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) + { + dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType)); + } + if(dg->returnType != ReturnType_Void) + { + returnStruct = GetReturnStruct(dg, g_SHPtr->GetOrigRet()); + rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL); + if(!rHndl) { - switch(info->params[i].type) + if(returnStruct) { - PARAMINFO_SWITCH_CASE(int, HookParamType_Int ,PassType_Basic); - PARAMINFO_SWITCH_CASE(bool, HookParamType_Bool ,PassType_Basic); - PARAMINFO_SWITCH_CASE(float, HookParamType_Float ,PassType_Float); - PARAMINFO_SWITCH_CASE(string_t, HookParamType_String ,PassType_Object); - PARAMINFO_SWITCH_CASE(string_t *, HookParamType_StringPtr ,PassType_Basic); - PARAMINFO_SWITCH_CASE(char *, HookParamType_CharPtr ,PassType_Basic); - PARAMINFO_SWITCH_CASE(Vector *, HookParamType_VectorPtr ,PassType_Basic); - PARAMINFO_SWITCH_CASE(CBaseEntity *, HookParamType_CBaseEntity ,PassType_Basic); - PARAMINFO_SWITCH_CASE(edict_t *, HookParamType_Edict ,PassType_Basic); - default: - paramInfo[i].flags = info->params[i].flag; - paramInfo[i].size = sizeof(void *); - paramInfo[i].type = PassType_Basic; - size += sizeof(void *); - break; + delete returnStruct; } + g_SHPtr->SetRes(MRES_IGNORED); + return 0; } - call = g_pBinTools->CreateVCall(info->offset, 0, 0, NULL, paramInfo, info->paramcount); + dg->plugin_callback->PushCell(rHndl); + } + if(*argsizep > 0) + { + paramStruct = GetParamStruct(dg, argStack, *argsizep); + pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL); + if(!pHndl) + { + if(returnStruct) + { + delete returnStruct; + } + if(paramStruct) + { + delete paramStruct; + } + g_SHPtr->SetRes(MRES_IGNORED); + return 0; + } + dg->plugin_callback->PushCell(pHndl); + } + cell_t result = (cell_t)MRES_Ignored; + dg->plugin_callback->Execute(&result); + + void *ret = g_SHPtr->GetOverrideRetPtr(); + void *res = 0; + + switch((MRESReturn)result) + { + case MRES_Handled: + case MRES_ChangedHandled: + g_SHPtr->DoRecall(); + g_SHPtr->SetRes(MRES_SUPERCEDE); + //ret = CallVFunction(dg, argStack, g_SHPtr->GetIfacePtr()); + memcpy(res, ret, sizeof(void *)); + break; + case MRES_ChangedOverride: + g_SHPtr->DoRecall(); + g_SHPtr->SetRes(MRES_SUPERCEDE); + //CallVFunction(dg, argStack, g_SHPtr->GetIfacePtr()); + if(dg->returnType != ReturnType_Void) + { + if(returnStruct->isChanged) + { + memcpy(ret, returnStruct->newResult, sizeof(void *)); + memcpy(res, returnStruct->newResult, sizeof(void *)); + } + else if(dg->post) + { + memcpy(ret, returnStruct->orgResult, sizeof(void *)); + memcpy(res, returnStruct->orgResult, sizeof(void *)); + } + } + break; + case MRES_Override: + g_SHPtr->SetRes(MRES_OVERRIDE); + if(dg->returnType != ReturnType_Void) + { + if(returnStruct->isChanged) + { + memcpy(ret, returnStruct->newResult, sizeof(void *)); + memcpy(res, returnStruct->newResult, sizeof(void *)); + } + else if(dg->post) + { + memcpy(ret, returnStruct->orgResult, sizeof(void *)); + memcpy(res, returnStruct->orgResult, sizeof(void *)); + } + } + break; + case MRES_Supercede: + g_SHPtr->SetRes(MRES_SUPERCEDE); + if(dg->returnType != ReturnType_Void) + { + if(returnStruct->isChanged) + { + memcpy(ret, returnStruct->newResult, sizeof(void *)); + memcpy(res, returnStruct->newResult, sizeof(void *)); + } + else if(dg->post) + { + memcpy(ret, returnStruct->orgResult, sizeof(void *)); + memcpy(res, returnStruct->orgResult, sizeof(void *)); + } + } + break; + default: + g_SHPtr->SetRes(MRES_IGNORED); + break; + } + + HandleSecurity sec(dg->plugin_callback->GetParentContext()->GetIdentity(), myself->GetIdentity()); + + if(returnStruct) + { + handlesys->FreeHandle(rHndl, &sec); + } + if(paramStruct) + { + handlesys->FreeHandle(pHndl, &sec); + } + + return res; +} +#else +void *Callback(DHooksCallback *dg, void **argStack) +{ + if(dg->returnType == ReturnType_Void) + { + META_CONPRINTF("String is %s\n", argStack[0]); + g_SHPtr->SetRes(MRES_IGNORED); } else { - call = g_pBinTools->CreateVCall(info->offset, 0, 0, NULL, NULL, 0); + //META_CONPRINTF("Entity %i\n", gamehelpers->ReferenceToIndex(gamehelpers->EntityToBCompatRef((CBaseEntity *)g_SHPtr->GetIfacePtr()))); + g_SHPtr->SetRes(MRES_SUPERCEDE); + void *ret = g_SHPtr->GetOverrideRetPtr(); + ret = (void *)false; + return false; } - - unsigned char *vstk = (unsigned char *)malloc(sizeof(void *) + size); - unsigned char *vptr = vstk; - - *(void **)vptr = iface; - vptr += sizeof(void *); - - size_t offset = STACK_OFFSET; - - if(info->paramcount > 0) - { - for(int i = 0; i < info->paramcount; i++) - { - switch(info->params[i].type) - { - VSTK_PARAM_SWITCH(int, HookParamType_Int); - VSTK_PARAM_SWITCH(bool, HookParamType_Bool); - VSTK_PARAM_SWITCH(float, HookParamType_Float); - VSTK_PARAM_SWITCH(string_t, HookParamType_String); - VSTK_PARAM_SWITCH(string_t *, HookParamType_StringPtr); - VSTK_PARAM_SWITCH(char *, HookParamType_CharPtr); - VSTK_PARAM_SWITCH(Vector *, HookParamType_VectorPtr); - VSTK_PARAM_SWITCH(CBaseEntity *, HookParamType_CBaseEntity); - VSTK_PARAM_SWITCH(edict_t *, HookParamType_Edict); - default: - *(void **)vptr = *(void **)(stack+offset); - if(i + 1 != info->paramcount) - { - vptr += sizeof(void *); - } - offset += sizeof(void *); - break; - } - } - } - call->Execute(vstk, NULL); - call->Destroy(); - - free(vstk); - - if(paramInfo) - free(paramInfo); + return 0; } -template -T CallFunction(DHooksCallback *info, unsigned long stack, void *iface) -{ - PassInfo *paramInfo = NULL; - ICallWrapper *call; - size_t size = 0; - - PassInfo returnInfo; - returnInfo.flags = PASSFLAG_BYVAL; - returnInfo.size = sizeof(T); - returnInfo.type = PassType_Basic; - - if(info->paramcount > 0) - { - paramInfo = (PassInfo *)malloc(sizeof(PassInfo) * info->paramcount); - for(int i = 0; i < info->paramcount; i++) - { - switch(info->params[i].type) - { - PARAMINFO_SWITCH_CASE(int, HookParamType_Int ,PassType_Basic); - PARAMINFO_SWITCH_CASE(bool, HookParamType_Bool ,PassType_Basic); - PARAMINFO_SWITCH_CASE(float, HookParamType_Float ,PassType_Float); - PARAMINFO_SWITCH_CASE(string_t, HookParamType_String ,PassType_Object); - PARAMINFO_SWITCH_CASE(string_t *, HookParamType_StringPtr ,PassType_Basic); - PARAMINFO_SWITCH_CASE(char *, HookParamType_CharPtr ,PassType_Basic); - PARAMINFO_SWITCH_CASE(Vector *, HookParamType_VectorPtr ,PassType_Basic); - PARAMINFO_SWITCH_CASE(CBaseEntity *, HookParamType_CBaseEntity ,PassType_Basic); - PARAMINFO_SWITCH_CASE(edict_t *, HookParamType_Edict ,PassType_Basic); - default: - paramInfo[i].flags = info->params[i].flag; - paramInfo[i].size = sizeof(void *); - paramInfo[i].type = PassType_Basic; - size += sizeof(void *); - break; - } - } - call = g_pBinTools->CreateVCall(info->offset, 0, 0, &returnInfo, paramInfo, info->paramcount); - } - else - { - call = g_pBinTools->CreateVCall(info->offset, 0, 0, &returnInfo, NULL, 0); - } - - unsigned char *vstk = (unsigned char *)malloc(sizeof(void *) + size); - unsigned char *vptr = vstk; - - *(void **)vptr = iface; - vptr += sizeof(void *); - - size_t offset = STACK_OFFSET; - - if(info->paramcount > 0) - { - for(int i = 0; i < info->paramcount; i++) - { - switch(info->params[i].type) - { - VSTK_PARAM_SWITCH(int, HookParamType_Int); - VSTK_PARAM_SWITCH(bool, HookParamType_Bool); - VSTK_PARAM_SWITCH(float, HookParamType_Float); - VSTK_PARAM_SWITCH(string_t, HookParamType_String); - VSTK_PARAM_SWITCH(string_t *, HookParamType_StringPtr); - VSTK_PARAM_SWITCH(char *, HookParamType_CharPtr); - VSTK_PARAM_SWITCH(Vector *, HookParamType_VectorPtr); - VSTK_PARAM_SWITCH(CBaseEntity *, HookParamType_CBaseEntity); - VSTK_PARAM_SWITCH(edict_t *, HookParamType_Edict); - default: - *(void **)vptr = *(void **)(stack+offset); - if(i + 1 != info->paramcount) - { - vptr += sizeof(void *); - } - offset += sizeof(void *); - break; - } - } - } - T ret; - call->Execute(vstk, &ret); - call->Destroy(); - - free(vstk); - - if(paramInfo) - free(paramInfo); - - return ret; -} -template <> -void DHooksCallback::Call() -{ - GET_STACK; - META_CONPRINTF("String %s\n", *(char **)(stack+STACK_OFFSET)); - strcpy(*(char **)(stack+STACK_OFFSET), "models/player/t_phoenix.mdl"); - - SH_GLOB_SHPTR->DoRecall(); - CallFunction_Void(this, stack, g_SHPtr->GetIfacePtr()); - RETURN_META(MRES_IGNORED); -} -template <> -bool DHooksCallback::Call() -{ - GET_STACK; - META_CONPRINTF("Entity %i\n", gamehelpers->ReferenceToIndex(gamehelpers->EntityToBCompatRef(*(CBaseEntity **)(stack+STACK_OFFSET)))); - /*__asm - { - mov ebp, stack - };*/ - META_RES result = MRES_IGNORED; - RETURN_META_VALUE(MRES_IGNORED, true); - /*do - { - SH_GLOB_SHPTR->DoRecall(); - if ((result) >= MRES_OVERRIDE) - { - void *pOverride = g_SHPtr->GetOverrideRetPtr(); - pOverride = (void *)false; - } - if(result != MRES_SUPERCEDE) - { - RETURN_META_VALUE(MRES_SUPERCEDE, CallFunction(this, stack, g_SHPtr->GetIfacePtr())); - } - else - { - RETURN_META_VALUE(MRES_SUPERCEDE, true); - } - } while (0);*/ -} \ No newline at end of file +#endif diff --git a/vhook.h b/vhook.h index 50cea8c..aa71fb1 100644 --- a/vhook.h +++ b/vhook.h @@ -3,8 +3,18 @@ #include "extension.h" #include +#include + +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 +}; -#define MAX_PARAMS 10 enum HookParamType { HookParamType_Unknown, @@ -19,6 +29,7 @@ enum HookParamType HookParamType_ObjectPtr, HookParamType_Edict }; + enum ReturnType { ReturnType_Unknown, @@ -35,52 +46,216 @@ enum ReturnType ReturnType_Edict }; -class ParamInfo +enum ThisPointerType +{ + ThisPointer_Ignore, + ThisPointer_CBaseEntity, + ThisPointer_Address +}; + +enum HookType +{ + HookType_Entity, + HookType_GameRules, + HookType_Raw +}; + +struct ParamInfo { -public: HookParamType type; size_t size; unsigned int flag; + SourceHook::PassInfo::PassType pass_type; +}; + +struct HookReturnStruct +{ + ReturnType type; + bool isChanged; + void *orgResult; + void *newResult; }; class DHooksInfo { public: - int paramcount; - ParamInfo params[MAX_PARAMS]; + CUtlVector params; int offset; + unsigned int returnFlag; + ReturnType returnType; + bool post; + IPluginFunction *plugin_callback; + int entity; + ThisPointerType thisType; + HookType hookType; }; -template class DHooksCallback : public SourceHook::ISHDelegate, public DHooksInfo { public: virtual bool IsEqual(ISHDelegate *pOtherDeleg){return false;}; - virtual void DeleteThis(){delete this;}; - virtual T Call(); + 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; }; + +#ifndef __linux__ +void *Callback(DHooksCallback *dg, void **stack, size_t *argsizep); +//float Callback_float(DHooksCallback *dg, void **stack, size_t *argsizep); +#else +void *Callback(DHooksCallback *dg, void **stack); +float Callback_float(DHooksCallback *dg, void **stack); +#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; + + masm.push(ebp); + masm.movl(ebp, esp); + masm.lea(eax, Operand(ebp, 12)); + masm.push(eax); + masm.push(Operand(ebp, 8)); + if(type == ReturnType_Float) + masm.call(ExternalAddress((void *)Callback_float)); + else + masm.call(ExternalAddress((void *)Callback)); + masm.addl(esp, 8); + masm.pop(ebp); + masm.ret(); + + void *base = g_pSM->GetScriptingEngine()->AllocatePageMemory(masm.length()); + masm.emitToExecutableMemory(base); + return base; +} +#else +static void *GenerateThunk(ReturnType type) +{ + MacroAssemblerX86 masm; + + masm.push(ebp); + masm.movl(ebp, esp); + masm.subl(esp, 4); + masm.push(esp); + masm.lea(eax, Operand(ebp, 8)); + masm.push(eax); + masm.push(ecx); + //if(type == ReturnType_Float) + // masm.call(ExternalAddress(Callback_float)); + //else + masm.call(ExternalAddress(Callback)); + masm.addl(esp, 12); + masm.pop(ecx); // grab arg size + 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 +{ +public: + HookParamsStruct() + { + this->orgParams = NULL; + this->newParams = NULL; + this->dg = NULL; + } + ~HookParamsStruct() + { + if(this->orgParams != NULL) + { + delete this->orgParams; + } + if(this->newParams != NULL) + { + delete this->newParams; + } + } +public: + //CUtlVector cleanup; + void **orgParams; + void **newParams; + 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; + }; + ~HookSetup(){}; +public: + unsigned int returnFlag; + ReturnType returnType; + HookType hookType; + ThisPointerType thisType; + CUtlVector params; + int offset; + IPluginFunction *callback; +}; + class DHooksManager { public: - DHooksManager() - { - this->callback_bool = NULL; - this->callback_void = NULL; - this->hookid = 0; - }; + DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, bool post); ~DHooksManager() { - if(this->hookid != 0) + if(this->hookid) { - SH_REMOVE_HOOK_ID(this->hookid); + g_SHPtr->RemoveHookByID(this->hookid); + if(this->remove_callback) + { + this->remove_callback->PushCell(this->hookid); + this->remove_callback->Execute(NULL); + } } } - DHooksCallback *callback_bool; - DHooksCallback *callback_void; +public: int hookid; - unsigned int returnFlag; + DHooksCallback *callback; + IPluginFunction *remove_callback; }; -bool SetupHookManager(ISmmAPI *ismm); extern IBinTools *g_pBinTools; +extern HandleType_t g_HookParamsHandle; +extern HandleType_t g_HookReturnHandle; #endif \ No newline at end of file diff --git a/vhook_macros.h b/vhook_macros.h index 83aa3b9..e69de29 100644 --- a/vhook_macros.h +++ b/vhook_macros.h @@ -1,32 +0,0 @@ -#define PARAMINFO_SWITCH_CASE(paramType, enumType, passType) \ - case enumType: \ - paramInfo[i].flags = info->params[i].flag; \ - paramInfo[i].size = sizeof(paramType); \ - paramInfo[i].type = passType; \ - size += sizeof(paramType); \ - break; - -#define VSTK_PARAM_SWITCH(paramType, enumType) \ - case enumType: \ - *(paramType *)vptr = *(paramType *)(stack+offset); \ - if(i + 1 != info->paramcount) \ - { \ - vptr += sizeof(paramType); \ - } \ - offset += sizeof(paramType); \ - break; -#ifndef __linux__ - -#define STACK_OFFSET 8 -#define GET_STACK \ - unsigned long stack; \ - __asm \ - { \ - mov stack, ebp \ - }; -#else -#define STACK_OFFSET 4 -#define GET_STACK \ - unsigned long stack = 0; \ - asm ("movl %%esp, %0;" : "=r" (stack)); -#endif \ No newline at end of file