Методы перехвата API-вызовов в Win32
Игорь В. Филимонов
Данная статья написана в результате анализа известных методов перехвата API-вызовов в Windows. В некоторых широко известных примерах реализации перехвата системных функций есть небольшие ошибки, которые в некоторых случаях приводят к тому, что перехват не работает. Один из таких примеров был описан в RSDN Magazine #1, другой – в известной книге Джеффри Рихтера «Windows для профессионалов: создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows», 4-е издание.
Перехват системных функций операционной системы – приём, известный давно. Обычно перехватывается некоторая системная функция с целью мониторинга или изменения её поведения. Во времена DOS программисты перехватывали программные прерывания (int 21h, int 16h, int 10h). С приходом Win16 понадобились средства для перехвата API-функций. И, наконец, с появлением Win32 средства перехвата ещё раз эволюционировали, подстроившись под новую систему. Операционные системы семейства Windows никогда не содержали встроенных средств, специально предназначенных для перехвата системных функций. И понятно почему – всё-таки это немного хакерский приём. Поэтому перехват обычно осуществляется «подручными средствами», и для его реализации нужно чётко представлять многие глубинные аспекты устройства и функционирования операционной системы.
В данной статье рассматриваются методы реализации перехвата системных API-функций в 32-разрядных операционных системах Windows. Рассматриваются особенности реализации перехвата в Win9X (Windows 95/98/98SE/ME) и WinNT (Windows NT/2000/XP/2003).
Так как перехват практически всегда связан с модификацией памяти (либо кода перехватываемой функции, либо таблиц импорта/экспорта), то для его осуществления необходимо учитывать особенности архитектуры памяти WinNT и Win9X.
Каждому процессу (начиная с Windows 95) выделяется собственное виртуальное адресное пространство. Для 32-разрядных процессов его размер составляет 4 Гб. Это адресное пространство разбивается на разделы, функциональное назначение и свойства которых довольно сильно отличаются у семейств ОС WinNT и Win9Х.
Адресное пространство любого процесса в Win9Х можно разделить на три раздела:
Младшие два гигабайта (00400000-7FFFFFFF) – код и данные пользовательского режима (в диапазоне 00000000-003FFFFF расположены разделы для выявления нулевых указателей и для совместимости с программами DOS и Win16);
Третий гигабайт – для общих файлов, проецируемых в память (MMF), и системных DLL.
Четвёртый гигабайт – для кода и данных режима ядра (здесь располагается ядро операционной системы и драйверы).
Старшие два гигабайта являются общими для всех процессов. Основные системные DLL – kernel32.dll, advAPI32.dll, user32.dll и GDI32.dll загружаются в третий гигабайт. По этой причине эти четыре библиотеки доступны всем процессам в системе. Поскольку этот гигабайт общий, они существуют во всех процессах по одним и тем же адресам. Из соображений безопасности Microsoft запретила запись в область, куда они загружаются. Если же запись туда всё же произвести (а это возможно из режима ядра или недокументированными методами), то изменения произойдут во всех процессах одновременно.
В WinNT общих разделов у процессов нет, хотя системные библиотеки по-прежнему во всех процессах загружаются по одинаковым адресам (но теперь уже в область кода и данных пользовательского режима). Запись в эту область разрешена, но у образов системных библиотек в памяти стоит атрибут «копирование при записи» (copy-on-write). По этой причине попытка записи, например, в образ kernel32.dll приведёт к появлению у процесса своей копии изменённой страницы kernel32.dll, а на остальных процессах это никак не отразится.
Все эти различия существенно влияют на способы реализации перехвата функций, расположенных в системных DLL.
Перехваты можно разделить на два типа: локальные (перехват в пределах одного процесса) и глобальные (в масштабах всей системы).
Локальный перехват с использованием раздела импорта
Локальный перехват может быть реализован и в Win9X, и в WinNT посредством подмены адреса перехватываемой функции в таблице импорта. Для понимания механизма работы этого метода нужно иметь представление о том, как осуществляется динамическое связывание. В частности, необходимо разбираться в структуре раздела импорта модуля.
В разделе импорта каждого exe- или DLL-модуля содержится список всех используемых DLL. Кроме того, в нем перечислены все импортируемые функции. Вызывая импортируемую функцию, поток получает ее адрес фактически из раздела импорта. Поэтому, чтобы перехватить определенную функцию, надо лишь изменить её адрес в разделе импорта. Для того чтобы перехватить произвольную функцию в некотором процессе, необходимо поправить её адрес импорта во всех модулях процесса (так как процесс может вызывать эту функцию не только из exe-модуля, но и из DLL-модулей). Кроме того, процесс может воспользоваться для загрузки DLL функциями LoadLibraryA, LoadLibraryW, LoadLibraryExA, LoadLibraryExW или, если она уже загружена, определить её адрес при помощи функции GetProcAddress. Поэтому для перехвата любой API-функции необходимо перехватывать и все эти функции.
Существует несколько широко известных примеров реализации этого метода, в частности один из них описан в книге Джеффри Рихтера «Windows для профессионалов: создание эффективных Win32 приложений с учетом специфики 64-разрядной версии Windows» (Jeffrey Richter «Programming Applications for Microsoft Windows»), 4-е издание. Другой пример – библиотека APIHijack, написанная Wade Brainerd на основе DelayLoadProfileDLL.CPP (Matt Pietrek, MSJ, февраль 2000). Для описания этого метода я взял за основу пример Джеффри Рихтера (с небольшими изменениями).
Для реализации перехвата был создан класс CAPIHook, конструктор которого перехватывает заданную функцию в текущем процессе. Для этого он вызывает метод ReplaceIATEntryInAllMods, который, перечисляя все модули текущего процесса, вызывает для каждого метод ReplaceIATEntryInOneMod, в котором и реализуется поиск и замена адреса в таблице импорта для заданного модуля.
void CAPIHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName, PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller) { //Получим адрес секции импорта ULONG ulSize; PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hmodCaller, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize;); if (pImportDesc == NULL) return; //Здесь её нет //Найдём нужный модуль for (; pImportDesc->Name; pImportDesc++) { PSTR pszModName = (PSTR)((PBYTE) hmodCaller + pImportDesc->Name); if (lstrcmpiA(pszModName, pszCalleeModName) == 0) { //Нашли if (pImportDesc->Name == 0) return; //Ни одна функция не импортируется //Получим адрес таблицы импорта PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((PBYTE) hmodCaller + pImportDesc->FirstThunk); //Переберём все импортируемые функции for (; pThunk->u1.Function; pThunk++) { PROC* ppfn = (PROC*) &pThunk-;>u1.Function; //Получим адрес функции BOOL fFound = (*ppfn == pfnCurrent); //Его ищем? if (!fFound && (*ppfn > sm_pvMaxAppAddr)) { // Если не нашли, то поищем поглубже. // Если мы в Win98 под отладчиком, то // здесь может быть push с адресом нашей функции PBYTE pbInFunc = (PBYTE) *ppfn; if (pbInFunc[0] == cPushOpCode) { //Да, здесь PUSH ppfn = (PROC*) &pbInFunc;[1]; //Наш адрес? fFound = (*ppfn == pfnCurrent); } } if (fFound) { //Нашли!!! DWORD dwDummy; //Разрешим запись в эту страницу VirtualProtect(ppfn, sizeof(ppfn), PAGE_EXECUTE_READWRITE, &dwDummy;); //Сменим адрес на свой WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew;, sizeof(pfnNew), NULL); //Восстановим атрибуты VirtualProtect(ppfn, sizeof(ppfn), dwDummy , &dwDummy;); //Готово!!! return; } } } } //Здесь этой функции не нашлось } Больше работ по теме:
Перехват методов COM интерфейсов
Реферат Перехват API-функций в Windows NT/2000/XP Реферат Создание в среде Borland C++ Builder dll, совместимой с Visual C++ Реферат Хуки и DLL Реферат Active Directory for Application Mode Реферат Предмет: Информатика, ВТ, телекоммуникации Тип работы: Реферат Новости образования
Российский государственный социальный университет реорганизует сеть своих филиалов
22 Июля 2016 16:26 Более 70 представителей крупных вузов АСЕАН подтвердили участие в форуме во Владивостоке 22 Июля 2016 12:51 Абызов: публикация первичных статсведений снизит бюрократическую нагрузку на школы 22 Июля 2016 11:53 В Чечне свыше 200 школьников сдали ЕГЭ с результатом свыше 90 баллов - министр 22 Июля 2016 05:36 Замглавы Минобрнауки РФ: задача сократить число людей с высшим образованием не стоит 21 Июля 2016 20:19 КОНТАКТНЫЙ EMAIL: [email protected] Скачать реферат © 2018 | Пользовательское соглашение ПРОФЕССИОНАЛЬНАЯ ПОМОЩЬ СТУДЕНТАМ |