Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
13
Добавлен:
20.04.2024
Размер:
20.22 Mб
Скачать

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ПРИВАТНОСТЬ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

← НАЧАЛО СТАТЬИw Click

 

BUY

 

m

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

СРАВНИВАЕМ БЕЗОПАСНЫЕ БРАУЗЕРЫ 2023 ГОДА

WATERFOX

Сайт: waterfox.net

Движок: Firefox

Исходный код: открытый

Первый выпуск: 2011 год

Версии: Windows, macOS, Linux

Вотличие от всех рассмотренных браузеров, Waterfox основан не на Chromium, а на Firefox, поэтому он может понравиться тем, кто привык именно к этому браузеру.

В версии для Windows этот браузер имеет 64-битную архитектуру. Программа установки предлагает стандартный (standard) и пользовательский (custom) режимы, в последнем можно выбрать папку для установки, указать, где следует размещать значки браузера… и всё. Не слишком много настроек!

Внешне этот браузер очень похож на Firefox, существенных отличий в интерфейсе нет. Окно с настройками тоже в точности такое же, разве что вместо вкладки More from Mozilla здесь имеется вкладка Look and Feel. Самая интересная для нас вкладка — Privacy & Security — также не отличается от такой в стандартном Firefox, все настройки находятся на своих привычных местах. Никаких дополнительных или особых опций, связанных с приватностью, здесь нет.

Waterfox на GitHub

Исходные коды Waterfox можно найти на GitHub. Сейчас этот проект насчитывает более 4700 участников (contributors), что довольно много. Хотя в 2011 году его развитием занимался всего один человек — Алекс Контос, которому на тот момент было 16 лет. В 2019 году права на Waterfox приобрело рекламное агентство System1.

На сайте BrowserLeaks Waterfox показывает в целом такие же результаты, как и обычный Firefox. Примечательно, что он опознает браузер как Firefox версии 102.0, в то время как актуальная версия нативного Firefox — 111.0. Это означает, что редакция лежащего в основе Waterfox браузера слегка устарела, хотя и не слишком.

Waterfox определяется в BrowserLeaks как Firefox 102.0

Разработчики утверждают, что Waterfox блокирует трекинг и препятствует показу рекламы на просматриваемых в браузере сайтах. Но если посмотреть на соединения этого браузера в Portmaster при открытии тех же веб-страниц, что и в других браузерах, мы увидим множество соединений с серверами ста-

тистики Google (вроде gstatic.com и googletagmanager.com) и другими сер-

висами для сбора данных. По умолчанию Waterfox их не блокирует.

Waterfox не блокирует многие подозрительные соединения

Впрочем, блокировка рекламы в сочетании с тем, что этот браузер принадлежит рекламному агентству, звучит несколько странно, не правда ли? Поскольку Waterfox основан на Firefox, на него можно установить все плагины от Mozilla, в том числе повышающие приватность, блокирующие рекламу и подключающие прокси. Но все то же самое можно сделать и с обычным

Firefox.

IRON

Сайт: srware.net/iron/

Движок: Chromium

Исходный код: закрытый

Первый выпуск: 2008 год

Версии: Windows, macOS, Linux, Android

Iron — браузер, разрабатываемый германской фирмой SRWare на основе исходников Chromium. Для Windows доступны 32-разрядная и 64-разрядная версии, интерфейс переведен на множество языков, в том числе и на русский.

Проект Iron появился в 2008 году как попытка создать такой аналог Chrome, который в отличие от оригинала не будет делиться телеметрией

ипрочими данными с компанией Google. Современная версия Iron содержит также встроенный блокировщик рекламы. Важное отличие от Chrome заключается еще и в том, что в этом браузере отсутствует Google Updater. С одной стороны, это экономит трафик и ресурсы машины, поскольку в фоне не болтается еще одна запущенная программа. С другой — в Iron нет автоматического обновления, все апдейты нужно загружать с сайта и устанавливать вручную.

Iron использует собственные безопасные DNS-серверы (Secure DNS Resolver), с помощью которых он выполняет фильтрацию рекламы и небезопасного контента.

Работает браузер на удивление быстро: складывается ощущение, что веб-страницы открываются даже быстрее, чем в обычном Chrome. При этом браузер с настройками по умолчанию раскрывает IP-адрес пользователя

иместоположение. В панели инструментов есть ссылка Anomymous VPN, которая ведет на сайт SRWare, но подключить эту услугу предлагают платно.

После установки браузера на рабочем столе появляется значок Iron Con g and Backup — конфигуратор браузера. Чтобы воспользоваться этой функцией, нужно закрыть все открытые ранее окна Iron.

Флажок Enable extended Privacy на вкладке Con guration блокирует некото-

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

Конфигуратор Iron Con g and Backup

Вкладки Backup и Restore позволяют сохранить и восстановить настройки браузера при необходимости. Вкладка UserAgent — изменить значение, с помощью которого этот браузер представляется сайтам в интернете. Можно выбрать другой UserAgent (например, Safari) или несколько разных и нажатием на кнопку создать ярлык для запуска браузера с этим значением

UserAgent.

ВIron Con g and Backup можно изменить UserAgent

Спомощью вкладки Import from Chrome можно импортировать все данные (значения форм, историю, пароли) в Iron из Chrome, если ты пользовался им раньше.

ВPortmaster браузер Iron отображается как Chrome. Видно, что некоторые сайты отправляют запросы к серверам аналитики и статистики Google, но Iron блокирует их.

Iron в Portmaster

В целом браузер производит приятное впечатление, работает быстро, для фильтрации рекламы и трекинга использует Secure DNS. К недостаткам можно отнести закрытый исходный код и отсутствие встроенного VPN. Впрочем, поскольку этот браузер основан на Chromium, на него можно установить бесплатные плагины из Chrome Web Store, в том числе и плагины, реализующие подключение через прокси.

LIBREWOLF

Сайт: librewolf.net

Движок: Firefox

Исходный код: открытый

Первый выпуск: 2021 год

Версии: Windows, macOS, Linux

LibreWolf — это созданная независимыми разработчиками версия Firefox, направленная на приватность и безопасность пользователей. Она появилась относительно недавно, но в последнее время активно набирает популярность. Браузер имеет открытый исходный код, ссылку на который можно найти на сайте разработчиков.

Для загрузки предлагают 64-разрядную версию браузера для Windows

ввиде стандартного инсталлятора и, в качестве альтернативы, портабельное приложение в ZIP-архиве.

Если обычно ты пользуется Firefox, интерфейс программы покажется тебе привычным. Сразу бросается в глаза, что в качестве поисковой системы по умолчанию в LibreWolf используется DuckDuckGo, но ее можно заменить

внастройках другими поисковыми системами, считающимися безопасными: например, Searx или Qwant. Настройки браузера в целом аналогичны Firefox, никаких специфичных опций в окне конфигурации браузера обнаружить не удалось.

LibreWolf — настройки

Если верить информации на сайте разработчиков, этот браузер создан для защиты от трекинга и ngerprinting, а также содержит целый ряд дополнительных инструментов для обеспечения безопасности. Сообщается, что LibreWolf не собирает телеметрию, а для блокировки рекламы и фильтрации контента в браузере установлен бесплатный плагин uBlock Origin, который также можно использовать и в обычном Firefox.

В LibreWolf в целях безопасности заблокирован стандартный менеджер паролей, но вместо него можно использовать сторонние плагины для Firefox. Также в браузере включен так называемый режим Enhanced Tracking Protection, который блокирует некоторые сторонние скрипты, если их не заблокировал плагин uBlock Origin.

Поскольку LibreWolf использует повышенные настройки безопасности, постоянная авторизация на некоторых сайтах может время от времени сбрасываться. Чтобы сохранить авторизацию при каждом обращении к сайту, например быть постоянно залогиненным «Вконтакте», этот сайт нужно добавить в список исключений в настройках браузера.

BrowserLeaks показывает, что этот браузер более безопасный по сравнению с обычным Firefox: например, в нем отключена поддержка WebGL.

LibreWolf в BrowserLeaks

В браузере отключена точная геолокация, работают 11 контентных фильтров для блокировки трекеров и рекламы, а также включен Canvas Protection — защита от ngerprinting с помощью анализа того, как отображается графика в браузере.

LibreWolf в BrowserLeaks

В Portmaster браузер LibreWolf не показывает никаких подозрительных соединений. Исходящие соединения присутствуют, но эти обращения использует плагин uBlock Origin, чтобы получить списки фильтрации контента, а также проверить цифровые сертификаты сайтов.

LibreWolf в Portmaster

Кроме того, в FAQ на сайте разработчиков написано, что LibreWolf использует некоторые соединения для проверки того, получает ли пользователь пуш-уведомления от сайтов, на которые подписан.

В целом можно сказать, что браузер произвел приятное впечатление. Он имеет привычный для поклонников Firefox удобный интерфейс и работает достаточно быстро.

ВЫВОДЫ

Настало время подвести субъективные итоги. На наш взгляд, первое место среди приватных браузеров можно смело отдать Brave. Он имеет открытый исходный код, удобен, безопасен, а также может похвастаться встроенной поддержкой Tor.

На второе место мы бы поставили LibreWolf. Это тоже браузер с открытым исходным кодом, его возможности могут быть расширены за счет плагинов, и он может больше понравиться тем, кто привык к Firefox.

Бронзовую медаль вручим браузерам Epic и Iron. Это коммерческие продукты с закрытым исходным кодом, но они достаточно быстрые и имеют большой ассортимент настроек. Еще в Epic есть даунлоадер контента, но он не работает в YouTube.

Остальные рассмотренные в этой статье приватные браузеры, включая браузеры от разработчиков антивирусов, мы бы поставили в конец списка. Это не означает, что они плохие, однако либо в них отсутствуют полезные функции, которые есть в других продуктах, либо они предлагаются за деньги, тогда как в альтернативных браузерах бесплатны.

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

w Click

 

BUY

o m

КОДИНГ

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

w

p

 

 

 

 

g

 

 

 

 

 

df

-x

 

n

e

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

.

 

 

c

 

 

 

o

 

 

 

 

 

 

.c

 

 

w

p

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

СМОТРИМ СКВОЗЬ СТЕНЫ И ДЕЛАЕМ АВТОПРИЦЕЛИВАНИЕ ДЛЯ 3D-ШУТЕРА

Сегодня мы с тобой напишем чит для сетевого шутера. Мы реализуем хаки типа extrasensory perception (ESP) и aimbot. ESP отображает информацию об игроках над их головами. Здесь может быть здоровье игрока, имя или текущее используемое оружие. Aimbot автоматически нацеливается на других игроков.

neeko mynxold@gmail.com

В предыдущей статье «Чит своими руками. Вскрываем компьютерную игру и пишем трейнер на C++» я заложил базу для будущих читов и объ- яснил основные понятия. Рекомендую ознакомиться с ней, чтобы лучше понимать, что мы будем сегодня делать.

ВЫБОР ИГРЫ

Мой выбор пал на AssaultCube — бесплатный многопользовательский шутер от первого лица, основанный на движке CUBE. Используется графическая библиотека OpenGL.

Использование читов нарушает пользовательское соглашение игры и может повлечь юридическое преследование. Мы обсуждаем здесь создание чита исключительно в целях обучения. Автор и редакция не несут ответственности за возможные последствия применения и распространения такого ПО.

ПОИСК ЗНАЧЕНИЙ

Для начала запустим игру и в настройках выберем оконный режим, ведь нам нужно, чтобы на экране помещалось еще что-то, кроме игры.

Оконный режим

Также создадим локальный сервер. Нужно будет настроить его, а именно задать время игры, чтобы таймер не торопил нас. Конфиг лежит по следующему пути:

C:\Program Files (x86)\AssaultCube 1.3.0.2\config\maprot.cfg

Стандартные настройки времени

Поменяем время на максимальное — 100 минут.

Новые настройки времени

А после уже запускаем сам сервер.

Запуск сервера

И подключаемся к нему.

Подключение к серверу

Запускаем Cheat Engine и подключаемся к процессу игры.

Подключимся к процессу игры

Поиск показателя здоровья

Для тестирования нам понадобится второй игрок. Можешь подключиться со второго устройства или, как сделал я, из виртуальной машины. Для поиска показателя здоровья выставляем параметры сканирования в Cheat Engine и вторым игроком наносим урон первому. После этого ищем здоровье в Cheat Engine.

Получение урона

Будем наносить урон до тех пор, пока не найдем адрес, по которому хранится показатель здоровья нашего игрока.

Найденный адрес HP

На этом все знакомые по прошлой статье действия в Cheat Engine заканчиваются и начинаются новые. Наша цель — реализовать extrasensory perception и aimbot. Для этого нам нужно узнать класс игрока и его статический адрес. Чтобы найти класс, кликаем правой кнопкой мыши по нашему адресу и выбираем Find out what writes to this address (можно просто нажать F6).

Поиск места, где идет запись по адресу

Появится новое окно, где будут отображаться инструкции, которые производят запись по нашему адресу. Чтобы они появились, снова наносим урон вторым игроком первому.

Найденная инструкция

Показатель здоровья записывает всего одна инструкция, она расположена по смещению 0xEC. Значит, значение, хранящееся в регистре edx, — это адрес класса игрока (но адрес в куче, а не статический). Поэтому добавим его вручную.

Структура

Поиск статического адреса объекта игрока

В прошлый раз я использовал отладчик, чтобы наглядно показать, что собой представляет статический адрес. В этот раз для поиска статического адреса мы будем использовать Cheat Engine. Жмем на ранее добавленный адрес 0x6AED20 правой кнопкой мыши и выбираем Pointer scan for this address.

Выбор сканирования адреса

Как видишь, у нас есть множество параметров для поиска указателя, но нас интересует Max level. Это значение отвечает за то, сколько раз будет разыменован наш указатель (статический адрес). Оно-то и поможет нам получить искомый адрес.

Стандартные настройки сканирования указателя

Исполняемый файл игры занимает мало, и кода в нем тоже негусто. Это наводит на мысль, что классов и структур в игре не так много и не будет большого количества смещений. Поэтому глубину поиска мы установим равной единице.

Новые настройки сканирования указателя

Мы видим следующий результат. Об адресах вида "ac_client. exe"+YYYYYYYY мы уже писали в прошлой статье. Именно они нам и понадобятся. А вот адреса формата "THREADSTACKX"-YYYYYYYY говорят нам о том, что искомый нами адрес был найден в стеке.

Результаты сканирования указателя

Добавим найденные пять адресов в список.

Добавленные указатели

И выставим для каждого адреса смещение до показателей здоровья.

Добавленный указатель на HP

Далее перезапускаем игру, и Cheat Engine предложит сохранить наши адреса. Мы их сохраняем, чтобы загрузить при повторном подключении.

Сохраняем наш cheat table

После переподключения к игре в списке адресов Cheat Engine видим, что только два адреса указывают на показатель здоровья: "ac_client.

exe"+0017E0A8 и "ac_client.exe"+0018AC00.

После перезапуска AC

Попробуем повторно получить урон и посмотреть, что будет с другими адресами. Как видим, еще в двух адресах появился наш показатель здоровья. Значит, в списке мы оставляем только два упомянутых ранее адреса.

Повторное получение урона

Добавим статический адрес "ac_client.exe"+0017E0A8 под именем

Player_ptr_1.

Добавляем первый указатель

Добавим статический адрес "ac_client.exe"+0018AC00 под именем

Player_ptr_2.

Добавляем второй указатель

Продолжение статьи

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

c

 

o m

КОДИНГ

 

 

 

 

 

 

 

 

 

to

BUY

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

← НАЧАЛО СТАТЬИw Click

 

BUY

 

m

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

СМОТРИМ СКВОЗЬ СТЕНЫ И ДЕЛАЕМ АВТОПРИЦЕЛИВАНИЕ ДЛЯ 3D-ШУТЕРА

Класс игрока

Предположим, что статический адрес Player_ptr_1 — тот, что мы ищем (что на самом деле не так, правильным статическим адресом будет Player_ptr_2, но в этом мы убедимся позже). Чтобы просмотреть класс игрока в памяти, нажимаем правой кнопкой мыши на адрес и выбираем

Browse this memory region (или жмем Ctrl-B).

Открытие региона памяти

К счастью, у Cheat Engine есть инструмент, который позволяет нам лучше визуализировать структуры памяти, а не просматривать байты в дампе. Просто жми правой кнопкой мыши по выделенному байту и выбирай Open in dissect data/structure.

Открытие анализа структур

Откроется новое окно с адресом выбранного байта. Нажми Structures, затем

De ne new structure (или Ctrl-N).

Создание структуры

Назовем структуру Player. Остальные настройки оставим по умолчанию: предположительный тип поля и размер структуры (4096).

Создание класса игрока

Поставив галочку Guess eld type, мы попросили Cheat Engine угадать тип поля. И он неплохо с этим справился.

Полученная структура

Перейдем по смещению 0xEC, чтобы убедиться, что там находится показатель здоровья нашего игрока.

Проверка класса

Также можно по смещению 0x205 обнаружить имя игрока.

Имя игрока

В дальнейшем нам нужен этот класс, но, к сожалению, Cheat Engine не позволяет экспортировать структуру, а делать это вручную — значит подвергать себя мучениям. Это не нужно, поскольку существует готовый инструмент — ReClass.NET. Он дает возможность напрямую выгрузить структуру в виде кода на C++. Скачиваем, устанавливаем и подключаемся к процессу игры.

Подключение к процессу

После присоединения к процессу создается класс по базовому адресу 400000, он называется N0000004E. Дважды кликаем по адресу и выставляем нужный нам: 0066ED48. Аналогично изменяем имя класса на Player и добавляем для отображения еще 4096 байт.

В данном контексте отображаемое количество байтов СE воспринимает как класс, который мы экспортируем. Если размер нашего класса больше, чем стандартное количество отображаемых байтов, нужно вручную увеличить размер.

Настройка ReClass.NET

Переходим к смещению 0xEC, к показателю здоровья. Меняем значение типа поля на DWORD (мы выставим значения типов для смещений, что позволит нам в дальнейшем экспортировать класс с нужными полями).

Присвоение типа

Поиск координат

Начиная с этого места, мы будем искать значения, нужные непосредственно для реализации ESP и aimbot. Для ESP нам понадобятся координаты самого игрока и его головы в трехмерном пространстве.

Тем, кто не знает или забыл, как работает трехмерная система координат в компьютерной графике, рекомендую статью «3D своими руками» на «Хабрахабре».

Для реализации aimbot нам понадобятся значения тангажа (pitch), рысканья (yaw) и крена (roll). Не знаешь, что это? Давай покажу на примере игрового движка Godot.

Координаты XYZ

Запись координат может разниться в зависимости от движка. Часто различается направление осей и то, какая из них считается высотой.

Вариации координат

Для демонстрации возьмем с GitHub готового персонажа и посмотрим, как он будет двигаться, если менять координаты.

Персонаж на нулевых координатах

Тангаж — движение персонажа относительно оси X. Нижняя стрелка — фактическое движение персонажа в данный момент, верхняя — другой вариант движения.

Pitch

Рысканье — движение персонажа относительно оси Y.

Yaw

Крен — движение персонажа относительно оси Z.

Roll

Поиск координат игрока

С новыми знаниями возвращаемся к игре и окну Cheat Engine. Начинаем перемещаться по карте и вертеть мышкой из стороны в сторону, а также вверх и вниз. В окне Cheat Engine можем видеть три последовательности из значений с плавающей запятой, которые менялись при наших действиях. Значит, это координаты игрока, координаты головы игрока и его поворот относительно осей.

Можно заметить, что два набора из трех повторяются по X и Y, а вот координата Z у них разная. Отсюда мы можем сделать вывод, что один набор — это координаты игрока, а второй — головы. Так как в OpenGL в качестве высоты используется координата Z, мы попытаемся поменять высоту для каждого набора. Начнем с первого, но после попытки поменять значение c -0.5 на другое оно снова станет прежним. Значит, это координаты головы, второй набор — координаты игрока, а третий — движение относительно осей. Но мы в этом еще должны убедиться.

Неправильный выбор числа

Теперь давай попробуем сделать для второго набора то, что мы делали для первого.

Правильный выбор

Для наглядной демонстрации встанем на ящик, а в Cheat Engine будем смотреть на значение по смещению 0x30.

Становимся на высоту

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

Изменение высоты игрока

Продолжение статьи

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

КОДИНГ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

← НАЧАЛО СТАТЬИw Click

 

BUY

 

m

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

СМОТРИМ СКВОЗЬ СТЕНЫ И ДЕЛАЕМ АВТОПРИЦЕЛИВАНИЕ ДЛЯ 3D-ШУТЕРА

Это значит, что наши предположения верны.

Наши координаты

Вернемся в окно ReClass.NET и выберем типы для этих смещений.

Переименовываем и задаем тип

Поиск pitch, yaw, roll

Сделаем такую же проверку. Веди мышью из стороны в сторону, а потом вверх и вниз. Попробуем поменять значения, и оказывается, что наши предположения были верны.

Наши значения

Вернемся в окно ReClass.NET и выберем типы для этих смещений.

Переименовываем и задаем тип

Вот так теперь выглядит наш класс. Но что за VTable? Это поле не нужно, я добавил его для красоты. Подробнее о том, что это и зачем, можешь про-

читать в статье Understandig Virtual Tables in C++.

Наш класс

Теперь экспортируем наш класс (нажми

на него правой кнопкой мыши

и выбери соответствующий пункт меню).

Можешь видеть, что есть поля,

которые мы с тобой не искали: armor, team и прочие. Думаю, ты при желании сможешь найти их сам.

Экспортируем

Entity List

С нашим игроком мы разобрались, а как быть с другими игроками? Обычно где-то есть огромный список всех игровых сущностей, в который входят и персонажи игроков. Можно предположить, что где-то в коде должен существовать и цикл, который перебирает игроков, и дальше с их данными как-то взаимодействует логика игры. Попробуем оттолкнуться от показателя здоровья и поискать, какие инструкции его запрашивают.

Доступ к адресу со здоровьем

С наскока ничего найти не удается, но наметанный глаз заметит, что доступ к показателям здоровья нашего игрока идет через какой-то статический адрес. Оказывается, мы выбрали неправильный! Правильный адрес такой:

"ac_client.exe"+0018AC00.

Правильный адрес

Попробуем теперь поискать через имя игрока, которое находится по смещению 0x205.

Имя игрока

И получим список инструкций, которые обращаются к имени.

Добавляем адрес

Ищем доступ к адресу

Перебираем варианты и находим такой, где доступ происходит в цикле.

Цикл сущностей

Те, кто знаком с ассемблером, понимают, что в регистре ebx находится адрес первого элемента, esi — это индекс, а умножение индекса говорит нам о типе данных, в данном случае это 4, DWORD.

Таким образом, статический адрес списка сущностей будет таким:

"ac_client.exe"+0018AC04

Список сущностей

Убедиться в этом можно, проверив по смещению 0x205 имя игрока.

Имя другого игрока

Также нам понадобится общее количество игроков. Полистав вывод дизассемблера, в конце цикла увидим проверку. В регистре edi хранится текущее количество игроков.

Количество игроков

Немного подебажив, замечаем, что выше цикла находится статический адрес количества игроков: "ac_client.exe"+0018AC0C.

Статический адрес для игроков

Перезапустим и проверим, что адреса правильные.

Поиск View Matrix

Матрица View (вид) нужна для корректной работы ESP, более подробно об этом можешь почитать в статье об OpenGL на «Хабрахабре».

Последовательность преобразований

1.Локальные координаты — это координаты объекта, измеряемые относительно той точки, в которой находится объект.

2.На следующем шаге локальные координаты преобразуются в координаты в пространстве мира. Они отложены от какой-то точки, единой для всех других объектов, расположенных в мировом пространстве.

3.Дальше мы трансформируем мировые координаты в координаты прос-

транства вида таким образом, чтобы каждая вершина стала видна, как если бы на нее смотрели из камеры или с точки зрения наблюдателя.

4.После того как координаты будут преобразованы в пространство вида, мы спроецируем их в координаты отсечения. Координаты отсечения задаются в диапазоне от -1.0 до 1.0 и определяют, какие вершины появятся на экране.

5.И наконец, в процессе преобразования, который мы назовем трансфор-

мацией области просмотра, мы преобразуем координаты отсечения от -1.0 до 1.0 в область экранных координат, заданную функцией glViewport.

Для поиска матрицы вида будем ориентироваться на координаты отсечения, они задаются в диапазоне от -1.0 до 1.0. В игре смотрим прямо вверх, а в CE выставляем следующие параметры поиска.

Смотрим вверх

Теперь смотрим прямо вниз и выставляем новые параметры поиска. И чередуем, пока не найдем приемлемое количество результатов. В данном случае понадобилось не так много повторений, чтобы отыскать два статических адреса. Их-то мы и будем проверять.

Смотрим вниз

Откроем в дампе первый адрес и для удобства изменим тип отображаемых данных с байтов на oat.

Изменение для удобного вида

Вот что мы имеем.

Измененный вид

Продолжение статьи

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

КОДИНГ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

← НАЧАЛО СТАТЬИw Click

 

BUY

 

m

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

СМОТРИМ СКВОЗЬ СТЕНЫ И ДЕЛАЕМ АВТОПРИЦЕЛИВАНИЕ ДЛЯ 3D-ШУТЕРА

Теперь нужно поднимать и опускать оружие и смотреть, как меняются значения. Мы видим, что в области, обозначенной красным, что-то изменилось. Причем 1.0 и -1.0 будет только в выделенной области, а перед ней, если судить по размерам матриц, будут, соответственно, матрица мира и матрица перемещения. Таким образом, статический адрес матрицы вида получается

"ac_client.exe"+17DFD0.

Найденная матрица вида

Не забываем перезапустить игру и проверить правильность наших находок.

НАПИСАНИЕ ЧИТА

Как и в предыдущей статье, мы будем писать внутренний чит, поэтому нам понадобится не только сама библиотека, но и инжектор, который внедрит нашу библиотеку в процесс игры. Инжектор получит список процессов, найдет процесс игры и выделит в ней память, в которую запишет наш внутренний чит. А потом создаст удаленный поток внутри игры для выполнения кода.

Injector

Код инжектора выглядит следующим образом.

#include <windows.h>

#include <tlhelp32.h>

// Имя внедряемой DLL

const char* dll_path = "internal_cheat_ac.dll";

int main(void) {

HANDLE process;

void* alloc_base_addr;

HMODULE kernel32_base;

LPTHREAD_START_ROUTINE LoadLibraryA_addr;

HANDLE thread;

HANDLE snapshot = 0;

PROCESSENTRY32 pe32 = { 0 };

DWORD exitCode = 0;

pe32.dwSize = sizeof(PROCESSENTRY32);

// Получение снапшота текущих процессов

snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

Process32First(snapshot, &pe32);

do {

// Мы хотим работать только с процессом AC

if (wcscmp(pe32.szExeFile, L"ac_client.exe") == 0) {

// Во-первых, нам нужно получить дескриптор процесса,

чтобы использовать его для следующих вызовов

process = OpenProcess(PROCESS_ALL_ACCESS, true, pe32.

th32ProcessID);

// Чтобы не повредить память, выделим дополнительную

память для хранения нашего пути к DLL

alloc_base_addr = VirtualAllocEx(process, NULL, strlen(

dll_path) + 1, MEM_COMMIT, PAGE_READWRITE);

// Записываем путь к нашей DLL в память, которую мы

только что выделили внутри игры

WriteProcessMemory(process, alloc_base_addr, dll_path,

strlen(dll_path) + 1, NULL);

// Создаем удаленный поток внутри игры, который будет

выполнять LoadLibraryA

// Этому вызову LoadLibraryA мы передадим полный путь к

нашей DLL, которую мы прописали в игру

kernel32_base = GetModuleHandle(L"kernel32.dll");

LoadLibraryA_addr = (LPTHREAD_START_ROUTINE)

GetProcAddress(kernel32_base, "LoadLibraryA");

thread = CreateRemoteThread(process, NULL, 0,

LoadLibraryA_addr, alloc_base_addr, 0, NULL);

// Чтобы убедиться, что наша DLL внедрена, мы можем

использовать следующие два вызова для синхронизации

WaitForSingleObject(thread, INFINITE);

GetExitCodeThread(thread, &exitCode);

// Наконец, освобождаем память и очищаем дескрипторы

процесса

VirtualFreeEx(process, alloc_base_addr, 0, MEM_RELEASE);

CloseHandle(thread);

CloseHandle(process);

break;

}

// Перебор процессов из снапшота

} while (Process32Next(snapshot, &pe32));

return 0;

}

DLL

Наша библиотека будет состоять из следующих модулей:

главный модуль — dllmain.cpp;

модуль смещений в игре и игровых структур — structures.h;

модуль хуков — hook.cpp и hook.h;

модуль рисования — gl_draw.cpp и gl_draw.h.

Главный модуль

При загрузке нашей библиотеки через функцию LoadLibraryA создается поток, в котором будет работать основная логика нашего чита. А именно:

получение указателей на нужные нам поля;

установка хука на функцию отрисовки сцен;

цикл, в котором реализовано включение и отключение хаков, завершение работы чита;

функция, рисующая меню;

хаки ESP и aimbot.

Приступим к реализации!

include <iostream>

#include <string>

#include <tchar.h>

#include <thread>

#include <mutex>

#define _USE_MATH_DEFINES

#include <math.h>

#include "hook.h"

#include "structures.h"

#include "gl_draw.h"

//Переменная игрока

Player* player;

//Переменная синхронизации std::mutex hook_mutex;

//Typedef для функции wglSwapBuffers

typedef BOOL(__stdcall* twglSwapBuffers) (HDC hDc);

Tramp_Hook* esp_hook;

Player** player_list = nullptr;

int* player_list_size = nullptr;

static int list_size = 0;

static Vector3 screen_position;

static Vector3 world_position;

static Vector3 player_position;

static float* view_matrix;

bool aimbot_enabled = false;

// Меню

void draw_menu(bool flag_esp) {

std::string esp = "ESP is ";

std::string aimbot = "Aimbot is ";

if (flag_esp) {

esp += "ON press F1 to OFF";

}

else {

esp += "OFF press F1 to ON";

}

if (aimbot_enabled) {

aimbot += "ON press F2 to OFF";

}

else {

aimbot += "OFF press F2 to ON";

}

GL::print_gl(50, 1200, rgb::gray, esp.c_str());

GL::print_gl(50, 1300, rgb::gray, aimbot.c_str());

GL::print_gl(50, 1400, rgb::gray, "Exit cheat press F3");

}

// Наша функция, которую вызывает установленный хук

BOOL _stdcall hooked_wglSwapBuffers(HDC hDc) {

hook_mutex.lock();

draw_menu(esp_hook->is_enabled());

if (esp_hook->is_enabled()) {

//Настроить орфографический режим

GL::setup_orthographic();

if (*player_list_size == list_size) {

for (int i = 0; i < list_size; ++i) {

// Проверить, действителен ли адрес игрока

if (!player_list[i]) {

continue;

}

if (player_list[i]->hp > 0 && player_list[i]->hp <

200) {

// Сохранить позицию других игроков в Vector3

world_position.x = player_list[i]->x_y_z_player.x

;

world_position.y = player_list[i]->x_y_z_player.y

;

world_position.z = player_list[i]->x_y_z_player.z

;

// Сохранить позицию головы других игроков в

Vector3

player_position.x = player->x_y_z_head.x;

player_position.y = player->x_y_z_head.y;

player_position.z = player->x_y_z_head.z;

// Рассчитать расстояние до другого игрока

float distance = sqrtf((player_position.x -

world_position.x) * (player_position.x - world_position.x) + (

player_position.y - world_position.y) * (player_position.y -

world_position.y) + (player_position.z - world_position.z) * (

player_position.z - world_position.z));

// Проверить, находится ли игрок в зоне обзора

if (distance > 5.0f && GL::world_to_screen(

world_position, screen_position, view_matrix)) {

// Проверить, находится ли другой игрок в

той же команде, что и мы

if (player_list[i]->team != player->team) {

// Команда врага

GL::draw_esp_box(screen_position.x,

screen_position.y, distance, rgb::red, player_list[i]->name,

player_list[i]->hp, player_list[i]->armor);

}

else {

// Наша команда

GL::draw_esp_box(screen_position.x,

screen_position.y, distance, rgb::green, player_list[i]->name,

player_list[i]->hp, player_list[i]->armor);

}

}

}

}

}

else {

list_size = *player_list_size;

}

GL::restore_gl(); // Восстановить исходный режим

}

if (aimbot_enabled && GetAsyncKeyState(VK_RBUTTON)) {

if (*player_list_size == list_size) {

// Эти переменные будут использоваться для удержания

ближайшего к нам врага

float closest_player = -1.0f;

float closest_yaw = 0.0f;

float closest_pitch = 0.0f;

// Выбор ближайшего игрока в качестве цели

for (int i = 0; i < list_size; ++i) {

// Проверить, действителен ли адрес игрока, при этом

пропускаем игроков из нашей команды и проверяем показатель здоровья

if (!player_list[i] || (player_list[i]->team ==

player->team) || (player_list[i]->hp < 0)) {

continue;

}

// Расчет абсолютного положения врага вдали от нас.

Позволяет убедиться, что наши будущие расчеты верны и основаны на

исходной точке

float abspos_x = player_list[i]->x_y_z_player.x -

player->x_y_z_player.x;

float abspos_y = player_list[i]->x_y_z_player.y -

player->x_y_z_player.y;

float abspos_z = player_list[i]->x_y_z_player.z -

player->x_y_z_player.z;

// Расчет дистанции до врага

float temp_distance = sqrtf((abspos_x * abspos_x) + (

abspos_y * abspos_y));

// Если это ближайший враг, рассчитываем рыскание и

тангаж, чтобы нацелиться на него

if (closest_player == -1.0f || temp_distance <

closest_player) {

closest_player = temp_distance;

// Рассчитываем рыскание

float azimuth_xy = atan2f(abspos_y, abspos_x);

// Переводим в градусы

float yaw = (float)(azimuth_xy * (180.0 / M_PI));

// Добавляем 90, так как игра предполагает, что

прямой север равен 90 градусам

closest_yaw = yaw + 90;

//Рассчитываем тангаж

//Поскольку значения Z настолько ограничены,

выбирай большее значение между X и Y, чтобы убедиться, что мы не

смотрим прямо в небо, когда находимся рядом с врагом

if (abspos_y < 0) {

abspos_y *= -1;

}

if (abspos_y < 5) {

if (abspos_x < 0) {

abspos_x *= -1;

}

abspos_y = abspos_x;

}

float azimuth_z = atan2f(abspos_z, abspos_y);

// Преобразовываем значение в градусы

closest_pitch = (float)(azimuth_z * (180.0 / M_PI

));

}

}

//Когда наш цикл завершится, устанавливаем для рысканья

итангажа самые близкие значения

player->yaw_pitch_roll.x = closest_yaw;

player->yaw_pitch_roll.y = closest_pitch;

}

else {

list_size = *player_list_size;

}

}

// Вызов перехваченной функции

BOOL ret_value = ((twglSwapBuffers)esp_hook->get_gateway())(hDc);

hook_mutex.unlock();

return ret_value;

}

DWORD WINAPI injected_thread(HMODULE hMod) {

//Получить адрес, по которому .exe был загружен внутри нашего игрового процесса

uintptr_t moduleBase = (uintptr_t)GetModuleHandle(0);

//Где находится указатель на нашего игрока

player = *reinterpret_cast<Player**>(moduleBase + player_offset);

// Указатель на список игроков

player_list = *reinterpret_cast<Player***>(moduleBase +

entity_offset);

// Указатель на размер списка игроков

player_list_size = reinterpret_cast<int*>(moduleBase +

entity_count_offset);

// Указатель на матрицу вида

view_matrix = reinterpret_cast<float*>(moduleBase +

view_matrix_offset);

// Получить дескриптор модуля OpenGL

HMODULE open_gl = GetModuleHandleA("opengl32.dll");

if (!open_gl) {

return -1; // OpenGL не загружен

}

// Получить адрес wglSwapBuffers

void* orig_wglSwapBuffers = GetProcAddress(open_gl,

"wglSwapBuffers");

// Установка хука на wglSwapBuffers

esp_hook = new Tramp_Hook(orig_wglSwapBuffers,

hooked_wglSwapBuffers, 5);

while (!GetAsyncKeyState(VK_F3)) {

if (GetAsyncKeyState(VK_F1) & 1) { // Включить ESP

esp_hook->is_enabled() ? esp_hook->disable() : esp_hook->

enable();

}

if (GetAsyncKeyState(VK_F2) & 1) { // Включить aimbot

aimbot_enabled = !aimbot_enabled;

}

Sleep(50);

}

hook_mutex.lock();

//Удаление хука delete esp_hook; hook_mutex.unlock();

//Извлечение нашей библиотеки

FreeLibraryAndExitThread(hMod, 0); return 0;

}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call,

LPVOID lpReserved) {

switch (ul_reason_for_call) {

case DLL_PROCESS_ATTACH:

CreateThread(0, 0, (LPTHREAD_START_ROUTINE)injected_thread,

hModule, 0, 0);

case DLL_THREAD_ATTACH:

case DLL_THREAD_DETACH:

case DLL_PROCESS_DETACH:

break;

}

return TRUE;

}

Модуль смещений в игре и игровых структур

Этот модуль содержит все нужные нам поля игрока, а также смещения.

#pragma once

#include "gl_draw.h"

class Player {

public:

DWORD* vftable; // 0x00

Vector3 x_y_z_head; // 0x04

BYTE pad_0010[24]; // 0x10

Vector3 x_y_z_player; // 0x28

Vector3 yaw_pitch_roll; // 0x34

BYTE pad_0040[172]; // 0x40

DWORD hp; // 0xEC

DWORD armor; // 0xF0

BYTE pad_00F4[273]; // 0xF4

BYTE name[16]; // 0x205

BYTE pad_0215[247]; // 0x215

BYTE team; // 0x30C

};

DWORD player_offset = 0x018AC00;

DWORD entity_offset = 0x018AC04;

DWORD entity_count_offset = 0x018AC0C;

DWORD view_matrix_offset = 0x17DFD0;

Модуль хуков

Это модуль, в котором будет перехватываться функция wglSwapBuffers, отвечающая за отрисовку сцен. Это необходимо для того, чтобы рисовать наше меню и боксы ESP.

hook.h

#pragma once

#include <windows.h>

#include <memory>

// Класс перехватчика

class Hook {

//Указатель на перехватчик void* this_to_hook;

//Сохраненные старые опкоды std::unique_ptr<char[]> old_opcodes;

//Длина перезаписанных инструкций int this_len;

//Включен ли перехватчик

bool enabled;

public:

// Конструктор для перехватчика

Hook(void* to_hook, void* our_func, int len);

//Деструктор для восстановления исходного кода

~Hook();

//Включить перехватчик

void enable();

//Отключить перехватчик void disable();

//Включен ли перехватчик bool is_enabled();

};

// Класс для реализации инлайн-перехватчика

class Tramp_Hook {

void* gateway;

Hook* managed_hook;

public:

Tramp_Hook(void* to_hook, void* our_func, int len);

// Восстанавливает исходный код

~Tramp_Hook();

void enable();

void disable();

bool is_enabled();

void* get_gateway();

};

Продолжение статьи

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

КОДИНГ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

← НАЧАЛО СТАТЬИw Click

 

BUY

 

m

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

СМОТРИМ СКВОЗЬ СТЕНЫ И ДЕЛАЕМ АВТОПРИЦЕЛИВАНИЕ ДЛЯ 3D-ШУТЕРА

hook.cpp

#include "hook.h"

Hook::Hook(void* to_hook, void* our_func, int len) : this_to_hook{

to_hook }, old_opcodes{ nullptr }, this_len{ len }, enabled{ false }

{

// Инструкция jmp имеет размер 5 байт. Место, которое мы

перезаписываем, должно быть как минимум такого размера

if (len < 5) {

return;

}

DWORD curr_protection;

//Сделать доступной для записи память с кодом, который мы хотим перезаписать

VirtualProtect(to_hook, len, PAGE_EXECUTE_READWRITE, & curr_protection);

//Сохранить текущие байты в массив символов

old_opcodes = std::make_unique<char[]>(len);

if (old_opcodes != nullptr) {

for (int i = 0; i < len; ++i) {

old_opcodes[i] = ((char*)to_hook)[i];

}

}

//Перезапишем место, которое хотим перехватить, инструкциями nop memset(to_hook, 0x90, len);

//Вычислить относительный адрес для перехода

DWORD rva_addr = ((DWORD)our_func - (DWORD)to_hook) - 5;

//Поместить опкод для инструкции jmp *(BYTE*)to_hook = 0xE9;

//Поместить адрес для перехода

*(DWORD*)((DWORD)to_hook + 1) = rva_addr;

//Восстановить старую защиту кода

VirtualProtect(to_hook, len, curr_protection, &curr_protection);

}

Hook::~Hook() {

if (old_opcodes != nullptr) {

DWORD curr_protection;

// Сделать память доступной для записи

VirtualProtect(this_to_hook, this_len, PAGE_EXECUTE_READWRITE

,&curr_protection);

//Записать старые опкоды обратно в перехваченное место for (int i = 0; i < this_len; ++i) {

((char*)this_to_hook)[i] = Hook::old_opcodes[i];

}

//Восстановить старую защиту памяти

VirtualProtect(this_to_hook, this_len, curr_protection, &

curr_protection);

}

}

void Hook::enable() {

this->enabled = true;

}

void Hook::disable() {

this->enabled = false;

}

bool Hook::is_enabled() {

return enabled;

}

Tramp_Hook::Tramp_Hook(void* to_hook, void* our_func, int len) :

gateway{ nullptr }, managed_hook{ nullptr } {

//jmp имеет размер 5 байт if (len < 5) {

return;

}

//Выделяем память для нашего трамплина

gateway = VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE,

PAGE_EXECUTE_READWRITE);

//Сохранение байтов, которые мы будем перезаписывать в трамплин memcpy_s(gateway, len, to_hook, len);

//Получить адрес возврата

uintptr_t ret_addr = (BYTE*)to_hook - (BYTE*)gateway - 5;

//Разместить опкод jmp в конец трамплина

*(BYTE*)((uintptr_t)gateway + len) = 0xE9;

//Разместить адрес возврата после jmp

*(uintptr_t*)((uintptr_t)gateway + len + 1) = ret_addr;

// Создание перехватчика

managed_hook = new Hook(to_hook, our_func, len);

}

Tramp_Hook::~Tramp_Hook() {

managed_hook->disable();

delete managed_hook;

VirtualFree(gateway, 0, MEM_RELEASE);

}

void Tramp_Hook::enable() {

managed_hook->enable();

}

void Tramp_Hook::disable() {

managed_hook->disable();

}

bool Tramp_Hook::is_enabled() {

return managed_hook->is_enabled();

}

void* Tramp_Hook::get_gateway() {

return gateway;

}

Модуль рисования

Здесь у нас функции для непосредственной отрисовки меню и боксов ESP.

gl_draw.h

#pragma once

#pragma comment(lib, "OpenGL32.lib")

#include <windows.h>

#include<gl/GL.h>

struct Vector3 {

float x, y, z;

};

struct Vector4 {

float x, y, z, w;

};

//Пространство имен цветов для рисования namespace rgb {

const GLubyte red[3] = { 255,0,0 }; const GLubyte green[3] = { 0,255,0 }; const GLubyte blue[3] = { 0,0,255 }; const GLubyte gray[3] = { 55,55,55 };

const GLubyte light_gray[3] = { 192,192,192 }; const GLubyte yellow[3] = { 255, 255, 0 }; const GLubyte black[3] = { 0,0,0 };

}

//Пространство имен функций для отрисовки меню и ESP-хака namespace GL {

void setup_orthographic(); void restore_gl();

void build_font();

void draw_filled_rectangle(float x, float y, float width, float height, const GLubyte color[3]);

void draw_out_line(float x, float y, float width, float height, float line_width, const GLubyte color[3]);

void draw_line(float fromX, float fromY, float toX, float toY, float line_width, const GLubyte color[3]);

void draw_esp_box(float pos_x, float pos_y, float distance, const GLubyte color[3], const BYTE* text, const int health_percent = -1, const int armor_percent = -1);

void print_gl(float x, float y, const GLubyte color[3], const char* fmt, ...);

bool world_to_screen(Vector3 pos, Vector3& screen, float matrix[ 16]);

}

gl_draw.cpp

#include "gl_draw.h"

#include <corecrt_math.h>

#include <stdio.h>

HDC

h_DC;

HFONT

h_old_font;

HFONT

h_font;

UINT

font_base;

bool

b_font_build = 0;

void GL::setup_orthographic() {

//Cохранение атрибутов glPushAttrib(GL_ALL_ATTRIB_BITS);

//Сохранение матрицы вида glPushMatrix();

//Размеры экрана

GLint view_port[4];

//Получение размеров экрана glGetIntegerv(GL_VIEWPORT, view_port);

//Установка размера экрана

glViewport(0, 0, view_port[2], view_port[3]);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

// Настройка орфографического режима

glOrtho(0, view_port[2], view_port[3], 0, -1, 1);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

// Отключение проверки глубины

glDisable(GL_DEPTH_TEST);

}

void GL::restore_gl() {

//Восстановление матрицы вида glPopMatrix();

//Восстановление всех атрибутов glPopAttrib();

}

void GL::draw_filled_rectangle(float x, float y, float width, float

height, const GLubyte color[3]) {

glColor3ub(color[0], color[1], color[2]);

glBegin(GL_QUADS);

glVertex2f(x, y);

glVertex2f(x + width, y);

glVertex2f(x + width, y + height);

glVertex2f(x, y + height);

glEnd();

}

void GL::draw_out_line(float x, float y, float width, float height,

float line_width, const GLubyte color[3]) {

glLineWidth(line_width);

glBegin(GL_LINE_STRIP);

glColor3ub(color[0], color[1], color[2]);

glVertex2f(x - 0.5f, y - 0.5f);

glVertex2f(x + width + 0.5f, y - 0.5f);

glVertex2f(x + width + 0.5f, y + height + 0.5f);

glVertex2f(x - 0.5f, y + height + 0.5f);

glVertex2f(x - 0.5f, y - 0.5f);

glEnd();

}

void GL::draw_line(float fromX, float fromY, float toX, float toY,

float line_width, const GLubyte color[3]) {

glLineWidth(line_width);

glBegin(GL_LINES);

glColor3ub(color[0], color[1], color[2]);

glVertex2f(fromX, fromY);

glVertex2f(toX, toY);

glEnd();

}

void GL::build_font()

{

h_DC = wglGetCurrentDC();

font_base = glGenLists(96);

h_font = CreateFont(-12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,

ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY,

FF_DONTCARE | DEFAULT_PITCH, L"Courier");

h_old_font = (HFONT)SelectObject(h_DC, h_font);

wglUseFontBitmaps(h_DC, 32, 96, font_base);

SelectObject(h_DC, h_old_font);

DeleteObject(h_font);

b_font_build = true;

}

void GL::print_gl(float x, float y, const GLubyte color[3], const

char* fmt, ...)

{

if (!b_font_build) {

GL::build_font();

}

if (fmt == NULL) {

return;

}

glColor3f(color[0], color[1], color[2]);

glRasterPos2i(x, y);

char

text[256];

va_list

ap;

va_start(ap, fmt);

vsprintf(text, fmt, ap);

va_end(ap);

glPushAttrib(GL_LIST_BIT);

glListBase(font_base - 32);

glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);

glPopAttrib();

}

void GL::draw_esp_box(float pos_x, float pos_y, float distance, const

GLubyte color[3], const BYTE* text, const int health, const int armor

) {

float line_width = 0.5f; // Толщина линии

GLint view_port[4];

glGetIntegerv(GL_VIEWPORT, view_port);

float height = (view_port[3] / distance) * 3; // Высота бокса

float width = (view_port[2] / distance); // Ширина бокса

// Snap lines

GL::draw_line(view_port[2] / 2.0f, (float)view_port[3], pos_x,

pos_y, line_width + 2.0f, rgb::black);

GL::draw_line(view_port[2] / 2.0f, (float)view_port[3], pos_x,

pos_y, line_width, color);

// Очертания

GL::draw_out_line(pos_x - (width / 2), pos_y - height, width,

height, line_width + 2.0f, rgb::black);

GL::draw_out_line(pos_x - (width / 2), pos_y - height, width,

height, line_width, color);

// Здоровье

if (health != -1) {

float perc = (width / 100);

float curr = perc * health;

GL::draw_filled_rectangle(pos_x - (width / 2) - 1, ((pos_y -

(height / 10)) - 1) - height, width + 2, (height / 15) + 2, rgb::

black);

GL::draw_filled_rectangle(pos_x - (width / 2), (pos_y - (

height / 10)) - height, width, height / 15, rgb::light_gray);

GLubyte Hcolor[3]{ static_cast<GLubyte>(255 - (2.5f * health

)), static_cast<GLubyte>(health * 2.5f), 0 };

GL::draw_filled_rectangle(pos_x - (width / 2), (pos_y - (

height / 10)) - height, curr, height / 15, Hcolor);

}

//

Броня

 

 

 

 

if

(armor

!= -1)

{

 

 

float

perc

=

(width

/ 100);

 

float

curr

=

perc *

armor;

GL::draw_filled_rectangle(pos_x - (width / 2) - 1, ((pos_y -

(height / 5)) - 1) - height, width + 2, (height / 15) + 2, rgb::black

);

GL::draw_filled_rectangle(pos_x - (width / 2), (pos_y - (

height / 5)) - height, width, height / 15, rgb::light_gray);

GL::draw_filled_rectangle(pos_x - (width / 2), (pos_y - (

height / 5)) - height, curr, height / 15, rgb::blue);

}

// Имя

GL::print_gl(pos_x - (width / 2), (pos_y - (height / 4)) - height

, rgb::yellow,(char *)text);

}

bool GL::world_to_screen(Vector3 pos, Vector3& screen, float matrix[

16]) {

//Получение ширины и высоты экрана

GLint view_port[4]; glGetIntegerv(GL_VIEWPORT, view_port); int window_width = view_port[2];

int window_height = view_port[3];

//Матрично-векторный результат, умножающий мировые (глазные) координаты на проекционную матрицу (clip_coords)

Vector4 clip_coords;

clip_coords.x = pos.x * matrix[0] + pos.y * matrix[4] + pos.z * matrix[8] + matrix[12];

clip_coords.y = pos.x * matrix[1] + pos.y * matrix[5] + pos.z * matrix[9] + matrix[13];

clip_coords.z = pos.x * matrix[2] + pos.y * matrix[6] + pos.z * matrix[10] + matrix[14];

clip_coords.w = pos.x * matrix[3] + pos.y * matrix[7] + pos.z * matrix[11] + matrix[15];

//Если координаты не на экране

if (clip_coords.w < 0.1f) {

return false;

}

//Перспективное деление, деление на clip.W, то есть нормализованные координаты устройства

Vector3 NDC;

NDC.x = clip_coords.x / clip_coords.w; NDC.y = clip_coords.y / clip_coords.w; NDC.z = clip_coords.z / clip_coords.w;

//Преобразование в координаты экрана

screen.x = (window_width / 2 * NDC.x) + (NDC.x + window_width / 2

);

screen.y = -(window_height / 2 * NDC.y) + (NDC.y + window_height

/ 2);

return true;

}

ПРОВЕРКА РАБОТОСПОСОБНОСТИ

Для начала запустим наш чит.

Меню чита

Для активации ESP-хака жмем F1, для деактивации — F2.

Проверка работоспособности ESP

Для активации aimbot жмем F2 и, чтобы он заработал, зажимаем правую кнопку мыши. Для деактивации хака жмем F2.

Проверка работоспособности aimbot

ВЫВОДЫ

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

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

 

o

 

 

.

 

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

 

g

 

 

 

 

 

df

-x

 

n

e

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

«Хакеру» нужны новые авторы, и ты можешь стать одним из них! Если тебе интересно то, о чем мы пишем, и есть желание исследовать эти темы вместе с нами, то не упусти возможность вступить в ряды наших авторов и получать за это все, что им причитается.

Авторы получают денежное вознаграждение. Размер зависит от сложности и уникальности темы и объема проделанной работы (но не от объема текста).

Наши авторы читают «Хакер» бесплатно: каждая опубликованная статья приносит месяц подписки и значительно увеличивает личную скидку. Уже после третьего раза подписка станет бесплатной навсегда.

Кроме того, наличие публикаций — это отличный способ показать работодателю и коллегам, что ты в теме. А еще мы планируем запуск англоязычной версии, так что у тебя будет шанс быть узнанным и за

рубежом.

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

Я ТЕХНАРЬ, А НЕ ЖУРНАЛИСТ. ПОЛУЧИТСЯ ЛИ У МЕНЯ НАПИСАТЬ СТАТЬЮ?

Главное в нашем деле — знания по теме, а не корочки журналиста. Знаешь тему — значит, и написать сможешь. Не умеешь — поможем, будешь сомневаться — поддержим, накосячишь — отредактируем. Не зря у нас работает столько редакторов! Они не только правят буквы, но и помогают с темами и форматом и «причесывают» авторский текст, если в этом есть необходимость. И конечно, перед публикацией мы согласуем с автором все правки и вносим новые, если нужно.

КАК ПРИДУМАТЬ ТЕМУ?

Темы для статей — дело непростое, но и не такое сложное, как может показаться. Стоит начать, и ты наверняка будешь придумывать темы одну за другой!

Первым делом задай себе несколько простых вопросов:

«Разбираюсь ли я в чем то, что может заинтересовать других?»

Частый случай: люди делают что-то потрясающее, но считают свое занятие вполне обыденным. Если твоя мама и девушка не хотят слушать про реверс малвари, сборку ядра Linux, проектирование микропроцессоров или хранение данных в ДНК, это не значит, что у тебя не найдется благодарных читателей.

«Были ли у меня в последнее время интересные проекты?» Если ты ресерчишь, багхантишь, решаешь crackme или задачки на CTF, если ты разрабатываешь что-то необычное или даже просто настроил себе какую-то удобную штуковину, обязательно расскажи нам! Мы вместе придумаем, как лучше подать твои наработки.

«Знаю ли я какую то историю, которая кажется мне крутой?»

Попробуй вспомнить: если ты буквально недавно рассказывал кому-то о чем-то очень важном или захватывающем (и связанным с ИБ или ИТ), то с немалой вероятностью это может быть неплохой темой для статьи. Или как минимум натолкнет тебя на тему.

«Не подмечал ли я, что в Хакере упустили что то важное?» Если мы о чем-то не писали, это могло быть не умышленно. Возможно, просто никому не пришла в голову эта тема или не было человека, который взял бы ее на себя. Кстати, даже если писать сам ты не собираешься, подкинуть нам идею все равно можно.

Уговорили, каков план действий?

1.Придумываешь актуальную тему или несколько.

2.Описываешь эту тему так, чтобы было понятно, что будет в статье и зачем ее кому-то читать. Обычно достаточно рабочего заголовка и нескольких предложений (pro tip: их потом можно пустить на введение).

3.Выбираешь редактора и отправляешь ему свои темы (можно главреду — он разберется). Заодно неплохо бывает представиться и написать пару слов о себе.

4.С редактором согласуете детали и сроки сдачи черновика. Также он выдает тебе правила оформления и отвечает на все интересующие вопросы.

5.Пишешь статью в срок и отправляешь ее. Если возникают какие-то проблемы, сомнения или просто задержки, ты знаешь, к кому обращаться.

6.Редактор читает статью, принимает ее или возвращает с просьбой

доработать и руководством к действию.

7. Перед публикацией получаешь версию с правками и обсуждаешь их

с редактором (или просто даешь добро).

8.Дожидаешься выхода статьи и поступления вознаграждения.

Если хочешь публиковаться в «Хакере», придумай тему для первой статьи и предложи редакции.

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

№3 (288)

Андрей­

Письмен­ ­ный

Вален­ тин­ Холмогоров­

Илья Русанен

Главный­ редактор­

 

Ведущий редактор­

Разработ­

­ка

 

pismenny@glc.ru

 

 

valentin@holmogorov.ru

 

rusanen@glc.ru

 

 

 

 

 

Евгения­

Шарипова­

 

 

 

 

 

 

Литератур­ ный­ редактор­

 

 

MEGANEWS

Мария­ Нефёдова­ nefedova@glc.ru

АРТ

yambuto yambuto@gmail.com

КОНСУЛЬТАЦИОННЫЙ СОВЕТ

Иван Андреев­ , Олег Афонин­ , Марк Бруцкий­ Стем ­ пковский, Алексей­ Глазков­ , Nik Zerof, Юрий Язев

РЕКЛАМА

Анна­ Яковлева­

Директор­ по спецпро­ ­ектам yakovleva.a@glc.ru

РАСПРОСТРАНЕНИЕ И ПОДПИСКА

Вопросы­

о подписке­

:

​Воп­росы о материалах­

:

 

lapina@glc.ru

 

 

 

support@glc.ru​

 

 

 

 

 

 

 

 

 

 

Адрес­ редакции­ : 125080, город Москва­ , Волоколам­ ­ское шоссе­ , дом 1, строение­ 1, этаж 8, помещение­ IX, комната­ 54, офис 7. Издатель­ : ИП Югай Александр­ Олегович­ , 400046, Волгоград­ ­ская область, г. Волгоград­ , ул. Дружбы­ народов, д. 54. Учредитель­ : ООО «Медиа Кар»​​125080, город Москва­ , Волоколам­ ­ское шоссе­ , дом 1, строение­ 1, этаж 8, помещение­ IX, комната­ 54, офис 7. Зарегистри­ ­рова­но в Федеральной­ службе­ по надзору­ в сфере­ связи­ , информацион­ ­ных технологий­ и массовых­ коммуника­ ­ций (Роскомнад­ ­зоре), свидетель­ ­ство ​Эл № ​ФС77-​67001 от ​30.​ 08.2016​ года. Мнение­ редакции­ не обязатель­ ­но совпада­ ­ет с мнением­ авторов­ . Все материалы­ в номере предос­ ­тавля­ются как информация­ к размышле­ ­нию. Лица, использующие­ данную­ информацию­ в противо­ ­закон­ных целях, могут быть привлечены­ к ответствен­ ­ности. Редакция­ не несет ответствен­ ­ности за содержание­ рекламных­ объявле­ ­ний в номере. По вопросам­ лицензирова­ ­ния и получения­ прав на использование­ редакцион­ ­ных материалов­ журнала­ обращай­ ­тесь по адресу­ : xakep@glc.ru. © Журнал­ «Хакер», РФ, 2022

Соседние файлы в папке журнал хакер