Перехват произвольной API-функции
Язык ассемблера выгодно отличается от Си тем, что позволяет реализовать универсальный перехватчик, поддерживающие все функции и не засирающий стек дублированными аргументами. Все очень просто. Вернемся к рис. 4. Скажите, на хрена держать в стеке сразу два адреса возврата, когда можно обойтись и одним? Ведь функции отрабатывают последовательно, передавая эстафету как степени реактивной ракеты. Короче.
В момент передачи управления на thunk на вершине стека находится адрес возврата в прикладную программу. Запоминаем его в глобальной переменной saved, и пишем сюда адрес возврата в thunk, на который будет передано управление после выхода из API-функции. Скопировав на стек сохраненный адрес мы сможем вернуться в прикладную программу по ret и при этом не придется химичить с аргументами!
Красота! А вот ее готовая программная реализация: (### а вот как эта красота реализуется):
// наш thunk
//============================================================================
// получаем управление до вызова перехватываемой 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] ; возвращаемся туда, откуда нас вызывали
retn
}
}
Листинг 5 ассемблерный код универсального перехватчика, работающего через подмену адреса возврата и способный нести на своем борту "боевую начинку", выполняемую до или после вызова API-функции