1.1 --- a/extensions/tf2/CDetour/detours.cpp Thu Feb 19 14:22:22 2009 +1300
1.2 +++ b/extensions/tf2/CDetour/detours.cpp Thu Feb 26 12:42:13 2009 +1300
1.3 @@ -26,7 +26,7 @@
1.4 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.5 * or <http://www.sourcemod.net/license.php>.
1.6 *
1.7 -* Version: $Id$
1.8 +* Version: $Id: detours.cpp 248 2008-08-27 00:56:22Z pred $
1.9 */
1.10
1.11 #include "detours.h"
1.12 @@ -34,7 +34,6 @@
1.13
1.14 ISourcePawnEngine *CDetourManager::spengine = NULL;
1.15 IGameConfig *CDetourManager::gameconf = NULL;
1.16 -int CDetourManager::returnValue = 0;
1.17
1.18 void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
1.19 {
1.20 @@ -42,9 +41,9 @@
1.21 CDetourManager::gameconf = gameconf;
1.22 }
1.23
1.24 -CDetour *CDetourManager::CreateDetour(void *callbackfunction, size_t paramsize, const char *signame)
1.25 +CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, const char *signame)
1.26 {
1.27 - CDetour *detour = new CDetour(callbackfunction, paramsize, signame);
1.28 + CDetour *detour = new CDetour(callbackfunction, trampoline, signame);
1.29 if (detour)
1.30 {
1.31 if (!detour->Init(spengine, gameconf))
1.32 @@ -59,50 +58,17 @@
1.33 return NULL;
1.34 }
1.35
1.36 -void CDetourManager::DeleteDetour(CDetour *detour)
1.37 -{
1.38 - delete detour;
1.39 -}
1.40 -
1.41 -CBlocker * CDetourManager::CreateFunctionBlock( const char *signame, bool isVoid )
1.42 -{
1.43 - CBlocker *block = new CBlocker(signame, isVoid);
1.44 -
1.45 - if (block)
1.46 - {
1.47 - if (!block->Init(spengine, gameconf))
1.48 - {
1.49 - delete block;
1.50 - return NULL;
1.51 - }
1.52 -
1.53 - return block;
1.54 - }
1.55 -
1.56 - return NULL;
1.57 -}
1.58 -
1.59 -void CDetourManager::DeleteFunctionBlock(CBlocker *block)
1.60 -{
1.61 - delete block;
1.62 -}
1.63 -
1.64 -CDetour::CDetour(void *callbackfunction, size_t paramsize, const char *signame)
1.65 +CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame)
1.66 {
1.67 enabled = false;
1.68 detoured = false;
1.69 detour_address = NULL;
1.70 - detour_callback = NULL;
1.71 + detour_trampoline = NULL;
1.72 this->signame = signame;
1.73 - this->callbackfunction = callbackfunction;
1.74 + this->detour_callback = callbackfunction;
1.75 spengine = NULL;
1.76 gameconf = NULL;
1.77 - this->paramsize = paramsize;
1.78 -}
1.79 -
1.80 -CDetour::~CDetour()
1.81 -{
1.82 - DeleteDetour();
1.83 + this->trampoline = trampoline;
1.84 }
1.85
1.86 bool CDetour::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
1.87 @@ -121,6 +87,12 @@
1.88 return enabled;
1.89 }
1.90
1.91 +void CDetour::Destroy()
1.92 +{
1.93 + DeleteDetour();
1.94 + delete this;
1.95 +}
1.96 +
1.97 bool CDetour::IsEnabled()
1.98 {
1.99 return enabled;
1.100 @@ -148,7 +120,6 @@
1.101 detour_restore.patch[i] = ((unsigned char *)detour_address)[i];
1.102 }
1.103
1.104 - //detour_callback = spengine->ExecAlloc(100);
1.105 JitWriter wr;
1.106 JitWriter *jit = ≀
1.107 jit_uint32_t CodeSize = 0;
1.108 @@ -158,47 +129,6 @@
1.109
1.110 jit_rewind:
1.111
1.112 - /* Push all our params onto the stack */
1.113 - for (size_t i=0; i<paramsize; i++)
1.114 - {
1.115 -#if defined PLATFORM_WINDOWS
1.116 - IA32_Push_Rm_Disp8_ESP(jit, (paramsize*4));
1.117 -#elif defined PLATFORM_LINUX
1.118 - IA32_Push_Rm_Disp8_ESP(jit, 4 +(paramsize*4));
1.119 -#endif
1.120 - }
1.121 -
1.122 - /* Push thisptr onto the stack */
1.123 -#if defined PLATFORM_WINDOWS
1.124 - IA32_Push_Reg(jit, REG_ECX);
1.125 -#elif defined PLATFORM_LINUX
1.126 - IA32_Push_Rm_Disp8_ESP(jit, 4 + (paramsize*4));
1.127 -#endif
1.128 -
1.129 - jitoffs_t call = IA32_Call_Imm32(jit, 0);
1.130 - IA32_Write_Jump32_Abs(jit, call, callbackfunction);
1.131 -
1.132 - /* Pop thisptr */
1.133 -#if defined PLATFORM_LINUX
1.134 - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); //add esp, 4
1.135 -#elif defined PLATFORM_WINDOWS
1.136 - IA32_Pop_Reg(jit, REG_ECX);
1.137 -#endif
1.138 -
1.139 - /* Pop params from the stack */
1.140 - for (size_t i=0; i<paramsize; i++)
1.141 - {
1.142 - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
1.143 - }
1.144 -
1.145 - //If TempDetour returns non-zero we want to load something into eax and return this value
1.146 -
1.147 - //test eax, eax
1.148 - IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG);
1.149 -
1.150 - //jnz _skip
1.151 - jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
1.152 -
1.153 /* Patch old bytes in */
1.154 if (wr.outbase != NULL)
1.155 {
1.156 @@ -207,15 +137,8 @@
1.157 wr.outptr += detour_restore.bytes;
1.158
1.159 /* Return to the original function */
1.160 - call = IA32_Jump_Imm32(jit, 0);
1.161 + jitoffs_t call = IA32_Jump_Imm32(jit, 0);
1.162 IA32_Write_Jump32_Abs(jit, call, (unsigned char *)detour_address + detour_restore.bytes);
1.163 -
1.164 - //_skip:
1.165 - //mov eax, [g_returnvalue]
1.166 - //ret
1.167 - IA32_Send_Jump8_Here(jit, jmp);
1.168 - IA32_Mov_Eax_Mem(jit, (jit_int32_t)&CDetourManager::returnValue);
1.169 - IA32_Return(jit);
1.170
1.171 if (wr.outbase == NULL)
1.172 {
1.173 @@ -223,15 +146,32 @@
1.174 wr.outbase = (jitcode_t)spengine->AllocatePageMemory(CodeSize);
1.175 spengine->SetReadWrite(wr.outbase);
1.176 wr.outptr = wr.outbase;
1.177 - detour_callback = wr.outbase;
1.178 + detour_trampoline = wr.outbase;
1.179 goto jit_rewind;
1.180 }
1.181
1.182 spengine->SetReadExecute(wr.outbase);
1.183
1.184 + *trampoline = detour_trampoline;
1.185 +
1.186 return true;
1.187 }
1.188
1.189 +void CDetour::DeleteDetour()
1.190 +{
1.191 + if (detoured)
1.192 + {
1.193 + DisableDetour();
1.194 + }
1.195 +
1.196 + if (detour_trampoline)
1.197 + {
1.198 + /* Free the allocated trampoline memory */
1.199 + spengine->FreePageMemory(detour_trampoline);
1.200 + detour_trampoline = NULL;
1.201 + }
1.202 +}
1.203 +
1.204 void CDetour::EnableDetour()
1.205 {
1.206 if (!detoured)
1.207 @@ -241,132 +181,12 @@
1.208 }
1.209 }
1.210
1.211 -void CDetour::DeleteDetour()
1.212 -{
1.213 - if (detoured)
1.214 - {
1.215 - DisableDetour();
1.216 - }
1.217 -
1.218 - if (detour_callback)
1.219 - {
1.220 - /* Free the gate */
1.221 - spengine->FreePageMemory(detour_callback);
1.222 - detour_callback = NULL;
1.223 - }
1.224 -}
1.225 -
1.226 void CDetour::DisableDetour()
1.227 {
1.228 if (detoured)
1.229 {
1.230 /* Remove the patch */
1.231 - /* This may screw up */
1.232 ApplyPatch(detour_address, 0, &detour_restore, NULL);
1.233 detoured = false;
1.234 }
1.235 }
1.236 -
1.237 -CBlocker::CBlocker( const char *signame, bool isVoid )
1.238 -{
1.239 - this->isVoid = isVoid;
1.240 - isEnabled = false;
1.241 - isValid = false;
1.242 -
1.243 - spengine = NULL;
1.244 - gameconf = NULL;
1.245 - block_address = NULL;
1.246 - block_sig = signame;
1.247 -
1.248 - if (isVoid)
1.249 - {
1.250 - /* Void functions we only patch in a 'ret' (1 byte) */
1.251 - block_restore.bytes = 1;
1.252 - }
1.253 - else
1.254 - {
1.255 - /* Normal functions need an mov eax, value */
1.256 - block_restore.bytes = 6;
1.257 - }
1.258 -}
1.259 -
1.260 -void CBlocker::EnableBlock( int returnValue )
1.261 -{
1.262 - if (!isValid || isEnabled)
1.263 - {
1.264 - return;
1.265 - }
1.266 -
1.267 - /* First, save restore bits */
1.268 - for (size_t i=0; i<block_restore.bytes; i++)
1.269 - {
1.270 - block_restore.patch[i] = ((unsigned char *)block_address)[i];
1.271 - }
1.272 -
1.273 - JitWriter wr;
1.274 - JitWriter *jit = ≀
1.275 - wr.outbase = (jitcode_t)block_address;
1.276 - wr.outptr = wr.outbase;
1.277 -
1.278 - if (isVoid)
1.279 - {
1.280 - IA32_Return(jit);
1.281 - }
1.282 - else
1.283 - {
1.284 - IA32_Mov_Reg_Imm32(jit, REG_EAX, returnValue);
1.285 - IA32_Return(jit);
1.286 - }
1.287 -
1.288 - isEnabled = true;
1.289 -}
1.290 -
1.291 -void CBlocker::DisableBlock()
1.292 -{
1.293 - if (!isValid || !isEnabled)
1.294 - {
1.295 - return;
1.296 - }
1.297 -
1.298 - /* First, save restore bits */
1.299 - for (size_t i=0; i<block_restore.bytes; i++)
1.300 - {
1.301 - ((unsigned char *)block_address)[i] = block_restore.patch[i];
1.302 - }
1.303 -
1.304 - isEnabled = false;
1.305 -}
1.306 -
1.307 -CBlocker::~CBlocker()
1.308 -{
1.309 - if (!isValid || !isEnabled)
1.310 - {
1.311 - return;
1.312 - }
1.313 -
1.314 - DisableBlock();
1.315 -}
1.316 -
1.317 -bool CBlocker::Init( ISourcePawnEngine *spengine, IGameConfig *gameconf )
1.318 -{
1.319 - this->spengine = spengine;
1.320 - this->gameconf = gameconf;
1.321 -
1.322 - if (!gameconf->GetMemSig(block_sig, &block_address))
1.323 - {
1.324 - g_pSM->LogError(myself, "Could not locate %s - Disabling blocker", block_sig);
1.325 - isValid = false;
1.326 - return false;
1.327 - }
1.328 -
1.329 - if (!block_address)
1.330 - {
1.331 - g_pSM->LogError(myself, "Sigscan for %s failed - Disabling blocker", block_sig);
1.332 - isValid = false;
1.333 - return false;
1.334 - }
1.335 -
1.336 - isValid = true;
1.337 -
1.338 - return true;
1.339 -}