bool CDetour::CreateDetour() { if (!gameconf->GetMemSig(signame, &detour_address)) { g_pSM->LogError(myself, "Could not locate %s - Disabling detour", signame); return false; } if (!detour_address) { g_pSM->LogError(myself, "Sigscan for %s failed - Disabling detour to prevent crashes", signame); return false; } detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE+1); /* First, save restore bits */ for (size_t i=0; i<detour_restore.bytes; i++) { detour_restore.patch[i] = ((unsigned char *)detour_address)[i]; } JitWriter wr; JitWriter *jit = ≀ jit_uint32_t CodeSize = 0; wr.outbase = NULL; wr.outptr = NULL; jit_rewind: /* Patch old bytes in */ if (wr.outbase != NULL) { copy_bytes((unsigned char *)detour_address, (unsigned char*)wr.outptr, detour_restore.bytes); } wr.outptr += detour_restore.bytes; /* Return to the original function */ jitoffs_t call = IA32_Jump_Imm32(jit, 0); IA32_Write_Jump32_Abs(jit, call, (unsigned char *)detour_address + detour_restore.bytes); if (wr.outbase == NULL) { CodeSize = wr.get_outputpos(); wr.outbase = (jitcode_t)spengine->AllocatePageMemory(CodeSize); spengine->SetReadWrite(wr.outbase); wr.outptr = wr.outbase; detour_trampoline = wr.outbase; goto jit_rewind; } spengine->SetReadExecute(wr.outbase); *trampoline = detour_trampoline; return true; }
// this was pretty much copied verbatim from pRED's CBaseServer code. Too much I didn't // understand in this area .... yet bool CDetour::StartDetour() { if (!DetourAddress) { Msg ("Detour for %s failed - no valid pointer was provided.\n", FunctionDetoured); return false; } orig_bytes.size_stored = copy_bytes((mem_t *)DetourAddress, NULL, OP_JMP_SIZE+1); for ( size_t i=0; i < orig_bytes.size_stored; i++ ) orig_bytes.bytes_from_memory[i] = ((mem_t *)DetourAddress)[i]; JitWriter wr; JitWriter *jit = ≀ jit_uint32_t CodeSize = 0; wr.outbase = NULL; wr.outptr = NULL; jit_rewind: /* Patch old bytes in */ if (wr.outbase != NULL) copy_bytes((mem_t *)DetourAddress, (mem_t *)wr.outptr, orig_bytes.size_stored); wr.outptr += orig_bytes.size_stored; /* Return to the original function */ jitoffs_t call = IA32_Jump_Imm32(jit, 0); IA32_Write_Jump32_Abs(jit, call, (mem_t *)DetourAddress + orig_bytes.size_stored); if (wr.outbase == NULL) { CodeSize = wr.get_outputpos(); wr.outbase = (jitcode_t)KE_AllocCode(g_pCodeCache, CodeSize); wr.outptr = wr.outbase; TrampolineAddress = wr.outbase; goto jit_rewind; } *TrampolineFunc = TrampolineAddress; return true; }
bool CriticalHitManager::CreateCriticalDetour() { if (!g_pGameConf->GetMemSig("CalcCritical", &critical_address) || !critical_address) { g_pSM->LogError(myself, "Could not locate CalcCritical - Disabling Critical Hit forward"); return false; } if (!g_pGameConf->GetOffset("CalcCriticalBackup", (int *)&(critical_restore.bytes))) { g_pSM->LogError(myself, "Could not locate CalcCriticalBackup - Disabling Critical Hit forward"); return false; } /* First, save restore bits */ for (size_t i=0; i<critical_restore.bytes; i++) { critical_restore.patch[i] = ((unsigned char *)critical_address)[i]; } critical_callback = spengine->ExecAlloc(100); JitWriter wr; JitWriter *jit = ≀ wr.outbase = (jitcode_t)critical_callback; wr.outptr = wr.outbase; /* Function we are detouring into is * * void CriticalDetour(CTFWeaponBase(void *) *pWeapon) * * push pWeapon [ecx] */ #if defined PLATFORM_WINDOWS IA32_Push_Reg(jit, REG_ECX); #elif defined PLATFORM_LINUX IA32_Push_Rm_Disp8_ESP(jit, 4); #endif jitoffs_t call = IA32_Call_Imm32(jit, 0); IA32_Write_Jump32_Abs(jit, call, (void *)TempDetour); #if defined PLATFORM_LINUX IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); //add esp, 4 #elif defined PLATFORM_WINDOWS IA32_Pop_Reg(jit, REG_ECX); #endif //If TempDetour returns non-zero we want to load something into eax and return this value //IA32_Test_Rm_Reg(jit, eax, eax, something); jit->write_ubyte(0x85); jit->write_ubyte(0xC0); //JNZ critical_callback+50 jit->write_ubyte(0x75); jit->write_ubyte(50-((jit->outptr+1)-jit->outbase)); /* Patch old bytes in */ for (size_t i=0; i<critical_restore.bytes; i++) { jit->write_ubyte(critical_restore.patch[i]); } /* Return to the original function */ call = IA32_Jump_Imm32(jit, 0); IA32_Write_Jump32_Abs(jit, call, (unsigned char *)critical_address + critical_restore.bytes); wr.outbase = (jitcode_t)critical_callback+50; wr.outptr = wr.outbase; //copy g_returnvalue into eax jit->write_ubyte(0xA1); jit->write_uint32((jit_uint32_t)&g_returnvalue); IA32_Return(jit); return true; }
bool CriticalHitManager::CreateCriticalMeleeDetour() { if (!g_pGameConf->GetMemSig("CalcCriticalMelee", &melee_address) || !melee_address) { g_pSM->LogError(myself, "Could not locate CalcCriticalMelee - Disabling Critical Hit forward"); return false; } if (!g_pGameConf->GetOffset("CalcCriticalMeleeBackup", (int *)&(melee_restore.bytes))) { g_pSM->LogError(myself, "Could not locate CalcCriticalMeleeBackup - Disabling Critical Hit forward"); return false; } /* First, save restore bits */ for (size_t i=0; i<melee_restore.bytes; i++) { melee_restore.patch[i] = ((unsigned char *)melee_address)[i]; } melee_callback = spengine->ExecAlloc(100); JitWriter wr; JitWriter *jit = ≀ wr.outbase = (jitcode_t)melee_callback; wr.outptr = wr.outbase; /* Function we are detouring into is * * void CriticalDetour(CTFWeaponBase(void *) *pWeapon) * * push pWeapon [ecx] */ #if defined PLATFORM_WINDOWS IA32_Push_Reg(jit, REG_ECX); #elif defined PLATFORM_LINUX IA32_Push_Rm_Disp8_ESP(jit, 4); #endif jitoffs_t call = IA32_Call_Imm32(jit, 0); IA32_Write_Jump32_Abs(jit, call, (void *)TempDetour); #if defined PLATFORM_LINUX IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); //add esp, 4 #elif defined PLATFORM_WINDOWS IA32_Pop_Reg(jit, REG_ECX); #endif //If TempDetour returns non-zero we want to load something into eax and return this value //IA32_Test_Rm_Reg(jit, eax, eax, something); jit->write_ubyte(0x85); jit->write_ubyte(0xC0); //JNZ critical_callback+50 jit->write_ubyte(0x75); jit->write_ubyte(50-((jit->outptr+1)-jit->outbase)); int callbyte = -1; /* The callbyte should return the nth byte (starting from 1) in the backup bytes - Should be an 0xE8 (call) */ g_pGameConf->GetOffset("CalcCriticalMeleeCallByte", &callbyte); callbyte--; void *function = NULL; if (callbyte > -1) { /* Check if the 'callbyte' is actually a call */ if (melee_restore.patch[callbyte] != 0xE8) { g_pSM->LogError(myself, "Invalid callbyte - Melee detour may work incorrectly"); } else { /* Find the absolute address of the function it calls */ void *offsetaddr = (void *)((unsigned char *)melee_address + callbyte + 1); int offset = (int)*(unsigned char *)offsetaddr; function = (unsigned char *)offsetaddr + offset + 4; } } /* Patch old bytes in */ for (size_t i=0; i<melee_restore.bytes; i++) { if ((int)i != callbyte) { jit->write_ubyte(melee_restore.patch[i]); continue; } /* Write in the adjusted call instead */ jitoffs_t call = IA32_Call_Imm32(jit, 0); IA32_Write_Jump32_Abs(jit, call, function); i += 4; } /* Return to the original function */ call = IA32_Jump_Imm32(jit, 0); IA32_Write_Jump32_Abs(jit, call, (unsigned char *)melee_address + melee_restore.bytes); wr.outbase = (jitcode_t)melee_callback+50; wr.outptr = wr.outbase; //copy g_returnvalue into eax jit->write_ubyte(0xA1); jit->write_uint32((jit_uint32_t)&g_returnvalue); IA32_Return(jit); return true; }