Как сделать тренер для игр

Обновлено: 31.05.2024

В этой статье я покажу, как сделать трейнер, используя Visual C++. На написание этой статьи меня подтолкнул тот факт, что когда я пытался найти в инете хоть какую-нибудь информацию о том, как сделать простой трейнер в VC, все, что я находил, были статьи, показывающие примеры на С/С++, а в основном на Delphi и MASM. Казалось бы что в этой ситуации можно было использовать материал статей на С/С++ если бы не одно "но" - сильная привязанность VC++ к классам, в следствии чего некоторые API функции ведут себя не так, как надо. Позже это станет понятно.

Итак приступим

Вот что нам понадобится:

Сама игра. Я выбрал интересную RPG - Avernum 3 (берем отсюда)

Программа типа GameHack или TSearch для поиска нужных нам значений в памяти. Я предпочитаю TSearch, поскольку, на мой взгляд, она наиболее функциональна из всех подобных программ. Хотя дело выбора каждого. (берем отсюда)

Visual C++. У меня стоит версия 6.0, поэтому туториал будет сделан на ней. Версия не особо принципиальна, как ты понимаешь :)

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

HP первого character'a 0x00C1C050 2 байта
MP первого character'a 0X00C1C054 4 байта

HP второго character'a 0x00C1C420 2 байта
MP второго character'a 0x00C1C424 4 байта

HP третьего character'a 0x00C1C7F0 2 байта
MP третьего character'a 0x00C1C7F4 4 байта

HP четвертого character'a 0x00C1CBC0 2 байта
MP четвертого character'a 0x00C1CBC4 4 байта

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

Приступим к самому главному и творческому процессу - написанию нашего трейнера. Делать будем, конечно, используя API функции, поскольку так будет проще, да и прога будет работать намного быстрее. Вот необходимые нам функции (посмотри их описания в Win32 API reference):

SetTimer
FindWindow
GetThreadProcessId
OpenProcess
WriteProcessMemory
GetAsyncKeyState
KillTimer
CloseHandle

Тепeрь создадим новый проект для будующего трейнера. Запусти Visual С и дави File->New. В появившемся окне выбирай тип MFC AppWizard (exe), набери имя проекта - Avernum3tr. Дави Next. Выбирай Dialog based. Next. Тут убери галочки с Active X и About box - они нам нафиг не нужны. Все, дави Finish и получай каркас. Как видишь AppWizard уже сгенерировал диалоговоё окно для нас, как и много кода, инициализирующего много всякой ерунды. Можешь сразу удалить static text и две кнопки с окна - они тоже лишние.

Разберемся с таймером и его функцией-обработчиком. Чтобы создать таймер, нажми Ctrl+W. Откроется окно MFC ClassWizard - эдакий редактор классов. Выбери следующее на вкладке Message Maps:

Class name - CAvernum3trDlg
Object ID's - CAvernum3trDlg
Member functions - OnIntiDialog

и нажми Edit code. Поскольку эта функция уже создана, попадем на кусок кода этой функции, которая вызывается когда создается наше окно. Там мы и инициализируем наш таймер. Добавляй перед строчкой return TRUE строку:

SetTimer(1, 100, NULL);

OK, перейдем к обработчику таймера. Ctrl+W и добавляй функцию WM_TIMER и перейди на её код. Вот. Эта функция будет вызываться каждый раз, когда сработает таймер. Как ты уже понял, тут мы будем писать код, который будет отвечать за отлов нажатия нужных нам клавиш и делать то, для чего, собственно, создается трейнер :)

Лови приколы:

Вот мы и подобрались к тому моменту, почему , собственно, многие статьи по написанию трейнера на С/С++ не срабатывали в VC. Попробуй в теле функции ON_WM_TIMER написать функцию FindWindow( и увидишь всплывшую подсказку о параметрах функции:

CWnd *FindWindow(LPCTSTR lpszClassName, LPCTSTR plszWindowName);

и сравни ее с тем, что нам нужно:

HWND FindWindow(LPCTSTR lpszClassName, LPCTSTR plszWindowName);

Дело в том, что первый вариант является функцией-членом класса нашего окна (я знаю, чтo это звучит запутанно, но тем не менее) и поэтому возвращает несколько другой тип. Что же делать. А сделаем мы вот что - создадим свой собственный независимый универсальный класс, который мы будем использовать не только в этой проге. Если у нас будет такой класс, то в следующий раз, когда Ты будешь писать свой следующий трейнер, ты просто добавишь этот класс к проекту, впишешь в тело функции таймера всего пару строчек (позже поймешь почему) и все - готово. Это, друг мой, классы - просто супер возможность ООП. Да, конечно, это займет некоторое время сейчас, но здорово сэкономит его позже. Не веришь - смотри.

Пальцы веером - лепим класс:

Справа, в окне выбери вкладку ClassView и кликни на Avernum3tr classes правой кнопкой. Выбери New Class. В появившемся окне выбирай:

Class type Generic Class
Name CProcess

и дави ОК и увидишь, что он появился в списке классов нашего проекта. Если Ты нажмешь на значок "+" рядом с названием нашего нового класса, то увидишь там две функции-члена - конструктор и деструктор класса.
Теперь я покажу как добавить одну функцию, а остальные Ты уже добавишь сам. Жми правой кнопкой на нашем классе и выбирай Add member function. В появившемся окне пиши следующее:

Function Type HANDLE
Function Declarations cOpenProcess(char *p_ClassName, char *p_WindowName)
Access Public

HWND hWindow;
DWORD pid;

hWindow = FindWindow(p_ClassName, p_WindowName);
if(hWindow)
GetWindowThreadProcessId(hWindow, &pid);
return ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
>
return NULL;

У тебя должно получится следующее:

HANDLE CProcess::cOpenProcess(char *p_ClassName, char *p_WindowName)
HWND hWindow;
DWORD pid;

hWindow = FindWindow(p_ClassName, p_WindowName);
if(hWindow)
GetWindowThreadProcessId(hWindow, &pid);
return ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
>
return NULL;
>

Таким же макаром пиши следующие функции:

bool CProcess::FindProcess(char *p_WindowTitle)
if(process==NULL)
process=this->cOpenProcess(NULL, p_WindowTitle);
>
if(process)
isrunning = TRUE;
return isrunning;
>
else
return FALSE;

bool CProcess::IsRunning()
return isrunning;
>

bool CProcess::IsKeyPressed(int key)
if (IsRunning()) return ((GetAsyncKeyState(key) & 1) == 1);
return FALSE;
>

bool CProcess::WriteByteToProcess(DWORD p_Adress, BYTE p_Value)
DWORD bytes;

if(isrunning)
return (WriteProcessMemory
(process, (void*)(p_Adress), (void*)(&p_Value), 1, &bytes) != 0);
>
return FALSE;
>

Ах да, чуть не забыл - добавь в класс две private переменных (правый click->Add member variable):

HANDLE pocess
bool isrunning

Почти финиш:

Это создаст глобальную переменную типа CProcess с названием game. Так мы будем общаться с нашим классом и с игрой (через него)

Теперь вернемся с нашей функции ON_WM_TIMER. Впиши туда вот этот фрагмент - я думаю с его пониманием проблем возникнуть не должно:

if(!check)
game.FindProcess("Avernum 3");
>
else
if(game.IsKeyPressed(VK_F4))
game.WriteByteToProcess(0x00c1c050, 0xFF);
game.WriteByteToProcess(0x00c1c051, 0x10);
>

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

Как создавать трейнеры

  • Программное обеспечение Magic Trainer Creator.

Одна из наиболее простых программ по созданию трейнеров - Magic Trainer Creator. После запуска программы происходит копирование части кода игры, который находится в оперативной памяти. В скопированном коде игры находятся такие параметры, как количество жизней, денег, манны, силы и т.д. В программе Magic Trainer Creator вы находите необходимые значения, затем просто их замораживаете, т.е. они не меняются.

После запуска игры необходимо открыть игру. Перейдите в программу, активируйте режим PID (Process ID), выберите игру, а также алгоритм поиска Normal. Введите искомое число в поле Value to search, затем нажмите кнопку Start.

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

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

В главном окне программы вам необходимо заполнить все информационные поля и нажать на кнопку создания трейнера. Файл трейнера стоит искать в папке программы.

Пишем trainer для игры


Пишем trainer для игры


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

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

Игра


Игра "Air Xonix"

В качестве "тренируемой" игрушки сегодня будет Air Xonix. Будем делать так, чтобы жизни в игре никогда не заканчивались. Игру сперва надо довести до ума, чтобы остался чистый исполняемый файл, после этого можно приступать к исследованиям.

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

Запускаем и начинаем игру, ставим на паузу во время игрового процесса, переключаем в ArtMoney и выбираем ее процесс по заголовку окна. Теперь нам надо найти значение жизней. Сперва это будет 4. Нажимаем кнопку "Искать", вводим значение "4" и выбираем тип значений для поиска.

По моему опыту чаще всего счетчики хранятся в целом виде или в 2 байтах (WORD), 4 байтах (DWORD) или 8 байтах (QWORD). Начинать поиск лучше с них, это значительно сократит диапазон поиска, особенно для малых значений. Найденных значений после первого поиска может быть (и будет!) очень много, а нам надо выбрать только нужные. Поэтому поиск разделяется на два этапа - поиск значений и отсев ненужных значений. В итоге получаем адреса, в которых находятся числа, и их можно изменить на нужные.

Отсеиваем изменившееся значение


Отсеиваем изменившееся значение

Переключаемся на игру, снимаем ее с паузы, нарываемся на противника и теряем жизнь. Снова ставим на паузу, переключаемся в ArtMoney и ищем новое значение. Но на этот раз воспользуемся кнопкой "Отсеять". Повторяем процедуру отсеивания до тех пор, пока в списке не останется только одно значение. В нашем случае это будет адрес 0257DA10. Мы выяснили адрес ячейки памяти, в которой хранится значение жизней. Теперь нам надо выяснить, какой код в исполняемом файле отвечает за изменение этого значения.

Запускаем отладчик и аттачимся к процессу игры. Переходим в окне дампа на адрес 0257DA10 и ставим точку останова на запись в память по этому адресу. Отпускаем игру и снова нарываемся на противника, чтобы потерять еще одну жизнь.

Отладчик остановится на вышеуказанном коде. Он очень простой и понятный. В регистр ESI загружается значение жизней, уменьшается на 1 (команда DEC), затем записывается обратно. То есть, чтобы стать бессмертным, надо заNOPить команду уменьшения регистра.

Прямо в отладчике заменяем команду DEC ESI на NOP. Теперь, по идее, значение жизней не должно уменьшаться.

Чтобы каждый раз не активировался отладчик, снимаем точку останова с ячейки памяти. Снимаем игру с паузы в отладчике, переключаемся на игровой процесс и снова нарываемся на противника. Но на этот раз мы видим, что значение жизней остается прежним, оно не уменьшается. А если подобрать бонусную жизнь, то значение увеличивается. Все, секрет бессмертия в игре Air Xonix разгадан.

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

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

Третий вариант трейнера модифицирует не исполняемый код, а замораживает нужную ячейку памяти, постоянно записывая в нее значение. Этот способ можно использовать в тех случаях, когда, например, увеличение и уменьшение нужных значений выполняется одним и тем же кодом или когда процесс игры контролирует свою целостность. В нашем случае все просто, адрес ячейки с количеством жизней постоянный, запускаем игру и с интервалом в 0,5 секунды пишем число 99 в ячейку с количеством жизней. Примерно по этому же принципу работает заморозка значений в программе ArtMoney. Если процесс игры завершится, то и трейнер должен завершить свою работу.

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

В приложении примеры всех трех вариантов трейнеров с исходными текстами, описанные в статье. Они протестированы и работают с игрой Air Xonix версии 1.45.

Всем привет, с вами Dart Vanya, и в этой статье я покажу как создать простой трейнер с использованием потоков. То есть сканирование сигнатуры будет выполняться в отдельном потоке и не подвешивать самого трейнера при выполнении. Смотрим, все показано в видео:

Код спишите лучше с видео урока,не поленитесь,только лучше запомнится!

Ссылка на проект -

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст


Всем привет, довольно часто задают вопросы: "Как в CиШарп читать/писать память клиента", и так далее.
Сегодня мы будем пробывать написать простенький трейнер для "Сапёр" на XP SP3, не забываем что на другой OC оффсеты другие .



1. Cheat Engine (для поиска оффсетов).
2. Компилятор кода, я использую MVS 2008.
3. И как всегда руки, мозг и точные действия по гайду.
4. Библиотека VAMemory, СКАЧАТЬ

Учтите!На разных Осях разные адреса!
А точнее, на 7ке например Сапер отличается чем на ХП, поэтому адреса будут разные!

Читайте также: