Sign in to follow this  
Followers 0
Cawfee

Принцип написания античитов. Написание античита на деньги для наглядности

3 posts in this topic

В предыдущем уроке я рассказал о том, как пользоваться перехватом функций. Также сказал, что перехваты функций применяются для того, чтобы можно было изменить поведение конкретной функции. Сегодня постараюсь объяснить принцип создания античита и для примера написать для вас античит на деньги.

 

Как работает античит? Рассмотрим такую ситуацию. При помощи запрещенных программных обеспечений Вы изменяете количество денег у своего игрока. Но спустя несколько секунд (а обычно даже секунду) это количество денег возвращается в прежнее состояние. Можно предположить, что существует какой-то таймер с интервалом, например, в секунду, внутри которого идет проверка: соответствует ли количество денег игрока сейчас тем цифрам, что были во время прежней проверки.

 

Итак, мы можем получить деньги игрока в данный момент при помощи функции GetPlayerMoney. А с чем нам сверять полученное количество средств? Следует создать новую переменную, в которую уже стоит заносить количество средств, которое должно быть у игрока. Следовательно, нам нужно перехватить функции, связанные с изменением денег, в которых уже производить изменения в значении переменной.

 

Далее, как я ранее упомянул, следует создать таймер, где уже производить проверку на то, пользуется ли игрок запрещенным программным обеспечением. На этом, в принципе, принцип написания античита завершен. Ровным счетом так же пишутся античиты на здоровье, броню, очки (уровень), телепортацию и многие други. То есть логика везде одинакова.

 

Начинаем писать античит.

Мое мнение таково, что античиты следует выносить в отдельные файлы (инклуды). Для этого предлагаю создать в папке "include" новую папку - "anticheats". Внутри новой папки создаем файл "ac_money.inc". Открываем файл.

 

Прежде всего нам следует задать некое начало нашему файлу, в котором стоит написать проверку на переподключение файла (об этом еще будет урок позже, в данный момент от вас требуется просто скопировать данный мною ниже код):

#if defined INC_AC_MONEY
	#endinput
#endif
#define INC_AC_MONEY

Далее мы объявим переменные, в которых будем хранить количество денег игрока (сколько у него должно быть) и ID таймера для игрока, чтобы могли удалять его после того, как игрок отключился.

static
	gPlayerMoney[MAX_PLAYERS], // количество денег, которое должно быть у игрока
	gPlayerTimer[MAX_PLAYERS]; // ID таймера для игрока, в котором будет идти проверка его баланса

Теперь приступим к перехватам. Запуск таймера мы начнем в функции OnPlayerConnect (вызывается, когда игрок подключается), а удалять таймер будем в OnPlayerDisconnect.

public OnPlayerConnect(playerid)
{
	// создаем таймер, где будем проверять игрока на пользование читами
	gPlayerTimer[playerid] = SetTimerEx("ac_money_OnPlayerSecondTimer", 1000*1, true, "i", playerid);
	
	#if defined ac_money_OnPlayerConnect
		return ac_money_OnPlayerConnect(playerid);
	#else
		return 1;
	#endif
}
#if defined _ALS_OnPlayerConnect
	#undef OnPlayerConnect
#else
	#define _ALS_OnPlayerConnect
#endif
#define OnPlayerConnect ac_money_OnPlayerConnect
#if defined ac_money_OnPlayerConnect
	forward ac_money_OnPlayerConnect(playerid);
#endif

public OnPlayerDisconnect(playerid, reason)
{
	KillTimer(ac_timerid[playerid]); // удалим таймер для этого игрока
	
	#if defined ac_money_OnPlayerDisconnect
		return ac_money_OnPlayerDisconnect(playerid, reason);
	#else
		return 1;
	#endif
}
#if defined _ALS_OnPlayerDisconnect
	#undef OnPlayerDisconnect
#else
	#define _ALS_OnPlayerDisconnect
#endif
#define OnPlayerDisconnect ac_money_OnPlayerDisconnect
#if defined ac_money_OnPlayerDisconnect
	forward ac_money_OnPlayerDisconnect(playerid);
#endif

Мы перехватили две функции - OnPlayerConnect и OnPlayerDisconnect, в которых будем создавать и удалять таймер для проверки игрока на пользование читами. Далее мы должны перехватить функции изменения денег (ResetPlayerMoney, GivePlayerMoney), чтобы в них происходило изменение значения переменной, где записано количество денежных средств данного игрока:

stock ac_money_GivePlayerMoney(playerid, money) // перехватываем функцию GivePlayerMoney
{
	gPlayerMoney[playerid] += money;
	return GivePlayerMoney(playerid, money);
}
#if defined _ALS_GivePlayerMoney
	#undef GivePlayerMoney
#else
	#define _ALS_GivePlayerMoney
#endif
#define GivePlayerMoney ac_money_GivePlayerMoney

stock ac_money_ResetPlayerMoney(playerid) // перехватим функцию ResetPlayerMoney
{
	gPlayerMoney[playerid] = 0;
	return ResetPlayerMoney(playerid);
}
#if defined _ALS_ResetPlayerMoney
	#undef ResetPlayerMoney
#else
	#define _ALS_ResetPlayerMoney
#endif
#define ResetPlayerMoney ac_money_ResetPlayerMoney

Последнее, что мы не сделали - функцию, в которой будем производить проверку: пользуется ли игрок запрещенными программными обеспечениями? Создаем ее (обратите внимание - я создаю функцию с модификатором public потому, что это будет таймер, а все таймеры следует объявлять с модификаторами public).

forward ac_money_OnPlayerSecond(playerid);
public ac_money_OnPlayerSecond(playerid)
{
	if(GetPlayerMoney(playerid) == gPlayerMoney[playerid])
		return 1; // все хорошо, деньги "тогда" и сейчас совпадают
		
	SendClientMessage(playerid, -1, "Система расценила Ваши действия как действия читера. Количество средств не совпадает.");
	Kick(playerid); // выкинем игрока с сервера за пользование сторонними ПО
	return 0;
}

На этом, вроде бы, все. файл с античитом, который должен был получиться у вас, если Вы следовали согласно данному уроку, я приложу ниже. Спасибо за внимание.

 

Автор данного урока: @Jawn

AntiCheat money.inc

Share this post


Link to post
Share on other sites

@mat300 принцип во всех играх один - хранить данные, которые могут быть подделаны, на сервере. А код, естественно, будет отличаться. Данный подойдет к SAMP/CRMP. 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • Sleash
      By Sleash
      Всем доброго времени суток. Сегодня мне бы хотелось вам рассказать от таких функциях в PAWN-языке, как SetTimer и SetTimerEx.
      Сразу сделаю такое примечание: Для SetTimer и SetTimerEx можно использовать ТОЛЬКО public!!!
      SetTimer
      Итак, для начала приступим к лёгкому и пойдём по нарастающей:
      Первое, это SetTimer. Функция включает в себя 3 параметра:
      native SetTimer(funcname[], interval, repeating); funcname[] - Это название функции, по сути - название вашего pablic в кавычках.
      interval - Интервалы от вызова таймера до срабатывания pablic
                     Так же если стоит повторение таймера, то будет работать как интервал между таймерами.
                     Измеряется в миллисекундах. 1000 миллисекунд равно 1 секунде
      repating - Тут всё просто: будет ли повторяться ваша функция. Может иметь значения: true - будет выполняться повторение ИЛИ false - вызывается 1 раз.
      Давайте разберём пример для наглядности:
      forward Info(); public Info() {     SendClientMessageToAll(0xFFFFFFFF, "Наш сайт: pawno-rus.ru"); } // И теперь давайте вызовем данный таймер при запуске мода public OngameModeInit() {     SetTimer("Info", 1000*60*20, true);     return true } Давайте разберёмся по интервалу: 1000*60*20. Так как я писал ранее, что 1000 млСек = 1 сек, то: 1 сек * 60 = 1 минута; 1 минута * 20 = 20 минут.
      Таким образом данный таймер будет выводить каждые 20 минут для всех игроков на сервере в чат: "pawno-rus.ru".
       
      SetTimerEx
       
      По сути с SetTimer - всё, теперь перейдём к следующей функции: SetTimerEx:
      native SetTimerEx(funcname[], interval, repeating, const format[], {Float,_}:...); Тут добавляются ещё 2 параметра:
      const format[] - формат данных для ввода в функцию. (Такие как: s, d, f);
      {Float,_}:... - переменные или значение для данных из const fromat[]
      Из данных объяснения мало что можно понять незнающему или начинающему скриптеру, поэтому давайте разберём на примере кода, который при входу даёт на авторизацию две минуты игроку:
      forward autorez(playerid); public autorez(playerid) {     if(/*проверка на то залогинился ли игрок*/)     {         SendClientMessage(playerid, 0xFFFFFFFF, "Вы были кикнуты по причине: Время на авторизацию истекло.");         Kick(playerid);         return true;     }     return true; } //Дальше уже добавлям сам таймер public OnPlayerConnect(playerid) {     SetTimerEx("autorez", 1000*60*2, false, "d", playerid);     return true; } Если первые три пункта мы уже разбирали. то начнём сразу с 4-го:
      4. Тут в кавычках надо вставлять тип данных. Наподобие функции format(output[], len, "%s %d %f", string, int, float), только без знака процента (%)
      5. Тут уже указывают сами данные, так же разберём как и предыдущий: format(output[], len, "%s %d %f ", string, int, float)
       
      Я надеюсь что кому-то помог, а если что непонятно, то спрашивайте, всегда помогу.
    • NoVate
      By NoVate
      Доброго времени суток 
       
      Многие новички задавались вопросом: "Как создать свой RP сервер?", "С чего начать разработку?", "Это сложно и я не справлюсь".
      После таких вопросов многие уходили с этой темы и оставляли её на последней полке. Некоторые брались и сталкивались с большими проблемами. И только часть из этих людей доходили до какого-то результата.
       
      Моя цель: сделать создание сервера в SA:MP проще. Чтобы каждый из тех, кто интересовался созданием сервера мог спокойно взять готовую, а что самое главное - базовую сборку и под неё уже создавать различные свои задумки. SA:MP на данный момент не особо актуален, а тем более самый обычный клиент, НО, как мне кажется, если сделать что-то невероятное, то аудитория заметит это и ей будет достаточно интересно "пощупать" данное новшество.
       
      Для тех, кто начнёт писать: "Ты видел свой код?", "Ты сделал не правильно в 777-ой строке" и так далее. Сразу отвечу, цитируя:
       
      Кому стало интересно и кто хотел бы ознакомиться со сборком - прошу в мой Github (не реклама).
      Буду делать коммиты по мере свободного времени и написании кода.
      Если есть какие-то идеи, то пишите в мой Discord сервера (не реклама), который можно будет найти на той же странице.
       
      Спасибо всем за прочтение и хорошего настроения 
    • xiemoniyaz
      By xiemoniyaz
      C:\Users\111\OneDrive\Ðàáî÷èé ñòîë\rrrr\gamemodes\arizona.pwn(78772) : error 017: undefined symbol "GEO_MAX_COUNTRY_NAME_LENGTH" C:\Users\111\OneDrive\Ðàáî÷èé ñòîë\rrrr\gamemodes\arizona.pwn(78772) : error 009: invalid array size (negative, zero or out of bounds) C:\Users\111\OneDrive\Ðàáî÷èé ñòîë\rrrr\gamemodes\arizona.pwn(78772) : error 036: empty statement C:\Users\111\OneDrive\Ðàáî÷èé ñòîë\rrrr\gamemodes\arizona.pwn(78772) : fatal error 107: too many error messages on one line Compilation aborted. Pawn compiler 3.2.3664          Copyright (c) 1997-2016, ITB CompuPhase 4 Errors.  
       
      cmd:get(playerid, params[]) {     extract params -> new player; else return SendClientMessage(playerid, -1, !"/get [playerid]");     new string[GEO_MAX_COUNTRY_NAME_LENGTH+GEO_MAX_REGION_NAME_LENGTH+GEO_MAX_CITY_NAME_LENGTH+GEO_MAX_PROVIDER_NAME_LENGTH+GEO_MAX_MOBILE_STATUS_LENGTH+GEO_MAX_PROXY_LENGTH-6+118];     format(string, sizeof(string),     "Страна: %s\n\     Регион: %s\n\     Город: %s\n\     Провайдер: %s\n\     Использует ли моб.сеть: %s\n\     Использует ли прокси: %s",     GetPlayerIpCountry(player),     GetPlayerIpRegion(player),     GetPlayerIpCity(player),     GetPlayerIpProvider(player),     GetPlayerIpMobileStatus(player),     GetPlayerIpProxyStatus(player));     ShowPlayerDialog(playerid, 0, DIALOG_STYLE_MSGBOX, !" ", string, !"Закрыть", !"");     return true; }  
    • DEST
      By DEST
      Командный процессор: zcmd / dc_cmd + sscanf.