![]() |
|
сделать стартовой | добавить в избранное |
![]() |
Методы перехвата API-вызовов в Win32 |
Игорь В. Филимонов Введение Данная статья написана в результате анализа известных методов перехвата API-вызовов в Wi dows. В некоторых широко известных примерах реализации перехвата системных функций есть небольшие ошибки, которые в некоторых случаях приводят к тому, что перехват не работает. Один из таких примеров был описан в RSD Magazi e #1, другой – в известной книге Джеффри Рихтера «Wi dows для профессионалов: создание эффективных Wi 32-приложений с учетом специфики 64-разрядной версии Wi dows», 4-е издание. Перехват системных функций операционной системы – приём, известный давно. Обычно перехватывается некоторая системная функция с целью мониторинга или изменения её поведения. Во времена DOS программисты перехватывали программные прерывания (i 21h, i 16h, i 10h). С приходом Wi 16 понадобились средства для перехвата API-функций. И, наконец, с появлением Wi 32 средства перехвата ещё раз эволюционировали, подстроившись под новую систему. Операционные системы семейства Wi dows никогда не содержали встроенных средств, специально предназначенных для перехвата системных функций. И понятно почему – всё-таки это немного хакерский приём. Поэтому перехват обычно осуществляется «подручными средствами», и для его реализации нужно чётко представлять многие глубинные аспекты устройства и функционирования операционной системы. В данной статье рассматриваются методы реализации перехвата системных API-функций в 32-разрядных операционных системах Wi dows. Рассматриваются особенности реализации перехвата в Wi 9X (Wi dows 95/98/98SE/ME) и Wi (Wi dows /2000/XP/2003). Особенности организации памяти в Wi dows Так как перехват практически всегда связан с модификацией памяти (либо кода перехватываемой функции, либо таблиц импорта/экспорта), то для его осуществления необходимо учитывать особенности архитектуры памяти Wi и Wi 9X. Каждому процессу (начиная с Wi dows 95) выделяется собственное виртуальное адресное пространство. Для 32-разрядных процессов его размер составляет 4 Гб. Это адресное пространство разбивается на разделы, функциональное назначение и свойства которых довольно сильно отличаются у семейств ОС Wi и Wi 9Х. Адресное пространство любого процесса в Wi 9Х можно разделить на три раздела: Младшие два гигабайта (00400000-7FFFFFFF) – код и данные пользовательского режима (в диапазоне 00000000-003FFFFF расположены разделы для выявления нулевых указателей и для совместимости с программами DOS и Wi 16); Третий гигабайт – для общих файлов, проецируемых в память (MMF), и системных DLL. Четвёртый гигабайт – для кода и данных режима ядра (здесь располагается ядро операционной системы и драйверы). Старшие два гигабайта являются общими для всех процессов. Основные системные DLL – ker el32.dll, advAPI32.dll, user32.dll и GDI32.dll загружаются в третий гигабайт. По этой причине эти четыре библиотеки доступны всем процессам в системе. Поскольку этот гигабайт общий, они существуют во всех процессах по одним и тем же адресам. Из соображений безопасности Microsof запретила запись в область, куда они загружаются. Если же запись туда всё же произвести (а это возможно из режима ядра или недокументированными методами), то изменения произойдут во всех процессах одновременно.
В Wi общих разделов у процессов нет, хотя системные библиотеки по-прежнему во всех процессах загружаются по одинаковым адресам (но теперь уже в область кода и данных пользовательского режима). Запись в эту область разрешена, но у образов системных библиотек в памяти стоит атрибут «копирование при записи» (copy-o -wri e). По этой причине попытка записи, например, в образ ker el32.dll приведёт к появлению у процесса своей копии изменённой страницы ker el32.dll, а на остальных процессах это никак не отразится. Все эти различия существенно влияют на способы реализации перехвата функций, расположенных в системных DLL. Перехваты можно разделить на два типа: локальные (перехват в пределах одного процесса) и глобальные (в масштабах всей системы). Локальный перехват Локальный перехват с использованием раздела импорта Локальный перехват может быть реализован и в Wi 9X, и в Wi посредством подмены адреса перехватываемой функции в таблице импорта. Для понимания механизма работы этого метода нужно иметь представление о том, как осуществляется динамическое связывание. В частности, необходимо разбираться в структуре раздела импорта модуля. В разделе импорта каждого exe- или DLL-модуля содержится список всех используемых DLL. Кроме того, в нем перечислены все импортируемые функции. Вызывая импортируемую функцию, поток получает ее адрес фактически из раздела импорта. Поэтому, чтобы перехватить определенную функцию, надо лишь изменить её адрес в разделе импорта. Для того чтобы перехватить произвольную функцию в некотором процессе, необходимо поправить её адрес импорта во всех модулях процесса (так как процесс может вызывать эту функцию не только из exe-модуля, но и из DLL-модулей). Кроме того, процесс может воспользоваться для загрузки DLL функциями LoadLibraryA, LoadLibraryW, LoadLibraryExA, LoadLibraryExW или, если она уже загружена, определить её адрес при помощи функции Ge ProcAddress. Поэтому для перехвата любой API-функции необходимо перехватывать и все эти функции. Существует несколько широко известных примеров реализации этого метода, в частности один из них описан в книге Джеффри Рихтера «Wi dows для профессионалов: создание эффективных Wi 32 приложений с учетом специфики 64-разрядной версии Wi dows» (Jeffrey Rich er «Programmi g Applica io s for Microsof Wi dows»), 4-е издание. Другой пример – библиотека APIHijack, написанная Wade Brai erd на основе DelayLoadProfileDLL.CPP (Ma Pie rek, MSJ, февраль 2000). Для описания этого метода я взял за основу пример Джеффри Рихтера (с небольшими изменениями). Для реализации перехвата был создан класс CAPIHook, конструктор которого перехватывает заданную функцию в текущем процессе. Для этого он вызывает метод ReplaceIA E ryI AllMods, который, перечисляя все модули текущего процесса, вызывает для каждого метод ReplaceIA E ryI O eMod, в котором и реализуется поиск и замена адреса в таблице импорта для заданного модуля. void CAPIHook::ReplaceIA E ryI O eMod(PCS R pszCalleeMod ame, PROC pf Curre , PROC pf ew, HMODULE hmodCaller) { //Получим адрес секции импорта ULO G ulSize; PIMAGE IMPOR DESCRIP OR pImpor Desc = RUE, IMAGE DIREC ORY E RY IMPOR , &ulSize); if (pImpor Desc == ULL) re ur ; //Здесь её нет //Найдём нужный модуль for (; pImpor Desc-> ame; pImpor Desc ) { PS R pszMod ame = (PS R)((PBY E) hmodCaller pImpor Desc-> ame); if (ls rcmpiA(pszMod ame, pszCalleeMod ame) == 0) { //Нашли if (pImpor Desc-> ame == 0) re ur ; //Ни одна функция не импортируется //Получим адрес таблицы импорта PIMAGE HU K DA A p hu k = (PIMAGE HU K DA A)((PBY E) hmodCaller pImpor Desc->Firs hu k); //Переберём все импортируемые функции for (; p hu k->u1.F
u c io ; p hu k ) { PROC ppf = (PROC ) &p hu k->u1.Fu c io ; //Получим адрес функции BOOL fFou d = ( ppf == pf Curre ); //Его ищем? if (!fFou d && ( ppf > sm pvMaxAppAddr)) { // Если не нашли, то поищем поглубже. // Если мы в Wi 98 под отладчиком, то // здесь может быть push с адресом нашей функции PBY E pbI Fu c = (PBY E) ppf ; if (pbI Fu c == cPushOpCode) { //Да, здесь PUSH ppf = (PROC ) &pbI Fu c; //Наш адрес? fFou d = ( ppf == pf Curre ); } } if (fFou d) { //Нашли!!! DWORD dwDummy; //Разрешим запись в эту страницу Vir ualPro ec (ppf , sizeof(ppf ), PAGE EXECU E READWRI E, &dwDummy); //Сменим адрес на свой Wri eProcessMemory(Ge Curre Process(), ppf , &pf ew, sizeof(pf ew), ULL); //Восстановим атрибуты Vir ualPro ec (ppf , sizeof(ppf ), dwDummy , &dwDummy); //Готово!!! re ur ; } } } } //Здесь этой функции не нашлось } При помощи функции ImageDirec oryE ry oDa a определяется дескриптор таблицы импорта и, если он есть, перебираются все DLL, из которых импортируются функции. Если DLL находится, то среди функций, импортируемых из неё, ищется нужная, а затем при помощи Wri eProcessMemory её адрес меняется на адрес своего обработчика. Теперь он будет вызываться каждый раз, когда из данного модуля будет происходить обращение к перехваченной функции. ПРИМЕЧАНИЕ Если вы читали уже упоминаемую выше книгу Джеффри Рихтера, то могли заметить, что в функции ReplaceIA E ryI O eMod я сделал одно изменение. У него она работала так: в таблице импорта находился список функций того модуля, функция из которого импортировалась, и если в этом списке эта функция не находилась, то ReplaceIA E ryI O eMod больше ничего не делала (т. е. перехват не происходил). Я столкнулся с таким поведением, когда написал тестовую программу на Delphi для примера Drive ype2 (этот пример описан ниже, в разделе «Глобальный перехват методом тотального локального перехвата», он перехватывает функцию Ge Drive ypeA во всех приложениях с использованием описываемого метода). Тест, написанный на Visual C , работал прекрасно – функция Ge Drive ypeA перехватывалась. А вот программа на Delphi всё равно для всех перехватываемых мной дисков возвращала реальные значения. Я посмотрел таблицу импорта тестовой программы при помощи утилиты DUMPBI и обнаружил, что компилятор Delphi не поместил все импортируемые функции из ker el32.dll в один список, а разбил их на 3 части, причём Ge Drive ypeA оказалась в третьей. Поэтому функция ReplaceIA E ryI O eMod Джеффри Рихтера, просмотрев все функции из первого списка Ker el32.dll, не нашла функции Ge Drive ypeA, хотя она и импортировалась модулем Drive ype es .exe. Я исправил эту функцию таким образом, чтобы она проверяла всю таблицу импорта и перебирала все списки с функциями из ker el32.dll (как оказалось, их может быть несколько). В описании формата РЕ-файла нигде не оговаривается, что каждый модуль, из которого импортируются функции, должен встречаться в секции импорта только один раз, и, видимо, некоторые компиляторы этим пользуются. При реализации данного метода следует учитывать, что вызовы из DllMai библиотеки, в которой находится перехватываемая функция, перехватить не удастся.
Однако часто возникает ситуация, когда одновременно используются СОМ и API-функции Win32, что не дает возможности применить эту технику. Рассмотрим следующий фрагмент кода, читающий строку из элемента редактирования и преобразующий ее в IID: HRESULT IIDFromHWND(HWND hwnd, IID& riid) { TCHAR szEditText[1024]; // call a TCHAR-based Win32 routine // вызываем TCHAR-процедуру Win32 GetWindowText(hwnd, szEditText, 1024); // call an OLECHAR-based СОМ routine // вызываем OLECHAR-процедуру СОМ return IIDFromString(szEditText, &riid); } Допуская, что этот код скомпилирован с указанным символом С-препроцессора UNICODE; он работает безупречно, так как TCHAR и OLECHAR являются просто псевдонимами wchar_t и никакого преобразования не требуется. Если же функция скомпилирована с версией Win32 API, не поддерживающей Unicode, то TCHAR является псевдонимом для char, и первый параметр для IIDFromString имеет неправильный тип. Чтобы решить эту проблему, нужно провести условную компиляцию: HRESULT IIDFromHWND(HWND hwnd, IID& riid) { TCHAR szEditText[1024]; GetWindowText(hwnd, szEditText, 1024); #ifdef UNICODE return IIDFromString(szEditText, &riid); #else OLECHAR wszEditText[l024]; ustrncpy(wszEditText, szEditText, 1024); return IIDFromString(wszEditText, &riid); #endif } Хотя этот фрагмент и генерирует оптимальный код, очень утомительно применять эту технику всякий раз, когда символьный параметр имеет неверный тип
1. Перехват методов COM интерфейсов
3. Изучение миксомицетов среднего Урала, выращенных методом влажных камер
4. Методы исследования в цитологии
5. МЕТОДЫ ИЗУЧЕНИЯ ЭВОЛЮЦИИ ЧЕЛОВЕКА
9. Схема вызова всех служб города Кургана
10. Методы и модели демографических процессов
11. Гидрохимический, атмохический и биогеохимический методы поисков
12. Добыча золота методами геотехнологии
13. Государственное регулирование экономики: формы и методы
15. Нелегальная миграция в России и методы борьбы с ней
16. Предмет и метод гражданского права
17. Предмет, метод и система гражданского процессуального права /Украина/
18. Корпорация BBC. Формы и методы государственного контроля вещания
19. Формы и методы выхода предприятий на внешний рынок
20. Финансовый контроль: формы, методы, органы
21. Эффективные методы изучения иностранных языков
25. Методы изучения музыкальных произведений крупной формы в старших классах общеобразовательной школы
26. Цивилизационные методы в изучении истории
27. Методы компьютерной обработки статистических данных
28. Решение транспортной задачи методом потенциалов
29. Решение дифференциальных уравнений 1 порядка методом Эйлера
30. Оценка методов и средств обеспечения безошибочности передачи данных в сетях
31. Обзор возможных методов защиты
32. Метод деформируемого многогранника
34. Методы прогнозирования основанные на нейронных сетях
35. Модифицированный симплекс-метод с мультипликативным представлением матриц
36. Методы приобретения знаний в интеллектуальных системах
37. Резидентный обработчик клавиатуры (перехват нажатий клавиш и запись в файл)
41. Компьютерные вирусы, типы вирусов, методы борьбы с вирусами
42. Анализ криптостойкости методов защиты информации в операционных системах Microsoft Window 9x
43. Парольные методы защиты информации в компьютерных системах от несанкционированного доступа
45. Лабораторная работа №6 по "Основам теории систем" (Решение задачи о ранце методом ветвей и границ)
46. Решение задач - методы спуска
47. Решение смешанной задачи для уравнения гиперболического типа методом сеток
48. Решение систем дифференциальных уравнений методом Рунге-Куты 4 порядка
49. Решение систем линейных алгебраических уравнений методом Гаусса и Зейделя
51. Вычисление определенного интеграла методами трапеций и средних прямоугольников
52. Решение нелинейного уравнения методом касательных
53. Методы корреляционного и регрессионного анализа в экономических исследованиях
57. Построение графика функции различными методами (самостоятельная работа учащихся)
58. Краткая методичка по логике
59. Методы решения систем линейных неравенств
60. Вычисление двойных интегралов методом ячеек
61. Методы обучения математике в 10 -11 класах
62. Решение задач линейной оптимизации симплекс – методом
63. Приближённые методы решения алгебраического уравнения
64. Решение дифференциальных уравнений 1 порядка методом Эйлера
65. Методы расчета электрических полей
66. Метод Алексея Юрьевича Виноградова для решения краевых задач
67. Решение задач на построение сечений в многогранниках методом следов
68. Новый метод «дополнительных краевых условий» Алексея Юрьевича Виноградова для краевых задач
69. Лазерные методы диагностики. Термография
73. Предмет, метод, содержание cудебной медицины
74. Методы оценки кровопотери в акушерстве
75. Метод Фолля
76. Некоторые методы лечения переломов длинных трубчатых костей
78. Сравнительная характеристика методов лабораторной диагностики трихомоноза
79. Продвинутые методы Ганемана. LМ-потенции: теория и практика
81. Предмет, понятие, метод и система криминологии
82. Характеристики методов расследования преступлений, связанных с квалифицированным вымогательством
83. Понятие и основные методы исследовательской фотографии
84. Загрязнение водных ресурсов и методы очистки
85. Методы очистки промышленных газовых выбросов
90. Игровые методы в логопедической практике
91. Компьютерные технологии как фактор эволюции форм и методов обучения
92. Методы изучения музыкальных произведений крупной формы в старших классах общеобразовательной школы
93. Наркомания школьников, методы профилактики
94. Средства и методы педагогического воздействия на личность
95. Эффективные методы изучения иностранных языков