Задача Перехватить определённые функции из определённых DLL (включая ntdll.dll и kernel32.dll). Условия - Архитектура x86. - Использовать метод подмены кода (сплайсинг). - Не использовать дизассемблер длин инструкций. - Поддержка Windows XP и Vista (любой Service Pack). Вопросы Возможно ли это? Если да, то как сие реализуется, какой принцип? Не предлагать - Изменение IAT / EAT. - Технологию Hot-Patching. - Остановку потоков и изменение EIP каждого. - Подмену обработчика исключений. Спасибо!
Собственно, сама техника сплайсинга далеко не нова и даже официально поддерживается Microsoft'ом - см. Detours. Если кто не в курсе, Microsoft предлагает следующий алгоритм перехвата API: 1. Скопировать первые 5 байт перехватываемой (target) функции в начало т.н. функции-трамплина (trampoline). 2. Дописать в конец (по смещению +5 от начала) функции-трамплина команду jmp near на код, находящийся по смещению +5 от начала перехватываемой функции. 3. Записать в начало перехватываемой функции 5 байт команды jmp near на нашу функцию-перехватчик. 4. Если нужно дёрнуть оригинальную функцию, сделать это командой call на функцию-трамплин. Этот алгоритм и кое-какая другая информация описана в этом документе в формате PDF. Ну вроде бы всё просто, но есть один момент, который мне не понятен. Данный способ перехвата будет прекрасно работать, если первые 5 байт целевой функции представляют собой целое число команд. Но в системных библиотеках мне попадался код, который не укладывается в 5 байт, например, вот такой: Код (Text): push ebp (1 байт) mov ebp, esp (2 байта) pop ebp (1 байт) jmp xxxxxxxx (5 байт) Соответственно, просто скопировать отсюда первые 5 байт не получится, т.к. вместе с последним байтом мы прихватим и кусочек команды jmp и по вышеприведённому алгоритму функция-трамплин выполняя команду jmp (пятый байт), "прыгнет" на левый код и приложение, скорее всего, банально упадёт. Проблема, думаю, понятна. Какое есть решение этой проблемы? Прежде всего, - дизассемблер длин инструкций, с помощью него мы получим длину минимально возможного кода, который можно вынести в функцию-трамплин, - в нашем случае это будет первые 9 байт. Но, к сожалению, по некоторым не зависящим от меня причинам дизассемблером длин инструкций я воспользоваться не могу, да и не нравится мне это решение. А других решений я, к стыду своему, не знаю. Кстати, не очень понятно, как сию проблему решает Detours, кто-нибудь в курсе? Вопрос остаётся открытым, как быть, господа?
Без дизасма длин код получится нестабильным. Прийдется тормозить потоки и восстанавливать из обработчика перебитые 5 байт. Потом опять ставить обработчик. На многоядерных тачках кодес периодически будет давать еррорс. Плюс, вам эта технология не подходит по условию. Статьи по поводу сплайсинга тоже давно написаны и откоментированы. раз два Технологии сто лет в обед. ЗЫ: в ntdll первые пять байт - это нопы и mov edi, edi специально сделано для сплайса
Это называется Hot-Patching, не подходит по условию (см. первый пост), т.к. не поддерживается в Windows XP < SP2.
На данный момент пришёл к выводу, что без минимального примитивнейшего дизассемблера длин не получится. Но может быть кто-то знает другие варианты? Ведь Detours как-то решает проблему, описанную во втором посте, интересно узнать как?
Оказывается, Detours поставляется в исходниках всем желающим, хм, не знал. Заглянув туда, выяснил, что они таки используют дизассемблер длин + остановку потоков когда вешают хук, в общем-то это гарантированный вариант, хотя я надеялся, что существует более простое решение, но по-видимому нет, тем более что сам Microsoft делает так. Ну теперь, думаю, тему можно считать закрытой.
NDIS иногда потоки можно не останавливать для ntdll, если делать перехват в таком кодепишу по памяти - не помню) mov eax,?? mov edx,address_xz call edx так тут просто меняем команду mov edx,xxxx где устанавливаем адрес своего кода. тогда можно не тормозить потоки. (У меня в Висте svchost.exe зависал когда я его тормозил и запускал опять, какой то глюк был)
если по честному - то нужно останавливать и потом запускать только активные в данный момент потоки, а не все. Иначе взаимная блокировка происходит в висте и зависание
Ни чего, хотелосьбы узанать как её в масме заюзать. и ещё хотелось бы узнать с каких процессоров она поддерживается
asmfan Атомарно-то оно может и атомарно, но это не спасёт же, если другой поток в данный момент остановлен, скажем, на втором байте функции. 2FED Скачал бы интелловские мануалы (vol2A & vol2B) уже cmpxchg16b - x64.
Данная проблема решается единственно возможным способом - проверкой контекстов приостановленных потоков и возврат их EIP на начало целевой функции. А вообще, по этому поводу, думаю, стоит внимательнее глянуть в исходники Detours'а.
push ebp mov ebp,esp ....<- тут остановился поток. попробуй верни управление на начало. Имхо, проще подождать, пока он уйдёт оттуда, или если уж совсем не терьпится eip переставить на ту-же самую команду, но уже в том месте, куда скопировали начало ф-ии.
Сделать откат инструкций, для этого стандартного пролога это еще возможно (просто сымитировать pop ebp) Ну а вообще проще, конечно, переставить EIP в трамплин-буффер в ту же самую команду.