Всем, привет!
Сразу же продолжу тему про модификацию игры Plants vs Zombies. Так как в прошлой части ничего интересного не было, а лишь только то что мы создали DLL, и подключили её к игре.
Это не очень интересно так как наша DLL пока еще ничего не делает полезного.
И так первое что нам понадобится это инициализация (запуск) нашей DLL в игре.
Сначала нужно подготовить наш проект, а именно нужно написать функции для работы с памятью игры. Чтобы не изобретать велосипед я нашел хороший пример в интернете.
Это мне понравилось не только тем что позволяет писать в память, а еще есть дефайны для проверки офстета и размера объекта. Что очень полезно при правильном создании классов игры.
CompileTimeSizeCheck
CompileTimeOffsetCheck
Так же создадим файлик Global.h
В котором напишем следующее
Вспомогательные внутри их мы будем писать найденные в игре структуры и перечисления, для глобального доступа по всему проекту.
Подключим наш файлик в stdafx.h
Код:
#pragma once
#include "Global.h"
На этом подготовка проекта закончена.
Теперь приступим к инициализации нашей DLL в игре.
Для того чтобы проверить к какой игре подключена DLL. Мы в IDA Pro перейдем по адресу 0x401000 и скопируем первые 8 байт нашей игры.
void DllInitializer(HMODULE hDllModule)
{
// Проверка разположения нашей библиотеки
if (((UINT64)hDllModule) < 0x7E000000 && ((UINT64)(&hGame)) < 0x7F000000)
{
// Провека игры PlantsVsZombies
if (*((UINT64*)0x401000) == 0xAE76E8CE8B575553)
{
// Открываем просесс игры
if ((hGame = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, GetCurrentProcessId())))
{
// Вот здесь мы можем делать что угодно с нашей игрой:)
// Но мы просто отобразим окошко о успешном подключении нашей DLL.
MessageBox(NULL, _T("DLL PROCESS ATTACH"), _T("DLL"), MB_OK | MB_ICONINFORMATION);
CloseHandle(hGame);
hGame = NULL;
}
else
{
Msg(_T("Ошибка при загрузке"), _T("[%s]\n не был выдан доступ к игре"), __WFILE__);
ExitProcess(1);
}
}
else
{
Msg(_T("Ошибка при загрузке"), _T("[%s]\n это не игра PlantsVsZombies\nИли DLL не совместима с этой версией игры"), __WFILE__);
ExitProcess(1);
}
}
else
{
Msg(_T("Ошибка при загрузке"), _T("[%s]\n Плохое размещение DLL в памяти"), __WFILE__);
ExitProcess(1);
}
}
Не забудьте запустить нашу функцию в DllMain
Код:
case DLL_PROCESS_ATTACH:
DllInitializer(hModule);
break;
Компилируем и убеждаемся что это работает с игрой. То есть процесс открыт для работы с ним.
Для примера, в первой части мы помним что патчили функцию __fptrap.
Давайте вернем её прежнее состояние, мы заменили 2 байтика 6A 02 на C3 90.
Код:
.text:006B5B17 nullsub_4 proc near ; DATA XREF: .data:off_718908
.text:006B5B17 ; .data:off_71890C ...
.text:006B5B17 retn
.text:006B5B17 nullsub_4 endp
.text:006B5B17
.text:006B5B17 ; ---------------------------------------------------------------------------
.text:006B5B18 db 2
.text:006B5B19 ; ---------------------------------------------------------------------------
.text:006B5B19 call __amsg_exit
.text:006B5B1E pop ecx
.text:006B5B1F retn
Для того чтобы изменить их через нашу DLL нам нужно узнать адрес в памяти игры. Помним что она была размещена по адресу 006B5B17. Почему мы здесь выбрали этот адрес, а не 002B4F17 смещение, спросите вы, а всё потому что мы будем работать с виртуальным адресом, а не с самим файлом игры. То было смещение именно в файле, а здесь это уже адрес в памяти.
То есть приложение запуститься и адреса уже будут виртуальные.
Теперь вернёмся к коду.
Для того чтобы записать 2 байта в память будем использовать функцию WriteMemoryWORD(...), так как WORD занимает 2 байта, это то что нам нужно.
Вместо функции
Код:
MessageBox(NULL, _T("DLL PROCESS ATTACH"), _T("DLL"), MB_OK | MB_ICONINFORMATION);
напишем
Код:
WriteMemoryWORD(0x006B5B17, 0x026A);
Скомпилируем и убедимся что при завершении игры вернулась наша ошибка
Runtime error R6002 floating point not loaded
Хотя если мы откроем EXE файл в WinHex и посмотрим что в нем ничего не изменилось. Мы видим байты C3 90. Магия? Теперь объясню что произошло.
Когда начала запускаться игра, наша библиотека в памяти игры изменила байтики, а не в EXE файле.
Мы могли бы пропатчить нашу программу и без WinHex. Это уже кому как удобней.
На этом конец этой части. Следующая часть будет еще интересней этой
Если нужен исходник:
[Ссылки могут видеть только зарегистрированные пользователи. ]