Реферат: Перехват API-функций в Windows NT2000XP
Системные программисты, работавшие под MS DOS, прекрасно помнят технологию перехвата системных прерываний, позволявшую брать под контроль практически все процессы, проходившие в любимой операционной системе.
С переходом на Windows использование системных ресурсов программистами в большом объеме стало осуществляться через функции API, и у многих «сиспрогов» стал возникать вопрос: «существуют ли в Windows технологии перехватов этих системных функций?» Особый интерес это вызывает применительно к высокозащищенным ОС, выполненным на ядре NT. Данная статья подробнейшим образом, с действующими примерами покажет практическую реализацию такой технологии (предполагается, что читатель знаком с принципами системного программирования в Windows и умеет применять в своей работе Visual C++).
Что такое «перехват API-функций»
Перехват системной функции API заключается в изменении некоторого адреса в памяти процесса или некоторого кода в теле функции таким образом, чтобы при вызове этой самой API-функции управление передавалось не ей, а вашей функции, подменяющей системную. Эта функция, работая вместо системной, выполняет какие-то запланированные вами действия, и затем, в зависимости от вашего желания, либо вызывает оригинальную функцию, либо не вызывает ее вообще. Перехват функций является очень полезным средством в том случае, если вы хотите отследить, изменить или заблокировать некоторые конкретные действия приложения.
Перехват функций чужого процесса удобнее всего осуществлять внедрением собственной DLL с функцией-двойником в адресное пространство того процесса, контроль над функциями API которого вы хотите установить. При написании двойников функций следует особое внимание обратить на соглашения о вызовах функций __cdecl и __stdcall. В __cdecl функциях подразумевается, что параметры кладутся в стек справа налево, и вызывающая функция очищает стек от аргументов. В __stdcall функциях подразумевается, что параметры кладутся в стек справа налево, но стек от аргументов очищает вызываемая функция. Кроме того, следует учитывать, что в Windows API многие функции встречается в 2-х экземплярах: ANSI и UNICODE. Первые обозначаются суффиксом A: например MessageBoxA, вторые – суффиксом W – например MessageBoxW.
Рассмотрим два метода перехвата API функций:
Непосредственная запись в код функции.
Подмена адреса функции в таблице импорта.
Метод 1. Перехват API непосредственной записью в код системной функции.
Прием заключается в том, чтобы в начало перехватываемой функции записать команду jmp ваша_функция_двойник или эквивалентную ей. Затираемые байты желательно где-нибудь сохранить. После вызова исправленной функции приложением управление будет передано вашей функции. Она должна корректно обработать стек, то есть извлечь переданные ей параметры и произвести необходимые вам действия. Затем, если вы собираетесь вызывать оригинальную функцию, необходимо восстановить затертые байты в начале оригинальной функции. Вызвать ее, передав ей все необходимые параметры. После возврата из оригинальной функции, необходимо снова в начало кода функции записать команду перехода на вашу функцию. Вернуть управление вызвавшей программе.
Достоинство данного метода состоит в том, что он позволяет перехватывать любые функции, а не только те, которые указаны в таблице импорта.
Недостаток: в многопоточных приложениях может возникнуть такая ситуация, когда один поток вызвал перехваченную вами функцию, управление было передано функции-двойнику, она восстановила оригинальное начало функции, но в этот момент параллельно выполняющийся поток произвел вызов той же функции. В результате управление будет передано сразу оригинальной функции, минуя вашу :(.
Разберем пример программы (в виде DLL-файла), перехватывающей функцию MessageBoxA методом 1.
Для работы нам потребуются следующие заголовочные файлы:
#include "stdafx.h" #include "intercpt.h" |
Далее подготовим структуру, содержащую код дальнего перехода на нашу функцию-двойник. Практика показала, что вместо обычного jmp лучше применять комбинацию
push xxxxxxxx ret |
где хххххххх – это адрес функции-двойника. В результате структура, которая будет хранить нужный код перехода, выглядит так:
struct jmp_far { BYTE instr_push; //здесь будет код инструкции push DWORD arg; //аргумент push BYTE instr_ret; //здесь будет код инструкции ret }; |
Зададим нужные переменные:
BYTE old[6]; //область для хранения 6-ти затираемых байт начала функции DWORD adr_MessageBoxA //будущий адрес оригинальной функции DWORD written; //вспомогательная переменная --> ЧИТАТЬ ПОЛНОСТЬЮ <-- К-во Просмотров: 410
Бесплатно скачать Реферат: Перехват API-функций в Windows NT2000XP
|