diff --git a/Makefile b/Makefile index 61e6105..ba8cbf6 100644 --- a/Makefile +++ b/Makefile @@ -19,12 +19,12 @@ MMSOURCE19 = ../mmsource-1.9 ### EDIT BELOW FOR OTHER PROJECTS ### ##################################### -PROJECT = sample +PROJECT = dhooks #Uncomment for Metamod: Source enabled extension USEMETA = true -OBJECTS = sdk/smsdk_ext.cpp extension.cpp vhook.cpp ../sourcemod-central/public/jit/x86/assembler-x86.cpp +OBJECTS = sdk/smsdk_ext.cpp extension.cpp vhook.cpp $(SMSDK)/public/jit/x86/assembler-x86.cpp listeners.cpp natives.cpp vfunc_call.cpp ############################################## ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### diff --git a/listeners.cpp b/listeners.cpp index 0d08f07..09ffe67 100644 --- a/listeners.cpp +++ b/listeners.cpp @@ -53,9 +53,8 @@ void DHooksEntityListener::OnEntityDestroyed(CBaseEntity *pEntity) 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/msvc10/sdk.vcxproj b/msvc10/sdk.vcxproj index 1ca0be9..c7cf75e 100644 --- a/msvc10/sdk.vcxproj +++ b/msvc10/sdk.vcxproj @@ -886,6 +886,7 @@ + @@ -893,6 +894,7 @@ + diff --git a/msvc10/sdk.vcxproj.filters b/msvc10/sdk.vcxproj.filters index 76a653c..a218cab 100644 --- a/msvc10/sdk.vcxproj.filters +++ b/msvc10/sdk.vcxproj.filters @@ -11,6 +11,7 @@ + @@ -34,6 +35,9 @@ Headers + + Headers + diff --git a/natives.cpp b/natives.cpp index 7e9312f..c4ca8f2 100644 --- a/natives.cpp +++ b/natives.cpp @@ -93,9 +93,10 @@ cell_t Native_HookEntity(IPluginContext *pContext, const cell_t *params) 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) + DHooksManager *manager = g_pHooks.Element(i); + if(manager->callback->hookType == HookType_Entity && manager->callback->entity == params[3] && manager->callback->offset == setup->offset && manager->callback->post == post && manager->remove_callback == pContext->GetFunctionById(params[4]) && manager->callback->plugin_callback == setup->callback) { - return g_pHooks.Element(i)->hookid; + return manager->hookid; } } CBaseEntity *pEnt = UTIL_GetCBaseEntity(params[3]); @@ -134,7 +135,7 @@ cell_t Native_GetParam(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err); } - if(params[2] > paramStruct->dg->params.Count() || params[2] < 0) + if(params[2] < 0 || params[2] > paramStruct->dg->params.Count()) { return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.Count()); } @@ -170,10 +171,89 @@ cell_t Native_GetParam(IPluginContext *pContext, const cell_t *params) } cell_t Native_GetReturn(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()); + HookReturnStruct *returnStruct; + + if((err = handlesys->ReadHandle(params[1], g_HookReturnHandle, &sec, (void **)&returnStruct)) != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err); + } + + switch(returnStruct->type) + { + case ReturnType_Int: + return *(int *)returnStruct->orgResult; + case ReturnType_Bool: + return *(cell_t *)returnStruct->orgResult; + case ReturnType_CBaseEntity: + return gamehelpers->EntityToBCompatRef((CBaseEntity *)returnStruct->orgResult); + case ReturnType_Edict: + return gamehelpers->IndexOfEdict((edict_t *)returnStruct->orgResult); + case ReturnType_Float: + return sp_ftoc(*(float *)returnStruct->orgResult); + default: + return pContext->ThrowNativeError("Invalid param type (%i) to get",returnStruct->type); + } return 1; } cell_t Native_SetReturn(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()); + HookReturnStruct *returnStruct; + + if((err = handlesys->ReadHandle(params[1], g_HookReturnHandle, &sec, (void **)&returnStruct)) != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err); + } + + CBaseEntity *pEnt; + edict_t *pEdict; + float *fpVal; + switch(returnStruct->type) + { + case ReturnType_Int: + returnStruct->newResult = (void *)((int)params[2]); + break; + case ReturnType_Bool: + returnStruct->newResult = (void *)(params[2] != 0); + break; + case ReturnType_CBaseEntity: + pEnt = UTIL_GetCBaseEntity(params[2]); + if(!pEnt) + { + return pContext->ThrowNativeError("Invalid entity index passed for return value"); + } + returnStruct->newResult = pEnt; + break; + case ReturnType_Edict: + pEdict = gamehelpers->EdictOfIndex(params[2]); + if(!pEdict || pEdict->IsFree()) + { + pContext->ThrowNativeError("Invalid entity index passed for return value"); + } + returnStruct->newResult = pEdict; + break; + case ReturnType_Float: + fpVal = new float; + *fpVal = sp_ctof(params[2]); + returnStruct->newResult = fpVal; + break; + default: + return pContext->ThrowNativeError("Invalid param type (%i) to get",returnStruct->type); + } + returnStruct->isChanged = true; return 1; } /*cell_t Native_SetParam(IPluginContext *pContext, const cell_t *params); @@ -196,7 +276,7 @@ cell_t Native_GetParamString(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err); } - if(params[2] > paramStruct->dg->params.Count() || params[2] <= 0) + if(params[2] <= 0 || params[2] > paramStruct->dg->params.Count()) { return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.Count()); } @@ -216,8 +296,42 @@ cell_t Native_GetParamString(IPluginContext *pContext, const cell_t *params) } //cell_t Native_GetReturnString(IPluginContext *pContext, const cell_t *params); //cell_t Native_SetReturnString(IPluginContext *pContext, const cell_t *params); + +//native DHookSetParamString(Handle:hParams, num, String:value[]) cell_t Native_SetParamString(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] <= 0 || params[2] > paramStruct->dg->params.Count()) + { + return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.Count()); + } + + int index = params[2] - 1; + + char *value; + pContext->LocalToString(params[3], &value); + + if(paramStruct->dg->params.Element(index).type == HookParamType_CharPtr) + { + if(paramStruct->newParams[index] != NULL) + delete (char *)paramStruct->newParams[index]; + + paramStruct->newParams[index] = new char[strlen(value)+1]; + strcpy((char *)paramStruct->newParams[index], value); + paramStruct->isChanged[index] = true; + } return 1; } @@ -249,4 +363,4 @@ sp_nativeinfo_t g_Natives[] = {"DHookSetParamObjectPtrVarVector", Native_SetParamObjectPtrVarVector}, {"DHookIsNullParam", Native_IsNullParam},*/ {NULL, NULL} -}; \ No newline at end of file +}; diff --git a/vfunc_call.cpp b/vfunc_call.cpp new file mode 100644 index 0000000..231ee1d --- /dev/null +++ b/vfunc_call.cpp @@ -0,0 +1,121 @@ +#include "vfunc_call.h" + +#define PARAMINFO_SWITCH(passType) \ + paramInfo[i].flags = dg->params.Element(i).flag; \ + paramInfo[i].size = dg->params.Element(i).size; \ + paramInfo[i].type = passType; + +#define VSTK_PARAM_SWITCH(paramType) \ + if(paramStruct->isChanged[i]) \ + { \ + *(paramType *)vptr = (paramType)(paramStruct->newParams[i]); \ + } \ + else \ + { \ + *(paramType *)vptr = (paramType)(paramStruct->orgParams[i]); \ + } \ + if(i + 1 != dg->params.Count()) \ + { \ + vptr += dg->params.Element(i).size; \ + } \ + break; +#define VSTK_PARAM_SWITCH_FLOAT() \ + if(paramStruct->isChanged[i]) \ + { \ + *(float *)vptr = *(float *)(paramStruct->newParams[i]); \ + } \ + else \ + { \ + *(float *)vptr = *(float *)(paramStruct->orgParams[i]); \ + } \ + if(i + 1 != dg->params.Count()) \ + { \ + vptr += dg->params.Element(i).size; \ + } \ + break; + +void *CallVFunction(DHooksCallback *dg, HookParamsStruct *paramStruct, void *iface) +{ + PassInfo *paramInfo = NULL; + PassInfo returnInfo; + + if(dg->returnType != ReturnType_Void) + { + returnInfo.flags = dg->returnFlag; + returnInfo.size = sizeof(void *); + returnInfo.type = PassType_Basic; + } + + ICallWrapper *pCall; + + size_t size = GetStackArgsSize(dg); + + unsigned char *vstk = (unsigned char *)malloc(sizeof(void *) + size); + unsigned char *vptr = vstk; + + *(void **)vptr = iface; + + if(paramStruct) + { + vptr += sizeof(void *); + paramInfo = (PassInfo *)malloc(sizeof(PassInfo) * dg->params.Count()); + for(int i = 0; i < dg->params.Count(); i++) + { + switch(dg->params.Element(i).type) + { + case HookParamType_Int: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(int); + case HookParamType_Bool: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(cell_t); + case HookParamType_Float: + PARAMINFO_SWITCH(PassType_Float); + VSTK_PARAM_SWITCH_FLOAT(); + case HookParamType_String: + PARAMINFO_SWITCH(PassType_Object); + VSTK_PARAM_SWITCH(int); + case HookParamType_StringPtr: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(string_t *); + case HookParamType_CharPtr: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(char *); + case HookParamType_VectorPtr: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(Vector *); + case HookParamType_CBaseEntity: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(CBaseEntity *); + case HookParamType_Edict: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(edict_t *); + default: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(void *); + } + } + } + + void *ret = 0; + if(dg->returnType == ReturnType_Void) + { + pCall = g_pBinTools->CreateVCall(dg->offset, 0, 0, NULL, paramInfo, dg->params.Count()); + pCall->Execute(vstk, NULL); + } + else + { + pCall = g_pBinTools->CreateVCall(dg->offset, 0, 0, &returnInfo, paramInfo, dg->params.Count()); + pCall->Execute(vstk, &ret); + } + + pCall->Destroy(); + free(vstk); + + if(paramInfo != NULL) + { + free(paramInfo); + } + + return ret; +} diff --git a/vfunc_call.h b/vfunc_call.h new file mode 100644 index 0000000..28a11fb --- /dev/null +++ b/vfunc_call.h @@ -0,0 +1,7 @@ +#ifndef _INCLUDE_VFUNC_CALL_H_ +#define _INCLUDE_VFUNC_CALL_H_ + +#include "vhook.h" + +void *CallVFunction(DHooksCallback *dg, HookParamsStruct *paramStruct, void *iface); +#endif diff --git a/vhook.cpp b/vhook.cpp index 1c4a91c..e02d956 100644 --- a/vhook.cpp +++ b/vhook.cpp @@ -1,4 +1,5 @@ #include "vhook.h" +#include "vfunc_call.h" SourceHook::IHookManagerAutoGen *g_pHookManager = NULL; @@ -39,13 +40,9 @@ DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *rem { 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); + protoInfo.SetReturnType(sizeof(void *), SourceHook::PassInfo::PassType_Basic, setup->returnFlag, NULL, NULL, NULL, NULL); } HookManagerPubFunc hook = g_pHookManager->MakeHookMan(protoInfo, 0, this->callback->offset); @@ -82,10 +79,9 @@ SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type) switch(type) { case HookParamType_Float: - return SourceHook::PassInfo::PassType::PassType_Float; - default: - return SourceHook::PassInfo::PassType::PassType_Basic; + return SourceHook::PassInfo::PassType_Float; } + return SourceHook::PassInfo::PassType_Basic; } size_t GetStackArgsSize(DHooksCallback *dg) { @@ -102,10 +98,12 @@ HookParamsStruct *GetParamStruct(DHooksCallback *dg, void **argStack, size_t arg res->dg = dg; res->orgParams = (void **)malloc(argStackSize); res->newParams = (void **)malloc(argStackSize); + res->isChanged = (bool *)malloc(dg->params.Count() * sizeof(bool)); memcpy(res->orgParams, argStack, argStackSize); for(int i = 0; i < dg->params.Count(); i++) { res->newParams[i] = NULL; + res->isChanged[i] = false; } return res; } @@ -114,8 +112,32 @@ HookReturnStruct *GetReturnStruct(DHooksCallback *dg, const void *result) HookReturnStruct *res = new HookReturnStruct(); res->isChanged = false; res->type = dg->returnType; - res->orgResult = &result; - res->newResult = 0; + res->newResult = NULL; + + float *fpVal = NULL; + + if(result && dg->post) + { + switch(dg->returnType) + { + //ReturnType_String, + //ReturnType_Vector, + case ReturnType_Int: + case ReturnType_Bool: + res->orgResult = (int *)result; + break; + case ReturnType_Float: + res->orgResult = new float; + *fpVal = *(float *)result; + res->orgResult = fpVal; + default: + res->orgResult = (void *)result; + } + } + else + { + res->orgResult = NULL; + } return res; } @@ -128,15 +150,23 @@ cell_t GetThisPtr(void *iface, ThisPointerType type) return (cell_t)iface; } + #ifndef __linux__ void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep) +#else +void *Callback(DHooksCallback *dg, void **argStack) +#endif { HookReturnStruct *returnStruct = NULL; HookParamsStruct *paramStruct = NULL; Handle_t rHndl; Handle_t pHndl; + #ifndef __linux__ *argsizep = GetStackArgsSize(dg); + #else + size_t argsize = GetStackArgsSize(dg); + #endif if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) { @@ -157,9 +187,16 @@ void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep) } dg->plugin_callback->PushCell(rHndl); } + + #ifndef __linux__ if(*argsizep > 0) { paramStruct = GetParamStruct(dg, argStack, *argsizep); + #else + if(argsize > 0) + { + paramStruct = GetParamStruct(dg, argStack, argsize); + #endif pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL); if(!pHndl) { @@ -180,32 +217,24 @@ void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep) dg->plugin_callback->Execute(&result); void *ret = g_SHPtr->GetOverrideRetPtr(); - void *res = 0; - + ret = 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 *)); + ret = CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr()); break; case MRES_ChangedOverride: g_SHPtr->DoRecall(); g_SHPtr->SetRes(MRES_SUPERCEDE); - //CallVFunction(dg, argStack, g_SHPtr->GetIfacePtr()); + ret = CallVFunction(dg, paramStruct, 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 *)); + ret = returnStruct->newResult; } } break; @@ -215,13 +244,11 @@ void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep) { if(returnStruct->isChanged) { - memcpy(ret, returnStruct->newResult, sizeof(void *)); - memcpy(res, returnStruct->newResult, sizeof(void *)); + ret = returnStruct->newResult; } else if(dg->post) { - memcpy(ret, returnStruct->orgResult, sizeof(void *)); - memcpy(res, returnStruct->orgResult, sizeof(void *)); + ret = (void *)returnStruct->orgResult; } } break; @@ -231,13 +258,11 @@ void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep) { if(returnStruct->isChanged) { - memcpy(ret, returnStruct->newResult, sizeof(void *)); - memcpy(res, returnStruct->newResult, sizeof(void *)); + ret = returnStruct->newResult; } else if(dg->post) { - memcpy(ret, returnStruct->orgResult, sizeof(void *)); - memcpy(res, returnStruct->orgResult, sizeof(void *)); + ret = returnStruct->orgResult; } } break; @@ -257,24 +282,5 @@ void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep) 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 - { - //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; - } - return 0; -} -#endif + return ret; +} \ No newline at end of file diff --git a/vhook.h b/vhook.h index aa71fb1..c71fab5 100644 --- a/vhook.h +++ b/vhook.h @@ -68,8 +68,32 @@ struct ParamInfo SourceHook::PassInfo::PassType pass_type; }; -struct HookReturnStruct +class HookReturnStruct { +public: + ~HookReturnStruct() + { + if(this->isChanged && this->newResult) + { + if(this->type == ReturnType_CharPtr) + { + delete (char *)this->newResult; + } + else if(this->type == ReturnType_VectorPtr) + { + delete (Vector *)this->newResult; + } + else if(this->type == ReturnType_Float) + { + if(this->orgResult) + { + free(this->orgResult); + } + free(this->newResult); + } + } + } +public: ReturnType type; bool isChanged; void *orgResult; @@ -129,9 +153,9 @@ static void *GenerateThunk(ReturnType type) masm.lea(eax, Operand(ebp, 12)); masm.push(eax); masm.push(Operand(ebp, 8)); - if(type == ReturnType_Float) + /*if(type == ReturnType_Float) masm.call(ExternalAddress((void *)Callback_float)); - else + else*/ masm.call(ExternalAddress((void *)Callback)); masm.addl(esp, 8); masm.pop(ebp); @@ -191,22 +215,41 @@ public: this->orgParams = NULL; this->newParams = NULL; this->dg = NULL; + this->isChanged = NULL; } ~HookParamsStruct() { if(this->orgParams != NULL) { - delete this->orgParams; + free(this->orgParams); + } + if(this->isChanged != NULL) + { + free(this->isChanged); } if(this->newParams != NULL) { - delete this->newParams; + 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]; + } + } + free(this->newParams); } } public: - //CUtlVector cleanup; void **orgParams; void **newParams; + bool *isChanged; DHooksCallback *dg; }; @@ -255,7 +298,9 @@ public: IPluginFunction *remove_callback; }; +size_t GetStackArgsSize(DHooksCallback *dg); + extern IBinTools *g_pBinTools; extern HandleType_t g_HookParamsHandle; extern HandleType_t g_HookReturnHandle; -#endif \ No newline at end of file +#endif diff --git a/vhook_macros.h b/vhook_macros.h deleted file mode 100644 index e69de29..0000000