После того как мы в предыдущих статьях, научились уже более менее хоть к чему-то. Теперь же мы перейдем к тому вопросу как заменить функции в памяти игры GTA Vice City, на свой код функции. Ради примера, мы своей заменяемой функцией лешим игру чит кодов. Даже заменим не просто функцию, а метод. Для начала работы откройте базу IDA для GTA Vice City 1.0. Теперь приступим, найдем саму функцию, которая отвечает за обработку чит кодов. Для этого в IDA как обычно нажмите “G” и вбейте адрес 004ABD20.
Обратите внимание, на то что еще красным маркером я выделил, регистр ecx. Это значит то что, это метод а не функция, это обязательно перед заменой важно понимать. По скольку
__thiscall как и
__stdcall после вызова очищает в конце параметры. Наглядно можно показать в конце самой функции:
Значит теперь мы знаем, что нашу пустую функцию, надо объявлять как
__stdcall. Если мы сделаем не пропишем
__stdcall, то по умолчанию наша функция скомпилируется как
__cdecl, который в свое время не очищает стек, после вызова. Последствия могут, привести к вылету игры. Сейчас мы напишем тот метод, который будет работать, но это пригодно лишь для пустой функции. Скажу прямо, что для правильных методик по замене функций, необходимо сперва все переписать в исходник, это называется реверсивная инженерия (об ней совсем отдельный разговор), затем лишь уже заменять. Истинно выглядело бы это как, метод класса. Но для этого надо сперва объявить класс, переписать поля (что нам на данный момент не известно) затем лишь переписывать методы и после делать только правки, по обращениям к ним. На это объяснение, одной статьи не хватит. Пока что мы просто поступим обычным образом. Так теперь наведем курсором мыши на заголовок метода в IDA:
.text:004ABD20 AddCharToCheatStringAndProcess proc near
Затем нажмем кнопку “X”, как я рассказывал в предыдущих статьях и попадем туда откуда идет вызов:
Для чего я перешел? Для того что-бы посмотреть передаются ли параметры. Обратите внимание, что стоит 1 push, который и делает передачу параметров. Т.е он помешает перед вызовом метода, в стек значение. Так вот это и есть сама передача параметров. Это также необходимо знать для замены. Пока не буду загружать, а скажу что параметры одно-байтовый char. Искать те сведения, что это за тип в качестве параметра, это уже совсем другой разговор. Поговорим об этом в других уроках, но не сейчас. Итак теперь наша задача состоит в следующем:
Образно, я маркером пометил что нам надо сделать, нам надо в начало записать процессорную инструкцию JMP у которой параметр будет адрес нашей функции. Догадываетесь что произойдет после такой операции? Вот именно что, как только вывозиться сам метод, произойдет прыжок на нашу функцию, которая не чего не выполнить, так как она пуста. Возврат произойдет туда куда надо и все будет функционировать как полагаться. Теперь перейдем к самому коду на C++ :
#include "stdafx.h"
//Пишем саму функцию которая заменит на нашу
void injectFunction (DWORD address, DWORD function) {
DWORD _old;
VirtualProtect((LPVOID)address,4, PAGE_READWRITE, &_old);
BYTE * patch = (BYTE *)address;
*patch = 0xE9; // JMP
*(DWORD *)(patch+1) = (function-(address+5));
VirtualProtect((LPVOID)address,4, _old, &_old);
}
//Напишем пустую функцию для замены
void __stdcall NullFunc(char key){
};
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//Заменяем
injectFunction(0x04ABD20, (DWORD)NullFunc);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Что тут говорить то, код абсолютно прост injectFunction, вычисляет относительный адрес, нашей функции и записывает команду jmp (0xE9) + адрес нашей функции, туда куда мы указываем в первом параметре. Нашу же пустую функцию мы объявили так, как обсуждали выше, с методом передачи параметров как __stdcall. Ну все, теперь по пробуйте наберите в GTA Vice City хоть один чит код. Уверяю не один из читов не будет работать. Приятного вам моддинга дорогие модмейкеры.