Add support to define function signatures in gamedata

A "Functions" section is parsed in gamedata files that allow you to define the signature of functions including metadata like the calling convention and specifying the register an argument is passed in.
A new native DHookCreateFromConf can be used to setup a hook or detour from one of that function sections in the "Functions" section.
This commit is contained in:
Peace-Maker 2018-01-25 17:18:30 +01:00
parent e2d71bae03
commit aa3018a27d
10 changed files with 792 additions and 7 deletions

View File

@ -255,6 +255,7 @@ program.sources += [
'extension.cpp',
'listeners.cpp',
'natives.cpp',
'signatures.cpp',
'vhook.cpp',
'util.cpp',
'dynhooks_sourcepawn.cpp',

View File

@ -1,6 +1,7 @@
#include "extension.h"
#include "listeners.h"
#include "dynhooks_sourcepawn.h"
#include "signatures.h"
DHooks g_DHooksIface; /**< Global singleton for extension's main interface */
SMEXT_LINK(&g_DHooksIface);
@ -57,6 +58,7 @@ bool DHooks::SDK_OnLoad(char *error, size_t maxlength, bool late)
sharesys->AddNatives(myself, g_Natives);
g_pEntityListener = new DHooksEntityListener();
g_pSignatures = new SignatureGameConfig();
return true;
}
@ -84,6 +86,7 @@ void DHooks::SDK_OnAllLoaded()
SM_GET_LATE_IFACE(SDKHOOKS, g_pSDKHooks);
g_pSDKHooks->AddEntityListener(g_pEntityListener);
gameconfs->AddUserConfigHook("Functions", g_pSignatures);
}
void DHooks::SDK_OnUnload()
@ -101,6 +104,8 @@ void DHooks::SDK_OnUnload()
handlesys->RemoveType(g_HookSetupHandle, myself->GetIdentity());
handlesys->RemoveType(g_HookParamsHandle, myself->GetIdentity());
handlesys->RemoveType(g_HookReturnHandle, myself->GetIdentity());
gameconfs->RemoveUserConfigHook("Functions", g_pSignatures);
}
bool DHooks::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late)

View File

@ -121,6 +121,7 @@
<ClCompile Include="..\extension.cpp" />
<ClCompile Include="..\listeners.cpp" />
<ClCompile Include="..\natives.cpp" />
<ClCompile Include="..\signatures.cpp" />
<ClCompile Include="..\util.cpp" />
<ClCompile Include="..\vhook.cpp" />
</ItemGroup>

View File

@ -37,6 +37,7 @@
<ClCompile Include="..\DynamicHooks\conventions\x86MsThiscall.cpp">
<Filter>DynamicHooks\conventions</Filter>
</ClCompile>
<ClCompile Include="..\signatures.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\extension.h">

View File

@ -1,6 +1,7 @@
#include "natives.h"
#include "util.h"
#include "dynhooks_sourcepawn.h"
#include "signatures.h"
// Must match same enum in sdktools.inc
enum SDKFuncConfSource
@ -48,7 +49,7 @@ cell_t Native_CreateHook(IPluginContext *pContext, const cell_t *params)
return hndl;
}
//native Handle:DHookCreateDetour(Address:funcaddr, CallingConvention callConv, ReturnType:returntype, ThisPointerType:thistype);
//native Handle:DHookCreateDetour(Address:funcaddr, CallingConvention:callConv, ReturnType:returntype, ThisPointerType:thistype);
cell_t Native_CreateDetour(IPluginContext *pContext, const cell_t *params)
{
HookSetup *setup = new HookSetup((ReturnType)params[3], PASSFLAG_BYVAL, (CallingConvention)params[2], (ThisPointerType)params[4], (void *)params[1]);
@ -64,6 +65,86 @@ cell_t Native_CreateDetour(IPluginContext *pContext, const cell_t *params)
return hndl;
}
// native Handle:DHookCreateFromConf(Handle:gameconf, const String:function[], DHookCallback:callback=INVALID_FUNCTION);
cell_t Native_DHookCreateFromConf(IPluginContext *pContext, const cell_t *params)
{
IGameConfig *conf;
HandleError err;
if ((conf = gameconfs->ReadHandle(params[1], pContext->GetIdentity(), &err)) == nullptr)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
}
char *function;
pContext->LocalToString(params[2], &function);
SignatureWrapper *sig = g_pSignatures->GetFunctionSignature(function);
if (!sig)
{
return pContext->ThrowNativeError("Function signature \"%s\" was not found.", function);
}
IPluginFunction *callback = nullptr;
if (params[3] != -1)
{
callback = pContext->GetFunctionById(params[3]);
if (!callback)
return pContext->ThrowNativeError("Failed to find callback function.");
}
HookSetup *setup = nullptr;
// This is a virtual hook.
if (sig->offset.length() > 0)
{
int offset;
if (!conf->GetOffset(sig->offset.chars(), &offset))
{
return BAD_HANDLE;
}
setup = new HookSetup(sig->retType, PASSFLAG_BYVAL, sig->hookType, sig->thisType, offset, callback);
}
// This is a detour.
else
{
void *addr = nullptr;;
if (sig->signature.length() > 0)
{
if (!conf->GetMemSig(sig->signature.chars(), &addr) || !addr)
{
return BAD_HANDLE;
}
}
else
{
if (!conf->GetAddress(sig->address.chars(), &addr) || !addr)
{
return BAD_HANDLE;
}
}
setup = new HookSetup(sig->retType, PASSFLAG_BYVAL, sig->callConv, sig->thisType, addr);
}
// Push all the arguments.
auto args = sig->args.iter();
while (!args.empty())
{
ParamInfo info = args->value;
setup->params.push_back(info);
args.next();
}
// Create the handle to hold this setup.
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:DHookSetFromConf(Handle:setup, Handle:gameconf, SDKFuncConfSource:source, const String:name[]);
cell_t Native_SetFromConf(IPluginContext *pContext, const cell_t *params)
@ -1232,10 +1313,11 @@ sp_nativeinfo_t g_Natives[] =
{
{"DHookCreate", Native_CreateHook},
{"DHookCreateDetour", Native_CreateDetour},
{"DHookSetFromConf", Native_SetFromConf },
{"DHookCreateFromConf", Native_DHookCreateFromConf},
{"DHookSetFromConf", Native_SetFromConf},
{"DHookAddParam", Native_AddParam},
{"DHookEnableDetour", Native_EnableDetour},
//{"DHookDisableDetour", Native_DisableDetour},
{"DHookDisableDetour", Native_DisableDetour},
{"DHookEntity", Native_HookEntity},
{"DHookGamerules", Native_HookGamerules},
{"DHookRaw", Native_HookRaw},

562
signatures.cpp Normal file
View File

@ -0,0 +1,562 @@
#include <signatures.h>
SignatureGameConfig *g_pSignatures;
enum ParseState
{
PState_None,
PState_Root,
PState_Function,
PState_Arguments,
PState_Argument
};
ParseState g_ParseState;
unsigned int g_IgnoreLevel;
// The parent section type of a platform specific "windows" or "linux" section.
ParseState g_PlatformOnlyState;
SignatureWrapper *g_CurrentSignature;
ke::AString g_CurrentFunctionName;
ParamInfo g_CurrentArgumentInfo;
ke::AString g_CurrentArgumentName;
SignatureWrapper *SignatureGameConfig::GetFunctionSignature(const char *function)
{
auto sig = signatures_.find(function);
if (!sig.found())
return nullptr;
return sig->value;
}
/**
* Game config "Functions" section parsing.
*/
SMCResult SignatureGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
{
// We're ignoring the parent section. Ignore all child sections as well.
if (g_IgnoreLevel > 0)
{
g_IgnoreLevel++;
return SMCResult_Continue;
}
// Handle platform specific sections first.
#if defined WIN32
if (!strcmp(name, "windows"))
#elif defined _LINUX
if (!strcmp(name, "linux"))
#elif defined _OSX
if (!strcmp(name, "mac"))
#endif
{
// We're already in a section for a different OS that we're ignoring. Can't have a section for our OS in here.
if (g_IgnoreLevel > 0)
{
smutils->LogError(myself, "Unreachable platform specific section in \"%s\" Function: line: %i col: %i", g_CurrentFunctionName, states->line, states->col);
return SMCResult_HaltFail;
}
// We don't support nested (useless) sections of the same OS like "windows" { "windows" { "foo" "bar" } }
if (g_PlatformOnlyState != PState_None)
{
smutils->LogError(myself, "Duplicate platform specific section for \"%s\". Already parsing only for that OS: line: %i col: %i", name, states->line, states->col);
return SMCResult_HaltFail;
}
// This is a specific block for us.
g_PlatformOnlyState = g_ParseState;
return SMCResult_Continue;
}
#if defined WIN32
else if (!strcmp(name, "linux") || !strcmp(name, "mac"))
#elif defined _LINUX
else if (!strcmp(name, "windows") || !strcmp(name, "mac"))
#elif defined _OSX
else if (!strcmp(name, "windows") || !strcmp(name, "linux"))
#endif
{
if (g_PlatformOnlyState != PState_None)
{
smutils->LogError(myself, "Unreachable platform specific section in \"%s\" Function: line: %i col: %i", g_CurrentFunctionName, states->line, states->col);
return SMCResult_HaltFail;
}
// A specific block for a different platform.
g_IgnoreLevel++;
return SMCResult_Continue;
}
switch (g_ParseState)
{
case PState_Root:
{
auto sig = signatures_.find(name);
if (sig.found())
g_CurrentSignature = sig->value;
else
g_CurrentSignature = new SignatureWrapper();
g_CurrentFunctionName = name;
g_ParseState = PState_Function;
break;
}
case PState_Function:
{
if (!strcmp(name, "arguments"))
{
g_ParseState = PState_Arguments;
}
else
{
smutils->LogError(myself, "Unknown subsection \"%s\" (expected \"arguments\"): line: %i col: %i", name, states->line, states->col);
return SMCResult_HaltFail;
}
break;
}
case PState_Arguments:
{
g_ParseState = PState_Argument;
g_CurrentArgumentName = name;
auto arg = g_CurrentSignature->args.find(name);
// Continue changing that argument now.
if (arg.found())
{
g_CurrentArgumentInfo = arg->value;
}
else
{
ParamInfo info;
memset(&info, 0, sizeof(info));
info.flags = PASSFLAG_BYVAL;
g_CurrentArgumentInfo = info;
}
break;
}
default:
smutils->LogError(myself, "Unknown subsection \"%s\": line: %i col: %i", name, states->line, states->col);
return SMCResult_HaltFail;
}
return SMCResult_Continue;
}
SMCResult SignatureGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
{
// We don't care for anything in this section or subsections.
if (g_IgnoreLevel > 0)
return SMCResult_Continue;
switch (g_ParseState)
{
case PState_Function:
if (!strcmp(key, "signature"))
{
if (g_CurrentSignature->address.length() > 0 || g_CurrentSignature->offset.length() > 0)
{
smutils->LogError(myself, "Cannot have \"signature\", \"address\" or \"offset\" keys at the same time in one function: line: %i col: %i", states->line, states->col);
return SMCResult_HaltFail;
}
g_CurrentSignature->signature = value;
}
else if (!strcmp(key, "address"))
{
if (g_CurrentSignature->signature.length() > 0 || g_CurrentSignature->offset.length() > 0)
{
smutils->LogError(myself, "Cannot have \"signature\", \"address\" or \"offset\" keys at the same time in one function: line: %i col: %i", states->line, states->col);
return SMCResult_HaltFail;
}
g_CurrentSignature->address = value;
}
else if (!strcmp(key, "offset"))
{
if (g_CurrentSignature->address.length() > 0 || g_CurrentSignature->signature.length() > 0)
{
smutils->LogError(myself, "Cannot have \"signature\", \"address\" or \"offset\" keys at the same time in one function: line: %i col: %i", states->line, states->col);
return SMCResult_HaltFail;
}
g_CurrentSignature->offset = value;
}
else if (!strcmp(key, "callconv"))
{
CallingConvention callConv;
if (!strcmp(value, "cdecl"))
callConv = CallConv_CDECL;
else if (!strcmp(value, "thiscall"))
callConv = CallConv_THISCALL;
else if (!strcmp(value, "stdcall"))
callConv = CallConv_STDCALL;
else
{
smutils->LogError(myself, "Invalid calling convention \"%s\": line: %i col: %i", value, states->line, states->col);
return SMCResult_HaltFail;
}
g_CurrentSignature->callConv = callConv;
}
else if (!strcmp(key, "hooktype"))
{
HookType hookType;
if (!strcmp(value, "entity"))
hookType = HookType_Entity;
else if (!strcmp(value, "gamerules"))
hookType = HookType_GameRules;
else if (!strcmp(value, "raw"))
hookType = HookType_Raw;
else
{
smutils->LogError(myself, "Invalid hook type \"%s\": line: %i col: %i", value, states->line, states->col);
return SMCResult_HaltFail;
}
g_CurrentSignature->hookType = hookType;
}
else if (!strcmp(key, "return"))
{
g_CurrentSignature->retType = GetReturnTypeFromString(value);
if (g_CurrentSignature->retType == ReturnType_Unknown)
{
smutils->LogError(myself, "Invalid return type \"%s\": line: %i col: %i", value, states->line, states->col);
return SMCResult_HaltFail;
}
}
else if (!strcmp(key, "this"))
{
if (!strcmp(value, "ignore"))
g_CurrentSignature->thisType = ThisPointer_Ignore;
else if (!strcmp(value, "entity"))
g_CurrentSignature->thisType = ThisPointer_CBaseEntity;
else if (!strcmp(value, "address"))
g_CurrentSignature->thisType = ThisPointer_Address;
else
{
smutils->LogError(myself, "Invalid this type \"%s\": line: %i col: %i", value, states->line, states->col);
return SMCResult_HaltFail;
}
}
else
{
smutils->LogError(myself, "Unknown key in Functions section \"%s\": line: %i col: %i", key, states->line, states->col);
return SMCResult_HaltFail;
}
break;
case PState_Argument:
if (!strcmp(key, "type"))
{
g_CurrentArgumentInfo.type = GetHookParamTypeFromString(value);
if (g_CurrentArgumentInfo.type == HookParamType_Unknown)
{
smutils->LogError(myself, "Invalid argument type \"%s\" for argument \"%s\": line: %i col: %i", value, g_CurrentArgumentName.chars(), states->line, states->col);
return SMCResult_HaltFail;
}
}
else if (!strcmp(key, "size"))
{
g_CurrentArgumentInfo.size = atoi(value);
if (g_CurrentArgumentInfo.size < 1)
{
smutils->LogError(myself, "Invalid argument size \"%s\" for argument \"%s\": line: %i col: %i", value, g_CurrentArgumentName.chars(), states->line, states->col);
return SMCResult_HaltFail;
}
}
else if (!strcmp(key, "flags"))
{
size_t flags;
if (strstr(value, "byval"))
flags |= PASSFLAG_BYVAL;
else if (strstr(value, "byref"))
flags |= PASSFLAG_BYREF;
else if (strstr(value, "byref"))
flags |= PASSFLAG_ODTOR;
else if (strstr(value, "octor"))
flags |= PASSFLAG_OCTOR;
else if (strstr(value, "oassignop"))
flags |= PASSFLAG_OASSIGNOP;
else if (strstr(value, "ocopyctor"))
flags |= PASSFLAG_OCOPYCTOR;
else if (strstr(value, "ounalign"))
flags |= PASSFLAG_OUNALIGN;
g_CurrentArgumentInfo.flags = flags;
}
else if (!strcmp(key, "register"))
{
g_CurrentArgumentInfo.custom_register = GetCustomRegisterFromString(value);
if (g_CurrentArgumentInfo.custom_register == Register_t::None)
{
smutils->LogError(myself, "Invalid register \"%s\": line: %i col: %i", value, states->line, states->col);
return SMCResult_HaltFail;
}
}
else
{
smutils->LogError(myself, "Unknown key in Functions section \"%s\": line: %i col: %i", key, states->line, states->col);
return SMCResult_HaltFail;
}
break;
default:
smutils->LogError(myself, "Unknown key in Functions section \"%s\": line: %i col: %i", key, states->line, states->col);
return SMCResult_HaltFail;
}
return SMCResult_Continue;
}
SMCResult SignatureGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
{
// We were ignoring this section.
if (g_IgnoreLevel > 0)
{
g_IgnoreLevel--;
// We were in a subsection of an ignored section. Keep ignoring.
if (g_IgnoreLevel > 0)
return SMCResult_Continue;
}
// We were in a section only for our OS.
if (g_PlatformOnlyState == g_ParseState)
{
g_PlatformOnlyState = PState_None;
return SMCResult_Continue;
}
switch (g_ParseState)
{
case PState_Function:
g_ParseState = PState_Root;
if (!g_CurrentSignature->address.length() && !g_CurrentSignature->signature.length())
{
smutils->LogError(myself, "Function \"%s\" doesn't have a \"signature\" nor \"address\" set: line: %i col: %i", g_CurrentFunctionName, states->line, states->col);
return SMCResult_HaltFail;
}
// Save this function signature in our cache.
signatures_.insert(g_CurrentFunctionName.chars(), g_CurrentSignature);
g_CurrentFunctionName = nullptr;
g_CurrentSignature = nullptr;
break;
case PState_Arguments:
g_ParseState = PState_Function;
break;
case PState_Argument:
g_ParseState = PState_Arguments;
if (g_CurrentArgumentInfo.type == HookParamType_Unknown)
{
smutils->LogError(myself, "Missing argument type for argument \"%s\": line: %i col: %i", g_CurrentArgumentName.chars(), states->line, states->col);
return SMCResult_HaltFail;
}
// The size wasn't set in the config. See if that's fine and we can guess it from the type.
if (!g_CurrentArgumentInfo.size)
{
if (g_CurrentArgumentInfo.type == HookParamType_Object)
{
smutils->LogError(myself, "Object param \"%s\" being set with no size: line: %i col: %i", g_CurrentArgumentName.chars(), states->line, states->col);
return SMCResult_HaltFail;
}
else
{
g_CurrentArgumentInfo.size = GetParamTypeSize(g_CurrentArgumentInfo.type);
}
}
if (g_CurrentArgumentInfo.pass_type == SourceHook::PassInfo::PassType::PassType_Unknown)
g_CurrentArgumentInfo.pass_type = GetParamTypePassType(g_CurrentArgumentInfo.type);
g_CurrentSignature->args.insert(g_CurrentArgumentName.chars(), g_CurrentArgumentInfo);
g_CurrentArgumentName = nullptr;
break;
}
return SMCResult_Continue;
}
void SignatureGameConfig::ReadSMC_ParseStart()
{
g_ParseState = PState_Root;
g_IgnoreLevel = 0;
g_PlatformOnlyState = PState_None;
g_CurrentSignature = nullptr;
g_CurrentFunctionName = nullptr;
g_CurrentArgumentName = nullptr;
}
ReturnType SignatureGameConfig::GetReturnTypeFromString(const char *str)
{
if (!strcmp(str, "void"))
return ReturnType_Void;
else if (!strcmp(str, "int"))
return ReturnType_Int;
else if (!strcmp(str, "bool"))
return ReturnType_Bool;
else if (!strcmp(str, "float"))
return ReturnType_Float;
else if (!strcmp(str, "string"))
return ReturnType_String;
else if (!strcmp(str, "stringptr"))
return ReturnType_StringPtr;
else if (!strcmp(str, "charptr"))
return ReturnType_CharPtr;
else if (!strcmp(str, "vector"))
return ReturnType_Vector;
else if (!strcmp(str, "vectorptr"))
return ReturnType_VectorPtr;
else if (!strcmp(str, "entity"))
return ReturnType_CBaseEntity;
else if (!strcmp(str, "edict"))
return ReturnType_Edict;
return ReturnType_Unknown;
}
HookParamType SignatureGameConfig::GetHookParamTypeFromString(const char *str)
{
if (!strcmp(str, "int"))
return HookParamType_Int;
else if (!strcmp(str, "bool"))
return HookParamType_Bool;
else if (!strcmp(str, "float"))
return HookParamType_Float;
else if (!strcmp(str, "string"))
return HookParamType_String;
else if (!strcmp(str, "stringptr"))
return HookParamType_StringPtr;
else if (!strcmp(str, "charptr"))
return HookParamType_CharPtr;
else if (!strcmp(str, "vectorptr"))
return HookParamType_VectorPtr;
else if (!strcmp(str, "entity"))
return HookParamType_CBaseEntity;
else if (!strcmp(str, "objectptr"))
return HookParamType_ObjectPtr;
else if (!strcmp(str, "edict"))
return HookParamType_Edict;
else if (!strcmp(str, "object"))
return HookParamType_Object;
return HookParamType_Unknown;
}
Register_t SignatureGameConfig::GetCustomRegisterFromString(const char *str)
{
if (!strcmp(str, "al"))
return AL;
else if (!strcmp(str, "cl"))
return CL;
else if (!strcmp(str, "dl"))
return DL;
else if (!strcmp(str, "Bl"))
return BL;
else if (!strcmp(str, "ah"))
return AH;
else if (!strcmp(str, "ch"))
return CH;
else if (!strcmp(str, "dh"))
return DH;
else if (!strcmp(str, "bh"))
return BH;
else if (!strcmp(str, "ax"))
return AX;
else if (!strcmp(str, "cx"))
return CX;
else if (!strcmp(str, "dx"))
return DX;
else if (!strcmp(str, "bx"))
return BX;
else if (!strcmp(str, "sp"))
return SP;
else if (!strcmp(str, "bp"))
return BP;
else if (!strcmp(str, "si"))
return SI;
else if (!strcmp(str, "di"))
return DI;
else if (!strcmp(str, "eax"))
return EAX;
else if (!strcmp(str, "ECX"))
return ECX;
else if (!strcmp(str, "EDX"))
return EDX;
else if (!strcmp(str, "EBX"))
return EBX;
else if (!strcmp(str, "esp"))
return ESP;
else if (!strcmp(str, "ebp"))
return EBP;
else if (!strcmp(str, "esi"))
return ESI;
else if (!strcmp(str, "edi"))
return EDI;
else if (!strcmp(str, "mm0"))
return MM0;
else if (!strcmp(str, "mm1"))
return MM1;
else if (!strcmp(str, "mm2"))
return MM2;
else if (!strcmp(str, "mm3"))
return MM3;
else if (!strcmp(str, "mm4"))
return MM4;
else if (!strcmp(str, "mm5"))
return MM5;
else if (!strcmp(str, "mm6"))
return MM6;
else if (!strcmp(str, "mm7"))
return MM7;
else if (!strcmp(str, "xmm0"))
return XMM0;
else if (!strcmp(str, "xmm1"))
return XMM1;
else if (!strcmp(str, "xmm2"))
return XMM2;
else if (!strcmp(str, "xmm3"))
return XMM3;
else if (!strcmp(str, "xmm4"))
return XMM4;
else if (!strcmp(str, "xmm5"))
return XMM5;
else if (!strcmp(str, "xmm6"))
return XMM6;
else if (!strcmp(str, "xmm7"))
return XMM7;
else if (!strcmp(str, "cs"))
return CS;
else if (!strcmp(str, "ss"))
return SS;
else if (!strcmp(str, "ds"))
return DS;
else if (!strcmp(str, "es"))
return ES;
else if (!strcmp(str, "fs"))
return FS;
else if (!strcmp(str, "gs"))
return GS;
else if (!strcmp(str, "si"))
return SI;
else if (!strcmp(str, "di"))
return DI;
else if (!strcmp(str, "st0"))
return ST0;
return Register_t::None;
}

41
signatures.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef _INCLUDE_SIGNATURES_H_
#define _INCLUDE_SIGNATURES_H_
#include "extension.h"
#include "util.h"
#include <am-string.h>
#include <sm_stringhashmap.h>
class SignatureWrapper {
public:
ke::AString signature;
ke::AString address;
ke::AString offset;
StringHashMap<ParamInfo> args;
CallingConvention callConv;
HookType hookType;
ReturnType retType;
ThisPointerType thisType;
};
class SignatureGameConfig : public ITextListener_SMC {
public:
SignatureWrapper *GetFunctionSignature(const char *function);
public:
//ITextListener_SMC
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
void ReadSMC_ParseStart();
private:
ReturnType GetReturnTypeFromString(const char *str);
HookParamType GetHookParamTypeFromString(const char *str);
Register_t GetCustomRegisterFromString(const char *str);
private:
StringHashMap<SignatureWrapper *> signatures_;
};
extern SignatureGameConfig *g_pSignatures;
#endif

View File

@ -0,0 +1,77 @@
"Games"
{
"cstrike"
{
"Signatures"
{
"Deafen"
{
"library" "server"
"windows" "\x55\x8B\xEC\x83\xEC\x2A\x89\x4D\x2A\x8B\x45\x2A\x8B\x10\x8B\x4D\x2A\x8B\x82\x2A\x2A\x2A\x2A\xFF\xD0\x85\xC0\x74"
"linux" "@_ZN9CCSPlayer6DeafenEf"
}
"CFlashbangProjectile::Detonate"
{
"library" "server"
"windows" "\x53\x56\x8B\xF1\x57\x8B\x86\x2A\x2A\x2A\x2A\xC1\xE8\x2A\xA8\x2A\x74\x2A\xE8\x2A\x2A\x2A\x2A\xD9\x05\x2A\x2A\x2A\x2A\x6A\x40\x6A\x00\x51\x8B\xCE"
"linux" "@_ZN20CFlashbangProjectile8DetonateEv"
}
"PercentageOfFlashForPlayer"
{
"library" "server"
"windows" "\x53\x8B\xDC\x83\xEC\x08\x83\xE4\x2A\x83\xC4\x2A\x55\x8B\x6B\x2A\x89\x6C\x2A\x2A\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\x56\x8B\x73\x08\x8D\x4D\xAC"
"linux" "@_Z26PercentageOfFlashForPlayerP11CBaseEntity6VectorS0_"
}
}
}
"csgo"
{
"Signatures"
{
// "tr_player_flashbanged" is in RadiusFlash which calls CCSPlayer::Deafen and PercentageOfFlashForPlayer
"Deafen"
{
"library" "server"
"windows" "\x55\x8B\xEC\x83\xEC\x28\x56\x57\x8B\xF9\xF3\x0F\x11\x4D\xFC"
"linux" "\x55\x89\xE5\x83\xEC\x48\x89\x7D\xFC\x8B\x7D\x08\x89\x5D\xF4\x89\x75\xF8\x8B\x07"
}
// "flashbang_detonate" and "Scorch"
"CFlashbangProjectile::Detonate"
{
"library" "server"
"windows" "\x55\x8B\xEC\x83\xEC\x6C\x53\x56\x57\x8B\xF1"
"linux" "\x55\x89\xE5\x57\x56\x53\x81\xEC\x0C\x01\x00\x00\x8B\x5D\x08\x89\x1C\x24\xE8\x2A\x2A\x2A\x2A\x85\xC0\x89\xC6"
}
"PercentageOfFlashForPlayer"
{
"library" "server"
"windows" "\x53\x8B\xDC\x83\xEC\x08\x83\xE4\xF0\x83\xC4\x04\x55\x8B\x6B\x04\x89\x6C\x24\x04\x8B\xEC\x81\xEC\x08\x01\x00\x00\x56\x8B\xF1"
"linux" "\x55\x89\xE5\x57\x56\x53\x81\xEC\x9C\x01\x00\x00\x8B\x5D\x08\x8B\x03"
}
}
"Functions"
{
"Deafen"
{
"signature" "Deafen"
"callconv" "thiscall"
"return" "void"
"this" "entity"
"arguments"
{
"distance"
{
"type" "float"
"windows"
{
"register" "xmm1"
}
}
}
}
}
}
}

View File

@ -33,14 +33,17 @@ public void OnPluginStart()
PrintToServer("CFlashbangProjectile::Detonate detoured!");
hFlashbangDeafen = DHookCreateDetour(Address_Null, CallConv_THISCALL, ReturnType_Void, ThisPointer_CBaseEntity);
hFlashbangDeafen = DHookCreateFromConf(temp, "Deafen");
if (!hFlashbangDeafen)
SetFailState("Failed to setup detour for Deafen");
/*hFlashbangDeafen = DHookCreateDetour(Address_Null, CallConv_THISCALL, ReturnType_Void, ThisPointer_CBaseEntity);
if (!hFlashbangDeafen)
SetFailState("Failed to setup detour for Deafen");
if (!DHookSetFromConf(hFlashbangDeafen, temp, SDKConf_Signature, "Deafen"))
SetFailState("Failed to load Deafen signature from gamedata");
DHookAddParam(hFlashbangDeafen, HookParamType_Float, .custom_register=DHookRegister_XMM1);
DHookAddParam(hFlashbangDeafen, HookParamType_Float, .custom_register=DHookRegister_XMM1);*/
if (!DHookEnableDetour(hFlashbangDeafen, false, Detour_OnDeafen))
SetFailState("Failed to detour Deafen.");

View File

@ -219,7 +219,7 @@ native bool DHookRemoveEntityListener(ListenType type, ListenCB callback);
* @param callback Callback function
*
* @return Returns setup handle for the hook.
* @error Failed to create hook setup handle.
* @error Failed to create hook setup handle or invalid callback function.
*/
native Handle DHookCreate(int offset, HookType hooktype, ReturnType returntype, ThisPointerType thistype, DHookCallback callback);
@ -237,6 +237,18 @@ native Handle DHookCreate(int offset, HookType hooktype, ReturnType returntype,
*/
native Handle DHookCreateDetour(Address funcaddr, CallingConvention callConv, ReturnType returntype, ThisPointerType thisType);
/**
* Setup a detour or hook for a function as described in a "Functions" section in gamedata.
*
* @param gameconf GameConfig handle
* @param name Name of the function in the gamedata to load.
* @param callback Callback function (only required for virtual hooks - ignored for detours).
*
* @return Setup handle for the detour or INVALID_HANDLE if offset/signature/address wasn't found.
* @error Failed to create detour setup handle, invalid gamedata handle, invalid callback function or failed to find function in gamedata.
*/
native Handle DHookCreateFromConf(Handle gameconf, const char[] name, DHookCallback callback=INVALID_FUNCTION);
/**
* Load details for a vhook or detour from a gamedata file.
*
@ -246,7 +258,7 @@ native Handle DHookCreateDetour(Address funcaddr, CallingConvention callConv, Re
* @param name Name of the property to find.
*
* @return True on success, false if nothing was found.
* @error Invalid setup handle.
* @error Invalid setup or gamedata handle.
*/
native bool DHookSetFromConf(Handle setup, Handle gameconf, SDKFuncConfSource source, const char[] name);