Рейтинг темы:
  • 1 Голос(ов) - 5 в среднем
  • 1
  • 2
  • 3
  • 4
  • 5
Модификация игры ASM/C++ Часть 3.
#1
Всем, привет!
После первых двух частей где мы подготавливали свою DLL к боюSmile, в этой части я обещал что будет очень интересно.
А именно будет представлен сам процесс модификации, а именно мы будем в IDA Pro искать нам нужные функции и редактировать их.

Создадим класс FixGame.

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

FixGame.h

FixGame.cpp

Теперь запустим игру и попробуем что-то внутри нее изменитьSmile
Показать скриншот

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

Показать скриншот

И в качестве примера сейчас попробуем это убрать. Запускаем IDA Pro. Переходим на вкладку Imports.
И ищем WINAPI функции связаны с фокусом окна.

Показать скриншот

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

Показать скриншот

И выбираем Jump to xref to operand... IDA Pro покажет где эта функция вызывается, в нашем случае только 1 раз в функции sub_602410. Нажимаем снова два раза на название чтобы нас переместили в то месте где она вызывается.
Показать скриншот

Теперь мы видим дизассемблированый код этой функции sub_602410. Нажимаем кнопку F5, чтобы увидеть приближенный к С++ код.

Показать скриншот

Поставим вот здесь breakpoint для того чтобы определить здесь ли нам нужно патчить или нет. И запускаем игру в IDA Pro. Пытаемся поставить игру на паузу.

Показать скриншот

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

Показать скриншот

Погуглив я нашел что можно определять фокус окна с помощью функции GetActiveWindow, проделываем то же самое что и с GetFocus.

Показать скриншот

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

Когда я проверил все функции, я увидел в последней то что при запуске игры, игра записывает результат выполнения в какую-то переменную. Значит это значение анализируется в другом месте. Посмотрев эту функцию sub_5D4CC0
Можно сделать вывод о том что здесь создается главное окно игры. Здесь можно увидеть то что игра передает созданному окну указатель на класс создателя.

Показать скриншот

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

Показать скриншот

Найдем функцию WndProc, которая указывается при регистрации класса окна.
В нашем случае зарегистрирован класс с наименованием MainWindow. Попробуем найти его регистрацию. Откроем вспомогательное окно в IDA Pro, Strings.

Показать скриншот

Попробуем найти все места где упоминаются MainWindow. Всё точно так же как и с поиском функций.

И вот мы видим функцию WndProc. Зайдем внутрь её. Для того чтобы найти наш таймер. С помощью Visual Studio узнаем номер сообщения

PHP код:
<?php 
WM_TIMER
= 0x113

Показать скриншот

Ищем его

Показать скриншот

Теперь переходим на LABEL_28 и снова ищем 0x113. Найдя это сообщения можно увидеть что оно просто сбрасывает переменную в 0. И это никак не может относится к проверки фокуса окна.

Показать скриншот

Вернемся к функции sub_5D4CC0 в которой создавалось окно и куда-то записывался результат выполнения функции GetActiveWindow. И переименуем переменную dwNewLong на THIS. Так как это адрес объекта который управляет созданием окна.
На скриншоте показано как это я определил.

Показать скриншот

Помним что класс передается окну указатель на самого себя

PHP код:
<?php 
SetWindowLongA
(*(HWND *)(THIS + 884), -21, THIS);
SetWindowLongA(*(HWND *)(THIS + 0x374), -21, THIS);
884 = 0x374

Видим куда записывается состояние окна

PHP код:
<?php 
*(_BYTE *)(THIS + 0x53E) = GetActiveWindow() == *(HWND *)(THIS + 0x374);

И возвращаемся к WndProc
Вначале находим получение указателя класса

PHP код:
<?php 
v38
= GetWindowLongA(hWnd, -21);

То есть v38, это тот же THIS что и в функции создания окна.
Ищем смещение 0x53E, то есть наша переменная активности окна. Долго искать не пришлось, вот что я нашел

PHP код:
<?php 
if ( v38 && !*(_BYTE *)(v38 + 0x581) && hWnd == *(HWND *)(v38 + 0x374) )
*(
_BYTE *)(v38 + 0x53E) = wParam != 0;

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

Код:
.text:005D14B7                 xor     ecx, ecx
.text:005D14B9                 cmp     [ebp+wParam], 0
.text:005D14BD                 setnz   cl
.text:005D14C0                 mov     edx, [ebp+var_4]
.text:005D14C3                 mov     [edx+53Eh], cl

Что можно здесь сделать, так это заменить setnz cl, на mov cl, 1.

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

Перейдем по адресу 005D14BD и видим все ту же инструкцию, только Cheat Engine вместо z пишет e, на самом деле это одно и то же. (Не важно) Главное мы видим рядом что эта инструкция занимает 3 байта, теперь нажмем правой кнопкой и нажмем Assemble.

Показать скриншот

Напишем mov cl, 1. И нажмем YES чтобы забить оставшиеся байты нопами. Сейчас увидите почему соглашаемся. Новая инструкция занимает всего 2, и для того чтобы не испортить приложение, нужно оставшийся байт занопить.

Главное мы теперь знаем какие байты нам нужно писать.

Код:
PlantsVsZombies.exe+1D14B9 - 83 7D 10 00           - cmp dword ptr [ebp+10],00
PlantsVsZombies.exe+1D14BD - B1 01                 - mov cl,01
PlantsVsZombies.exe+1D14BF - 90                    - nop
PlantsVsZombies.exe+1D14C0 - 8B 55 FC              - mov edx,[ebp-04]

А это B1 01 90. Пробуем пропатчить нашу игру Smile

Изменим нашу функцию

PHP код:
<?php 
void FixGame
::Initialize(void)
{
BYTE bytes[] = { 0xB1, 0x01, 0x90 };
WriteMemoryBYTES(0x005D14BD, bytes, 3);
}

Компилируем и пробуем поставить игру на паузуSmile
Видим что в фокусе находится окно проводника, но в игре паузы нет.

Показать скриншот

На этом всеSmile Отвечу на все ваши вопросыSmile

Следующая часть будет не менее интересней этойSmile

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

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

1 часть
2 часть
Ответ


Возможно похожие темы ...
Тема Автор Ответы Просмотры Последний пост
  Бот для игры kanmisha 6 1,718 01-28-2024, 06:17 PM
Последний пост: osazonov
  Модификация игры ASM/C++ Часть 5. VOLKyiv 7 2,968 07-28-2016, 09:57 PM
Последний пост: VOLKyiv
  Модификация игры ASM/C++ Часть 4. VOLKyiv 7 3,119 07-28-2016, 01:50 AM
Последний пост: Deazer
  Модификация игры ASM/C++ Часть 2. VOLKyiv 0 1,669 07-27-2016, 02:04 PM
Последний пост: VOLKyiv
  Модификация игры ASM/C++ Часть 1. VOLKyiv 0 2,772 07-27-2016, 01:59 PM
Последний пост: VOLKyiv

Перейти к форуму:


Пользователи, просматривающие эту тему: 1 Гость(ей)