Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Создание эффективных приложений для Windows Джеффри Рихтер 2004 (Книга).pdf
Скачиваний:
385
Добавлен:
15.06.2014
Размер:
8.44 Mб
Скачать

И, наконец, есть еще одна проблема, связанная с GetProcAddress. Допустим, поток выполняет такой код

typedef int (WINAPI *PFNEXITPROCESS)(UINT uExitCode); PFNEXITPROCESS pfnExitProcess = (PFNEXITPROCESS) GetProcAddress( GetModuleHandle("Kernel32"), "ExitProcess");

pfnExitProcess(0);

Этот код сообщает системе, что надо получить истинный адрес ExitProcess в Kernel32.dll, а затем сделать вызов по этому адресу. Данный код будет выполнен в обход Вашей подставной функции. Проблема решается перехватом обращений к GetProcAddress При cc вызове Вы должны возвращать адрес своей функции

В следующем разделе я покажу, как на практике реализовать перехват API-вызовов и решить все проблемы, связанные с использованием LoadLibrary и GetProcAddress.

Программа-пример LastMsgBoxlnfo

Эта программа, «22 LabtMsgBoxInfo.exe» (см листинг на рис. 22-5), демонстрирует перехват API-вызовов. Она перехватывает все обращения к функции MessageBox из User32.dll. Для этого программа внедряет DLL с использованием ловушек. Файлы исходного кода и ресурсов этой программы и DLL находятся в каталогах 22LastMsgBoxInfo и 22-LastMsgBoxIntoLib на компакт-диске, прилагаемом к книге*

После запуска LastMsgBoxInfo открывает диалоговое окно, показанное ниже.

В этот момент программа находится в состоянии ожидания. Запустите какое-нибудь приложение и заставьте его открыть окно с тем или иным сообщением Тестируя свою программу, я запускал Notepad, набирал произвольный текст, а затем пытался закрыть его окно, не сохранив набранный текст Это заставляло Notepad выводить вот такое окно с предложением сохранить документ.

DWORD dwOummy;

VirtualProtect(ppfn, Sizeof(ppfn), PAGE_EXECUTE_READWRITE, &dwDummy);

После отказа от сохранения документа диалоговое окно LastMsgBoxInfo приобретает следующий вид

Как видите, LastMsgBoxlnfo позволяет наблюдать за вызовами функции MessageBox из других процессов

Код, отвечающий за вывод диалогового окна LastMsgBoxInfo и управление им весьма прост. Трудности начинаются при настройке перехвата API-вызовов. Чтобы упростить эту задачу, я создал С++-класс CAPIHook, определенный в заголовочном файле APTHook.h и реализованный в файле APIHook.cpp. Пользоваться им очень легко, так как в нем лишь несколько открытых функций-членов: конструктор, деструктор и метод, возвращающий адрес исходной функции, на которую Вы ставите ловушку

Для перехвата вызова какой-либо функции Вы просто создаете экземпляр этого класса:

CAPIHook g_MessageBoxA( "User32 dll", "MessageBoxA", (PROC) Hook_MessageBoxA, TRUE);

CAPIHook g_MessageBoxW("User32 dll", "MessageBoxW", (PROC)

Hook_MessageBoxW, TRUE);

Мне приходится ставить ловушки на две функции; MessageBoxA и MessageBoxW. Обе эти функции находятся в User32.dll. Я хочу, чтобы при обращении к MessageBoxA вызывалась

Hook_MessageBoxA, а при вызове MessageBoxW— Hook_MessageBoxW.

Конструктор класса CAPIHook просто запоминает, какую API-функцию нужно перехватывать, и вызывает ReplaceMTEntryInAllMods, которая, собственно, и выполняет эту задачу.

Следующая открытая функция-член — деструктор. Когда объект CAPlHook выходит за пределы области видимисти, деструктор вызывает ReplacelATEntryInAllMods для восстановления исходного адреса идентификатора во всех модулях, т. e. для снятия ловушки.

Третий открытый член класса возвращает адрес исходной функции Эта функция обычно вызывается из подставной функции для обращения к перехватываемой функции. Вот как выглядит код функции Hook_MessageBoxA:

int WTNAPI Hook_MessageBoxA(HWND hWnd, PCSTR pszText, PCSIR pszCaption, UINT uType)

{

int nResult = ((PFNMESSAGEBOXA)(PROC) q_MessageBoxA) (hWnd, pszText, pszCaption, uType);

SendLastMsgBoxInfo(FALSE, (PVOTD) pszCaption, (PVOID) pszText, nResult);

return(nResult);

}