Просмотр полной версии : [Вопрос] Вызов / перехват public-функций
Приветствую, собственно, появился вопрос, как перехватить или хотя бы вызвать public-функцию (коллбэк) из плагина. Это, по идее, должно делаться примерно также, как и с нативными функциями, так как в структуре AMX_HEADER предусмотрена запись оффесета не только нативных функций, но и public-функций. Код в итоге выглядит примерно вот так, но не работает.
int index;
if(amx_FindPublic(amx, "OnPlayerConnect", &index) != AMX_ERR_NONE) return logprintf("Not found"), 0;
AMX_HEADER* hdr = (AMX_HEADER*)amx->base;
AMX_FUNCSTUB* func_stub = GETENTRY(hdr, publics, index);
AMX_CALLBACK Callback = (AMX_CALLBACK)func_stub->address;
cell retval , PARAMS[] = { 4, 5 };
Callback(amx, index, &retval, PARAMS);
Daniel_Cortez
09.07.2021, 19:58
Так это ж не нативный код, а интерпретируемый. Вызывать его следует с помощью функции amx_Exec.
Об этом я, к сожалению, вспомнил только после этого ответа. А можно ли как-нибудь хукнуть вызов коллбэка?
Есть, конечно, один вариант, до которого я додумался, но он, как не странно, костыльный.
Напрямую в павн создавать нужный коллбэк, и вызывать в нём нативную функцию. В плагине она, в принципе, будет выступать, как коллбэк, но опять же, способ не очень из-за костыля
Проблема решена. В конечном счёте, я разобрался, и вот решение.
Я использовал библиотеку subhook от Zeex (https://github.com/Zeex/subhook)
Пару функций я взял из sampgdk
Пример будет приведён на коллбэке OnPlayerText
cell* amx_GetParamStart(AMX* amx)
{
unsigned char* data = amx->data != NULL
? amx->data
: amx->base + ((AMX_HEADER*)amx->base)->dat;
return (cell*)(data + amx->stk);
}
void amx_GetParamValue(AMX* amx, int index, cell* param)
{
*param = amx_GetParamStart(amx)[index];
}
subhook_t amx_Exec_hook;
void amx_Exec_func(AMX* amx, cell* retval, int index)
{
subhook_remove(amx_Exec_hook);
logprintf("Public-function index: %d", index);
if (index == 10) // У меня 10 = индексу OnPlayerText
{
int playerid;
char text[145];
int len;
cell* addr;
amx_GetParamValue(amx, 0, &playerid);
amx_GetAddr(amx, amx_GetParamStart(amx)[1], &addr); // [1] - это номер параметра, как и 0 на строку выше
amx_StrLen(addr, &len);
amx_GetString(text, addr, NULL, len + 1);
logprintf("%d | %s", playerid, text);
}
amx_Exec(amx, retval, index);
subhook_install(amx_Exec_hook);;
}
PLUGIN_EXPORT bool PLUGIN_CALL Load(void** ppData)
{
#ifndef WIN32_
amx_Exec_hook = subhook_new((void*)0x401C90, (void*)amx_Exec_func, {}); // Адрес для Виндовс
#else
amx_Exec_hook = subhook_new((void*)0x8096780, (void*)amx_Exec_func, {}); // Адрес для Линукс
#endif
subhook_install(amx_Exec_hook);
return true;
}
Эти адреса - адреса функции amx_Exec непосредственно в samp-server.exe и samp03svr
В функцию amx_Exec_func в аргумент index приходит индекс коллбэка. Через amx_FindPublic мы можем сравнять индексы, и узнать, какой именно коллбэк был вызван.
P.S. На линуксе я не тестировал, но уверен, что адрес подойдёт
Powered by vBulletin® Version 4.2.0 Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot