# KZ Anti-Cheat
**Обнаружение читов, связанных с перемещением, на серверах KZ для Counter-Strike 1.6**
Автор: **illusion @ CodeStrike** · [codestrike.store](https://codestrike.store)
---
## Что он обнаруживает
| Детектор | Уловы |
|---|---|
| `BUNNYHOP` | автоматический банихоп, скрипты для прыжков, циклы `+jump`макросов |
| `GROUNDSTRAFE` | Скрипты GS и SGS, включая варианты, которые никогда не затрагивают `+duck` |
| `STRAFE-STABILIZER` | оптимизаторы воздушного стрельбы / хаки для «идеальной стрельбы» |
| `PRESTRAFE-STABILIZER` | оптимизаторы наземного обстрела (экспериментальная функция, по умолчанию отключена) |
| `INPUT-ANOMALY` | speedhack и манипуляции с часами клиента |
---
## Идея
Движение игрока в GoldSrc является полностью детерминированным. В каждый такт сервер получает
usercmd — кнопки, мс, forwardmove, sidemove, viewangles — и запускается
`PM_Friction`, `PM_Accelerate`, и`PM_AirAccelerate` на`PM_Jump` нём.
Этот плагин переосуществляет эту математику. Для каждого отдельного тика он знает не только
не то, что сделал движок, а **то, что дал бы оптимальный входной сигнал**.
`PM_AirAccelerate` увеличивает`min(K, 30 − dot(v, wishdir)) · wishdir` скорость,
с `K = sv_airaccelerate · wishspeed · frametime`. Максимизация этого по
Свободно выбранный угол рыскания имеет замкнутую форму:
```
Δv_max = √(v² + wishspd² − max(0, wishspd − K)²) − v
```
Всё определяется на основе этого и настроек cvars рабочего сервера. Ничто не является
«волшебное число», взятое с потолка.
### Почему это важно для airaccelerate
Один и тот же чит ведет себя совершенно по-разному в зависимости от `sv_airaccelerate`,
поэтому использование одного фиксированного порогового значения не может сработать:
| | `sv_airaccelerate 10` | `sv_airaccelerate 100` |
|---|---|---|
| K при 250 единиц/сек, 100 кадров/сек | 25 | 250 |
| оптимальный `dot(v, wishdir)` | 5 | 0 |
| угол обзора, который следует соблюдать | 88.9° | 90° |
| диапазон для КПД ≥0,90 | **±0.85°** | **±2.2°** |
Стабилизатор, написанный для сервера с 100 AA, нацелен перпендикулярно, что как раз и является
там — оптимальное значение, а на сервере с 10 AA отклонение составляет 1,1°, из-за чего прирост становится *меньше*
чем хороший человек. Каждый порог в этом плагине интерполируется между его
Значения 10 AA и 100 AA определяются с помощью параметра live cvar, поэтому оба значения оцениваются правильно.
Тот же принцип применим и к FPS. Все временные показатели маневра «страф» измеряются в
**миллисекунд по настенным часам**, но ни в коем случае не в тиках, поскольку 25 тиков равны 250 мс при
100 кадров в секунду и 27 мс при 940 кадрах в секунду.
---
## Установка
1. Скопировать в`kz_anticheat.amxx` `cstrike/addons/amxmodx/plugins/`
2. Добавьте эту строку в `cstrike/addons/amxmodx/configs/plugins.ini`:
```
kz_anticheat.amxx
```
3. Смените карту или перезапустите сервер.
При первом запуске плагин создаёт и запускает:
```
addons/amxmodx/configs/CodeStrikePlugins/kz_anticheat.cfg
```
Этот файл создается **один раз** на основе собственных настроек по умолчанию плагина и больше никогда не
снова перезаписано. Удалите его, чтобы сгенерировать заново. Всё настраивается в файле
Вот в чём дело — исходные файлы никогда не нужно редактировать или перекомпилировать.
В консоли сервера вы увидите баннер, подтверждающий загрузку и перемещение
cvars, которые он прочитал, и предел prestrafe, вычисленный на их основе.
---
## Первые пять минут на новом сервере
```
kzac_physics
```
Запустите это перед всем остальным. Программа выведет модель движения, реализованную в плагине.
получено. **Если указанный в отчете предельный уровень, до которого наносится штраф, не совпадает с тем, что у ваших игроков
фактически достигают (обычно ~278 u/s), ваши параметры движения не соответствуют тем, которые заданы в плагине
читает, и ничего другого тоже не будет в порядке.**
```
kzac_diag
```
Подтверждает, что хуки движения активны. Необходимо`ticks processed` подниматься, пока
кто-то переезжает.
---
## Команды администратора
Все они требуют флага **`c`**(`ADMIN_KICK`).
Буквы флага AMXX: `a`иммунитет · `b`резервирование · **`c`**исключение из **игры** · `d`бан ·
`e` slay · `f`map · `g`cvar · `l`rcon.
| Команда | Цель |
|---|---|
| `kzac_stats <target>` | все показатели, которые плагин хранит для одного игрока |
| `kzac_watch <цель\|off>` | отображение данных телеметрии в реальном времени на консоли |
| `kzac_physics` | полученная модель движения и все пороги активности |
| `kzac_diag` | срабатывают ли хуки движения и какой гвардист отбрасывает тики |
| `kzac_reset <target>` | удалить накопленные доказательства одного игрока |
`kzac_stats` — это самое важное. Каждый результат обнаружения можно проверить вручную
по сравнению с показателями, которые он выводит, и каждый детектор отображает **пиковые значения** **сеанса**
блок — самые экстремальные значения, которые достигал этот игрок. Именно это вы
использовать в качестве ориентира, если когда-нибудь понадобится сдвинуть пороговое значение.
---
## Настройка
### Объявления
```
kzac_announce_mode 1 // 0 = silent, 1 = admins only, 2 = everyone
kzac_announce_flag "c" // flag required to see them in mode 1
```
Режим **1 специально установлен по умолчанию**. По умолчанию флаг имеет значение `c`(`ADMIN_KICK`),
тот же, что требуется для команд администратора, поэтому любой, кто сможет провести расследование
обнаружение также свидетельствует об этом. Публичное обвинение нельзя отозвать,
и ни одна система защиты от читов не идеальна. Вывод на консоль и запись в файл журнала всегда происходят
независимо от этого параметра.
### Наказание
```
kzac_punish_bhop 0 // 0 = nothing, 1 = kick, 2 = ban
kzac_punish_gstrafe 0
kzac_punish_strafe 0
kzac_punish_prestrafe 0
kzac_punish_input 0
kzac_punish_hits 3 // detections of the SAME type before it fires
kzac_ban_minutes 0 // 0 = permanent
```
Каждый детектор содержит собственное обоснование, поэтому заблокированному игроку сообщается, в чём заключалась
на самом деле поймал, а не просто общая фраза:
```
kzac_reason_bhop "Bunnyhop Cheat Detected"
kzac_reason_gstrafe "Ground Strafe Cheat Detected"
kzac_reason_strafe "Strafe Stabilizer Cheat Detected"
kzac_reason_prestrafe "Prestrafe Stabilizer Cheat Detected"
kzac_reason_input "Speedhack Detected"
kzac_punish_reason "Movement cheat detected" // fallback
```
Оставьте одно поле **пустым,** и система переключится на `kzac_punish_reason`. Очистить все пять
использовать одну строку для всего.
**По умолчанию** наказания отключены. Включайте их сознательно и отдавайте предпочтение
Начните с (`1`kick), одновременно следя за показателями своего сервера.
Они специально настраиваются для каждого детектора. `BUNNYHOP`и имеют`GROUNDSTRAFE`
наибольшее измеренное расстояние между рукой и текстом — именно такие варианты являются самыми безопасными
для автоматизации. имеет`STRAFE-STABILIZER` самые низкие маржи.
### Команда «Ban»
**Вся команда** является cvar, поэтому плагину неважно, какая система банов используется
Вы запускаете программу — записывайте всё, что от вас требуется, в любом порядке аргументов, какой вам удобен.
```
kzac_ban_cmd amx_ban %n %m %r // default
kzac_kick_cmd amx_kick %n %r // default
```
| | |
|---|---|
| `%m` | продолжительность блокировки в минутах, `0`= бессрочная |
| `%n` | имя игрока — **уже взято в кавычки** |
| `%r` | текст обоснования — **уже приведён выше** |
| `%u` | userid, использовать как `#%u` |
| `%s` | steamid |
| `%i` | IP-адрес |
| `%N` `%R` | имя и причина **без кавычек**, если ваша система блокировки требует их в исходном виде |
**Сначала проверьте свой собственный сервер.** Введите команду без`amx_ban` аргументов на сервере
консоль, и она выводит ожидаемое описание использования. Порядок аргументов **не** соответствует
одинаково во всех системах запретов — одни предпочитают сначала указывать цель, другие — сначала время.
Если сделать это неправильно, то произойдет сбой с `Client with that name or userid not found`.
```
amx_ban %n %m %r # target first (default)
amx_ban %m %n %r # minutes first
amx_ban #%u %m %r # by userid
amx_banip %s %m %r # by steamid
banid %m %s ; writeid ; kick # %u # engine level ban
```
Порядок аргументов вы выбираете сами — заполнители расширяются в том месте, где вы их разместите,
а несколько команд можно объединить с помощью `;`.
### Если наказание не последует
Консоль всегда выводит точную команду, которую она выполнила:
```
[KZ-AC] executing: amx_kick "illusion" "Bunnyhop Cheat Detected"
```
Если эта строка появится, а игрок всё ещё останется на месте, значит, плагин выполнил свою задачу и
команда не сработала. Обычно это происходит из-за того, что **`amx_kick` и не `amx_ban`учитывают
Иммунитет AMXX** — игрок, удерживающий флаг `a`(`ADMIN_IMMUNITY`), на каком сервере
которую обычно выделяют сами владельцы, молчаливо игнорируется. Самостоятельное тестирование
Поэтому аккаунт выглядит именно как неработающий плагин.
Для подтверждения выполните эту же команду вручную в консоли сервера. Движок
команды полностью игнорируют иммунитет:
```
kzac_kick_cmd kick # %u
kzac_ban_cmd banid %m %s ; writeid ; kick # %u
```
Если эта `executing:`строка **не** отображается, проверьте консоль на наличие следующих сообщений:
```
[KZ-AC] illusion :: BUNNYHOP held - 1 of 3 detections needed (kzac_punish_hits)
```
В учет принимаются только объявленные обнаружения`kzac_punish_hits`; те, которые были скрыты
`kzac_cooldown` не делайте этого.
**Ни в коем случае не вводите символ кавычки в эти значения самостоятельно.** Значение cvar заканчивается на
первая кавычка, которую распознает движок, поэтому шаблон, написанный с кавычками вокруг
размышление на этом прервалось бы, и мысль незаметно исчезла бы. То есть
именно почему и`%n` уже `%r`приводятся в кавычках.
### Ведение журнала
```
kzac_log 1
kzac_log_file "kzac_detections.log"
```
Записано в `addons/amxmodx/logs/`. Результаты обнаружения также всегда направляются в стандартный
Журнал AMXX через `log_amx`.
### Чувствительность
```
kzac_min_conf 80.0
```
Перед объявлением об обнаружении необходимо убедиться в его достоверности. Повысьте уровень уверенности до , чтобы`90` сохранить
Правила действуют только в случае максимальной строгости. Если снизить уровень строгости, начнут появляться спорные решения.
```
kzac_immunity ""
```
Административные нарушения, о которых никогда не сообщается и за которые никогда не наказывают. Пустое поле означает, что никто не обладает иммунитетом.
---
## Проведенные испытания
Проверено на **реальных читерах**, а не на симуляциях, на действующем сервере KZ:
| Читер | `sv_airaccelerate 10` | `sv_airaccelerate 100` |
|---|---|---|
| Автоматический банихоп | обнаружено | обнаружено |
| Скрипт «Bunnyhop» | обнаружено | обнаружено |
| Скрипт GS | обнаружено | обнаружено |
| Скрипт SGS | обнаружено | обнаружено |
| Стабилизатор бокового хода | обнаружено | обнаружено |
Законные приёмы проверялись в том же диапазоне — ручной банихоп с помощью
колесико прокрутки, ручное управление GS и SGS, стрельба из воздуха, предварительная стрельба — со скоростью 100 кадров в секунду и при
1000 кадров в секунду при обоих настройках AirAccelerate.
### Измеренное расстояние
Каждый порог активности находится в диапазоне между значением, полученным на основе реальной игры человека, и
значение, полученное в результате реального читинга на том же сервере:
| Сигнал | Человек | Пороговое значение | Читер |
|---|---|---|---|
| `+jump` количество нажатий за прыжок | 5.26 | 1.20 | 1.00 |
| идеальные прыжки подряд | 3 | 12 | 20–23 |
| идеальный прыжок — поделиться | 26.6% | 80% | 100% |
| `+duck` ударов в секунду | 13.3 | 35.0 | — |
| `+duck` изменение зазора | 0.70–0.88 | 0.10 | — |
| ошибка при обработке нулевых перемещений | 3 % (по сравнению с 9 % вероятности) | 50 % и 3-кратный шанс | 99 % (против 5 %) |
| эффективность обстрела с воздуха, интервал в 300 тиков | 0.583–0.65 | 0.85 | 0.909 |
| изменение эффективности, окно в 300 тиков | 0.172 | 0.075 | — |
### Как на самом деле выглядит законный обстрел с земли
Это стоит знать, поскольку именно по этой причине сама по себе скорость никогда не используется в качестве доказательства:
```
GS spd 324.9->323.2 bound 324.5 | grnd 11 run 6 | z 36.03
GS spd 571.4->569.2 bound n/a | grnd 11 run 1 | z 36.03
+duck edges 102 | +duck held 102 ticks
```
Значение GS было измерено на уровне **571 ед./с при верхнем пределе 278,7 ед./с**. Каждый
`+duck` Нажатие длилось ровно один тик — то есть один оборот колесика прокрутки. По тикам
когда игрок действительно стоит на месте, получаемая скорость всегда составляет чуть *меньше, чем*
закрытое выражение: физика явления остается неизменной. Скорость определяется
однотактные воздушные рамы, создаваемые каждым переходом в положение «утка».
Таким образом, детектор наземного удара никогда не учитывает скорость. Он анализирует входные данные
поток: как быстро он повторяется`+duck`, насколько он регулярный и происходит ли контакт с землей
нарушается командами, в которых время вообще не указывается.
---
## Ни одна система защиты от читерства не является идеальной
Этот тоже не подходит, и вам следует запускать его, зная об этом.
**Возможны ложные срабатывания.** В ходе разработки было обнаружено шесть таких случаев, и все они были исправлены,
каждое из них было связано с разными правилами, но у всех была одна и та же первопричина: пороговое значение
которые казались логически обоснованными, но никогда не проверялись на практике в условиях человеческой игры
в данной конкретной ситуации. Статистика передвижения людей меняется под воздействием ускорения воздуха,
в зависимости от частоты кадров и от того, что делает игрок — боковое перемещение по земле, «заячий прыжок» и
Удар по воздуху и обстрел с воздуха дают совершенно разные результаты у одного и того же человека.
Пять правил были **отключены** после того, как они дали ложные срабатывания, и они поставляются
отключены. Они по-прежнему присутствуют в конфигурации для тех, кто хочет с ними ознакомиться:
`kzac_st_err_aa10`, `kzac_st_err_aa100`, `kzac_st_err_sd`, `kzac_st_inband`.
Что это означает на практике:
- **Не включайте автоматические блокировки с самого первого дня.** Некоторое время ограничьтесь предупреждениями.
и прочитайте, что выводится с вашего собственного сервера.
- **`kzac_stats` прежде чем действовать.** При каждом обнаружении выводятся цифры, стоящие за
. Если они не выглядят крайними, рассматривайте этот вызов как предельный.
- **Детектор воздушных обстрелов — самый ненадежный из этих трех.** Его погрешность
— самые тонкие. Лучше предупредить или дать пинок; запрещать стоит только «банихоп» и
детекторы «groundstrafe», расстояние между которыми значительно больше.
- **Частично использованный чит сложнее обнаружить.** Стабилизатор, который игрок
борясь с собственными входными данными, он добивается меньших результатов и выглядит более человечным. Обнаружение
масштабируется с учетом преимущества, что является разумным свойством, но
не полный.
- **Можно написать чит, который будет оставаться ниже любого порогового значения**, намеренно
хуже, чем могло бы быть. В этот момент это перестаёт давать значительное преимущество,
но справедливо будет сказать, что охват не является абсолютным.
Если игрок оспаривает обнаружение, `kzac_stats`на него и сравнить с
оцененные человеческие ценности, приведенные в таблице выше. Плагин предоставляет вам данные, позволяющие
Сделайте этот вывод — от вас не требуют слепо доверять этому.
---
## Файлы
```
kz_anticheat.sma main plugin
include/kzac_core.inc movement math, guards, reporting, punishment
include/kzac_bhop.inc bunnyhop detector
include/kzac_gstrafe.inc ground strafe detector
include/kzac_strafe.inc air strafe detector
include/kzac_config.inc config file generator
compiled/kz_anticheat.amxx ready to use
```
Для запуска плагина требуется`kz_anticheat.amxx` только . Исходный код прилагается, поэтому
вы можете провести его аудит или расширить его.
Чтобы перекомпилировать, поместите пять файлов`kzac_*.inc` в папку `scripting/include/`
папку и скомпилируйте, как`kz_anticheat.sma` обычно. Сборка проходит без ошибок на AMX Mod X
1.10 без** ошибок и предупреждений**.
---
## Рекомендации по безопасности
**Имена игроков очищаются перед передачей в консольную команду.** Имя
содержащая кавычку или точку с запятой, в противном случае позволила бы пойманному мошеннику выполнить
произвольные серверные команды через шаблон «kick» или «ban». Кавычки, точки с запятой
а управляющие символы заменяются на `_`.
**Наказания никогда не выполняются в рамках конвейера движений.** Они помещаются в очередь и
выстрелил из задания на один кадр позже. Синхронное выполнение удара ногой изнутри
Действие «вперед» прерывает работу плеера в середине обратного вызова и приводит к сбою сервера —
эта проблема была обнаружена и устранена в ходе тестирования.
---
## Требования
- AMX Mod X версии 1.8.2 или более поздней (разработан и скомпилирован на версии 1.10)
- `fakemeta` модуль
- Counter-Strike 1.6 — работает с HLDS, ReHLDS и ReGameDLL
Никаких других плагинов, модулей или зависимостей не требуется.
---
## Производительность
Один форвард (`FM_CmdStart`) ведёт всю игру. На каждого игрока за каждый такт
Плагин выполняет несколько операций с числами с плавающей запятой и несколько операций `pev`чтения; переменные конфигурации сервера
сохраняются в кэше и обновляются один раз в секунду, а не считываются при каждом такте.
Отсутствует сканирование объектов для каждого кадра, отсутствуют `set_task`циклы для каждого игрока, а также отсутствуют
работа со строками в «горячем» контейнере.
---
## Поддержка
Куплено на сайте [codestrike.store](https://codestrike.store).
При сообщении о проблеме укажите вывод команды и`kzac_stats <player>`
`kzac_physics`. Эти два дампа содержат всё необходимое для того, чтобы определить подлинность
обнаружение на основе порогового значения, которое необходимо настроить на вашем сервере.
---
*KZ Anti-Cheat — illusion @ CodeStrike*
---
## Зрелость детектора — прочитайте это перед тем, как включить штрафные санкции
Не все три детектора одинаково проверены на практике, и разница между ними достаточно велика
что их не следует настраивать одинаково.
### BUNNYHOP и GROUNDSTRAFE — готовы к выпуску
Проверено на **двух независимых игроках**, с обоими настройками AirAccelerate, и
настоящие мошенники. Ни один показатель даже близко не приблизился к пороговому значению ни в ту, ни в другую сторону:
| Сигнал | Игрок А | Игрок B | Пороговое значение | Читер |
|---|---|---|---|---|
| `+jump` количество нажатий за прыжок | 5.26 | 5.30–6.19 | 1.20 | 1.00 |
| идеальные прыжки подряд | 3 | 2–4 | 12 | 20–23 |
| `+duck` в секунду | 13.3 | 9.0–20.2 | 35.0 | — |
| `+duck` изменение зазора | 0.70–0.88 | 1.03–1.16 | 0.10 | — |
| прерывания при нулевых перемещениях | 3% | 0% | 50% | 99% |
Их можно без опасений автоматизировать. и`kzac_punish_bhop 2` `kzac_punish_gstrafe 2`
являются обоснованными.
### STRAFE-STABILIZER — только предупреждение
В ходе разработки было обнаружено девять ложных срабатываний, каждое из которых было связано с отдельным правилом.
Пять правил пришлось **отключить** из-за пересечения распределений «честных игроков» и «игроков, использующих читы»:
| Правило об инвалидах | Почему |
|---|---|
| погрешность угла | человек 1,83°, обман 1,34–2,20° — пересечение |
| стандартное отклонение угловой погрешности | диапазон для человека 0,69–5,47°, восьмикратный разброс |
| внутриполосная передача | это угловое окно, зависящее от скорости, а не постоянное |
| поворотный замок | минимальный показатель для одного игрока — 0,139, для другого — **0,026** |
| эффективность однократного прыжка | человек 0,684–0**,956**, мошенник 0,835–0,946 — *в обратном порядке* |
Именно в этом заключается важный урок. При выполнении одного прыжка игрок, который просто
Страфы, которые хорошо прыгают, достигают эффективности уровня решателя, а значения, вычисляемые человеком, составляют
прямо через них и мимо значений, полученных обманным путём. Разница между комбинацией и
машина появляется только после усреднения **сотен тиков**.
Остаются активными два правила с окнами, охватывающие более 300 отметки «чистый воздух» —
среднее значение эффективности и ее колебания — которые никогда не приводили к ложным
положительный во всех записанных сессиях. Они надежно улавливают стабилизатор на высоких
`sv_airaccelerate`, где этот показатель составляет 0,909 при максимальном значении для человека, равном 0,65.
`sv_airaccelerate 10`**Стабилизатор, настроенный на угол 90°, демонстрирует меньший коэффициент усиления, чем качественный
человека и не поддаётся достоверному обнаружению.** Это объективное ограничение, а не
Проблема настройки: при имеющихся данных отсутствует измеренный сигнал, который
в этом случае разделяет эти два элемента.
Рекомендуется:
```
kzac_punish_bhop 2 // ban
kzac_punish_gstrafe 2 // ban
kzac_punish_strafe 0 // warn only, decide by hand
```
Применяйте `kzac_stats`к любому, о ком сообщает детектор обстрела. Цифры после
Все данные для вынесения вердикта уже имеются, и администратор-человек сравнивает их с приведёнными выше таблицами
является более точным критерием, чем любой из существующих в настоящее время пороговых значений.