Модификация игры ASM/C++ Часть 4. - Форум администраторов игровых серверов
Форум администраторов игровых серверов StormWall - Защита от DDos атак
Регистрация Мнения Справка Сообщество Календарь
Вернуться   Форум администраторов игровых серверов > Полезное / Common > Программирование / Programming

Программирование / Programming
Ищете помощи в написании программы, есть сложность в выполнении задания (в институте и т.д.), пожалуйста, спросите у нас в данном форуме и мы обязательно вам поможем.

Ответ
Опции темы
Непрочитано 27.07.2016, 14:35   #1
Аватар для VOLKyiv
Пользователь

Автор темы (Топик Стартер) Модификация игры ASM/C++ Часть 4.

Всем, привет!
В этой части я хочу рассказать про поиск объектов в игре. А так же про перехват функций.

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

Посмотреть сккриншот:
Свернуть ↑Развернуть ↓


Вот мы нашли 2 адреса в памяти игры, попробуем узнать функцию которая записывает в этот адрес в памяти. Показывать как это найти в Cheat Engine, я не буду, так как в интернете полно видео уроков как пользоваться Cheat Engine.

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

Посмотреть сккриншот:
Свернуть ↑Развернуть ↓


И видим инкрементирование и декрементирование когда солнце пропадает, очень похоже на то что нам нужно.
Копируем адрес инструкции инкрементирования, и переходим в IDA Pro. Для того чтобы понять что там происходит. Запустим под отладчиком, и поставим breakpoint чтобы узнать какая функция вызывает sub_476100. Смотрим на скриншот.

Посмотреть сккриншот:
Свернуть ↑Развернуть ↓


Это функция sub_477CB0. Смотрим где она вызывается.

Посмотреть сккриншот:
Свернуть ↑Развернуть ↓


Пробуем найти где именно, для этого просто выйдем из функции нажав сочетание клавиш Ctrl + F7. И вызвали её из sub_467970. С параметрами

 
v18 = sub_477CB0(*(_DWORD *)(*(_DWORD *)(v23 + 2368) + 8), *(_DWORD *)(v4 + 8), 0.0, 0.0, 0);
Code: C++
На что очень сомнительно чтобы последние параметры были 0. Попробуем через Cheat Engine, занопить вызов sub_477CB0.

Код:
.text:00467BD3 fst     [esp+28h+var_24]                ; float
.text:00467BD7 fstp    [esp+28h+var_28]                ; float
.text:00467BDA call    sub_477CB0
.text:00467BDF mov     esi, eax
.text:00467BE1 push    ebp
.text:00467BE2 mov     ecx, esi
.text:00467BE4 call    sub_4779A0
И мы увидели что создалось солнце, и через 1-2 сек игра крашнулась. А нам интересен был факт того что солнце создалось, а значит это не та функция что нам нужна.
Берем второй адрес и точно так же делаем все с ним.

Посмотреть сккриншот:
Свернуть ↑Развернуть ↓


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


Посмотреть код:
Свернуть ↑Развернуть ↓


Пробуем сделать выход из функции sub_4163D0, заменив первый байт на retn.

Посмотреть сккриншот:
Свернуть ↑Развернуть ↓


И видим что солнышко больше никогда не создастся. Ура мы нашли функцию которая создает солнце. А если быть более точным это функция sub_40F400.

Давайте попробуем проанализировать что это за функция.

int __thiscall sub_40F400(_DWORD *this, int a2, int a3, int a4, int a5)
Code: C++
Видим что первый параметр это указатель на объект который управляет созданием солнц в игре. Остальные параметры не понятные, знаем что последний равен 0, а3 равен 60, а параметр а4 принимает значение 4 или 6.

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

	v3 = sub_5FF2A0(550);
	++*(_DWORD *)(a1 + 21844);
	v4 = v3 + 100;
Code: C++
И так что мы имеем в плане этого класса который управляет солнцами. Некий класс в котором есть функция sub_40F400(int, int, int, int)

Например класс у нас такой.
class Creator
{
public:
	void sub_40F400(int, int, int, int);
}
Code: C++
Попробуем реализовать это в нашей DLL.

И так чтобы работала та функция которая нам нужна нам нужно указать её адрес в памяти. Смотрим код ниже

void Creator::CreateSun(int a2, int a3, int a4, int a5)
{
	typedef void(__thiscall *t)(Creator*, int, int, int, int);
	t f = (t)0x0040F400;
	f(this, a2, a3, a4, a5);
}
Code: C++
Всё класс объекта создан теперь осталось найти адрес этого объекта в памяти игры. Для этого вернемся в IDA Pro. И найдем какую-то функцию которая использует соглашение о вызове __cdecl, __stdcall.
Чуть не забыл о соглашениях, подробно можно о них почитать вот здесь

Почему именно __cdecl, __stdcall, а все потому что эти функции проще всего перехватить. Так как аргументы функции передаются через стек, а не через регистры.
Хотя я покажу в следующих частях, как перехватить функцию где соглашение о вызове не позволяет это просто сделать. Например __usercall это последствия оптимизации программы/игры.

Помним что функция sub_40F400 вызывается в sub_4163D0, ищем где вызывается sub_4163D0. В функции sub_4181E0, но здесь все еще __thiscall, идем дальше sub_418600, тоже самое, дальше...

Код:
.rdata:006E4D8C                 dd offset sub_549210
.rdata:006E4D90                 dd offset sub_418600
.rdata:006E4D94                 dd offset sub_549930
Видим что функция sub_418600 виртуальная, а значит ищем чуть выше указатель на деструктор, а там где он и будет сам конструктор

Совсем рядом находится начало

Код:
.rdata:006E4D38 off_6E4D38      dd offset sub_40AF10    ; DATA XREF: sub_40A3C0+3D
.rdata:006E4D38                                         ; sub_40AF40+1F
.rdata:006E4D3C                 dd offset sub_547BB0
А именно off_6E4D38 ищем где оно применяется. И видим применение его в функции

int __thiscall sub_40A3C0(_DWORD *this, int a2)
 
v2 = this;
  v51 = 0;
  sub_54BE80(a2); 
  v58 = 0;
  *(_DWORD *)(a2 + 160) = &off_6F4000;
  *(_DWORD *)a2 = &off_6E4D38; //Вот оно
  *(_DWORD *)(a2 + 160) = &off_6E4E50;
  *(_DWORD *)(a2 + 168) = 0;
  *(_DWORD *)(a2 + 172) = 0;
Code: C++
То есть а2, и есть указатель на наш объект. Но соглашение все еще __thiscall. Идем дальше и видим что функция sub_40A3C0, вызывается в sub_4528B0

Показать код:
Свернуть ↑Развернуть ↓


Сразу на будущее хочу сказать что размер нашего объекта равен 0x57D8u, тогда и напишем это в нашем классе

Creator.h:
Свернуть ↑Развернуть ↓


Creator.cpp:
Свернуть ↑Развернуть ↓


и видим что CompileTimeSizeCheck(Creator, 0x57D8); не подсвечивается красным, для примера просто измените значение размера.

Продолжаем поиск __cdecl, __stdcall. И видим что функция sub_4528B0, вызывается из sub_452B30. Идем дальше sub_452820, и дальше
Поиск очень долгая и нудная работа. Для того чтобы не писать здесь, я сделал видео о том как я нашел эту функцию.

Видео

И так вот мы нашли эту функцию
int __stdcall sub_40D840(signed int a1)

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

Creator.h:
Свернуть ↑Развернуть ↓


Creator.cpp:
Свернуть ↑Развернуть ↓


Осталось только перезаписать вызов нашей функции в игре. Находим адрес где вызывается sub_40D840.

Код:
.text:00452B47                 push    eax
.text:00452B48                 call    sub_40D840
.text:00452B4D                 mov     dword ptr [esi+9A8h], 0
Делается это в нашей FixGame::Initialize вот так.

void FixGame::Initialize(void)
{
	BYTE bytes[] = { 0xB1, 0x01, 0x90 };
	WriteMemoryBYTES(0x005D14BD, bytes, 3);
 
	WriteInstructionCall(0x00452B48, (UINT)Creator::sub_40D840);
}
Code: C++
Теперь мы можем управлять нашим объектом, из любого места в DLL. Например вот так:
	if (g_Creator)
		g_Creator->CreateSun(100, 60, 4, 0);
Code: C++
Круто ведь, да?)
Можем когда угодно создать солнце)
Например можем по нажатию кнопки, или еще после чего-то) Это уже в пределах вашей фантазии)

Теперь я покажу как в игре, расширить объект, например создадим переменную(объект, любого другого класса) в которой будет хранится количество солнц, созданные нами с помощью нашей DLL.
Создадим класс CreatorEx.

CreatorEx.h:
Свернуть ↑Развернуть ↓


CreatorEx.cpp:
Свернуть ↑Развернуть ↓


Добавляем вконец переменную CreatorEx.
class Creator
{
	Creator() {};
public:
	static int __stdcall sub_40D840(Creator* pCreator);
 
	void CreateSun(int a2, int a3, int a4, int a5);
 
	/* 000 */ virtual ~Creator() {}; // Помним что внутри объекта есть виртуальные функции, а значит по адресу 0000, лежит таблица виртуальных функций
	/* 004 */
 
 
	/* 0004 */ unsigned long __uUnkValue0004[0x15F6 - 1]; // 0x57D8u делим на 4 так как мы используем тип long, 
														  //а 0x57D8u размер в байтах. -1 потому что первые 4 байта это указатель на таблицу виртуальных функций
	/* 57D8 */ CreatorEx objCreatorEx; 
	/* 57E0 */
};
 
extern Creator* g_Creator;
 
CompileTimeSizeCheck(Creator, 0x57E0);
Code: C++
Очевидно что размер изменился, заставим теперь игру выделить память под нашу переменную.
Вспоминаем место где мы видели размер нашего класса, а это было в функции sub_4528B0.

Код:
.text:004528CE                 push    57D8h           ; size_t
.text:004528D3                 call    ??2@YAPAXI@Z    ; operator new(uint)
.text:004528D8                 add     esp, 4
Вот это место, нам нужно заменить push 57D8h , на свой. Давайте это и сделаем.

Код:
004528CE  68 D8 57 00 00 E8 FA 75  24 00 83 C4 04 89 44 24  h+W..ш·u$.Г-.ЙD$
Нам нужно записать новый размер по адресу 004528CE + 1, потому что 68 - это push, его мы не трогаем.
Действуем.

void FixGame::Initialize(void)
{
	BYTE bytes[] = { 0xB1, 0x01, 0x90 };
	WriteMemoryBYTES(0x005D14BD, bytes, 3);
 
	WriteMemoryDWORD(0x004528CF, sizeof(Creator)); // patch new size
	WriteInstructionCall(0x00452B48, (UINT)Creator::sub_40D840);
}
Code: C++
Всё теперь мы заставили игру выделить для нас память, и нам осталось лишь вызвать конструктор нашего объекта.
Поправим инициализацию, объекта.

int __stdcall Creator::sub_40D840(Creator* pCreator)
{
	typedef int(__stdcall *t)(Creator*);
	t f = (t)0x0040D840;
 
	new (&pCreator->objCreatorEx) CreatorEx();
 
	g_Creator = pCreator;
 
	return f(pCreator);
}
Code: C++
Теперь у нас создано и наше расширение, и мы можем вызывает его функции.

Например вот так.

DWORD dwCountSuns;
	if (g_Creator)
	{
		dwCountSuns = g_Creator->objCreatorEx.GetCountSuns();
		if (dwCountSuns == 0)
		{
			g_Creator->CreateSun(100, 60, 4, 0);
			g_Creator->objCreatorEx.Increment();
		}
	}
Code: C++
Но нам же так же нужно и вызвать деструктор, это я уже покажу в следующей статье А на этом все

Жду ваши вопросы

Так же сделал репозиторий с исходным кодом проекта.
GitHub

Если нужен исходник:
PlantsVsZombies.rar

1 часть
2 часть
3 часть

Последний раз редактировалось VOLKyiv; 27.07.2016 в 23:07.
VOLKyiv вне форума Ответить с цитированием
Сказали спасибо:
Непрочитано 27.07.2016, 21:54   #2
Аватар для Zubastic
ZG troll squad

По умолчанию Re: Модификация игры ASM/C++ Часть 4.

Неплохо, только все в один пост можно было запихнуть.
__________________
Zubastic вне форума Ответить с цитированием
Непрочитано 27.07.2016, 22:47   #3
Аватар для VOLKyiv
Пользователь

Автор темы (Топик Стартер) Re: Модификация игры ASM/C++ Часть 4.

Сейчас готовлю 5 часть, в которой будет редактирование объектов, при создании. Например солнце появляется, и у него есть время жизни. И чтобы после его создания можно было жизнь увеличить примерно в 2 раза. А так же при нажатии кнопки по солнцу, хочу сделать автоподбор солнц. Не знаю вместится ли в 5 часть все или нет.
VOLKyiv вне форума Ответить с цитированием
Непрочитано 27.07.2016, 22:58   #4
Аватар для Zubastic
ZG troll squad

По умолчанию Re: Модификация игры ASM/C++ Часть 4.

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

Добавлено через 35 секунд
Плюс советую юзать такой код:
Код:
[\SRC="c++"][/SRC]
__________________

Последний раз редактировалось Zubastic; 27.07.2016 в 22:59. Причина: Добавлено сообщение
Zubastic вне форума Ответить с цитированием
Непрочитано 27.07.2016, 23:06   #5
Аватар для Deazer

По умолчанию Re: Модификация игры ASM/C++ Часть 4.

Почему так много текста я не понимаю, не могли на ютаб скажем залить обзор. Типа как ломать игру за минуту. Вообще ужас какой то тут происходит, ничего не ясно - я хочу так хоп хоп и все снято.
Deazer вне форума Ответить с цитированием
Непрочитано 27.07.2016, 23:12   #6
Аватар для VOLKyiv
Пользователь

Автор темы (Топик Стартер) Re: Модификация игры ASM/C++ Часть 4.

Цитата:
Сообщение от Deazer Посмотреть сообщение
Почему так много текста я не понимаю, не могли на ютаб скажем залить обзор. Типа как ломать игру за минуту. Вообще ужас какой то тут происходит, ничего не ясно - я хочу так хоп хоп и все снято.
Согласен что видео будет эффективней. Возможно дальше буду записывать всё на видеo.

Последний раз редактировалось VOLKyiv; 28.07.2016 в 00:36.
VOLKyiv вне форума Ответить с цитированием
Непрочитано 27.07.2016, 23:25   #7
Пользователь

По умолчанию Re: Модификация игры ASM/C++ Часть 4.

Согласен, слишком много текста. В видео на все 4 части ушло бы дай бог 10-15 минут, с подробным разжёвыванием.
Emperor вне форума Ответить с цитированием
Непрочитано 28.07.2016, 01:50   #8
Аватар для Deazer

По умолчанию Re: Модификация игры ASM/C++ Часть 4.

Вообще я шутил и считаю что дыбилы которые лезут в асм/реверс/дебагинг вообще не должны ходить по земле не читая документации , а особенно пробивает на смех когда кричат:"А ПАЧИМУ НЕТ ВИДИВА КАК ЭТА ЗАПИЛИВАТЬ". Меня сразу начинает трусить.
Они не могут понять что эта работа не запекания мафинов в микроволновке.
Deazer вне форума Ответить с цитированием
Ответ

Метки
модификация игры, создание чита


Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Модификация игры ASM/C++ Часть 3. VOLKyiv Программирование / Programming 0 27.07.2016 14:22
Модификация игры ASM/C++ Часть 2. VOLKyiv Программирование / Programming 0 27.07.2016 14:04
Модификация игры ASM/C++ Часть 1. VOLKyiv Программирование / Programming 0 27.07.2016 13:59
Визуальная часть игры Ajax52 Документация 5 04.01.2012 21:10
Часть Клиента и часть серверная DRAGYN Lineage II 3 20.02.2011 00:25


© 2007–2024 «Форум администраторов игровых серверов»
Защита сайта от DDoS атак — StormWall
Работает на Булке неизвестной версии с переводом от zCarot
Текущее время: 21:17. Часовой пояс GMT +3.

Вверх