Честно говоря не очень в этом разбираюсь, сделал как показалось логичным, но ничего не работает. Код (Text): typedef struct PATCH { BYTE b1; DWORD address; PATCH() { b1 = 0x9E;}; }PATCH; void PATCH_PROC() { char *s_msg; __asm mov ebp,eax; // это оригинальный код который __asm cmp ebp,-1; // был на месте моего JMP __asm push eax; __asm push ecx; __asm push edx; __asm push ebx; __asm mov s_msg,esp __asm push esp; __asm push esi; l.AddToLog(s_msg); __asm pop eax; __asm pop ecx; __asm pop edx; __asm pop ebx; __asm pop esp; __asm pop esi; } //..... DllMain DWORD dwDummy; LPVOID mem = (LPVOID)0x0053F4E7; PATCH p; p.address = (DWORD)PATCH_PROC; //sizeof(p) = 5, граница выравнивания 1 байт VirtualProtect(mem, sizeof(p), PAGE_EXECUTE_READWRITE, &dwDummy); memcpy(mem,&p,sizeof(p)); VirtualProtect(mem, sizeof(p), dwDummy , &dwDummy); Патчит какую то ерунду, даже записывает не ту информацию , что в p =( Смотрю через OllyDgb.
Darkcloud В твоей PATCH_PROC уже куча ошибок. mov ebp,eax ;eax имеет неизвестное науке значение, ebp, который будет указателем фрейма, ты портишь cmp ebp,-1; непонятно, зачем проверка, ее результатами ты не пользуешься mov s_msg,esp4; а в стеке фигня всякая к этому моменту порядок выталкивания из стека должен быть обратным по отношению к заталкиванию (FILO - first in last out, т.е. последнее заpushенное значение должно быть первым заpopленным)
Darkcloud Ассемблерный код это вообще что-то странное. Адрес места правки должен вычисляться динамически. Не всегда DLL загрузиться по нужному адресу. Что это за конструктор в середине структуры? Если уж заполняешь её - так в одном месте. Какая польза с оригинального кода если пролог твоей функции void PATCH_PROC() ещё никто не отменял? Да и тему в WASM.BEGINNERS нужно было размещать. P.S. Что такое 9E ? sahf ?
Оригинальный код НЕ патченной программы выглядит так Я хочу заменить это на jmp 12345678, где 12345678 адрес моей функции По крайней мере в OllyDbg можно так заменить и jmp по размеру(если адрес не short) действительно занимает 5 байт ! Далее после вызова процедуры(а она у меня ещё ни разу не вызывалась, т.к. патчится неверно) должны выполниться оригинальные команды, т.е. При этом регистр esi всегда(в данном контексте) указывает на строку. Пожтому я адрес копирую в указатель, ну и регистры засовываю в стек, потом делаю некоторые операции(в данном случает просто l.AddToLog(s_msg)), потом вытаскиваю и стека, и далее идее должно продолжиться выполнение программы, т.е. долже выполниться код который идёт в оригинале после cmp ebp,-1. Что не так, у меня даже memcpy нормально не копирует, копирует ккаую то чушь... =( Я думал 9E - это jmp. По крайней мере, если я в OllyDbg заменяю кусок кода на jmp 12345678, код изменяется на 9E 12345678. Какая разница где конструктор стоит ? Просто первый байт всегда один и тот же, вот и заполняю к конструкторе. Пролог ? Это что такое ? Тему можете переместить хоть в WASM.MEGANOOBS, главное скажите что не так...
Darkcloud E9 - jmp а не 9E Твой код анализируют люди. Им не очень интересно разбираться в хитросплетениях кода. Пролог это например push ebp/mov ebp, esp Сделай NAKED функцию. В её конце вместо RET исполни оригинальные команды и передай управление дальше. Оригинальные команды следует вызывать в конце работы твоей функции. (иногда на самом нечале - но это сейчас не для тебя)
Darkcloud К чему такие сложности? Распредели код своего патча по свободным от кода дыркам программы и срасти куски кода jmp-ами.
фигня какая-то. почитай мою статью про сплайсинг. https://forum.antichat.ru/thread32176.html я вроде нормально расписал что к чему и как делать. я написал и какой опкод, и как считать разницу, и как патчить и вообще полезно тебе будет. а тему реально надо в BEGINNERS.
Darkcloud Дешовый 5 минутный пример: Код (Text): int origRetAddr = 0x0053F4E7 + 5; /* static */ void __declspec(naked) PATCH_PROC() { __asm { push ebp mov ebp, esp sub esp, 64 //make room for one local variable pushad } __asm mov s_msg, esi l.AddToLog(s_msg); __asm { popad mov esp,ebp pop ebp // original commands mov ebp,eax cmp ebp,-1 jmp origRetAddr // return } } Если тебе нужно пропатчить воспользуйся советом crypto Если динамически изменять/читать инфу - слушать совет Great гуглить и читать про сплайсинг. P.S. И на старуху найдёться ... У меня была ошибка jmp origRetAddr+5 не катит. Сразу добавь 0x0053F4E7+5. Иначе вычитаешь непонятно что.
Всем спасибо, особенно DelExe. Теперь почти всё работает, правда остался один очень неприятный баг =( При вызове функции программа через некоторое время вылетает. Причём не на любой функции вылетает, например HandlerFunc1 проходит отлично, но она ничего и не далает. А вот с HandlerFunc2 - хреново. Код (Text): char *s_msg; DWORD origRetAddr = 0x0053F4E7 + 5; FILE *f; void HandlerFunc1() { int k = 10+1; } void HandlerFunc2() { f = fopen("C:\\log.txt","a"); fprintf(f,"%s",s_msg); //тут можно написать даже fprintf(f,"Hi, yo") - всё равно эффект тот же fclose(f); } void __declspec (naked) PATCH_PROC() { __asm push esp; __asm push eax; __asm push ecx; __asm push edx; __asm mov eax,esp; __asm mov DWORD PTR[s_msg],eax; //HandlerFunc1(); //- вызов функции прохдит нормально HandlerFunc2(); //- а при выхове этой функции программы вылетает __asm pop edx; __asm pop ecx; __asm pop eax; __asm pop esp; __asm mov ebp,eax; __asm cmp ebp,-1; __asm jmp origRetAddr; } Все регистры проверил, после выхода из моей функции(PATCH_PROC), все они имею точно такое же значиние, что и при входе в функцию. Правда может я что то упустил ? Проверил EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI Может ещё какие есть ?
Darkcloud __asm mov eax,esp; // Получить указатель вершины стека __asm mov DWORD PTR[s_msg],eax; // Записать указатель вершины стека в s_msg Вопрос: что ты хочешь увидеть на вершине стека? __asm push edx; ? P.S. Всё-равно не понимаю смысловую нагрузку ассемберного кода, что там проверять по eax если регистр затёртый вызовом HandlerFunc2();
Дело в том, что esp ссылается на строку, которую мне надо получить. Сначала я писал просто __asm mov DWORD PTR[s_msg],esp; но программа выдавала на этом месте Access Violation(х3 почему), поэтому я решил сначала скопировать в eax, а потом уж оттуда брать. И это работает - в файл дествительно сохраняется требуемая строка, только потом программа вылетает =( Я ничего не проверяю по eax... Я сохраняю указатель на строку в глобальную переменную s_msg, из которой потом читаю и сохраняю в файл. З.Ы. тут подумал, может строка кривая и не всегда заканчивается \0 символом... щас проверю...
Darkcloud При засылке в стек данных регистр ESP уменьшаеться. При выталкивании данных регистр увеличивается. Команды push/pop изменяют регистр ESP. Команда mov eax,esp занесёт в регистр EAX указатель на вершину стека ESP. На вершине стека лежит edx Содержимое стека в момент выполнения команды mov eax,esp: [esp +0] edx [esp +4] ecx [esp +8] eax [esp +C] esp (esp в момент входа в функцию PATCH_PROC) [esp +10] eip +............ Если у тебя строка выводится, то как я понимаю, ты ожидаешь двойной указатель на строку. Указатель что находиться в регистре EDX ?
Ну про регистр esp я не знал, хотя в моём случае edx и esp отличаются Указатель у меня записывается правильно, тут дело даже не в этом. НЕ РАБОТАЕТ даже если записать так. Код (Text): __asm push eax; __asm push ecx; __asm push edx; __asm push ebx; __asm push ebp; __asm push esi; __asm push edi; Beep(100,100); //вызов простой апи функции, //если её закомментировать, то всё ОК __asm pop edi; __asm pop esi; __asm pop ebp; __asm pop ebx; __asm pop edx; __asm pop ecx; __asm pop eax; __asm mov ebp,eax; __asm cmp ebp,-1; __asm jmp origRetAddr; //DWORD origRetAddr Тотальный анализ регистров показал следующие изменение между рабочим и не рабочим вариантом. SetLastError(ERROR_SUCCESS), пробовал ставить - не помогает. Что такое EFL 00000217 (NO,B,NE,BE,NS,PE,GE,G) ? З.Ы. это я извращаюсь над mirc клиентом, может там какая то защита есть ?
Darkcloud Мне что-то подсказывает что тебе немного рано пользоваться технологиями сплайсинга. Для начала стоит изучить ассембер, понять какие регистры стоит сохранять (в зависимости от компилятора), что такое this, порядок помещения аргументов в стек в зависимости от конвенций вызова (__cdecl, __fastcall, __stdcall)... Так что считаю - пока код будет доведён до нужного состояния у кого-то из нас не выдержит сердце Есть книги прекрасного автора Криса Касперски. С них начинали многие. Тебе пригодятся "Фундаментальные основы хакерства", "Образ мышления - дизассемблер IDA". Ну и книги по ассемблеру - их куча в электронном виде.
DelExe, почему рано ? норм =) Что такое this и конвенции вызова я и так знаю, только какой от этого прок здесь ? У Beep, как и у всех апи функций __stdcall и что мне это даёт ? Я создавал свою пустую stdcall функцию и все проходило нормально. Да и крутым хакером я не хочу быть =) ,обсуждаемый код мне нужен для вполне мирных целей. Скорей всего дествительно нужо разобраться самому - либо здесь действительно какая то защита есть, либо что то ооочень простое, что я упустил =) В любом случае - спасибо, тему можно считать закрытой.
Ну вот и всё, проблема решена. Оказывается место jump-а я выбрал неудачо, там после вызова любого апи изменялись вот эти "регистры" (или что это ? =)) как их push-ить и pop-ить - х3, явно не регистры общего назначения. push/pop ES естественно не работает. Зато если поставить JMP немного выше(там всё равно есть указатель на нужную мне строку), что всё работает с первого раза =) Вот и всё.