Программа-пример LastMsgBoxlnfo
Эта программа, «22 LabtMsgBoxInfo.exe» (см листинг на рис. 22-5), демонстрирует перехват API-вызовов. Она перехватывает все обращения к функции MessageBox из User32.dll. Для этого программа внедряет DLL с использованием ловушек. Файлы исходного кода и ресурсов этой программы и DLL находятся в каталогах 22-LastMsgBoxInfo и 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);
}
Этот код ссылается на глобальный объекту MessageBoxA класса CAPIHook. Приведение его к типу PKOC заставляет функцию-член вернуть адрес исходной функции MessageBoxA в User32.dll.
Всю работу по установке и снятию ловушек этот С++-класс берет на себя. До конца просмотрев файл CAPIIIook.cpp, Вы заметите, что мой С++-класс автоматически
создает экземпляры объектов CAPIHook для перехвата вызовов LoadLibraryA, LoadLibraryW, LoadLibraryExA, LoadLibraryExW и GetProcAddress. Так что он сам справляется с проблемами, о которых я расскаяывал в предыдущем разделе.
LastMsgBoxlnfo