/** * vim: set ts=4 : * ============================================================================= * SourceMod Sample Extension * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, version 3.0, as published by the * Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . * * As a special exception, AlliedModders LLC gives you permission to link the * code of this program (as well as its derivative works) to "Half-Life 2," the * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software * by the Valve Corporation. You must obey the GNU General Public License in * all respects for all other code used. Additionally, AlliedModders LLC grants * this exception to all derivative works. AlliedModders LLC defines further * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), * or . * * Version: $Id$ */ #include "extension.h" #include "CDetour/detours.h" #include static struct SrcdsPatch { const char *pSignature; const unsigned char *pPatchSignature; const char *pPatchPattern; const unsigned char *pPatch; unsigned char *pOriginal; uintptr_t pAddress; uintptr_t pPatchAddress; } gs_Patches[] = { { "_ZN7CGameUI5ThinkEv", (unsigned char *)"\xC7\x44\x24\x04\x10\x00\x00\x00\x89\x34\x24\xE8\x00\x00\x00\x00", "xxxxxxxxxxxx????", (unsigned char *)"\xC7\x44\x24\x04\x10\x00\x00\x00\x89\x34\x24\x90\x90\x90\x90\x90", 0, 0, 0 }, { "_ZN17CMovementSpeedMod13InputSpeedModER11inputdata_t", (unsigned char *)"\xFF\x90\x8C\x05\x00\x00\x85\xC0\x0F\x85\x75\x02\x00\x00", "xxxxxxxxxxxxxx", (unsigned char *)"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90", 0, 0, 0 } }; class CBaseEntity; struct variant_hax { const char *pszValue; }; struct inputdata_t { // The entity that initially caused this chain of output events. CBaseEntity *pActivator; // The entity that fired this particular output. CBaseEntity *pCaller; // The data parameter for this output. variant_hax value; // The unique ID of the output that was fired. int nOutputID; }; uintptr_t FindPattern(uintptr_t BaseAddr, const unsigned char *pData, const char *pPattern, size_t MaxSize); /** * @file extension.cpp * @brief Implement extension code here. */ CSSFixes g_Interface; SMEXT_LINK(&g_Interface); IGameConfig *g_pGameConf = NULL; CDetour *detourInputTestActivator = NULL; DETOUR_DECL_MEMBER1(InputTestActivator, void, inputdata_t *, inputdata) { if(!inputdata || !inputdata->pActivator || !inputdata->pCaller) return; DETOUR_MEMBER_CALL(InputTestActivator)(inputdata); } bool CSSFixes::SDK_OnLoad(char *error, size_t maxlength, bool late) { char conf_error[255] = ""; if(!gameconfs->LoadGameConfigFile("CSSFixes", &g_pGameConf, conf_error, sizeof(conf_error))) { if(conf_error[0]) snprintf(error, maxlength, "Could not read CSSFixes.txt: %s", conf_error); return false; } CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf); detourInputTestActivator = DETOUR_CREATE_MEMBER(InputTestActivator, "CBaseFilter_InputTestActivator"); if(detourInputTestActivator == NULL) { snprintf(error, maxlength, "Could not create detour for CBaseFilter_InputTestActivator"); return false; } detourInputTestActivator->EnableDetour(); void *pServerSo = dlopen("cstrike/bin/server_srv.so", RTLD_NOW); if(!pServerSo) { snprintf(error, maxlength, "Could not dlopen server_srv.so"); return false; } for(size_t i = 0; i < sizeof(gs_Patches) / sizeof(*gs_Patches); i++) { struct SrcdsPatch *pPatch = &gs_Patches[i]; int PatchLen = strlen(pPatch->pPatchPattern); pPatch->pAddress = (uintptr_t)memutils->ResolveSymbol(pServerSo, pPatch->pSignature); if(!pPatch->pAddress) { snprintf(error, maxlength, "Could not find symbol: %s", pPatch->pSignature); dlclose(pServerSo); SDK_OnUnload(); return false; } pPatch->pPatchAddress = FindPattern(pPatch->pAddress, pPatch->pPatchSignature, pPatch->pPatchPattern, 1024); if(!pPatch->pPatchAddress) { snprintf(error, maxlength, "Could not find patch signature for symbol: %s", pPatch->pSignature); dlclose(pServerSo); SDK_OnUnload(); return false; } pPatch->pOriginal = (unsigned char *)malloc(PatchLen * sizeof(unsigned char)); SourceHook::SetMemAccess((void *)pPatch->pPatchAddress, PatchLen, SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC); for(int j = 0; j < PatchLen; j++) { pPatch->pOriginal[j] = *(unsigned char *)(pPatch->pPatchAddress + j); *(unsigned char *)(pPatch->pPatchAddress + j) = pPatch->pPatch[j]; } SourceHook::SetMemAccess((void *)pPatch->pPatchAddress, PatchLen, SH_MEM_READ|SH_MEM_EXEC); } dlclose(pServerSo); return true; } void CSSFixes::SDK_OnUnload() { if(detourInputTestActivator != NULL) { detourInputTestActivator->Destroy(); detourInputTestActivator = NULL; } gameconfs->CloseGameConfigFile(g_pGameConf); for(size_t i = 0; i < sizeof(gs_Patches) / sizeof(*gs_Patches); i++) { struct SrcdsPatch *pPatch = &gs_Patches[i]; int PatchLen = strlen(pPatch->pPatchPattern); if(!pPatch->pOriginal) continue; SourceHook::SetMemAccess((void *)pPatch->pPatchAddress, PatchLen, SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC); for(int j = 0; j < PatchLen; j++) { *(unsigned char *)(pPatch->pPatchAddress + j) = pPatch->pOriginal[j]; } SourceHook::SetMemAccess((void *)pPatch->pPatchAddress, PatchLen, SH_MEM_READ|SH_MEM_EXEC); free(pPatch->pOriginal); pPatch->pOriginal = NULL; } } bool CSSFixes::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) { return true; } uintptr_t FindPattern(uintptr_t BaseAddr, const unsigned char *pData, const char *pPattern, size_t MaxSize) { unsigned char *pMemory; uintptr_t PatternLen = strlen(pPattern); pMemory = reinterpret_cast(BaseAddr); for(uintptr_t i = 0; i < MaxSize; i++) { uintptr_t Matches = 0; while(*(pMemory + i + Matches) == pData[Matches] || pPattern[Matches] != 'x') { Matches++; if(Matches == PatternLen) return (uintptr_t)(pMemory + i); } } return 0x00; }