#include "amxxmodule.h" #include #define OFFSET_TEAM 456 #define TEAM_SPECTATOR 3 #define FREELOOK_ENABLE 0 #define FREELOOK_DISABLE 1 const BYTE signature[]= {0x8B,0x83,0xC8,0x01,0x00,0x00,0xC6,0x44,0x24,0x1C,0x01,0x83,0xF8,0x03}; BYTE patch[]= {0xC6,0x44,0x24,0x1C,0x01,0xB8,0x90,0x90,0x90,0x90,0xFF,0xD0,0x85,0xC0}; cvar_t amx_adminfreelook = {"amx_adminfreelook", "1", 1, 1.0}; cvar_t amx_adminfreelookflag = {"amx_adminfreelookflag", "d"}; cvar_t *amx_afl; cvar_t *amx_aflf; static DWORD get_patch_loc() { MEMORY_BASIC_INFORMATION mem; if(!VirtualQuery(MDLL_AddToFullPack, &mem, sizeof(mem))) return NULL; if(mem.AllocationBase == NULL) return NULL; DWORD address = (DWORD)mem.AllocationBase; IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)address; if(IsBadReadPtr(dos, sizeof(IMAGE_DOS_HEADER)) || dos->e_magic != IMAGE_DOS_SIGNATURE) return NULL; address += dos->e_lfanew; IMAGE_NT_HEADERS *pe = (IMAGE_NT_HEADERS *)address; if(IsBadReadPtr(pe, sizeof(IMAGE_NT_HEADERS)) || pe->Signature != IMAGE_NT_SIGNATURE) return NULL; DWORD begin = address + pe->OptionalHeader.BaseOfCode; DWORD end = begin + pe->OptionalHeader.SizeOfCode - sizeof(signature); for(DWORD addr = begin; addr < end; ++addr) { if(!memcmp((PVOID)addr, signature, sizeof(signature))) return addr; } return NULL; } inline int PrivateToIndex(const PVOID pdata) { if(pdata) { char *ptr = (char *)pdata; ptr += 4; entvars_t *pev = *(entvars_t **)ptr; if(pev && pev->pContainingEntity) return ENTINDEX(pev->pContainingEntity); } return -1; } int UTIL_ReadFlags(const char* c) { int flags = 0; while(*c) flags |= (1<<(*c++ - 'a')); return flags; } int admin_freelook() { int team; __asm mov eax, [ebx + OFFSET_TEAM]; __asm mov team, eax; if(amx_afl->value == 0) return team != TEAM_SPECTATOR; PVOID pWatcher = NULL; __asm mov pWatcher, ebx; int id = PrivateToIndex(pWatcher); if(MF_GetPlayerFlags(id) & UTIL_ReadFlags(amx_aflf->string)) return FREELOOK_ENABLE; return team != TEAM_SPECTATOR; } void OnMetaAttach() { PVOID addr = (PVOID)get_patch_loc(); if(!addr) { SERVER_PRINT("[ADMIN FREE LOOK] patch failed.\n"); return; } union { PVOID func; BYTE fbyte[4]; }ptob; ptob.func = &admin_freelook; patch[6] = ptob.fbyte[0]; patch[7] = ptob.fbyte[1]; patch[8] = ptob.fbyte[2]; patch[9] = ptob.fbyte[3]; DWORD oldflags; if(VirtualProtect(addr, sizeof(signature), PAGE_EXECUTE_READWRITE, &oldflags)) { memcpy(addr, patch, sizeof(patch)); DWORD flags; if(VirtualProtect(addr, sizeof(signature), oldflags, &flags)) { SERVER_PRINT("[ADMIN FREE LOOK] patch succeed.\n"); CVAR_REGISTER(&amx_adminfreelook); CVAR_REGISTER(&amx_adminfreelookflag); amx_afl = CVAR_GET_POINTER(amx_adminfreelook.name); amx_aflf = CVAR_GET_POINTER(amx_adminfreelookflag.name); return; } } SERVER_PRINT("[ADMIN FREE LOOK] patch failed.\n"); return; }