Это статья скорее о том как использовать Hamsandwich при кодинге на pawn для AmxModX.
Меня же интересует реализация механизмов работы этого модуля на С++.
---------------------------------------------------------------------------------
В этой теме судя по обсуждению, его участники приходят к какому-то решению, но самого решения нет.
Там же есть ссылка на
Вы должны зарегистрироваться, чтобы видеть ссылки., где подробно рассматривается алгоритм перехвата, который заключается в получении адреса таблицы виртуальных функций класса через его экземпляр с последующим патчем адресов функций, но приведенное решение является лишь наброском.
На данный момент я использую такой код установки хука для Spawn, взятый с alliedmods:
[pawn]
void *someFunc = NULL;
void SetHooks(void)
{
//Полученние экземпляра класса игрока через ENTITY
const char *classname = "player";
edict_t *pEdict = CREATE_ENTITY();
CALL_GAME_ENTITY(PLID, classname, &pEdict->v);
if(pEdict->pvPrivateData == NULL)
{
REMOVE_ENTITY(pEdict);
return;
}
//Получение таблицы виртуальных функций через pvPrivateData экземпляра
void *pthis = pEdict->pvPrivateData;
void **vtbl = *(void ***)pthis;
REMOVE_ENTITY(pEdict);
if(vtbl == NULL)
return;
//Получаем адрес оригинальной функции Spawn
someFunc = vtbl[0];
int **ivtbl = (int **)vtbl;
//Меняем тип доступа к памяти и подменяем адрес оригинальной функции своей функцией Hook_Spawn;
DWORD oldflags;
if(VirtualProtect(&ivtbl[0], sizeof(int *), PAGE_READWRITE, &oldflags))
{
ivtbl[0] = (int *)Hook_Spawn;
}
}
[/pawn]
Функция которая получает управление при spawn'е игрока имеет вид:
[pawn]
void Hook_Spawn(void)
{
void *pthis;
__asm mov pthis, ecx;
//действия до вызова оригинала
SERVER_PRINT("::Spawn(void) prehook!\n");
//вызов оригинальной функции
#if defined _WIN32
reinterpret_cast<void (__fastcall*)(void*,int)>(someFunc)(pthis,0);
#elif defined __linux__
reinterpret_cast<void (*)(void*)>(someFunc)(pthis);
#endif
//действия после вызова оригинала
SERVER_PRINT("::Spawn(void) posthook!\n");
}
[/pawn]
Сейчас трудность заключается в той же проблеме, которая обсуждалась ранее. А именно вызов оригинальной функции, при котором возникает ошибка доступа к памяти и сервер падает.
Причины возникновения ошибки пока не ясны.