Так уж получилось, что я в свое время увлекался созданием читов для
всяких игрушек. В основном мультиплеерных шутеров, но и mmorpg
досталось тоже...
Читы
для меня были интересны сугубо с технической точки зрения - обойти
античит, поковыряться во внутренностях движка и так далее. Начну я, наверное, с Half Life. Многие слышали про засилье мультиплеерных читов для HL, например о OGC. Как оно работает и что оно делает? Вводная часть: HL состоит из трех частей. Первая: ядро. Состоит из рендера, сетевого кода, работы с устройствами ввода и так далее. Вторая: клиентская часть мода Третья: серверная часть мода.
По сути, игра в понимании HL это комплект из двух DLL (серверной и клиенской части мода) + данные для них. Ядро "общается" с клиентской (и серверной частью) через два интерфейса: интерфейс ядра и интерфейс модуля. Интерфейс
ядра предоставляет всякие разные функции для работы с рендерингом и
т.д. Интерфейс модуля используется как таблица callback, когда что то
происходит. Например - начинает рендериться кадр. Тоже самое для
серверной части, разве что интерфейсы отличаются. Если не касаться
статики и BSP, то основным игровым объектом является entity. Все entity
синхронизируются между клиентами в мультиплеерной игре. Для уменьшения
нагрузки на канал, апдейтятся только те entity, которых можно видеть
(проверка по порталам).
Что делает чит? Он перехватывает
необходимые функции из интерфейса клиентского модуля и получает доступ
к интерфейсу ядра и делает что хочет. Например - рисует квадратик в
screen space с именем игрока. Поскольку игрок может сидеть за дверью (а
дверь не учитывается как закрытая нода портала), то точно станет ясно
что за дверью кто то сидит. Второй вариант, он же wallhack - отключаем
Z test для моделек игроков (можно контролировать флаги с которыми будут
рисоваться entity). Ну и тому подобное - можно делать все, что
позволяет движок.
Следующее что придумали - а почему бы и не
прицеливаться автоматически? Высчитать view angle зная две точки (где
мы и куда надо смотреть) совсем не сложно. Сделали. Эволюция метода -
использование скелета модельки для определения куда надо целиться +
нелинейное предсказание (учитывая ускорение и скорость) для компенсации
лага и предсказания траектории движения. Вот и получались 95%
headshot'ы при хорошем пинге. Counter Strike, например, позволял
стрелять сквозь стены. Сделано было достаточно просто - если материал
стены "позволял" простреливать сквозь, то в зависимости от типа оружия
определялось какое количество "стен" пуля может пройти. Стена в данном
случае - полигон. Так что теперь стало возможно прицельно стрелять
сквозь стены.
Были, конечно, и извраты - серия читов XQZ, где
кто то сделал враппер над opengl32.dll и считал количество вертексов на
модельку. По количеству вертексов определял что это рисуется и
соответственно изменял флажки рендеринга. Понятное дело что такая штука
ломалась когда выходили патчи для моделек. Aimbot тут работал просто -
проецировали одну из вершин и делали SetCursorPos. Тут начинается
самое интересное. Понятное дело, что с читами мириться никто не хотел,
особенно игроки которые чит не смогли достать, либо не поняли как им
пользоваться. Начинают появляться античиты.
Первый самый популярный античит (эх, забыл название), был сугубо на серверной стороне. Обладал следующими свойствами: 1. Мог проверять переменные клиента (cvar). Обычно читы в них хранили свои настройки. 2.
Жестко трейсил лучи на сервере и принудительно выключал модельки
невидимых персонажей, чем серьезно грузил машину на которой он стоят. Первое обошли очень просто: 1.
Добавили уникальный префикс к cvar переменным (хитрость в том, что
сервер не может перебрать все переменные клиента, а может только
запросить значение переменной по имени). Альтернатива - вообще убрали
cvar переменные и сделали свою встроенную консоль в чите. 2. Тут
хитро. Я придумал следующую штуку (которая потом в OGC попала): у HL
очень мощная звуковая система, с учетом разных материалов, с
позиционированием звука и так далее. К счастью (или сожалению), при
проигрывании звука передается ID entity которая его произвела. Пример:
идет кто то за стеночкой, клацает ботинками. Позиция звука известна,
кто издал известно - почему бы не использовать. Целиться на звук, увы,
сложно, так как апдейт не очень частый. Дополнительный плюс метода -
теперь порталы стали не помеха, если я нахожусь в зоне получения звука.
А зона эта достаточно большая. Вобщем, этот античит долго не просуществовал.
Второй достаточно известный античит - Cheating Death. По сути работал
как чит - хукал интерфейсы и проверял что бы ничего лишнего не было
(адреса функцией в интерфейсах принадлежали HL и т.д.). Содержал
клиентскую и серверную части. Серверная ждала определенного хендшейка
от клиентской и если его не было, кикала игрока. Клиентская часть была
защищена весьма неплохо и малейшее вмешательство воспринимала как чит.
К сожалению, у CD оказалась одна бооольшая дырка - серверная часть под
Linux содержала debug info. Просто забыли strip'нуть .so'шку. В
результате, алгоритм хендшейка быстренько разобрали на части и просто
начали фальсифицировать. Началась возня с версиями, когда новая версия
CD была не совместимой с предидущей (поменяли хендшейк), в тот же день
выходил апдейт к читу с поддержкой нового CD и так далее. Продолжалось
это все около года, пока разработчики CD наконец не поняли где собака
порылась. А может и не поняли, а тому кто делал читы надоело, я не знаю.
Самое интересное началось с появлением VAC - Valve Anti Cheat. Есть
подозрение что его писал кто то из Львова. Подозрение простое - была
своя "тусовка", технический форум где обсуждались аспекты
программирования читов. Админ (как потом оказалось - из Львова)
высказал идею как бы он сделал античит. Как оказалось, VAC работает по
той самой схеме как описал данный мсье. Это только предположения, но
кто знает. VAC работает почти как CD, только теперь оффициально от
Valve. Есть серверная часть, есть клиентская. Серверная часть
скачивается самим сервером с некого защищенного хоста Valve. Клиентская
часть скачивается при коннекте с защищенному серверу. Файлы на диск не
сохраняются, и сервер и клиент содержат свой loader. Если сдампить что
пришло, получается какой то свой формат, который получен из исходной
.DLL'ки. (Кстати, в HL2 систему упростили - качается .DLL'ка в temp
папку и оттуда грузится. Видимо решили что коль для HL сделали дампилку
этих .DLL, то смысла нет дергаться). Клиентская часть работала как и CD
- следила что с клиентом и время от времени рапортовала серверной
части. Интересная особенность клиентской части - большой
интерпритатор. По сути, что бы понять что оно сейчас делает надо было
написать декомпилятор для скриптов. Банальный дизассемблированный код
ничего не показывал. Серверная часть для Windows была тоже зашифрована,
протокол работы античита тяжело было расковырять. Linux версия VAC
сохранялась в .so'шку и оттуда грузилась. В принципе, в начале она даже
debug info содержала, потом, правда, прикрыли лавочку.
Первая
проблема, которая появилась с античитом - при коннекте к серверу
скачивался клиентский модуль. Модуль, как уже говорил, был в
определенном формате и получался путем конвертирования DLL'ки. Как
оказалось, модуль оказался неподписанным. Результат: подправляем .so
файл для Linux сервера и начинаем рассылать троянцев для всех, кто к
нам в гости на сервер пожалует. Месяцев через 6 дыру прикрыли, начали
подписывать. Вторая проблема - за найденный чит начали банить. 40
у.е. терять как то не хотелось, начали придумывать способы обхода
античита. Самый простой способ - спрятаться.
Первые версии
VAC достаточно легко обходились. Например, была у него проверка - все
функции из интерфейса ядра должны указывать на адресное пространство
HL.exe, а не какой то левой .dll, что логично. "Фиксили" просто -
находили неиспользуемую область и делали там jump gate - в эту область
памяти писали JMP myHandler, в интерфейсе ядра указывали на эту
область. Тоже самое и с интерфейсом клиентского модуля. Ну и так далее.
В тот момент у меня появилась мега идея как можно достаточно эффективно скрыть вообще наличие каких либо патчей.
Как известно, у x86 есть система защиты памяти. На каждую страницу
(4кб) есть три флага: можно читать, можно писать, можно запускать. К
сожалению, можно читать и можно запускать это один флаг. Почему к
сожалению - объясню позже. Так вот, идея - читаем кусок памяти, который мы собираемся патчить. Патчим память. И снимаем флаг "можно читать" со страницы. Как только кто то попытается прочитать что то по указанному адресу, выскочит exception, который мы словим и сделаем следующее: 1. Восстанавливаем полномочия доступа к странице (с проверкой наш ли это вообще exception) 2. Проверим откуда произошла попытка "читать". 3. Если из ядра или клиентского модуля - ничего не делаем. 4. Если откуда то еще - восстанавливаем из бекапа оригинальные данные. 5. Включаем флаг трассировки. В смысле для процессора, при выполнении каждой комманды будет происходить exception.
Как только сработал exception по трассировке: 1. Убираем флаг трассировки 2. Восстанавливаем патч 3. Снова убираем флаги доступа к странице.
При
таком раскладе, обойти такую защиту можно было только снятием защиты со
страницы памяти. Что решалось хуком на всякие там функции
VirtualProtect и эмуляцией когда пытались нашу страницу поломать.
Второй вариант - глобально перехватить мой хендлер эксепшенов. И
пытаться понять что же там такое со страницей памяти происходит. Это
можно было полечить захукав NtDispatchException (или что то типа
такого, забыл уже). Недостаток простой был - на каждый exception
теряется очень много тактов CPU. В результате, проседал FPS. Но даже на
Athlon 1 GHz ниже 40 не опускался в Counter Strike. Так что было вполне
приемлимо. А теперь о проблемах x86. Поскольку флаг
читать/запускать один, то нельзя защищать таким образом код, ибо
получались жуткие тормоза, ибо каждая инструкция давала 2 exception. Вобщем, было весело.
Что могу сказать про Quake 3. Q3 содержит VM, которая интерпретирует
скрипты. Причем для x86 они даже написали JIT. Идея та же что и в HL
(или наоборот), разве что модуля стало 3. UI почему то вынесли
отдельно. Для вызова функций в/из скриптов существует мега функция,
которая принимает н-цать параметров и по ID функции вызывает ее.
Вобщем, хукаем эту функцию и повторяем все для HL.
Все
остальные игрушки на базе движка Q3 ломаются аналогично, разве что ID
функций другие. Я точно ковырялся в JK2 и Wolf:ET - никаких проблем.
Добро
пожаловать на cstriker.info,
Спектатор. Чтобы получить доступ к функциям сайта и форума Вам
необходимио зарегистрироваться
или войти со своим логином и паролем.
Остальной CS - статьи о других версиях Контер-Страйк. CS:CZ, CS 2, CS Promod, CS Online и т.д. Киберспорт и прочее. Или общие статьи которые нельзя отнести к какой-то одной версии контера.