делаю перехват на основе перезаписи начальных байт. проблема в том что когда я передаю управление на функ подобного вида: void a(){ MessageBox(0,"Hook","",0); }; то изменяются все регистры что как раз и очень плохо, для того чтоб такого не было делал так: __asm{ pusha //все регистры в стек call a popa //все регистры из него }; но все равно регистры не правильно востанавливаются. такое чувство как будто а() портит стек( хотя не должна. весь исходных код прикреплять к теме, мож кто подскажет в чем проблема
и еще как заставить компилятор в такую процедуру void(){ }; не вставлять лишний асм. код который изменяет регистры вот так ее генирирует с++ 6.0 Код (Text): push ebp mov ebp,esp sub esp,40 push ebx push esi push edi lea edi,[ebp-40]; mov ecx,10h mov eax,0ccccccccch rep stos dword ptr [edi] pop edi pop esi pop ebx mov esp,ebp pop ebp ret зачем это : Код (Text): sub esp,40 lea edi,[ebp-40]; mov ecx,10h mov eax,0ccccccccch rep stos dword ptr [edi] не понимаю. как сделать чтоб код процедур генировался как в Дельфи 7.0 (по умолчанию) ??
Во-первых, собирай Release, а не Debug сборку. Чтобы совсем убрать пролог/эпилог,используй __declspec(naked). (в этом случае возникнет проблема с локальными переменными. если тебе все же нужны локальные переменные, а так же нужен свой пролог, то нужно делать примерно так: Код (Text): __declspec(naked) void _stdcall someFunction (int arg1) { int local; __asm { push ebp mov ebp, esp sub esp, __LOCAL_SIZE ; предопределенная константа содержит размер локальных переменых текущей функции } local = arg1; printf("hello: %d\n", local); __asm { leave retn 4 } } Так же обрати внимание на соответствие конвенций вызова (stdcall, cdecl, fastcall): в этом может быть причина порчи стека.
Протрассируй вызов WriteFile в отладчике и увидишь, что ты копируешь некоторый call, который использует относительную адресацию и становится невалидным в новом месте. Используй только 5-байтовый джамп. То, что ты показал во втором посте -- бывает только в отладочной версии. Собирай релиз =)
вопрос если я перехват делаю так: 1) ищу в перехватываемой функ. свободных 10байт(инструкций без относительных адресаций) 2)сохраняю в буфер 10байт( перехватываемая функ.) 3)далее на первые 5байт пишем call для нашей функ а на следующии 5байт джамп на буфер а в конце буфера джамп на на перехватываемую функ. какие недостатки этого метода, и в каких случаях от него может валится вся перехватываемая функ.
В случае, когда в 10 байтах не помещается целое число инструкций, что и происходит у меня на машине с твоим кодом.
Нужен дизассемблер длин. Целое число инструкций, длина которых >=5, копируется во временный буфер, при необходимости фиксапится (если там попались jxx), завершается jmp'ом на продолжение. а вместо этих инструкций пишется 5 байтовый джамп на хук. чтобы вызвать из хука оригинальную функцию, нужно передать управление во временный буффер
хм а разве одни и теже инструкции на разных машинах разные по размеру ??? у меня в том месте 4 mov находиться.
а у тебя не хр sp 2 ?? не подскажешь какие есть функ условной адресации кроме call , jmp? если делать программу которая делает перехват по такому методу надо учитовать модель процессора для под счета размера операндов команд?
тоесть на процесорах с такой виндой как и у меня будет работать мой перехват если он работает у меня. да ?
все равно не понимаю если функ/ которая получает управление при перехвате вот такая: Код (Text): void __declspec (naked) mess(){ __asm{ pusha popa ret } } все хорошо. а вот если так сделать; Код (Text): void __declspec (naked) mess(){ __asm{ pusha popa ret } } void a(){ MessageBox(0,"","",0); return; } то падает перехват так как popa востанавливает совсем другие данные
ошибся в #14 там вот так void __declspec (naked) mess(){ __asm{ pusha call a popa ret } } то падает перехват так как функ. востанавливает совсем другие данные
XshStasX Ес-но палает, т.к. ты заменяешь вызов ф-и WriteFile c 5-ю параметрами на вызов своей mess() без параметров, что приводит к нарушению стека после ret. Замени на ret 5*4 и будет тебе счастие
1) Для отладки используй Release и хороший дебаггер (Олю здесь всегда советуют) - тогда можно увидеть чем отличается вызов "call a" от "a();" а они отличаются, как уже говорили прологом/эпилогом, которые определяются конвенциями (stdcall, cdecl, fastcall) 2) Возможно, Great имел ввиду, что __declspec (naked) надо писать при объявлении функции a()...?
нет падает не из-за этого. я перед вызвом ставил pusha . после прочитав manual от Intel. понял что надо pushad. а то что один параметр у функ. которою я вызываю значения почти не имеет. так как после своего завершения она поставит обратно значение стека. а popad в остановить все регистры.