- 237
- 442
Примечание: Для дизассемблирования кода понадобится любая из этих программ: OllyDbg, Cheat Engine, Ida Pro, SoftICE. Я буду использовать Cheat Engine.
В процессе урока мы заинжектимся из нашей длл в функцию samp.dll AddChatMessage(...), где сможем изменить текст, который приходит с сервера.
Для начала нам понадобится смещение функции, а так же её входящие аргументы. Обычно я их добываю сам, но вы можете найти большое их количество в исходниках собейта.
0x79700 ; int __stdcall addClientMessage(DWORD color, LPSTR str)
Глянем начало функции в дизассемблере (откроем гта, откроем cheat engine, нажмём MemoryView в ce, жмакаем Ctrl+G, там вводим samp.dll+79700, жмакаем Enter):
Вспоминаем что нам понадобится 5 байтов для инжекта, их у нас занимают 2 опкода, которые легко подменить.
Напишем функцию для инжекта, я использую c++:
Для примера сделаем функцию, которая добавит в конец текста строку "Injected".
Теперь нам надо сделать "прослойку", можно конечно обойтись без неё, но это сильно упрощает жизнь, при этом потери в скорости очень незначительны.
Задача прослойки: сохранить регистры, вызвать функцию (AddClientMessageCallback), восстановить регистры, вызвать опкоды, которые мы подменили инжектом (5 байт).
Для того, чтобы компилятор не добавил своегоговно-кода, мы пропишем _declspec( naked ) перед функцией
Осталось только прописать инжект в памяти при запуске
В итоге получили:
В процессе урока мы заинжектимся из нашей длл в функцию samp.dll AddChatMessage(...), где сможем изменить текст, который приходит с сервера.
Для начала нам понадобится смещение функции, а так же её входящие аргументы. Обычно я их добываю сам, но вы можете найти большое их количество в исходниках собейта.
0x79700 ; int __stdcall addClientMessage(DWORD color, LPSTR str)
Глянем начало функции в дизассемблере (откроем гта, откроем cheat engine, нажмём MemoryView в ce, жмакаем Ctrl+G, там вводим samp.dll+79700, жмакаем Enter):
Код:
samp.dll+79700 - 56 - push esi
samp.dll+79701 - 8B 74 24 0C - mov esi,[esp+0C]
samp.dll+79705 - 8B C6 - mov eax,esi
samp.dll+79707 - 57 - push edi
samp.dll+79708 - 8B F9 - mov edi,ecx
Напишем функцию для инжекта, я использую c++:
Код:
void InjectJump(DWORD _offset, DWORD target)
{
unsigned long Protection;
VirtualProtect((void*)_offset, 5, PAGE_EXECUTE_READWRITE, &Protection);
target -= (_offset + 5);
*((char*)_offset) = 0xE9;
memcpy((LPVOID)(_offset+1), &target, sizeof(DWORD));
VirtualProtect((void*)_offset, 5, Protection, 0);
}
Код:
VOID _stdcall AddClientMessageCallback(DWORD color, LPSTR str) //не забываем _stdcall, иначе компилятор может подкинуть нам свинью
{
strcat_s(str, 256, " Injected");
}
Задача прослойки: сохранить регистры, вызвать функцию (AddClientMessageCallback), восстановить регистры, вызвать опкоды, которые мы подменили инжектом (5 байт).
Для того, чтобы компилятор не добавил своего
Код:
LPVOID _injectedAddClientMessageCallbackRetAddr; //Нужно указать при создании инжекта, чтобы функция знала, куда ей возвращаться
_declspec( naked ) VOID _injectedAddClientMessageCallback()
{
_asm
{
pushad//Сохраняем регистры
//Количество пушей - это количество аргументов функции
//Смещение в стэке расчитывается так: (кол-во аргументов)*4+0x20
//У нас получается 2*4=8
push [esp+0x28]//строка
push [esp+0x28]//цвет
call AddClientMessageCallback
popad //Восстанавливаем регистры
//Ниже повторяем действия, которые мы подменили
push esi
mov esi,[esp+0xC]
//Возвращаемся в функцию
jmp _injectedAddClientMessageCallbackRetAddr
}
}
Код:
_injectedAddClientMessageCallbackRetAddr = (LPVOID)(dwSAMP+0x79705); //0x79700 + 5 конец опкода, которые мы перезаписываем
InjectJump(dwSAMP+0x79700, (DWORD) &_injectedAddClientMessageCallback);