Рейтинг темы:
  • 0 Голос(ов) - 0 в среднем
  • 1
  • 2
  • 3
  • 4
  • 5
L2 PTS
#21
Удивительно как можно совершить столько ошибок в паре строчек кода Sad
[SRC="c++"]tramp = new unsigned char[6];[/SRC]
Memory leak без delete[] в конце. Лучше сразу на стеке объявить char tramp[6];
[SRC="c++"]tramp[1] = (char)pNewFunc;[/SRC]
Это копирует только один младший байт адреса.
[SRC="c++"]WriteMemory(pAddress, &tramp, sizeof(tramp));[/SRC]
Cразу две ошибки. У тебя tramp - это указатель, следовательно &tramp - адрес этой переременной, а не самого буфера с кодом; по той же причине sizeof(tramp) будет == 4, а не 6.

[SRC="c++"]
char trampoline[6];
trampoline[0] = 0x68; // push imm32
memcpy(&trampoline[1], pNewFunc, 4); // тут я не понял. pNewFunc у тебя это уже адрес новой функции или это указатель на переменную с адресом новой функции?
trampoline[5] = 0xС3; // ret
WriteMemory(pAddress, trampoline, sizeof(trampoline));
[/SRC]
Ответ
#22
Да уж, как можно так издеваться над c++
Ответ
#23
Ugly Написал:Удивительно как можно совершить столько ошибок в паре строчек кода Sad
[SRC="c++"]tramp = new unsigned char[6];[/SRC]
Memory leak без delete[] в конце. Лучше сразу на стеке объявить char tramp[6];
[SRC="c++"]tramp[1] = (char)pNewFunc;[/SRC]
Это копирует только один младший байт адреса.
[SRC="c++"]WriteMemory(pAddress, &tramp, sizeof(tramp));[/SRC]
Cразу две ошибки. У тебя tramp - это указатель, следовательно &tramp - адрес этой переременной, а не самого буфера с кодом; по той же причине sizeof(tramp) будет == 4, а не 6.

[SRC="c++"]
char trampoline[6];
trampoline[0] = 0x68; // push imm32
memcpy(&trampoline[1], pNewFunc, 4); // тут я не понял. pNewFunc у тебя это уже адрес новой функции или это указатель на переменную с адресом новой функции?
trampoline[5] = 0xС3; // ret
WriteMemory(pAddress, trampoline, sizeof(trampoline));
[/SRC]

спасибо)
только теперь адрес то верно пишет, но когда выполняется патченый код то приложение крашится тупо..в чем может быть проблема?
UDP: Посмотрел дебагером, а там по адресу pNewFunc расположено что то очень странное..
[Изображение: weaOr9BBnL4.jpg]
Ответ
#24
Просто длл не загружена, если не ошибаюсь.
А вообще критует из-за ошибки записи скорее всего. Писать через виртуалпротект же надо Smile

Добавлено через 1 минуту
[SRC="c++"]void HookFunction(void* dest, void* src, int countBytes)
{
DWORD dwProtect = PAGE_READWRITE;
VirtualProtect(dest, countBytes, dwProtect, &dwProtect);
*(int*)dest = (int)src;
VirtualProtect(dest, countBytes, dwProtect, &dwProtect);
}[/SRC]

Для моих нужд этого хватает.
[Изображение: 4e38c909fcd08c5fcdf363b54a62.png]
Ответ
#25
Zubastic Написал:Просто длл не загружена, если не ошибаюсь.
А вообще критует из-за ошибки записи скорее всего. Писать через виртуалпротект же надо Smile

Добавлено через 1 минуту
[SRC="c++"]void HookFunction(void* dest, void* src, int countBytes)
{
DWORD dwProtect = PAGE_READWRITE;
VirtualProtect(dest, countBytes, dwProtect, &dwProtect);
*(int*)dest = (int)src;
VirtualProtect(dest, countBytes, dwProtect, &dwProtect);
}[/SRC]

Для моих нужд этого хватает.

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

Добавлено через 19 минут
Я тут подумал, а у меня вообще адрес функции правильно определятся?Big Grin
[SRC="c++"]CPatchEngine::Instance()->WriteCall((BYTE *)0x14010DF47, (DWORD *)PatchInit);[/SRC]
[SRC="c++"]
void CPatchEngine::WriteCall(BYTE *pAddress, DWORD *pNewFunc)
{
char trampoline[6];
trampoline[0] = 0x68; // push imm32
memcpy(&trampoline[1], &pNewFunc, 4);
trampoline[5] = 0xC3; // ret
WriteMemory(pAddress, trampoline, sizeof(trampoline));
}
[/SRC]
Ответ
#26
Функция называется WriteCall, но вообще-то равносильна jmp, а не call. Предварительно на стек следует положить адрес, куда вернётся управление после возврата из функции.
Ответ
#27
Ugly Написал:Функция называется WriteCall, но вообще-то равносильна jmp, а не call. Предварительно на стек следует положить адрес, куда вернётся управление после возврата из функции.

Я что то вообще запутался:redlol:
мне в начале темы говорили про:
push Adr
ret
я как понял в данном случае это не верно будет для call?
Ответ
#28
Ответ
#29
Sojang, для начала определитесь вообще, что Вы хотите, а не бездумно копируйте код)
jmp - безусловный переход и не более того.
push/ret - аналог jmp.
call - кидает на стек текущий адрес и прыгает на указанный адрес; если функция ret-ается, то у нас происходит возврат туда откуда был call (адрес caller'a на стеке же есть).

Для вызова оригинальной функции нужно выполнить, то что было затерто переходом (jmp/push-ret/call), обычно это пролог функции по какому-нибудь calling conventions, а-ля, stdcall для win32. При вызове оригинальной функции, мы смещаемся на то количество байтов, которое мы перетерли.
Пример: адрес функции 0x1000, мы переписали первые 5 байт на jmp, значит мы реализуем перетертые 5 байт и делаем переход на 0x1005, грубо говоря.

Если затерто было БОЛЬШЕ пролога, да и вообще чето как-то получилось, то что размер перетертых команд не совпадает с размером команд, которыми мы заменили, то пишем дизассемблер длин, нопим кривые куски команд и делаем все то же самое, но реализовывать обратный переход надо уже с учетом того, что мы нопнули.

Можно конечно оботись костылем такого вида: если у нас перехваченная функция гарантированно дергается в один поток, то можно просто снимать хук, когда мы хотим перейти назад и ставить его опять, после того, как мы получим результат работы функции. Главное не забыть сбросить instruction cache, иначе ничего не поменяетсяWink
m0nster.art - clear client patches, linkz to utils & code.
Гадаю по капче.
Ответ
#30
n3k0nation Написал:Sojang, для начала определитесь вообще, что Вы хотите, а не бездумно копируйте код)
jmp - безусловный переход и не более того.
push/ret - аналог jmp.
call - кидает на стек текущий адрес и прыгает на указанный адрес; если функция ret-ается, то у нас происходит возврат туда откуда был call (адрес caller'a на стеке же есть).

Для вызова оригинальной функции нужно выполнить, то что было затерто переходом (jmp/push-ret/call), обычно это пролог функции по какому-нибудь calling conventions, а-ля, stdcall для win32. При вызове оригинальной функции, мы смещаемся на то количество байтов, которое мы перетерли.
Пример: адрес функции 0x1000, мы переписали первые 5 байт на jmp, значит мы реализуем перетертые 5 байт и делаем переход на 0x1005, грубо говоря.

Если затерто было БОЛЬШЕ пролога, да и вообще чето как-то получилось, то что размер перетертых команд не совпадает с размером команд, которыми мы заменили, то пишем дизассемблер длин, нопим кривые куски команд и делаем все то же самое, но реализовывать обратный переход надо уже с учетом того, что мы нопнули.

Можно конечно оботись костылем такого вида: если у нас перехваченная функция гарантированно дергается в один поток, то можно просто снимать хук, когда мы хотим перейти назад и ставить его опять, после того, как мы получим результат работы функции. Главное не забыть сбросить instruction cache, иначе ничего не поменяетсяWink

Такс я чет не понял про пролог..я вообще патчил в приложении вызовы например call это оказывается не правильно?Sad
Я вообще туплю что то и нихуа не понимаю :redlol::redlol:
Ответ


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


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