Half-Life и Adrenaline Gamer форум
http://econ.aghl.ru/forum/

Перехват status
http://econ.aghl.ru/forum/viewtopic.php?f=38&t=2207
Страница 1 из 2

Автор:  ImperNik [ 01 июл 2015, 13:25 ]
Заголовок сообщения:  Перехват status

Можно ли средствами metamod перехватить команду status, либо подменить её вывод?

Код:
...
REG_SVR_COMMAND("status", my_status);
...
void DLLHIDDEN my_status(void) {
   META_CONS("Hello!!!");
}
...
Если сделать так, то при запуске будет обычное, ожидаемое сообщение:
Цитата:
Cmd_AddCommand: status already defined

Автор:  Lev [ 01 июл 2015, 18:29 ]
Заголовок сообщения:  Re: Перехват status

Через API нельзя.
Только через поиск в памяти и патчинг.

Автор:  ImperNik [ 01 июл 2015, 19:07 ]
Заголовок сообщения:  Re: Перехват status

А каким образом в памяти это искать?

Автор:  Lev [ 01 июл 2015, 19:42 ]
Заголовок сообщения:  Re: Перехват status

О, блин, полез смотреть как, и понял что сказал неверно.
Можно через API.
https://svn.aghl.ru:8443/svn/HLSDK/trunk/dlls/memory.cpp
Задать где-нибудь структуру
Код:
struct CommandLink
{
   CommandLink *nextCommand;
   char *commandName;
   void (*handler)(void);
   int addedByMod;
};
Привести cl_enginefunc_s к виду
Код:
   void                  ( *pfnGetMousePos )( struct tagPOINT *ppt );
   void                  ( *pfnSetMousePos )( int x, int y );
   void                  ( *pfnSetMouseEnable )( qboolean fEnable );

   int      pfnUnks001[1];

   struct   CommandLink *      ( *pfnGetCommandsList )      ( void );
} cl_enginefunc_t;
Использовать такой код для поиска и подмены:
Код:
void (*g_pOldMotdWriteHandler)(void) = 0;
void MotdWriteHandler(void);

void PatchCommandsList(void)
{
   if (gEngfuncs.pfnGetCommandsList)
   {
      CommandLink *cl;

      // Unhook commands
      cl = gEngfuncs.pfnGetCommandsList();
      while (cl != NULL)
      {
         // Search by address cos some commands has invalidated name references due to unloading process
         if (g_pOldMotdWriteHandler && cl->handler == MotdWriteHandler && !_stricmp(cl->commandName, "motd_write"))
         {
            cl->handler = g_pOldMotdWriteHandler;
            g_pOldMotdWriteHandler = NULL;
         }
         cl = cl->nextCommand;
      }

      // Hook commands
      cl = gEngfuncs.pfnGetCommandsList();
      while (cl != NULL)
      {
         if (!_stricmp(cl->commandName, "motd_write"))
         {
            g_pOldMotdWriteHandler = cl->handler;
            cl->handler = MotdWriteHandler;
         }
         cl = cl->nextCommand;
      }
   }
}
Соответственно есть код для хука и для анхука. Поиск по адресу нужен чтобы не напороться на ссылки на строки в диапазоны адресов уже выгруженных модулей.

Добавлено спустя 1 час 10 минут 29 секунд:
Хотя, в этом случа можно без HookDWord обойтись. Просто заменить значение, оно в области данных находится.

Автор:  ImperNik [ 02 июл 2015, 00:08 ]
Заголовок сообщения:  Re: Перехват status

Погоди, я не настолько крут в написании модулей :)

Пока я дошел до этого:
Вложение:
my_plugin.zip [18.46 КБ]
Скачиваний: 461

Всё, что по сути там делается, это регается команда status2 и после её ввода отправляется ответ. Это всё в my_func.cpp

Что за gEngfuncs? Откуда её взять?
Как я понял, мне нужно еще что-то подключить.

Автор:  Lev [ 02 июл 2015, 00:27 ]
Заголовок сообщения:  Re: Перехват status

Подумал ещё немного и понял что тебе на сервер это надо, а я для клиента написал.
Сейчас напишу как на сервере делать.

Добавлено спустя 1 час 21 минуту 40 секунд:
Вобщем, наиболее оптимальным будет найти функцию Cmd_GetFirstCmd
Код:
typedef struct cmd_function_s
{
   struct cmd_function_s *next;
   char *name;
   xcommand_t function;
   int flags;
} cmd_function_t;

struct cmd_function_s *Cmd_GetFirstCmd(void);

Под линуксом поиск по имени, под виндой по сигнатуре:
Код:
   "A1D83E0002C39090 9090909090909090 6800000000 6800000000 E8",
   "FF00000000FFFFFF FFFFFFFFFFFFFFFF FF00000000 FF00000000 FF",

Дальше использовать как в коде выше. CommandLink - это и есть cmd_function_t.
Вместо
Код:
cl = gEngfuncs.pfnGetCommandsList();
Использовать найденную функцию.

Автор:  ImperNik [ 02 июл 2015, 14:57 ]
Заголовок сообщения:  Re: Перехват status

Что-то делаю не так.

Код:
#include <extdll.h>
#include <meta_api.h>

#include "sdk_util.h"
#include "my_func.h"

typedef void ( *xcommand_t ) ( void );

typedef struct cmd_function_s
{
   struct cmd_function_s *next;
   char *name;
   xcommand_t function;
   int flags;
} cmd_function_t;

struct cmd_function_s *Cmd_GetFirstCmd(void);

void PatchCommandsList(void)
{
   cmd_function_s *cm;
   cm = Cmd_GetFirstCmd();
   
   while (cm != NULL) {
      // Search by address cos some commands has invalidated name references due to unloading process
      if (!strcasecmp(cm->name, "status")) {
         cm->function = NULL;
      }
      cm = cm->next;
   }   
}

void run_my_func()
{
   SERVER_PRINT("All okay\n");
   REG_SVR_COMMAND("status2", my_status);
   PatchCommandsList();
}

void my_status()
{
   SERVER_PRINT("HI!!!\n");
}

В этом случае модуль не грузится (BAD Load).
Если закомментировать
Код:
cm = Cmd_GetFirstCmd();
То произойдёт crash, что итак понятно.
А если вместе с while закомментировать, то модуль запускается. Разве, что нужная подмена status не работает.

Автор:  Lev [ 02 июл 2015, 17:40 ]
Заголовок сообщения:  Re: Перехват status

Код:
struct cmd_function_s *Cmd_GetFirstCmd(void);
Это был лишь прототип функции из движка, чтобы было понятнее о чем речь идет.
Тебе надо так:
Код:
typedef struct cmd_function_s *Cmd_GetFirstCmd_Type(void);
Cmd_GetFirstCmd_Type *pCmd_GetFirstCmd = NULL;

   cm = pCmd_GetFirstCmd();
Т.е. надо указатель на функцию использовать, и для этого надо найти адрес этой функции.
У тебя, похоже, линукс, так что это не сложно:
Код:
size_t HIDDEN FindSymbol(const char* symbolName)
{
   size_t moduleHandle = (size_t)dlopen("engine_i486.so", RTLD_NOW);   // lock from unloading
   size_t address;
   address = (size_t)dlsym((void *)moduleHandle, symbolName);
   return address;
}

   pCmd_GetFirstCmd = (Cmd_GetFirstCmd_Type *)FindSymbol("Cmd_GetFirstCmd");
И ты не можешь просто занулить адрес хендлера
Код:
cm->function = NULL;
Тебе надо свой туда прописать (например my_status). Иначе упадет при вызове в движке.

Автор:  ImperNik [ 02 июл 2015, 18:27 ]
Заголовок сообщения:  Re: Перехват status

Благодарю! Получилось.
Результат ниже, может кому ещё пригодится.
 Результат

Автор:  withou7 [ 29 июл 2015, 23:46 ]
Заголовок сообщения:  Re: Перехват status

Здраствуйте. Хотелось бы отойти от темы т.к. я знаком разве, что с такими языками как html/pawn,для начала хотел бы узнать, как компилировать плагины для метомода и, что для этого нужно.
И второе, если перехватывать команду status таким способом, возможно ли посредствам amxx плагина выводить свою информацию (где эта информация будет выводится при вводе status), не будит ли она блокирована т.к. команда status будет перехвачена.
Спасибо :)

Страница 1 из 2 Часовой пояс: UTC + 5 часов [ Летнее время ]
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/