- Статус
- Онлайн
- Регистрация
- 22 Авг 2022
- Сообщения
- 1,339
- Реакции
- 215
Всем привет. Тема относится к людям, которые не понимают каким образом читеры находят глобальные переменные, функции, или бездумно копируют код и не понимают откуда он взялся. Сегодня мы разберёмся, каким образом ВЫ должны были изучать игру кс2 изнутри.
Предисловие или почему всё так легко?
Если вы хоть раз видели как кто-то обновляет себе оффсеты или сигнатуры под функции вы наверняка удивлялись насколько быстро это происходит. Также большиство говорит, что кс2 дырявая, давайте разберёмся правда ли это.
Если говорить с точки зрения защищённости клиента и античита, то тут кс2 очень сильно разочаровывает потому, что иметь такое количество гавна это надо постараться. Мне до сих пор непонятно, почему игра собрана в дебаг режиме. Почему-то в коде часто виден путь до исходного файла:
Почему-то игра имеет RTTI (Run-Time Type Information):
Ещё валвы любят добавлять огромную кучу команд и описывать их значение, что ещё сильно упрощает анализ. А также игра имеет очень много схожестей с CS:GO, исходный код которого сливался аж несколько раз. И поверьте, мне есть что ещё добавить.
GlobalVars
Начнём с того, что в движке сурс2 (а также в сурс1) есть глобальные переменные, распространяющиеся между движком и игрой:
Такой вывод можно сделать из их комментария. Глобальные переменные хранят в себе название карты, количество сущностей, тип режима игры и тд:
Вспомним как мы можем узнать на какой мы карте? Напрягаем извилины и вспоминаем про
Также глобальные переменные хранят игровое время, которое тоже палится из команды
И ещё
Все они отображаются в одном месте в коде.
Давайте посмотрим что такое
Что ты маленький привет. Теперь мы знаем, что оффсет
А вот и RenderTime (значение чуть чуть расходится с игрой, т.к. чит энжин не так часто обновляет значения).
Ray Tracing
Для того, чтобы понять, попала ли в противника пуля и сколько нанесла урона используется технология Ray Tracing. Она пробрасывает луч от точки A до точки B и ищет соприкосновения по фильтру. Фильтром может являться что угодно: вода, сущности, игроки, материалы на карте ну или же ничего. И да, для неё тоже есть консольная команда -
Она визуально показывает откуда пробрасывался луч (на скриншоте в момент написания команды я стоял справа) и где он соприкоснулся, эта информация также передаётся вам в консоль:
Откуда прекрасно виден hitbox, hitgroup, кость, поверхность, позиция и остальные параметры. Попробуем ещё раз, но уже в стену:
На этот раз мы попали в мировую сущность, у неё нету костей, однако видна поверхность Wood_Plank и тип материала - mesh.
Данная команда находится не в client.dll:
т.к. C-Style строчка это просто последовательность символов оканчивающаяся на нулевой байт, то мы можем просто найти слово cast_ray, просканировав файлы игры. Вы можете использовать абсолютно любой инструмент, я лично пользуюсь notepad++, особого значения кроме скорости здесь нет:
Заходим в функцию с выполнением cast_ray и находим там сообщения, которые видели ранее в консоли:
Идём от обратного
Видим, что большинство информации приходит к нам из v45. Заранее кстати интересно посмотреть что за функция sub_B892B0, уж больно много параметров она принимает:
и мы попадаем в серверный TraceShape. Однако мы работаем с клиентом, поэтому давайте попробуем найти по этой строчке функцию в клиенте:
и она действительно существует
А по хрефам я уже начинаю замечать присутствие фильтров. Кстати каждый раз в первый аргумент идёт какая-то константа. Посмотрев на использование первого аргумента в функции становится ясно, что это какой-то виртуальный класс:
Так как у нас есть RTTI информация мы можем с лёгкостью посмотреть что это. Я использую чит энжин, т.к. он умеет считывать название класса с RTTI:
А вот и указатель на класс
Более подробно эту функцию вы можете изучить сами, я не вижу смысла тратить половину содержимого статьи на разжёвывание одной функции.
Дамаг сквозь стены AKA Penetration
Если вы уже реализовали свой первый аим, наверняка столкнулись с проблемой простреливаний через стены. К счастью и такая команда у меня для вас есть -
После выстрела вы увидите каждое соприкосновение пули и её продолжение сквозь некоторые стены. На каждом выстреле появляется текст с жирностью стены (или STOPPED при её достаточной твёрдости для остановки пули), потерянный урон, название поверхности соприкосновения, урон после соприкосновения и дистанцию.
Снова отправляемся в server.dll:
Текст здесь форматируется в отдельной функции, и дамаг получается с использованием третьего аргумента.
Вот вызов этой функции:
Чтобы не закидывать вам триллион скриншотов, я соберу основной флоу:
sub_9EA850 проходится по всем поверхностям и заполняет информацию о результате простреливания:
WorldToScreen и ViewMatrix
Для отрисовки точки с мировыми координатами в 2д пространстве нам нужно перевести их, используя видовую матрицу. В игре мы также можем встретить такой элемент:
это простой худ под союзником. Находится эта функция довольно просто:
Функция создаёт худ панель в панораме и ставит хук на получение пакета от сервера, в случае которого игрок должен иметь healthbar над собой:
Сам код обновления позиции healthbar'а довольно большой, поэтому я как и в прошлый раз покажу вам его в сокращённом виде:
Здесь мы видим sub_B726B0, который работает как первая часть реализации WorldToScreen:
Вот тут остановимся. View matrix лежит в unk_232EAC0, поэтому теперь вы знаете как найти видовую матрицу.
Продолжаем. sub_CEE0C0 отвечает за вторую часть WorldToScreen:
Отсюда вы также можете взять функции получения размера экрана
v1 это указатель на width, v2 на height. qword_2324E60 указывает на CEngineClient.
Конец
На этом всё, пишите что думаете насчёт этого. Думал кстати, что получится больше. Всем пока
Предисловие или почему всё так легко?
Если вы хоть раз видели как кто-то обновляет себе оффсеты или сигнатуры под функции вы наверняка удивлялись насколько быстро это происходит. Также большиство говорит, что кс2 дырявая, давайте разберёмся правда ли это.
Если говорить с точки зрения преимуществ в читах, то есть игры и по хуже, например мобильные. В них много расчётов производит клиент и отправляет на сервер (либо вообще нахуй не отправляет), что даёт плоды реализациям от вечных патронов до режима бога или полёте по всей карте. Обосновывается это тем, что игры создаются на телефон, а как правило интернет на телефоне не самый быстрый, поэтому во избежания отправки лишних данных они переносят большую часть основной логики в клиент. В кс2 такого почти нету, вы не можете летать по всей карте, убивать каждого с одной пули в ногу с глока или включить себе режим бога. Однако не ясно, почему доверие генерации сприда на данный момент отдана клиенту, и всё ещё игру нельзя назвать слишком дырявой, ведь условно в том же фортнайте банально можно телепортироваться и летать находясь в машине :)
Если говорить с точки зрения защищённости клиента и античита, то тут кс2 очень сильно разочаровывает потому, что иметь такое количество гавна это надо постараться. Мне до сих пор непонятно, почему игра собрана в дебаг режиме. Почему-то в коде часто виден путь до исходного файла:
Почему-то игра имеет RTTI (Run-Time Type Information):
Ещё валвы любят добавлять огромную кучу команд и описывать их значение, что ещё сильно упрощает анализ. А также игра имеет очень много схожестей с CS:GO, исходный код которого сливался аж несколько раз. И поверьте, мне есть что ещё добавить.
GlobalVars
Начнём с того, что в движке сурс2 (а также в сурс1) есть глобальные переменные, распространяющиеся между движком и игрой:
Такой вывод можно сделать из их комментария. Глобальные переменные хранят в себе название карты, количество сущностей, тип режима игры и тд:
Вспомним как мы можем узнать на какой мы карте? Напрягаем извилины и вспоминаем про
cl_showfps:
Также глобальные переменные хранят игровое время, которое тоже палится из команды
cl_showpos:
И ещё
cl_showtick:
Все они отображаются в одном месте в коде.
Давайте посмотрим что такое
20496A0 в чит энжине (вы можете использовать ReClass, однако я в своей жизни ни разу им не пользовался):
Что ты маленький привет. Теперь мы знаем, что оффсет
0x20496A0 указывает на GlobalVars, где +0x180 является путём до карты.
А вот и RenderTime (значение чуть чуть расходится с игрой, т.к. чит энжин не так часто обновляет значения).
Ray Tracing
Для того, чтобы понять, попала ли в противника пуля и сколько нанесла урона используется технология Ray Tracing. Она пробрасывает луч от точки A до точки B и ищет соприкосновения по фильтру. Фильтром может являться что угодно: вода, сущности, игроки, материалы на карте ну или же ничего. И да, для неё тоже есть консольная команда -
cast_ray:
Она визуально показывает откуда пробрасывался луч (на скриншоте в момент написания команды я стоял справа) и где он соприкоснулся, эта информация также передаётся вам в консоль:
Откуда прекрасно виден hitbox, hitgroup, кость, поверхность, позиция и остальные параметры. Попробуем ещё раз, но уже в стену:
На этот раз мы попали в мировую сущность, у неё нету костей, однако видна поверхность Wood_Plank и тип материала - mesh.
Данная команда находится не в client.dll:
т.к. C-Style строчка это просто последовательность символов оканчивающаяся на нулевой байт, то мы можем просто найти слово cast_ray, просканировав файлы игры. Вы можете использовать абсолютно любой инструмент, я лично пользуюсь notepad++, особого значения кроме скорости здесь нет:
Заходим в функцию с выполнением cast_ray и находим там сообщения, которые видели ранее в консоли:
Идём от обратного
Видим, что большинство информации приходит к нам из v45. Заранее кстати интересно посмотреть что за функция sub_B892B0, уж больно много параметров она принимает:
и мы попадаем в серверный TraceShape. Однако мы работаем с клиентом, поэтому давайте попробуем найти по этой строчке функцию в клиенте:
и она действительно существует
А по хрефам я уже начинаю замечать присутствие фильтров. Кстати каждый раз в первый аргумент идёт какая-то константа. Посмотрев на использование первого аргумента в функции становится ясно, что это какой-то виртуальный класс:
Так как у нас есть RTTI информация мы можем с лёгкостью посмотреть что это. Я использую чит энжин, т.к. он умеет считывать название класса с RTTI:
А вот и указатель на класс
CVPhys2World.Более подробно эту функцию вы можете изучить сами, я не вижу смысла тратить половину содержимого статьи на разжёвывание одной функции.
Дамаг сквозь стены AKA Penetration
Если вы уже реализовали свой первый аим, наверняка столкнулись с проблемой простреливаний через стены. К счастью и такая команда у меня для вас есть -
sv_showimpacts_penetration 1:
После выстрела вы увидите каждое соприкосновение пули и её продолжение сквозь некоторые стены. На каждом выстреле появляется текст с жирностью стены (или STOPPED при её достаточной твёрдости для остановки пули), потерянный урон, название поверхности соприкосновения, урон после соприкосновения и дистанцию.
Снова отправляемся в server.dll:
Текст здесь форматируется в отдельной функции, и дамаг получается с использованием третьего аргумента.
Вот вызов этой функции:
Чтобы не закидывать вам триллион скриншотов, я соберу основной флоу:
C++:
sub_9EA850((__int64)v179, (float)a8, a5, a10, a6, v33, (__int64)v32);
while (1) {
hit = hits + 24 * idx; // элемент соприкосновения
if ((*(_BYTE *)(hit + 20) & 1) == 0) // проверка, остановилась ли пуля
break;
damage_applied = *(float *)(hit + 8); // итоговый урон
hit_number++;
idx++;
if (hit_number >= max_hits)
break;
}
C++:
surfaces_count = (int *)(a1 + 0x1820);
for ( i = 0; ; i += 24 ) {
surface = *(_QWORD *)(a1 + 0x1828) + i;
need_stop = sub_A07990(a1, (float *)v18, surface, a6, a7); // заполнение информации о простреливании:
// +0x0 - текущий урон
// +0x4 - множитель пробиваемости
// +0x8 - урон после соприкосновения
// +0xC - hitgroup
// +0x12 - surface id
// +0x14 - флаги, если первый бит равен 0 - значит пуля остановилась
if (need_stop)
break;
if (i >= *surfaces_count)
break;
}
WorldToScreen и ViewMatrix
Для отрисовки точки с мировыми координатами в 2д пространстве нам нужно перевести их, используя видовую матрицу. В игре мы также можем встретить такой элемент:
это простой худ под союзником. Находится эта функция довольно просто:
Функция создаёт худ панель в панораме и ставит хук на получение пакета от сервера, в случае которого игрок должен иметь healthbar над собой:
Сам код обновления позиции healthbar'а довольно большой, поэтому я как и в прошлый раз покажу вам его в сокращённом виде:
C++:
player_pos = ...; // позиция игрока
sub_B726B0(&player_pos, modified); // преобразование мировых координат в нормализованные 2д (NDC)
sub_CEE0C0(modified); // преобразуем NDC координаты в 2д пиксели на экране
screen_x = modified->x;
screen_y = modified->y;
scale = 1.0 / (*(*v45 + 64i64))(v45);
// центрирование. v53, v54 - размеры хп текста
bar_x = ((screen_x - (v53 * 0.5)) * scale);
bar_y = ((screen_y - (v54 * 0.5)) * scale);
panorama_translate3d = util::allocate(32i64, v59);
*panorama_translate3d = &panorama::CTransformTranslate3D::`vftable';
*(panorama_translate3d + 8) = bar_x;
*(panorama_translate3d + 16) = bar_y;
Вот тут остановимся. View matrix лежит в unk_232EAC0, поэтому теперь вы знаете как найти видовую матрицу.
Продолжаем. sub_CEE0C0 отвечает за вторую часть WorldToScreen:
Отсюда вы также можете взять функции получения размера экрана
v1 это указатель на width, v2 на height. qword_2324E60 указывает на CEngineClient.
Конец
На этом всё, пишите что думаете насчёт этого. Думал кстати, что получится больше. Всем пока
Последнее редактирование:
