Xhayla Опубликовано 24 августа, 2019 Поделиться Опубликовано 24 августа, 2019 Всем привет. Имеется приложение для теста Dll`ки, вот ее код. Спойлер #include "stdafx.h" #include <windows.h> int main() { while (true) { MessageBox(0, L"TEST", 0, 0); Sleep(5000); } return 0; } Мне нужно изменить Sleep(5000) - 5 секунд на Speel(1000) к примеру. Я нашел инструкцию в которой хранится значение "sleep(5000)", вот так выглядит(ТЫК) За счет Dll`ки, я хочу перевести код на копию этого участка, где значение будет уже не 5000мс, а к примеру 1000мс.(для того чтобы понять, работает DLL или нет). Вот код самой DLL Спойлер DWORD origAddress; DWORD copyAddress; LONG WINAPI HookPage(EXCEPTION_POINTERS *pExceptionInfo) { if(pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) { if (pExceptionInfo->ExceptionRecord->ExceptionAddress == (GetModuleHandle("ForHookMessage.exe") + 0x116F3)) { pExceptionInfo->ContextRecord->Eip = (DWORD)copyAddress; return EXCEPTION_CONTINUE_EXECUTION; } } return EXCEPTION_CONTINUE_SEARCH; } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { origAddress = (DWORD)GetModuleHandle("ForHookMessage.exe") + 0x116F3; // 0x116F3 смещение до инструкции где хранится значение задежки Sleep, видно на скриншоте. MEMORY_BASIC_INFORMATION system_info = { 0 }; VirtualQuery((LPCVOID)origAddress, &system_info, sizeof(MEMORY_BASIC_INFORMATION)); // получаю информацию об адрессе. copyAddress = (DWORD)malloc(system_info.RegionSize); // выделяю нужное кол-во байт памяти. memcpy((void*)copyAddress, reinterpret_cast<void*>(origAddress), system_info.RegionSize); // копирую оригинальную страницу в копию. AddVectoredExceptionHandler(1, HookPage); // устанавливаю отлов исключений. //SetUnhandledExceptionFilter(HookFunc); DWORD OldProt = 0; VirtualProtect((void*)origAddress, system_info.RegionSize, system_info.Protect | PAGE_GUARD, &OldProt); // изменяю в оригинальной странице защиту на PAGE_GUARD, чтобы вылезло исключение. break; } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } Теперь, я делаю инжект этой DLL в процесс, а программа просто зависает. ЗАПИСАЛ ВИДЕО НА YOUTUBE Ссылка на комментарий Поделиться на другие сайты Поделиться
roma912 Опубликовано 24 августа, 2019 Поделиться Опубликовано 24 августа, 2019 (изменено) *(int*)( ((DWORD)GetModuleHandleA(NULL)) + 0x116F3 + 1 ) = 1000; Вроде все что необходимо Что-то ты слишком много делаешь чтобы добиться такого простого результата Изменено 24 августа, 2019 пользователем roma912 Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 24 августа, 2019 Автор Поделиться Опубликовано 24 августа, 2019 15 минут назад, roma912 сказал: *(int*)( ((DWORD)GetModuleHandleA(NULL)) + 0x116F3 + 1 ) = 1000; Вроде все что необходимо Что-то ты слишком много делаешь чтобы добиться такого простого результата Я хочу понять, как делается PageGuard Hooking на C++, а это программа просто для проверка, работает или нет. Ссылка на комментарий Поделиться на другие сайты Поделиться
partoftheworlD Опубликовано 24 августа, 2019 Поделиться Опубликовано 24 августа, 2019 2 часа назад, Xhayla сказал: Я хочу понять, как делается PageGuard Hooking на C++, а это программа просто для проверка, работает или нет. По тому коду, который ты используешь оно даже работать не будет. Сейчас код напишу и закомментирую. Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 24 августа, 2019 Автор Поделиться Опубликовано 24 августа, 2019 (изменено) 28 минут назад, partoftheworlD сказал: По тому коду, который ты используешь оно даже работать не будет. Сейчас код напишу и закомментирую. @partoftheworlD, Жду, очень нужно, 2 день в тупике, сперва пробовал на игре, ничего не получалось, потом подумал, неужели вообще не работает, решил ТУПА попробовать на приложение где 3 строчки когда, ЦИКЛ - СООБЩЕНИЕ - ЗАДЕРЖКА, даже тут не получилось... Вы хорошо знаете C++? Изменено 24 августа, 2019 пользователем Xhayla Ссылка на комментарий Поделиться на другие сайты Поделиться
partoftheworlD Опубликовано 24 августа, 2019 Поделиться Опубликовано 24 августа, 2019 26 минут назад, Xhayla сказал: @partoftheworlD, Жду, очень нужно, 2 день в тупике, сперва пробовал на игре, ничего не получалось, потом подумал, неужели вообще не работает, решил ТУПА попробовать на приложение где 3 строчки когда, ЦИКЛ - СООБЩЕНИЕ - ЗАДЕРЖКА, даже тут не получилось... Вы хорошо знаете C++? https://pastebin.com/4tXXM0av Думаю подставить вместо &value адрес указывающий на копию куска памяти не составит труда. 26 минут назад, Xhayla сказал: Вы хорошо знаете C++? Нет 1 Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 24 августа, 2019 Автор Поделиться Опубликовано 24 августа, 2019 (изменено) @partoftheworlD, огромное спасибо, а откуда Вы взяли значение INS_SIZE = 10, почему 10? А еще, если я вместо value() укажу адрес указывающий на копию памяти, после того код ее выполнит, в конце нужно будет возвращаться на оригинал? Изменено 24 августа, 2019 пользователем Xhayla Ссылка на комментарий Поделиться на другие сайты Поделиться
partoftheworlD Опубликовано 24 августа, 2019 Поделиться Опубликовано 24 августа, 2019 14 минут назад, Xhayla сказал: а откуда Вы взяли значение INS_SIZE = 10, почему 10? 10 байт размер инструкций, но защита все равно поставится на весь регион памяти. 14 минут назад, Xhayla сказал: в конце нужно будет возвращаться на оригинал? Да, хотя не уверен, проблем не должно быть, ведь по идее ведь код одинаковый везде будет, но желательно вернуть управление оригинальному коду. Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 24 августа, 2019 Автор Поделиться Опубликовано 24 августа, 2019 1 минуту назад, partoftheworlD сказал: Да К примеру у меня есть участок скопированного кода, размером 300 байт, я перевожу код на копию, и в конце чтобы вернутся нужно к оригинальному адресу прибавить 300(размер копии оригинала) + 1(след инструкция), верно? Ссылка на комментарий Поделиться на другие сайты Поделиться
partoftheworlD Опубликовано 24 августа, 2019 Поделиться Опубликовано 24 августа, 2019 22 минуты назад, Xhayla сказал: верно? Лучше так вообще не делать, а отлавливать исключения и делать возврат на оригинал сразу как копия становится не нужной, чем скорее управление вернется в оригинальный код тем лучше. Чтобы посчитать адрес возврата достаточно воспользоваться стеком, например так, сразу перед записью нового EIP. jmp_original = (DWORD)(pExceptionInfo->ContextRecord->Esp); Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 24 августа, 2019 Автор Поделиться Опубликовано 24 августа, 2019 (изменено) 26 минут назад, partoftheworlD сказал: Лучше так вообще не делать, а отлавливать исключения и делать возврат на оригинал сразу как копия становится не нужной, чем скорее управление вернется в оригинальный код тем лучше. Чтобы посчитать адрес возврата достаточно воспользоваться стеком, например так, сразу перед записью нового EIP. jmp_original = (DWORD)(pExceptionInfo->ContextRecord->Esp); и сразу после того как копия выполнится, прыгнуть в jml_original? Если к примеру у меня копия не 1 инструкция, а к примеру 1000 строк, если прыгнуть в jmp_original он все равно в правильный адрес прыгнет? Как у Вас в видео, Вы сперва из 0x0042578C прыгаете на свою функцию, после возвращаетесь на 2 инструкцию после 0x0042578C, а если к примеру, прыгать из 0x0042578C и выполнять 5 инструкций, чтобы правильно приземлиться после хука, нужно jmp_original так вычислять - jpm_original = (DWORD)(pExceptionInfo->ContextRecord->Esp + 5; ? На счет защиты, как только мне перестанет быть нужен ХУК, нужно вернуть старую защиту и снять отлов исключений? Изменено 24 августа, 2019 пользователем Xhayla Ссылка на комментарий Поделиться на другие сайты Поделиться
partoftheworlD Опубликовано 24 августа, 2019 Поделиться Опубликовано 24 августа, 2019 12 минут назад, Xhayla сказал: а к примеру 1000 строк, если прыгнуть в jmp_original он все равно в правильный адрес прыгнет? Хоть тысячу, хук работает как в CE, главное чтобы состояние измененных регистров не приводило к крашу. 12 минут назад, Xhayla сказал: jpm_original = (DWORD)(pExceptionInfo->ContextRecord->Esp + 5; ? Это не так работает, советую посмотреть основы о том как работает стек. 12 минут назад, Xhayla сказал: На счет защиты, как только мне перестанет быть нужен ХУК, нужно вернуть старую защиту и снять отлов исключений? Да Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 24 августа, 2019 Автор Поделиться Опубликовано 24 августа, 2019 (изменено) @partoftheworlD, еще раз огромное спасибо Вам, все получилось, переделал когда под игру, изменил адрес прыжка и адрес возврата, так же код изменил на нужный, вот только тут проблема, игра стала зависать, fps упал до 30 и начал идти рывка, в меню игры все хорошо, но как только игра начинается, сразу начинает идти рывками что-ли, не связано ли это с тем, что PageGuard Hooking сам по себе медленный? Поскольку в виндовс на отлов исключений нужно какое-то время. Изменено 24 августа, 2019 пользователем Xhayla Ссылка на комментарий Поделиться на другие сайты Поделиться
partoftheworlD Опубликовано 24 августа, 2019 Поделиться Опубликовано 24 августа, 2019 16 минут назад, Xhayla сказал: PageGuard Hooking сам по себе медленный? Да, но не настолько медленный, так же еще зависит от того сколько кода вторая часть обработчика проверяет(которая SINGLE STEP). Явно, если пошаговая отладка будет работать для 10000 инструкций в поиске той самой на которую повешен хук, то быстродействия ждать не стоит. Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 24 августа, 2019 Автор Поделиться Опубликовано 24 августа, 2019 (изменено) 9 минут назад, partoftheworlD сказал: Да, но не настолько медленный, так же еще зависит от того сколько кода вторая часть обработчика проверяет(которая SINGLE STEP). Ну смотрите, я изменил INS_SIZE с 10 на 5. А в value вписал следующий код - Спойлер __declspec(naked) void value() { __asm { xor eax,eax nop nop nop jmp to_addr } } Ну и конечно же поменял адреса начала прыжка и обратный прыжок, странно почему он так зависает.(Если что адрес прыжка состоит из 5 байт, поэтому в INS_SIZE вписал 5). 9 минут назад, partoftheworlD сказал: Да, но не настолько медленный, так же еще зависит от того сколько кода вторая часть обработчика проверяет(которая SINGLE STEP). Явно, если пошаговая отладка будет работать для 10000 инструкций в поиске той самой на которую повешен хук, то быстродействия ждать не стоит. То-есть, если выше адреса, который жду в исключении, будет очень много инструкций будет - зависать? Насколько я понимаю, там где вешается Protect: PAGE_GUARD он тоже будет отлавливаться, тогда как сделать так, чтобы VirtualProtect ставил PAGE_GUARD только на те кол-во байт, которые я указал, а не на всю страницу, можно ли с этим что-то сделать? Ведь в CE не виснет как тут, хотя он там тоже выставляет на всю страницу PAGE_GUARD. Изменено 24 августа, 2019 пользователем Xhayla Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 24 августа, 2019 Автор Поделиться Опубликовано 24 августа, 2019 @partoftheworlDя Вас уже замучал ?, скажите пожалуйста. Как вписать в copyAddress, чтобы от туда в конце прыгать на оригинальный код, а именно на jmp_back. Спойлер DWORD origAddress = 0x6F361390; // оригинальный адресс DWORD jmp_back = 0x6F361395; // адресс на который будем прыгать после прыжка на копию. copyAddress = malloc(30); //выделяет к примеру 30 байт. memcpy(copyAddress, origAddress, 5); // копируем 5 байт из оригинального адресса в выделенную память. Ссылка на комментарий Поделиться на другие сайты Поделиться
Xipho Опубликовано 25 августа, 2019 Поделиться Опубликовано 25 августа, 2019 PBYTE copyAddress = (PBYTE) malloc(5); //выделяет к примеру 30 байт. или BYTE *copyAddress = (BYTE *) malloc(5); // или BYTE copyAddress[] = (BYTE *) malloc(5); // не точно, вроде может прокатить и без приведения типа. Но не помню, где квадратные скобки ставить. memcpy((void *)copyAddress, origAddress, 5); Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 25 августа, 2019 Автор Поделиться Опубликовано 25 августа, 2019 (изменено) 2 часа назад, Xipho сказал: PBYTE copyAddress = (PBYTE) malloc(//выделяет к примеру 30 байт. или BYTE *copyAddress = (BYTE *) malloc(// BYTE copyAddress[] = (BYTE *) malloc(// не точно, вроде может прокатить и без приведения типа. Но не помню, где квадратные скобки ставить.memcpy5 Мне нужно из копии в конце прыгнуть на вот этот адрес 0x6F361395, то-есть чтобы в копии был оригинальные байты + прыжок обратно. Изменено 25 августа, 2019 пользователем Xhayla Ссылка на комментарий Поделиться на другие сайты Поделиться
TechnoBOY Опубликовано 25 августа, 2019 Поделиться Опубликовано 25 августа, 2019 Расчитай прыжок с нужного места на нужный адрес и объедени (добавь в новый) свой массив байт с массивом байт прыжка Ссылка на комментарий Поделиться на другие сайты Поделиться
partoftheworlD Опубликовано 25 августа, 2019 Поделиться Опубликовано 25 августа, 2019 Возможно, это подойдет. На счет VirtualProtect не уверен, но вроде он здесь нужен. Спойлер void copy_base(unsigned char* ©_buffer, const MODULEINFO mi) { DWORD dwOldProtect = 0; //получаем размер образа const auto size = mi.SizeOfImage; //копируем memcpy_s(copy_buffer, size, mi.lpBaseOfDll, size); VirtualProtect(copy_buffer, size, PAGE_EXECUTE_READWRITE, &dwOldProtect); //добавляем jmp to_addr *reinterpret_cast<BYTE*>(copy_buffer[size]) = 0xE9; *reinterpret_cast<DWORD*>(copy_buffer[size + 1]) = to_addr; VirtualProtect(copy_buffer, size, dwOldProtect, 0); } void use_copy() { //получений информации о модуле MODULEINFO mi; GetModuleInformation(0, 0, &mi, sizeof mi); // выделение памяти под копию c запасом в 5 байт // для записи jmp to_addr(прыжка в оригинал) auto buffer = new BYTE[mi.SizeOfImage + 5]; //создание копии copy_base(buffer, mi); /* * * * Какие-то действия с буфером * * */ //Удаление копии delete[] buffer; } Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 25 августа, 2019 Автор Поделиться Опубликовано 25 августа, 2019 1 час назад, partoftheworlD сказал: Возможно, это подойдет. На счет VirtualProtect не уверен, но вроде он здесь нужен. Показать контент void copy_base(unsigned char* ©_buffer, const MODULEINFO mi) { DWORD dwOldProtect = 0; //получаем размер образа const auto size = mi.SizeOfImage; //копируем memcpy_s(copy_buffer, size, mi.lpBaseOfDll, size); VirtualProtect(copy_buffer, size, PAGE_EXECUTE_READWRITE, &dwOldProtect); //добавляем jmp to_addr *reinterpret_cast<BYTE*>(copy_buffer[size]) = 0xE9; *reinterpret_cast<DWORD*>(copy_buffer[size + 1]) = to_addr; VirtualProtect(copy_buffer, size, dwOldProtect, 0); } void use_copy() { //получений информации о модуле MODULEINFO mi; GetModuleInformation(0, 0, &mi, sizeof mi); // выделение памяти под копию c запасом в 5 байт // для записи jmp to_addr(прыжка в оригинал) auto buffer = new BYTE[mi.SizeOfImage + 5]; //создание копии copy_base(buffer, mi); /* * * * Какие-то действия с буфером * * */ //Удаление копии delete[] buffer; } А хотя если подумать, есть ли смысл копировать из оригинального адреса байты в выделенную память, потом оттуда прыгать на оригинальный код, если Вы( @partoftheworlD ), показали другой способ. Спойлер __declspec(naked) void patch() { __asm { xor eax,eax nop nop nop jmp to_addr } } Просто при срабатывании нужного хука, буду переводить туда оригинальный код. pExceptionInfo->ContextRecord->Eip = reinterpret_cast<DWORD>(&patch); Вот только странно, почему в CE когда изменяешь байты через StealthEdit, игры не зависает и не идет рывками, а через PugaGuard на С++ наоборот, зависает. Хотя и там и там тот же адрес хукается. Ссылка на комментарий Поделиться на другие сайты Поделиться
partoftheworlD Опубликовано 25 августа, 2019 Поделиться Опубликовано 25 августа, 2019 39 минут назад, Xhayla сказал: Вот только странно, почему в CE когда изменяешь байты через StealthEdit, игры не зависает и не идет рывками, а через PugaGuard на С++ наоборот, зависает. Хотя и там и там тот же адрес хукается. Да, это странно, потому что, вчера когда писал пример проверял на скайриме никаких проблем не было, фпс не просаживал, все так же плавно было. Могу предположить, что проблема в алгоритме, либо в самой игре, возможно у неё есть собственный обработчик исключений, который что-то с ними делает. И наверное было бы лучше просто убить эту защиту. 39 минут назад, Xhayla сказал: показали другой способ. Способ с asm вставками не будет работать если игра x64 Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 25 августа, 2019 Автор Поделиться Опубликовано 25 августа, 2019 (изменено) 6 минут назад, partoftheworlD сказал: Да, это странно, потому что, вчера когда писал пример проверял на скайриме никаких проблем не было, фпс не просаживал, все так же плавно было. Могу предположить, что проблема в алгоритме, либо в самой игре, возможно у неё есть собственный обработчик исключений, который что-то с ними делает. Игра называется Warcraft 3 TFT, возможно в CE StealthEdit это реализовано по другому. Изменено 25 августа, 2019 пользователем Xhayla Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 25 августа, 2019 Автор Поделиться Опубликовано 25 августа, 2019 17 минут назад, partoftheworlD сказал: Способ с asm вставками не будет работать если игра x64 код который Вы скинули мне выше, это для того чтобы с копии прыгать в нужный мне адрес? 2 часа назад, partoftheworlD сказал: Возможно, это подойдет. На счет VirtualProtect не уверен, но вроде он здесь нужен. Показать контент void copy_base(unsigned char* ©_buffer, const MODULEINFO mi) { DWORD dwOldProtect = 0; //получаем размер образа const auto size = mi.SizeOfImage; //копируем memcpy_s(copy_buffer, size, mi.lpBaseOfDll, size); VirtualProtect(copy_buffer, size, PAGE_EXECUTE_READWRITE, &dwOldProtect); //добавляем jmp to_addr *reinterpret_cast<BYTE*>(copy_buffer[size]) = 0xE9; *reinterpret_cast<DWORD*>(copy_buffer[size + 1]) = to_addr; VirtualProtect(copy_buffer, size, dwOldProtect, 0); } void use_copy() { //получений информации о модуле MODULEINFO mi; GetModuleInformation(0, 0, &mi, sizeof mi); // выделение памяти под копию c запасом в 5 байт // для записи jmp to_addr(прыжка в оригинал) auto buffer = new BYTE[mi.SizeOfImage + 5]; //создание копии copy_base(buffer, mi); /* * * * Какие-то действия с буфером * * */ //Удаление копии delete[] buffer; } Ссылка на комментарий Поделиться на другие сайты Поделиться
Xhayla Опубликовано 25 августа, 2019 Автор Поделиться Опубликовано 25 августа, 2019 51 минуту назад, partoftheworlD сказал: Да, это странно, потому что, вчера когда писал пример проверял на скайриме никаких проблем не было, фпс не просаживал, все так же плавно было. Могу предположить, что проблема в алгоритме, либо в самой игре, возможно у неё есть собственный обработчик исключений, который что-то с ними делает. И наверное было бы лучше просто убить эту защиту. Способ с asm вставками не будет работать если игра x64 Пробовал с помощью кода выше с копии прыгнуть обратно на оригинал, не получилось. (У меня:) ) Ссылка на комментарий Поделиться на другие сайты Поделиться
Рекомендуемые сообщения