В прятки с отладчиком Крис Касперски ака мыщъх Хакер, номер #086, стр. 086-120-7 Вообще-то, можно просто проанализировать значение регистра ESP до и после выполнения API-функции. Дельта и будет тем количеством байт, на которые мы должны увеличить ESP. Но есть и более короткие пути: если перехватываемая функция известна, то достаточно просто создать функцию, имеющую тот же самый прототип. На языке Си это будет выглядеть так (в данном случае перехватывается MessageBoxA, в заголовке которой насильно прописывается строка "hacked", подтверждающая, что перехватчик исправно работает): __stdcall thunk(HWND h, LPCTSTR lpTxt, LPCTSTR lpCaption, UINT uType) { _do(_UNINSTALL_THUNK_); // восстанавливаем оригинальную функцию MessageBox(h,lpTxt,"hacked",uType); // вызываем оригинальную функцию _do(_INSTALL_THUNK_); // вновь устаналиваем thunk } [перехват произвольной API-функции] Язык ассемблера выгодно отличается от Си тем, что позволяет реализовать универсальный перехватчик, поддерживающий все функции и не захламляющий стек дублированными аргументами. Все очень просто. Вернемся к схемам нашего стека приведенным выше. Скажи, зачем держать в стеке сразу два адреса возврата, когда можно обойтись и одним? Ведь функции отрабатывают последовательно, передавая эстафету как степени реактивной ракеты. Короче. В момент передачи управления на thunk на вершине стека находится адрес возврата в прикладную программу. Запоминаем его в глобальной переменной saved и пишем сюда адрес возврата в thunk, на который будет передано управление после выхода из API-функции. Скопировав в стек сохраненный адрес, мы сможем вернуться в прикладную программу по ret, и при этом не придется химичить с аргументами! А вот как эта красота реализуется: // ассемблерный код универсального перехватчика, работающего // через подмену адреса возврата и способный нести на своем // борту "боевую начинку", выполняемую до или после вызова API-функции __declspec( naked ) thunk() { __asm{ push offset _UNINSTALL_THUNK_ ; снимаем thunk с функции call _do_asm add esp,4 pop [saved] ; подменяем ret_addr на post_exit push offset post_exit ; "боевая нагрузка" до вызова функции ; ======================================================================== ; подменяем строку заголовка и меняем тип диалогового окна pre_run: mov eax, offset my_string ; mov [esp+12], offset my_string ; ms vc не поддерживает такую команду :( mov [esp+12], eax mov [esp+10h], 1 mov eax,[p] ; вызываем перехваченную функцию as is jmp eax ; "боевая нагрузка" после вызова функции ;========================================================================= ; ничего не делаем (добавьте сюда собственный код, если хотите) post_exit: push offset _INSTALL_THUNK_ ; снова устанавливаем thunk на функцию call _do_asm add esp,4 push [saved] ; возвращаемся туда, откуда нас вызывали |