OvidiuS icon

Hook Module

OvidiuS | PRO | 08/30/12 05:11:34 PM UTC | 0 ⭐ | 591 👁️ | Never ⏰ | []
C++ |

8.81 KB

|

None

|

0 👍

/

0 👎

#include <extdll.h>
#include <meta_api.h>
#include <stdarg.h>
#include <cbase.h>
 
#ifdef __linux__
    #include <sys/mman.h>
    #include <malloc.h>
#endif
 
#if _MSC_VER
    #if _MSC_VER >= 1400
        #define stricmp _stricmp
    #endif
#endif
 
#ifdef __linux__
    #define stricmp strcasecmp
#endif
 
#ifdef _WIN32
    #define VirtFuncSpawn       0
    #define VirtFuncTakeDamage  12
#elif __linux__
    #define VirtFuncSpawn       2
    #define VirtFuncTakeDamage  14
#endif
 
#ifdef _WIN32
    #define PrivateToEdict(pPrivate) (*(entvars_t **)((char*)pPrivate + 4))->pContainingEntity
#elif __linux__
    #define PrivateToEdict(pPrivate) (*(entvars_t **)pPrivate)->pContainingEntity
#endif
 
plugin_info_t Plugin_info =
{
    META_INTERFACE_VERSION,            // ifvers
    "WPMG",                  // name
    "Alpha",                        // version
    "2011/11/7",                  // date
    "WPMG Team",                     // author
    "http://www.wpmg.ru",            // url
    "WPMG",                  // logtag, all caps please
    PT_ANYTIME,                     // (when) loadable
    PT_ANYPAUSE                     // (when) unloadable
};
 
meta_globals_t *gpMetaGlobals;
mutil_funcs_t *gpMetaUtilFuncs;
enginefuncs_t g_engfuncs;
globalvars_t  *gpGlobals;
 
bool g_bActivated = false;
bool g_bInitialized = false;
 
void *pOrigFuncSpawn = NULL;
void *pOrigFuncTakeDamage = NULL;
 
void print_srvconsole(char *fmt, ...)
{
        va_list argptr;
        static char string[384];
        va_start(argptr, fmt);
        vsnprintf(string, sizeof(string) - 1, fmt, argptr);
        string[sizeof(string) - 1] = '\0';
        va_end(argptr);
       
        SERVER_PRINT(string);
}
 
#ifdef _WIN32
void __fastcall HookSpawn(void *pthis)
#elif __linux__
void HookSpawn(void *pthis)
#endif
{
    print_srvconsole("::Spawn(void) %d prehook!\n", ENTINDEX(PrivateToEdict(pthis)));
 
#ifdef _WIN32
    reinterpret_cast<int (__fastcall *)(void *, int)>(pOrigFuncSpawn)(pthis, 0);
#elif __linux__
    reinterpret_cast<int (*)(void *)>(pOrigFuncSpawn)(pthis);
#endif
 
    SERVER_PRINT("::Spawn(void) posthook!\n");
}
 
#ifdef _WIN32
int __fastcall HookTakeDamage(void *pthis, int i, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamage)
#elif __linux__
int HookTakeDamage(void *pthis, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamage)
#endif
{
    SERVER_PRINT("::TakeDamage(int) prehook!\n");
 
#ifdef _WIN32
    int iOrigRet = reinterpret_cast<int (__fastcall *)(void *, int, entvars_t *, entvars_t *, float, int)>(pOrigFuncTakeDamage)(pthis, 0, pevInflictor, pevAttacker, flDamage, bitsDamage);
#elif __linux__
    int iOrigRet = reinterpret_cast<int (*)(void *, entvars_t *, entvars_t *, float, int)>(pOrigFuncTakeDamage)(pthis, pevInflictor, pevAttacker, flDamage, bitsDamage);
#endif
 
    SERVER_PRINT("::TakeDamage(int) posthook!\n");
 
    return iOrigRet;
}
 
void MakeHookSpawn()
{
    edict_t *pEdict = CREATE_ENTITY();
 
    CALL_GAME_ENTITY(PLID, "player", &pEdict->v);
    
    if (pEdict->pvPrivateData == NULL)
    {
        REMOVE_ENTITY(pEdict);
        
        return;
    }
 
#ifdef _WIN32
    void **vtable = *((void***)((char*)pEdict->pvPrivateData));
#elif __linux__
    void **vtable = *((void***)(((char*)pEdict->pvPrivateData) + 0x94));
#endif
    
    REMOVE_ENTITY(pEdict);
    
    if(vtable == NULL)
        return;
    
    int **ivtable = (int **)vtable;
    
    pOrigFuncSpawn = (void *)ivtable[VirtFuncSpawn];
    
#ifdef _WIN32
    DWORD OldFlags;
 
    VirtualProtect(&ivtable[VirtFuncSpawn], sizeof(int *), PAGE_READWRITE, &OldFlags);
#elif __linux__
    mprotect(&ivtable[VirtFuncSpawn], sizeof(int*), PROT_READ | PROT_WRITE);
#endif
 
    ivtable[VirtFuncSpawn] = (int *)HookSpawn;
}
 
void MakeHookTakeDamage()
{
    edict_t *pEdict = CREATE_ENTITY();
 
    CALL_GAME_ENTITY(PLID, "player", &pEdict->v);
    
    if (pEdict->pvPrivateData == NULL)
    {
        REMOVE_ENTITY(pEdict);
        
        return;
    }
 
#ifdef _WIN32
    void **vtable = *((void***)((char*)pEdict->pvPrivateData));
#elif __linux__
    void **vtable = *((void***)(((char*)pEdict->pvPrivateData) + 0x94));
#endif
 
    REMOVE_ENTITY(pEdict);
    
    if(vtable == NULL)
        return;
    
    int **ivtable = (int **)vtable;
    
    pOrigFuncTakeDamage = (void *)ivtable[VirtFuncTakeDamage];
    
#ifdef _WIN32
    DWORD OldFlags;
 
    VirtualProtect(&ivtable[VirtFuncTakeDamage], sizeof(int *), PAGE_READWRITE, &OldFlags);
#elif __linux__
    mprotect(&ivtable[VirtFuncTakeDamage], sizeof(int*), PROT_READ | PROT_WRITE);
#endif
 
    ivtable[VirtFuncTakeDamage] = (int *)HookTakeDamage;
}
 
void ServerActivatePost(edict_t *pEdictList, int edictCount, int clientMax)
{
    if (g_bActivated)
        RETURN_META(MRES_IGNORED);
 
    MakeHookSpawn();
    MakeHookTakeDamage();
 
    g_bActivated = true;
 
    RETURN_META(MRES_IGNORED);
}
 
void ServerDeactivatePost()
{
    if (!g_bInitialized)
        RETURN_META(MRES_IGNORED);
 
    g_bInitialized = false;
 
    RETURN_META(MRES_IGNORED);
}
 
void ClientCommandPost(edict_t *pEntity)
{
    const char *szArg;
 
    szArg = CMD_ARGV(0);
 
    if (stricmp(szArg, "say"))
        RETURN_META(MRES_IGNORED);
 
    szArg = CMD_ARGV(1);
 
    if (stricmp(szArg, "/damage"))
        RETURN_META(MRES_IGNORED);
 
#ifdef _WIN32
    reinterpret_cast<int (__fastcall *)(void *, int, entvars_t *, entvars_t *, float, int)>((*((void***)((char*)pEntity->pvPrivateData)))[VirtFuncTakeDamage])(pEntity->pvPrivateData, 0, &(pEntity->v), &(pEntity->v), 50.0, DMG_SLASH);
#elif defined __linux__
    reinterpret_cast<int (*)(void *, entvars_t *, entvars_t *, float, int)>((*((void***)(((char*)pEntity->pvPrivateData) + 0x94)))[VirtFuncTakeDamage])(pEntity->pvPrivateData, &(pEntity->v), &(pEntity->v), 50.0, DMG_SLASH);
#endif
 
    RETURN_META(MRES_IGNORED);
}
 
int SpawnPre(edict_t *pEnt)
{
    if (g_bInitialized)
        RETURN_META_VALUE(MRES_IGNORED, 0);
 
    g_bActivated = false;
    g_bInitialized = true;
 
    RETURN_META_VALUE(MRES_IGNORED, 0);
}
 
C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs)
{
    gpMetaUtilFuncs = pMetaUtilFuncs;
 
    *pPlugInfo = &Plugin_info;
 
    return(TRUE);
}
 
static META_FUNCTIONS gMetaFunctionTable;
C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs)
{
    gpMetaGlobals = pMGlobals;
 
    gMetaFunctionTable.pfnGetEntityAPI2 = GetEntityAPI2;
    gMetaFunctionTable.pfnGetEntityAPI2_Post = GetEntityAPI2_Post;
 
    memcpy(pFunctionTable, &gMetaFunctionTable, sizeof(META_FUNCTIONS));
    
    return(TRUE);
}
 
#ifdef __linux__
// linux prototype
C_DLLEXPORT void GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals)
{
#else
#ifdef _MSC_VER
// MSVC: Simulate __stdcall calling convention
C_DLLEXPORT __declspec(naked) void GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals)
{
    __asm           // Prolog
    {
        // Save ebp
        push        ebp
        // Set stack frame pointer
        mov         ebp, esp
        // Allocate space for local variables
        // The MSVC compiler gives us the needed size in __LOCAL_SIZE.
        sub         esp, __LOCAL_SIZE
        // Push registers
        push        ebx
        push        esi
        push        edi
    }
#else   // _MSC_VER
#ifdef __GNUC__
// GCC can also work with this
C_DLLEXPORT void __stdcall GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals)
{
#else   // __GNUC__
// compiler not known
#error There is no support (yet) for your compiler. Please use MSVC or GCC compilers or contact the AMX Mod X dev team.
#endif  // __GNUC__
#endif // _MSC_VER
#endif // __linux__
 
    // ** Function core <--
    memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t));
    gpGlobals = pGlobals;
    // --> ** Function core
 
#ifdef _MSC_VER
    // Epilog
    if (sizeof(int*) == 8)
    {   // 64 bit
        __asm
        {
            // Pop registers
            pop edi
            pop esi
            pop ebx
            // Restore stack frame pointer
            mov esp, ebp
            // Restore ebp
            pop ebp
            // 2 * sizeof(int*) = 16 on 64 bit
            ret 16
        }
    }
    else
    {   // 32 bit
        __asm
        {
            // Pop registers
            pop edi
            pop esi
            pop ebx
            // Restore stack frame pointer
            mov esp, ebp
            // Restore ebp
            pop ebp
            // 2 * sizeof(int*) = 8 on 32 bit
            ret 8
        }
    }
#endif // #ifdef _MSC_VER
}
 
DLL_FUNCTIONS gFunctionTable;
C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion)
{
    memset(&gFunctionTable, 0, sizeof(DLL_FUNCTIONS));
 
    gFunctionTable.pfnSpawn = SpawnPre;
 
    memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS));
 
    return 1;
}
 
DLL_FUNCTIONS gFunctionTable_Post;
C_DLLEXPORT int GetEntityAPI2_Post(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion)
{
    memset(&gFunctionTable_Post, 0, sizeof(DLL_FUNCTIONS));
 
    gFunctionTable_Post.pfnServerActivate = ServerActivatePost;
    gFunctionTable_Post.pfnServerDeactivate = ServerDeactivatePost;
    gFunctionTable_Post.pfnClientCommand = ClientCommandPost;
 
    memcpy(pFunctionTable, &gFunctionTable_Post, sizeof(DLL_FUNCTIONS));
 
    return 1;
}

Comments