Показаны сообщения с ярлыком Взлом игр. Показать все сообщения
Показаны сообщения с ярлыком Взлом игр. Показать все сообщения

20160222

Куда податься с YouTube?

Ребята, всем привет!

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

Исходя из предыдущего абзаца, у меня есть несколько выходов:

- Отставить всё, как есть, и продолжать выкладывать видео на этом же канале\хостинге. Плюсы - делать ничего не нужно, минусы - видео будут удалять, а я не всегда сохраняю их у себя.

- Сменить видеохостинг. Плюсы - если это будет какой-нибудь VK, то видео вряд ли будут удалять. Минусы - нужно будет по-новой заполнять весь канал.

- Вести только блог. Статьи + картинки. Плюсы - вряд ли удалят. Минусы - займёт много времени, не так интересно читателю.

Ваши варианты - в комментарии.

---------------------------------------- 
Вопросы? Пожелания? Предложения? 
Вот как можно со мной связаться: 
Email: 00 keng [at] gmail [dot] com 
VK: kekekeng 
Twitter: @ultrakeng 
Telegram: @remizovm 
----------------------------------------

20160105

Блог снова оживает.

Всем привет!

У меня вновь появилось свободное время, которое я буду уделять блогу. А чему ещё-то, верно?


Так вот. На замечательном видеохостинге YouTube начали удалять мои видео совершенно безо всякой на то причины, и это делает меня грустить. Я не знаю, где мне теперь выкладывать новые видео. Если вдруг есть предложения - милости прошу в комментарии или в самый низ любого поста - за обратной связью. Пока что буду вести блог в текстово-картиночном формате, а видео будут (я верю)
выкладываться в официальной группе GameHackLab ВКонтакте:

[http://vk.com/gamehacklab]

А пока что у меня есть исключительно две задумки:

- Дальше топаем по рубрике "Перезагрузка. Ассемблер."
- Берём C++ и пишем свой движок для трейнеров с музыкой и менюшкой

Такие вот планы.


----------------------------------------
Вопросы? Пожелания? Предложения?
Вот как можно со мной связаться:
[email]
[vk]
[twitter]
[telegram]

----------------------------------------

20150920

Перезагрузка. Ассемблер. Часть 3. Знакомимся с отладчиком.

Оглавление:
----------
Часть 0. [Установка и настройка]
Часть 1. [Пишем первую программу]
Часть 2. [Как работает процессор и что такое регистры]

Часть 3. [Знакомимся с отладчиком]

------------------------------------
Весь исходный код можно взять [тут].
------------------------------------


Привет, блога моего читатели!

Сегодня у нас будет чуть более практическая тема статьи. Я уже немного рассказал о том, как работает процессор и что такое регистры. Если коротко подвести итог, то процессор - тупая считалка. Ему нужно сказать, где брать код программы (по какому адресу), а затем он начнет выполнять этот код построчно, команда за командой, буква за буквой. Сам код (программа) при этом загружен в оперативную память компьютера. Чтобы каждый раз не загружать программу с диска в память и не указывать глупому процессору, откуда начинать исполнять программу, нужна операционная система. А вы думали, что в игры играть? Не-а. Так вот. Раньше программы писали путем переключения выключателей (0 и 1), затем - выбивая дырочки на перфокартах (те же 0 и 1) и скармливая стопки этих перфокарт компьютеру, а потом произошло чудо чудное и придумался язык ассемблера - *мнемоническая* запись команд процессора в форме, понятной для человека. После этого стали появляться более крутые (высокоуровневые) языки вроде фортрана или алгола, си, паскаля и так далее. Чем дальше в лес - тем сильнее ощущалась нужда в возможности контролировать ход выполнения программы, потому что эти самые программы становились все больше и сложнее. С этой мыслью программисты того времени придумали инструмент под названием отладчик - специальную программу, позволяющую контролировать ход исполнения другой программы. Эдакий воспитатель в детском саду - тут играть можно, еще можно кашу, а Машу за косички подергать - нельзя, и песком кидаться в Витю тоже нельзя.

В рамках этой серии статей мы будем рассматривать мой любимый отладчик (на самом деле, они не очень сильно друг от друга отличаются - принцип работы у всех одинаковый) под названием Olly Debugger. Скачать его можно или на официальном [сайте] или где-нибудь еще в интернете. На момент написания этой статьи используемая мной версия - 2.01. Скачиваем архив, распаковываем куда-нибудь и - это важно! - запускаем с правами администратора. Вот оно, окошко:



Как и у практически любой другой программы Windows, у этой тоже есть меню. Помните программу из предыдущих статей, которая выводит на экран сообщение? Ищем ее в скомпилированном виде и открываем в отладчике через его меню (File -> Open):




Вот это да, как много всего! Давайте по часовой стрелки, начиная с верхнего-левого угла. Там у нас вот такое:

CPU Disasm
Address   Hex dump               Command                                  Comments
00401000  /$  6A 00              PUSH 0                                   ; /Type = MB_OK|MB_DEFBUTTON1|MB_APPLMODAL
00401002  |.  6A 00              PUSH 0                                   ; |Caption = NULL
00401004  |.  E8 0E000000        CALL 00401017                            ; |Text = "j", jump over immediate data
00401009  |.  48 65 6C 6C 6F 2C  ASCII "Hello, World!",0                  ; |ASCII "Hello, World!"
00401017  |>  6A 00              PUSH 0                                   ; |hOwner = NULL
00401019  |.  FF15 80204000      CALL DWORD PTR DS:[<&USER32.MessageBoxA> ; \USER32.MessageBoxA
0040101F  |.  6A 00              PUSH 0                                   ; /ExitCode = 0
00401021  \.  FF15 60204000      CALL DWORD PTR DS:[<&KERNEL32.ExitProces ; \KERNEL32.ExitProcess

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

Я разберу одну строчку, а дальше станет немного понятней:

00401000 6A 00 PUSH 0 ; /Type = MB_OK|MB_DEFBUTTON1|MB_APPLMODAL

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

6A 00 - это то, как команда выглядит в исполняемом файле, в уже скомпилированном виде. Человеку такое запоминать трудновато, так что для него придумали вот это:

PUSH 0

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

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

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

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




Дык вот. У нас есть вершина стека (кстати, есть даже специальный регистр процессора, который постоянно указывает на вершину стека - ESP). Мы можем положить данные на вершину и снять с вершины. Только так. Смотрим на картинку с игрушкой. Чтобы снять нижнее, самое большое кольцо с палки, нужно сначала снять все, что выше. Но при этом нижнее колько на палку попало первым. Вот тут так же. Есть две основные команды для работы со стеком - PUSH и POP. Первая кладет, вторая вытаскивает. Примерно так:

PUSH 0 (|-> 0 )
PUSH 1 (|-> 1 0)
PUSH 2 (|-> 2 1 0)
POP EAX (|-> 1 0, в EAX при этом теперь лежит 2)
PUSH EAX (|-> 2 1 0, да, в стек можно засунуть содержимое регистра)
PUSH 25 (|-> 25 2 1 0)
POP EBX (|-> 2 1 0, EBX=25)
POP ECX (|-> 1 0, ECX=2)

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

invoke MessageBox,HWND_DESKTOP,"Hello, World!",0,MB_OK

invoke - это специальный макрос, позволяющий вот так просто, в одну строчку, вызывать функцию и сообщить нужные аргументы.
MessageBox - имя (адрес!) функции.
Все, что дальше идет - это аргументы.

В отладчике у нас нет никаких макросов и прочих удобств, там все сурово:

PUSH 0 ; Это MB_OK
PUSH 0 ; Это указатель на текстовую строку-заголовок, ее у нас нет.
PUSH 123321 ; Это указатель на текстовую строку-сообщение.
PUSH 0 ; Это HWND_DESKTOP, идентификатор окна-владельца сообщения
CALL MessageBoxA ; Это сам вызов функции

Как видите, в суровом варианте аргументы кладутся на стек по одному, причем в обратном порядке, а не так, как мы записываем в случае с invoke. Invoke при компиляции делает ровно одно - "разворачивается" в набор push и call. Итак, чтобы вызвать функцию, нужно положить на стек аргументы (в обратном порядке!), если они есть, а потом вызывать функцию через call.

Такие дела. Посмотрим, как это выглядит вживую? Конечно, посмотрим! Сейчас наша программа "поставлена на паузу" и отладчик ждет каких-то дальнейших указаний. Мы можем "проиграть" программу по шагам и посмотреть, что с ней происходит. Для этого у нас есть замечательная кнопка F8, позволяющая сделать один "шажок" (выполнить одну инструкцию), при этом "перепрыгивая" вызовы других процедур (call, например). Иначе отладчик "провалится" внутрь этой процедуры и начнет показывать код, который там внутри. Итак, видим команду:

PUSH 0

Что она делает? Она кладет 0 на вершину стека. Смотрим на стек - в самой верхней строчке лежит какая-то непонятная фигня. Давим F8! Получаем вот такую картину:




Процессор проехал на одну команду вниз, выполнив предыдущую, а на вершине стека оказался ноль. Круто? Еще как круто! Давим F8 еще пару раз, выскакивает наше сообщение, жмем в нем OK и на этом программа завершается, о чем нам и сообщает отладчик в строке состояния (Process terminated, exit code 0). Кстати, код возврата мы задаем при вызове функции ExitProcess, единственным ее аргументом. Так-то!

Пока что - на этом все. Можно выбрать в меню Debug->Restart, а можно найти какую-нибудь другую программу и попробовать посмотреть в отладчике на нее. В следующей статье я покажу, как можно при помощи отладчика исправить самый настоящий БАГ. :)

----------------------------------------
Вопросы? Пожелания? Предложения?
Вот как можно со мной связаться:
[email]
[vk]
[twitter]
[telegram]

----------------------------------------


20150808

Про конкурс от gamehacklab, пожертвования и будущие посты.

Ребята, всем привет!

Я кенг, дела у меня хорошо, спасибо. Почему я так долго ничего не писал и ничего не выкладывал? Да, меня тоже это бесит, прекратите кидаться, пожалуйста. Во-первых, наступило лето, но меня, равно как и вас, это не должно особенно волновать. Во-вторых, у меня сменилось место работы. Поэтому я последние 2-3 месяца на работе сижу просто безвылазно - испытательный срок, то да се. Но в этом есть и хорошая сторона - теперь у меня будет больше свободного времени, как минимум по выходным, а выходных как раз хватает на написание поста и\или запись видео.

Сейчас на моем youtube-канале самый актуальный и живой раздел - это "Перезагрузка". Суть в том, что я перезаписываю все старые видео с нуля, с хорошим качеством звука и видео, другими играми и немного на новый лад - то есть немного по-другому объясняю.

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

Я решил начать со второго пункта, очень аккуратно и потихоньку объяснив язык ассемблера как таковой, как это все работает и что вообще происходит, так что видео будут выходить сначала с объяснениями - мы будем сидеть и изучать сам ассемблер в отладчике на абстрактных примерах, постепенно создавая трейнерный движок, а параллельно я буду показывать некоторые вещи в Cheat Engine - про Code Injection, Code Shifting, Code Relocation, Staple Intersection и тому подобные вещи.

Да, вы все правильно прочитали - теперь в блоге будет ТОЛЬКО ассемблер. Почему? Потому что я его люблю - раз. Потому что с ним в любом случае придется работать хотя бы во время взлома игры - два. Потому что он не такой пугающе сложный, как может поначалу показаться - три. И четыре - потому что его более чем достаточно для написания движка, зато можно будет неплохо выпендриться перед друзьями.

Вы могли заметить в верхней части блога штучку с подписью "помоги кенгу!". Для осмелившихся на ней кликнуть откроется возможность просто так взять и выдать мне любое количество денег на ваше усмотрение. Не то, чтобы они были мне жизненно необходимы и тем более я не собираюсь жить за счет блога, но это будет приятная плюшка, на которую можно будет купить игры или какие-то программы. Текущая цель - Bandicam, который стоит 39 сатанинских долларов. Плюс это в любом случае будет очень сильно меня мотивировать, потому что альтруистичный энтузиазм, на котором уже пять лет держится вся затея, не резиновый. И мне совершенно не хочется бросать это дело.

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

Кстати, возможно я уже говорил, но на форуме gamehacklab несколько месяцев назад официально открылся раздел по взлому многопользовательских игр. И уже даже есть свои наработки, да-да!

А что за конкурс? Конкурс, к сожалению, уже прошедший, но я все равно хочу о нем написать. Берем игру, берем сроки в 2-3-4 дня и затем участники конкурса делают как можно больше опций для игры - бессмертие, бесконечные патроны или что-то еще, быстрое перемещение, возможность летать и так далее. А дальше разыгрывается призовой фонд в виде репутации на форуме, уважухи и разнообразных скидок и игр в Steam. Интересно? Добро пожаловать на форум! Уверен, конкурс этот - не единственный.

Еще совсем недавно открылась страничка Вконтакте, посвященная сайту gamehacklab.ru. Там наш админ выкладывает свою собственную серию обучающих видео, причем он любит C++. Ознакомиться будет все равно полезно, даже если вы все это уже знаете.

Вот она - [ссылочка] на официальную страницу ВК.

На этом - пока все. Думаю, что запишу хотя бы видео-введение по программированию. Критика и пожелания - в комментарии. :)

20150324

Перезагружаемся.

Перезагрузка идет полным ходом. Кто-нибудь смотрит? Как ощущения? (:
[Вот] ссылка на плейлист, если кто-то еще не видел.

20150309

Можно ли при помощи Cheat Engine взломать сетевую игру?

...задал мне вопрос один из зрителей на youtube. Попробую ответить.

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

(К0)
  ^
  |---------(С)
  v
(К1)


К0 бежит себе по полю, видит монстра. Потому что сервер ему об этом сказал. К0 берет и убивает монстра. Говорит серверу - "Я убил монстра!". Сервер думает и отвечает - вот тебе 3 золотых. К0 видит на экране появившиеся 3 золотых и подбирает их. Говорит серверу - "Я подобрал золото! 3 штуки!!". Сервер открывает у себя блокнотик и записывает - у К0 золота стало на 3 больше. Далее К0 открывает инвентарь (спрашивая у сервера, "Что у меня в инвентаре?"), а сервер ему и отвечает - столько-то золотых, половинка дарницкого и литр кефира.

Бывают такие невообразимо глупые игры, где можно заморозить здоровье на стороне клиента и он просто будет сообщать серверу, что здоровье полное. То есть на стороне сервера не будет никаких проверок на это. Бывает, например, World of Tanks, к которому толком нет читов, потому что весь клиент игры - это большой слайд-проектор, которому сервер выдает картинки, а всю информацию считает у себя. Чуть что не сошлось - клиента выкидывает из игры. Бывает так, что на одни показатели в игре косвенно влияют другие. Скажем, как это было у моих друзей в LineAge - если сильно нагрузить персонажа багажом, у него не будет со временем восстанавливаться здоровье. Если после этого умереть и в момент возрождения разорвать соединение клиента с сервером, то игрок возрождается с 0 здоровья и становится бессмертным. Баг был быстро исправлен, но было весело. (:

Вторая сторона монеты, помимо сканирования адресов и ковыряния в отладчике - разбор сетевых данных, которыми обменивается сервер и клиент. Те самые цитаты от клиента серверу и обратно, что я приводил выше. Можно, скажем, взять утилиту, которая позволяет увидеть и прочитать сетевые пакеты, передаваемые между клиентом и сервером (такие утилиты называются снифферами, от английского to sniff - нюхать), и увидеть там (например):

(К0): Я нашел 3 золота!
(С): Положил тебе в инвентарь 3 золота.

Берем пакет, отправляемый клиентом, исправляем в нем цифру 3 на 10000, а затем отправляем опять. Смотрим, что ответит сервер:

(С): Положил тебе в инвентарь 10000 золота.

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

20150303

ESP. Часть 2. Выводим найденное в консольку.

А вот и видео!


В нем я вслух и почти построчно разбираю 100 строк кода на Си, которые делают следующее:

0. Находят окно игры
1. Получают хэндл процесса с правами чтения из памяти
2. Читают количество игроков на карте
3. Бегут в цикле, читая адрес каждой структуры игрока
4. Выводят в консоль его здоровье и координаты

В следующем уроке я расскажу, как именно мы будем выводить данные в окно игры (напомню, что это будет НЕ через DirectX-хук - мы легких путей не ищем!) и что для этого понадобится (не бойтесь, одна-единственная, но очень важная переменная в памяти игры. Будет еще немного СЕ), а через урок - покажу, какой код это делает.

ESP. Часть 1. Ищем нужные нам данные.

Сначала - видео:


А теперь, для начала, я приведу наш небольшой план еще раз:
0. Получение данных из игры
1. Чтение данных из игры программно
2. Рисование в окне игры
3. Вывод данных из игры в окно


Итого, руководствуясь видео выше и своей смекалкой, мы получаем следующие данные:

0. Указатель на коллекцию структур игроков
1. Смещения до здоровья и координат в структуре игрока
2. Адрес общего количества игроков
3. Смещения между структурами игроков в коллекции из п. 0

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

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

20140803

D3D: Chameleon Wallhack

Привет, ребята! Для начала, вот видео:


А [вот] ссылка на репозиторий с исходным кодом.

Значит, скачали вы исходники, взяли любимый компилятор и любимую IDE, скомпилировали это дело и ничего не поняли. В видео я, отсылась к предыдущим статьям и урокам, рассказываю о том, что мы написали логгер, позволяющий нам узнать некоторую необходимую для нашей бурной деятельности информацию. А именно - stride, или номер куска экрана, который мы сейчас будем рисовать, и NumVertiles, аргумент функции [DrawIndexedPrimitive], который показывает нам количество вершин того куска, который мы будем рисовать. Мир игры состоит из моделек, модельки - из полигонов. Полигон - это треугольник, то есть у него три вершины. На модельки, собственно, сверху натянуты текстуры, чтобы было видно, что металл - это металл, оружие - это оружие, а враги - это враги. Нашли мы, значит, нужную нам текстуру. Дальше видим такой кусок кода:

pDev->SetRenderState(D3DRS_ZENABLE, false);
pDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
pDev->SetTexture(0, red);
oDrawIndexedPrimitive(pDev, PrimType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
pDev->SetRenderState(D3DRS_ZENABLE, true);
pDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
pDev->SetTexture(0, green);

Что мы тут делаем? А всё просто, как выяснилось. Функция [SetRenderState] позволяет нам задать параметры отображения того, что мы сейчас будем отображать. Тут важно помнить, что мы ещё пока ничего рисовать не пытались. У этой самой функции всего два аргумента - что мы меняем и на что мы меняем. Первым вызовом мы утверждаем, будто нужно выключить буфер глубины. Что это такое? Это перспектива, если вдруг так будет понятнее. Экран монитора - он плоский, а игра хочет казаться трёхмерной, так что ей нужно как-то трёхмерность симулировать. Вот эта вот штука отвечает за то, что мы видеть должны, а что - нет. Например, когда какой-то объект находится за стеной. Игра при отрисовке постоянно думает, что и как ей рисовать. Вот небольшая схемка:

0            1             2
             |                   
X -----------|-------------O
             | 

X - это мы. Палочки - это стена перед нами, а O - это нечто за этой стеной. Циферки обозначают позицию одного относительно другого в этом самом буфере глубины. У кого цифра 1 - того мы и видим, у кого больше - значит он чем-то от нас закрыт. Если товарищ О выйдет из-за стены, то у него Z-order (позиция в буфере глубины) станет равным 1, так что игра должна будет его перед нами отрисовать и в результате мы его увидим.

Если отключить буфер глубины, то игра решит, что все игровые объекты в поле нашего зрения находятся перед нами - то есть нету никаких препятствий и никто никого не перекрывает. Получится каша, потому что одновременно будут рисоваться стены, мебель, пол, потолок, оружие, гранаты, люди, враги, союзники, словом - всё. Для того, чтобы вычленить из этой каши то, что нам нужно, мы и использовали наш логгер. В общем-то, только у нужных нам объектов мы буфер глубины и отключили. Давайте вернёмся к коду, а то я заболтался. Отключив буфер глубины, мы говорим, что текущий объект мы будем рисовать сплошным цветом. Сразу после этого мы вызываем функцию [SetTexture], которая указывает, что мы будем использовать текстуру по имени red - красненькую. Напомню, что пока мы ещё ничего не рисовали и не пытались даже. Что мы делаем следующей строчкой? Верно, рисуем, вызвав оригинальную функцию рисования вместо нашей перехваченной.

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

Что получается в результате таких жутких махинаций? А получается так, что выбранная нами моделька рисуется через стены красным, а перед нами - зелёным. Эта фича отличает Chameleon wallhack от обычного. В обычном мы просто выключали бы буфер глубины и всё, а тут удобно, с подсветочкой.

Тэк-с. Я упоминал текстуры. Собственно, чуть ниже, в перехваченной функции [EndScene], мы их и создаём. Тут я в подробности вдаваться не буду, так как этот кусок кода я нашёл и честно скопировал себе, скажу только, что цвет мы задаём вот в этой строчке:

((PDWORD)d3dlr.pBits)[xy] = 0xFF00FF00;

Тут нас интересуют последние три пары чисел шестнадцатиричного значения. Догадливые уже поняли, что это RGB, он же - Red Green Blue, то есть три цветовых канала. Первые две цифры в том числе выше - это прозрачность, которая не используется в данном случае, как я понял. Собственно, FF0000 - это красный, 00FF00 - это зелёный, а 0000FF - это синий. Значения лежат в пределах от 00 до FF. Подходящий цвет можно выбрать в любом графическом редакторе или же в интернете найти.

В той же перехваченной EndScene мы первой строчкой узнаём ViewPort - это, собственно, то, куда мы смотрим, когда играем. Узнаём мы его затем, чтобы выводить туда текст, так что после создания текстур мы создаём шрифт и пишем им на экран, в данном случае - включён ли наш wallhack.

На этом, в принципе, можно бы было и остановиться, но есть ещё одна важная деталь. В комментариях некоторые люди жаловались, что игра вылетает с ошибкой при попытке сделать alt+tab или поменять разрешение экрана. Это чинится перехватом функции [Reset], в которой мы уничтожаем наши текстуры и шрифт, чтобы они не засоряли видеокарту и пересоздались, дабы игра снова могла их рисовать.

Вот теперь - всё. До новых встреч! (:

20140124

Про гитхаб.

Ребята, как вы заметили, я теперь в постах привожу ссылки на свой [репозиторий] на гитхабе. Я не знаю, как лучше организовать процесс, т.к. я там тоже что-то пишу и что-то может не работать или работать не так, как задумано, в тот или иной момент времени. Хранить 100500 папок\архивов с исходниками мне банально негде. Так что варианта два - тащим себе весь репозиторий и разбираемся, попутно глядя в блог и поставив себе 2013-студию, или же смотрим нужный кусок кода и копируем себе в проект. Сейчас это, по сути, песочница для экспериментов, так как я, как и вы, с темой знаком довольно поверхностно.

20140122

D3D: Рисуем прицел.

Привет!

Пока я записываю очередное видео, вот небольшой и простой для понимания участок кода, которым можно нарисовать прицел в любой DirectX9-игре:


Что-то объяснять, кроме комментариев в самом коде, я не буду - всё и без этого понятно. (:

Полный исходник - на [гитхабе]!

20140119

[Опрос] Перепись видеоуроков.

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

Новости по блогу.

Итак, уважаемые! Раз уж у меня нашлись время и силы возобновить публикации своих скромных потуг, то возникает пара вопросов:

Редизайн блога. Переписывание всех старых видео (одно из которых зачем-то удалил гадкий гугл), заливка видео на какой-нибудь другой хостинг или обменник (торренты!). Были мысли понаписать серию статей с красивыми картинками из какого-нибудь abode illustrator, потому что в виндовом пейнте рисовать как-то не слишком солидно. Так же были мысли создать три отдельных секции - Ассемблер, C\C++, C#.

Дело тут всё в том, что си ришотка (C#) достаточно фигово подходит для геймхакинга - он слишком высокоуровневый со всякими своими ООП и прочими классами, не даёт вменяемый доступ к WinAPI, потому что safe code и всё такое, но он красивый-быстрый-удобный для создания GUI, интерфейса, т.е.

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

Посему, на данный момент, мой инструментарий:

1. MSVS Express 2013. Потому что привык. Планирую перелезть на GCC.
2. Cheat Engine. Потому что удобно инжектить DLL-ки и в будущем понадобится для прочих исследований относительно взлома.
3. Olly Debugger. Использую в качестве основного отладчика, так же в силу привычки. Могу написать серию уроков по нему, но не вижу большого смысла - поменяются полторы кнопки на клавиатуре, да и уроков\статей по этому отладчику в сети есть куча.

Ещё один момент - игры на заказ мне ломать не очень хочется. Отчасти потому, что игра (чаще всего) стоит денег, а в основном потому, что это "повторение пройденного", но в другой обёртке. Прошу не обижаться, но это всё ещё не блог "кенг! сломай мне игру N!". Исключение - если попадётся какая-то нестандартная опция (это не повод с сего момента присылать мне по 9000 писем с предложениями).

Но всё ещё - feel free to присылать мне письма, любые. Общие рекомендации я дать могу, что-то подсказать или объяснить.

Вектор развития блога на данный момент:
Мы занялись D3D и графикой в целом. Мне не нравится текущий подход, используемый большинством - а именно конкретные адреса или указатели, поиски по сигнатурам и всё в том же духе. Я решил покопать поглубже и стремлюсь к автоматизации - как вы помните, нашему хуку нужны только смещения функций в табличке указателей интерфейса. Этот подход работает на DX 9, которая до сих пор используется крайне широко. В дальнейшем мы проапгрейдимся до поддержки DX 10 и 11, а затем и до OpenGL - это не так сложно. Так как наше приложение всё ещё очень хочет быть движком для трейнеров, добавим поддержку записи в память, codecave-ов, поиска сигнатур. Может, какой-то конструктор напишем, чтобы из файла брать адреса и названия функций и сразу пихать их в собранный exe. А, да, объединим загрузчик и хук в один исполняемый файл, чтобы не таскать их оба с собой.

Пока что - вот так.

D3D: Трагически наступившее "скоро".

Всем привет!

У меня нашлось время и я решил ещё немного поковыряться с D3D и прочими неприличными словами. (:

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

Это всё, конечно, круто, но не очень сильно впечатляет и далековато от наших амбиций. Итак, встречаем:


Вот эта самая функция нам и понадобится. Я, честно сказать, фигово разбираюсь в 3д-графике и рисовании в целом, так что гуру этой области прошу меня сильно не пинать - объяснять буду, как понял сам.

Как мы помним, читали или где-нибудь слышали, нельзя просто так взять и нарисовать оружие, машину или нечто такое. Видеокарточки туповаты и рисовать умеют только примитивы - точки, линии, треугольники. Захотели квадрат - сложили два треугольника вместе. Эти штуки ещё иногда зовут полигонами, ага. Дык вот эта самая функция используется для отрисовки примитивов, если очень кратко. Нас там будет интересовать параметр BaseVertexIndex, в суть которого я тоже вник крайне смутно и пытаться объяснить это кому-то пока что не стану - давайте просто звать эту штуку индексом. Ещё пара крутых штук ждёт нас чуть дальше, когда я код приведу. Так как у меня возникли некоторые трудности с перехватом этой функции, то перехватывать мы её будем не вручную, а при помощи библиотечки detours от microsoft (все необходимые файлы идут в комплекте с исходниками), так что код слегка видоизменился. Вот, например:



Тут сразу бросаются в глаза последние три строчки - это, собственно, и есть перехват. Делает библиотека всё то же самое - мы скармливаем ей адрес найденной фунции, которую нужно перехватить, в её начало дописывается переход (JMP 00112233) на перехваченную функцию, а перехваченная выставляет всё, как было, отрабатывает и возвращает хук на место. Едем дальше:



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

1. Каждый вызов у нас есть некие данные (Stride и BaseVertexIndex) , которые нам надо узнать и запомнить для использования уже в чите. Они характеризуют тот или иной объект на экране.
2. Каждый раз, когда игра пытается что-нибудь нарисовать, мы заносим структуру этих данных в массив.
3. В логгере есть кнопки, позволяющие управлять процессом - менять значения Stride и BaseVertexIndex, выбранные на данный момент будут подсвечиваться зелёным цветом.
4. Задача - натыкать такое значение, чтобы нужный нам объект(-ты) подсветился(-лись) зелёным. Запомнить цифры.

Скомпилируется всё это дело в DLL, которую надо будет заинжектить в процесс игры (я не парюсь и продолжаю делать это через Cheat Engine). Поддерживаются любые игры, которые рисуют при помощи D3D9.

ВНИМАНИЕ тем, кто запускает игры из Steam (как я, например): В стиме в свойствах игры надо отрубить steam overlay ui, так как он работает точно так же - иначе получим вылет.

ВНИМАНИЕ тем, кто до сих пор не использует MS Visual Studio 2013 (как я, например): Если вам лень ставить 13-ю студию, то просто слейте все исходники и создайте новый проект (DLL). Ему понадобится в свойствах указать путь до include и lib для MS DirectX SDK (полгига которого можно спокойно скачать в гугле), если заругается на отсутствие detours.lib - она лежт в папке проекта.

Результат:


А вот и [ссылка] на все исходники. На днях будем учить этих инопланетных парней просвечивать сквозь стены. (:

20130803

IT'S ALIVE! ALIVE!!

Привет всем, кто это читает! Ещё не забыли моё имя и тему этого блога? (:

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

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

1. Я смотрю последние видео и пробую продолжить от них (d3d, хуки, воллхаки и прочая прелесть на C++). Плюсы я знаю средне, d3d - ещё более средне, так что это будет медленно и, скорее всего, корявенько, но я учусь и исправляюсь.
2. Мы садимся и с нуля пишем движок для трейнеров на C++. Или на ассемблере. Или на C#. С фичами, которые предложите вы, или до которых не догадаюсь я. Весь код я буду заливать на GitHub, конечно же.
3. С нуля пишем какую-нибудь простенькую игру на d3d, потом - компаемся отладчиком в её потрохах и понимаем, как и что работает. Ещё более медленный вариант, но сулит много интересного.
3. Что-нибудь повеселее - то, что вы предложите в комментариях.

20121124

D3D: Пишем DLL-инжектор, но уже на C++

[Ссылочка] на урок. Разбираем код DLL-инжектора на C++, который я сваял из тестового D3D-приложения.

А [вот] ссылочка на весь проект, выложенная на [GitHub]. Комментарии на английском. Проект будет пилиться вместе с записью уроков, так что можно его считать тестовой площадкой. Для компиляции понадобится MSVS, я использую 2012 Express.

Сейчас буду записывать следующий урок, для затравки - читаем [это] и [это].

20121103

Монетизация

...если это можно так назвать. :)

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

Обсуждения и другие варианты - в комментарии.

20121031

Я тут начитался всяких крутых форумов и вот, что получилось в процессе экспериментирования:


Это, товарищи, обыкновенный Prince of Persia: Sands of Time, только вот ему было сказано не заполнять полигоны текстурами, а оставлять только сетку. Wireframe mode, типа.

PS: Я не ожидал, что wallhack и прочие подобные читы делаются настолько просто, пусть и в довольно сыром виде. Вот и будет тема следующих уроков, когда загрузчик для меню допишем. :)

20121030

D3D: Новый алгоритм и работа со шрифтами.

Да-да, видеоурок с подробными объяснениями, но достаточно плохимм звуком. Выложу тут ссылку (видео будет доступно как на youtube, так и на форуме gamehacklab.ru), как только оно обработается.

[Ссылка] на урок.

Собственно, полный исходный код из видео:


#include
#include
#pragma comment(lib,"d3dx9.lib")

typedef IDirect3D9* (__stdcall *DIRECT3DCREATE9)(unsigned int);
typedef long (__stdcall *PRESENT9)(IDirect3DDevice9* self, const RECT*, const RECT*, HWND, void*);

PRESENT9 g_D3D9_Present = 0;
BYTE g_codeFragment_p9[5] = {0, 0, 0, 0, 0};
BYTE g_jmp_p9[5] = {0, 0, 0, 0, 0};
DWORD g_savedProtection_p9 = 0;
DWORD present9 = 0;
bool indicator = 0;
D3DRECT rec = {10, 10, 120, 30};
ID3DXFont *m_font = 0;
RECT fontRect = {10, 15, 120, 120};
D3DCOLOR bkgColor = 0;
D3DCOLOR fontColor = 0;

void DrawIndicator(void* self)
{
        IDirect3DDevice9* dev = (IDirect3DDevice9*)self;
        dev->BeginScene();
D3DXCreateFont(dev, 12, 0, FW_BOLD, 0, 0, 1, 0, 0, 0 | FF_DONTCARE, TEXT("Arial"), &m_font);
if(indicator)
{
bkgColor = D3DCOLOR_XRGB(0, 0, 255);
fontColor = D3DCOLOR_XRGB(0, 255, 255);
}
else
{
bkgColor = D3DCOLOR_XRGB(255, 0, 0);
fontColor = D3DCOLOR_XRGB(255, 0, 0);
}
        dev->Clear(1, &rec, D3DCLEAR_TARGET, bkgColor, 1.0f, 0);
m_font->DrawText(0, "keng.gamehacklab.ru", -1, &fontRect, 0, fontColor);
        dev->EndScene();
}

void GetDevice9Methods()
{
HWND hWnd = CreateWindowA("STATIC","dummy", 0, 0, 0, 0, 0, 0, 0, 0, 0);
HMODULE hD3D9 = LoadLibrary("d3d9");
DIRECT3DCREATE9 Direct3DCreate9 = (DIRECT3DCREATE9)GetProcAddress(hD3D9, "Direct3DCreate9");
IDirect3D9* d3d = Direct3DCreate9(D3D_SDK_VERSION);
    D3DDISPLAYMODE d3ddm;
    d3d->GetAdapterDisplayMode(0, &d3ddm);
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = 1;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = d3ddm.Format;
IDirect3DDevice9* d3dDevice = 0;
    d3d->CreateDevice(0, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3dDevice);
DWORD* vtablePtr = (DWORD*)(*((DWORD*)d3dDevice));
present9 = vtablePtr[17] - (DWORD)hD3D9;
d3dDevice->Release();
d3d->Release();
FreeLibrary(hD3D9);
CloseHandle(hWnd);
}

long __stdcall HookedPresent9(IDirect3DDevice9* self, const RECT* src, const RECT* dest, HWND hWnd, void* unused)
{
BYTE* codeDest = (BYTE*)g_D3D9_Present;
codeDest[0] = g_codeFragment_p9[0];
*((DWORD*)(codeDest + 1)) = *((DWORD*)(g_codeFragment_p9 + 1));
DrawIndicator(self);
DWORD res = g_D3D9_Present(self, src, dest, hWnd, unused);
codeDest[0] = g_jmp_p9[0];
*((DWORD*)(codeDest + 1)) = *((DWORD*)(g_jmp_p9 + 1));
return res;
}

void HookDevice9Methods()
{
HMODULE hD3D9 = GetModuleHandle("d3d9.dll");
g_D3D9_Present = (PRESENT9)((DWORD)hD3D9 + present9);
g_jmp_p9[0] = 0xE9;
DWORD addr = (DWORD)HookedPresent9 - (DWORD)g_D3D9_Present - 5;
memcpy(g_jmp_p9 + 1, &addr, sizeof(DWORD));
memcpy(g_codeFragment_p9, g_D3D9_Present, 5);
VirtualProtect(g_D3D9_Present, 8, PAGE_EXECUTE_READWRITE, &g_savedProtection_p9);
memcpy(g_D3D9_Present, g_jmp_p9, 5);
}

DWORD __stdcall TF(void* lpParam)
{
GetDevice9Methods();
HookDevice9Methods();
return 0;
}

DWORD __stdcall KeyboardHook(void* lpParam)
{
        while(1)
        {
                if(GetAsyncKeyState(VK_F1))  
                {
                        indicator = !indicator;
                        Beep(500,200);
                }
                Sleep(100);
        }    
        return 0;
}

int __stdcall DllMain(HINSTANCE hInst, DWORD  ul_reason_for_call, void* lpReserved)
{
        switch (ul_reason_for_call)  
        {
        case DLL_PROCESS_ATTACH:
CreateThread(0, 0, &TF, 0, 0, 0);
CreateThread(0, 0, &KeyboardHook, 0, 0, 0);
        }
        return 1;
}

Изменения с предыдущей версии:
-Новый алгоритм перехвата, похож на MS Detours - работает при помощи инъекции кода.
-Поддержка (какая-никакая) шрифтов.

В следующем видео будем свой инжектор для этого дела писать. :)