Издание четвертое windows ® для профессионалов создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows



Pdf просмотр
страница57/68
Дата28.11.2016
Размер3.57 Mb.
Просмотров12591
Скачиваний0
1   ...   53   54   55   56   57   58   59   60   ...   68
Г ЛАВА 22
Внедрение DLL и перехват вызовов новой DLL? Если в только что загруженной DLL имеются вызовы
ExitProcess, она будет обращаться не к Вашей функции, а к исходной. Для решения этой проблемы Вы должны перехватывать функции
LoadLibraryA, LoadLibraryW, LoadLibraryExA и Load
LibraryExW и вызывать ReplaceIATEntryInOneMod для каждого загружаемого модуля.
И, наконец, есть еще одна проблема, связанная с
GetProcAddress. Допустим, поток выполняет такой код int (WINAPI *PFNEXITPROCESS)(UINT uExitCode);
PFNEXITPROCESS pfnExitProcess = (PFNEXITPROCESS) GetProcAddress(
GetModuleHandle("Kernel32"), "Этот код сообщает системе, что надо получить истинный адрес
ExitProcess в Ker nel32.dll, а затем сделать вызов поэтому адресу. Данный код будет выполнен в обход
Вашей подставной функции. Проблема решается перехватом обращений к
GetProc
Address. При ее вызове Вы должны возвращать адрес своей функции.
В следующем разделе я покажу, как на практике реализовать перехват API вызовов и решить все проблемы, связанные с использованием
LoadLibrary и GetProcAddress.
Программа-пример LastMsgBoxInfo
Эта программа, «22 LastMsgBoxInfo.exe» (см. листинг на рис. 22 5), демонстрирует перехват API вызовов. Она перехватывает все обращения к функции
MessageBox из. Для этого программа внедряет DLL с использованием ловушек. Файлы исходного кода и ресурсов этой программы и DLL находятся в каталогах 22 LastMsgBox
Info и 22 LastMsgBoxInfoLib на компакт диске, прилагаемом к книге.
*
После запуска LastMsgBoxInfo открывает диалоговое окно, показанное ниже.
В этот момент программа находится в состоянии ожидания. Запустите какое нибудь приложение и заставьте его открыть окно стем или иным сообщением. Тестируя свою программу, я запускал Notepad, набирал произвольный текста затем пытался закрыть его окно, не сохранив набранный текст. Это заставляло Notepad выводить вот такое окно с предложением сохранить документ.
*
Как сообщил сам автор, эта программа, к сожалению, работает не со всеми приложениями. Чтобы исправить эту ошибку, Вы должны модифицировать метод
CAPIHook::Replace
IATEntryInOneMod так, чтобы перед вызовом WriteProcessMemory он обращался к Virtual
Protect:
DWORD dwDummy;
VirtualProtect(ppfn, sizeof(ppfn), PAGE_EXECUTE_READWRITE, &dwDummy);

568
Ч АС Т Ь I V
ДИНАМИЧЕСКИ ПОДКЛЮЧАЕМЫЕ БИБЛИОТЕКИ
После отказа от сохранения документа диалоговое окно LastMsgBoxInfo приобретает следующий вид.
Как видите, LastMsgBoxInfo позволяет наблюдать за вызовами функции
MessageBox
из других процессов.
Код, отвечающий за вывод диалогового окна LastMsgBoxInfo и управление им весьма прост. Трудности начинаются при настройке перехвата API вызовов. Чтобы упростить эту задачу, я создал C++ класс CAPIHook, определенный в заголовочном файле и реализованный в файле APIHook.cpp. Пользоваться им очень легко, так как в нем лишь несколько открытых функций членов конструктор, деструктор и метод, возвращающий адрес исходной функции, на которую Выставите ловушку.
Для перехвата вызова какой либо функции Вы просто создаете экземпляр этого класса g_MessageBoxA("User32.dll", "MessageBoxA",
(PROC) Hook_MessageBoxA, TRUE);
CAPIHook g_MessageBoxW("User32.dll", "MessageBoxW",
(PROC) Hook_MessageBoxW, Мне приходится ставить ловушки на две функции
MessageBoxA и MessageBoxW. Обе эти функции находятся в User32.dll. Я хочу, чтобы при обращении к
MessageBoxA вызывалась, а при вызове MessageBoxWHook_MessageBoxW.
Конструктор класса CAPIHook просто запоминает, какую API функцию нужно перехватывать, и вызывает
ReplaceIATEntryInAllMods, которая, собственно, и выполняет эту задачу.
Следующая открытая функция член — деструктор. Когда объект CAPIHook выходит за пределы области видимости, деструктор вызывает
ReplaceIATEntryInAllMods для восстановления исходного адреса идентификатора во всех модулях, те. для снятия ловушки.
Третий открытый член класса возвращает адрес исходной функции. Эта функция обычно вызывается из подставной функции для обращения к перехватываемой функции. Вот как выглядит код функции
Hook_MessageBoxA:
int WINAPI Hook_MessageBoxA(HWND hWnd, PCSTR pszText,
PCSTR pszCaption, UINT uType) {
int nResult = ((PFNMESSAGEBOXA)(PROC) g_MessageBoxA)
(hWnd, pszText, pszCaption, uType);
SendLastMsgBoxInfo(FALSE, (PVOID) pszCaption, (PVOID) pszText, Этот код ссылается на глобальный объект
g_MessageBoxA класса CAPIHook. Приведение его к типу PROC заставляет функцию член вернуть адрес исходной функции
MessageBoxA в Всю работу по установке и снятию ловушек этот C++ класс берет на себя. До конца просмотрев файл CAPIHook.cpp, Вы заметите, что мой C++ класс автоматически

569
Г ЛАВА 22
Внедрение DLL и перехват вызовов создает экземпляры объектов CAPIHook для перехвата вызовов
LoadLibraryA, Load
LibraryW, LoadLibraryExA, LoadLibraryExW и GetProcAddress. Так что он сам справляется с проблемами, о которых я рассказывал в предыдущем разделе.
LastMsgBoxInfo.cpp
/******************************************************************************
Модуль: Автор Copyright (c) 2000, Джеффри Рихтер (Jeffrey Richter)
******************************************************************************/
#include "..\CmnHdr.h"
/* см. приложение А */
#include
#include
#include "Resource.h"
#include "..\22 LastMsgBoxInfoLib\LastMsgBoxInfoLib.h"
///////////////////////////////////////////////////////////////////////////////
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) {
chSETDLGICONS(hwnd, IDI_LASTMSGBOXINFO);
SetDlgItemText(hwnd, IDC_INFO,
TEXT("Waiting for a Message Box to be dismissed"));
return(TRUE);
}
///////////////////////////////////////////////////////////////////////////////
void Dlg_OnSize(HWND hwnd, UINT state, int cx, int cy) {
SetWindowPos(GetDlgItem(hwnd, IDC_INFO), NULL,
0, 0, cx, cy, SWP_NOZORDER);
}
///////////////////////////////////////////////////////////////////////////////
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) {
switch (id) {
case IDCANCEL:
EndDialog(hwnd, id);
break;
}
}
///////////////////////////////////////////////////////////////////////////////
BOOL Dlg_OnCopyData(HWND hwnd, HWND hwndFrom, PCOPYDATASTRUCT pcds) {
// какой то из перехватываемых процессов прислал информацию об открытом им окне с сообщением выводим ее на экран
Рис. 22-5.
Программа-пример LastMsgBoxInfo
см. след. стр.

570
Ч АС Т Ь I V
ДИНАМИЧЕСКИ ПОДКЛЮЧАЕМЫЕ БИБЛИОТЕКИ
Рис. 22-5.
продолжение
SetDlgItemTextA(hwnd, IDC_INFO, (PCSTR) pcds >lpData);
return(TRUE);
}
///////////////////////////////////////////////////////////////////////////////
INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_SIZE, Dlg_OnSize);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
chHANDLE_DLGMSG(hwnd, WM_COPYDATA, Dlg_OnCopyData);
}
return(FALSE);
}
///////////////////////////////////////////////////////////////////////////////
int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) {
DWORD dwThreadId = 0;
#ifdef _DEBUG
HWND hwnd = FindWindow(NULL, TEXT("Untitled Paint"));
dwThreadId = GetWindowThreadProcessId(hwnd, NULL);
#endif
LastMsgBoxInfo_HookAllApps(TRUE, dwThreadId);
DialogBox(hinstExe, MAKEINTRESOURCE(IDD_LASTMSGBOXINFO), NULL, Dlg_Proc);
LastMsgBoxInfo_HookAllApps(FALSE, 0);
return(0);
}
//////////////////////////////// Конец файла //////////////////////////////////
LastMsgBoxInfoLib.cpp
/******************************************************************************
Модуль: Автор Copyright (c) 2000, Джеффри Рихтер (Jeffrey Richter)
******************************************************************************/
#define WINVER
0x0500
#include " \CmnHdr.h"
#include
#include
#include
#include "APIHook.h"
#define LASTMSGBOXINFOLIBAPI extern "C" __declspec(dllexport)
#include "LastMsgBoxInfoLib.h"

571
Г ЛАВА 22
Внедрение DLL и перехват API-вызовов
Рис. 22-5.
продолжение
///////////////////////////////////////////////////////////////////////////////
// прототипы перехватываемых функций typedef int (WINAPI *PFNMESSAGEBOXA)(HWND hWnd, PCSTR pszText,
PCSTR pszCaption, UINT uType);
typedef int (WINAPI *PFNMESSAGEBOXW)(HWND hWnd, PCWSTR pszText,
PCWSTR pszCaption, UINT uType);
// нам приходится ссылаться на эти переменные до их создания extern CAPIHook g_MessageBoxA;
extern CAPIHook g_MessageBoxW;
///////////////////////////////////////////////////////////////////////////////
// эта функция отсылает сообщение MessageBox в наше диалоговое окно void SendLastMsgBoxInfo(BOOL fUnicode,
PVOID pvCaption, PVOID pvText, int nResult) {
// получаем полное имя процесса, открывшего окно с сообщением char szProcessPathname[MAX_PATH];
GetModuleFileNameA(NULL, szProcessPathname, MAX_PATH);
// преобразуем возвращенное значение в строку, понятную человеку pszResult = "(Unknown)";
switch (nResult) {
case IDOK: pszResult = "Ok"; break;
case IDCANCEL: pszResult = "Cancel"; break;
case IDABORT: pszResult = "Abort"; break;
case IDRETRY: pszResult = "Retry"; break;
case IDIGNORE: pszResult = "Ignore"; break;
case IDYES: pszResult = "Yes"; break;
case IDNO: pszResult = "No"; break;
case IDCLOSE: pszResult = "Close"; break;
case IDHELP: pszResult = "Help"; break;
case IDTRYAGAIN: pszResult = "Try Again"; break;
case IDCONTINUE: pszResult = "Continue"; break;
}
// формируем строку для отсылки в наше диалоговое окно char sz[2048];
wsprintfA(sz, fUnicode
? "Process: (%d) %s\r\nCaption: %S\r\nMessage: %S\r\nResult: %s"
: "Process: (%d) %s\r\nCaption: %s\r\nMessage: %s\r\nResult: %s",
GetCurrentProcessId(), szProcessPathname,
pvCaption, pvText, pszResult);
// отсылаем ее в наше диалоговое окно cds = { 0, lstrlenA(sz) + 1, sz };
FORWARD_WM_COPYDATA(FindWindow(NULL, TEXT("Last MessageBox Info")),
NULL, &cds, SendMessage);
}
см. след. стр.

572
Ч АС Т Ь I V
ДИНАМИЧЕСКИ ПОДКЛЮЧАЕМЫЕ БИБЛИОТЕКИ
Рис. 22-5.
продолжение
///////////////////////////////////////////////////////////////////////////////
// функция, заменяющая MessageBoxW
int WINAPI Hook_MessageBoxW(HWND hWnd, PCWSTR pszText, LPCWSTR pszCaption,
UINT uType) {
// вызываем исходную функцию MessageBoxW
int nResult = ((PFNMESSAGEBOXW)(PROC) g_MessageBoxW)
(hWnd, pszText, pszCaption, uType);
// посылаем полученную информацию в наше диалоговое окно, (PVOID) pszCaption, (PVOID) pszText, nResult);
// возвращаем результат вызвавшему модулю return(nResult);
}
///////////////////////////////////////////////////////////////////////////////
// функция, заменяющая MessageBoxA
int WINAPI Hook_MessageBoxA(HWND hWnd, PCSTR pszText, PCSTR pszCaption,
UINT uType) {
// вызываем исходную функцию MessageBoxA
int nResult = ((PFNMESSAGEBOXA)(PROC) g_MessageBoxA)
(hWnd, pszText, pszCaption, uType);
// посылаем полученную информацию в наше диалоговое окно, (PVOID) pszCaption, (PVOID) pszText, nResult);
// возвращаем результат вызвавшему модулю return(nResult);
}
///////////////////////////////////////////////////////////////////////////////
// ставим ловушки на функции MessageBoxA и MessageBoxW
CAPIHook g_MessageBoxA("User32.dll", "MessageBoxA",
(PROC) Hook_MessageBoxA, TRUE);
CAPIHook g_MessageBoxW("User32.dll", "MessageBoxW",
(PROC) Hook_MessageBoxW, TRUE);
// поскольку мы внедряем DLL, пользуясь Windows ловушками нам придется сохранить описатель ловушки в общем блоке памяти (кстати, в Windows 2000 этого не требуется data_seg("Shared")
HHOOK g_hhook = NULL;
#pragma data_seg()
#pragma comment(linker, "/Section:Shared, rws")
///////////////////////////////////////////////////////////////////////////////

573
Г ЛАВА 22
Внедрение DLL и перехват API-вызовов
Рис. 22-5.
продолжение
static LRESULT WINAPI GetMsgProc(int code, WPARAM wParam, LPARAM lParam) {
// Примечание в Windows 2000 первый параметр CallNextHookEx может принимать значение NULL. Вон обязательно должен содержать описатель ловушки, code, wParam, lParam));
}
///////////////////////////////////////////////////////////////////////////////
// возвращает HMODULE, содержащий указанный адрес памяти static HMODULE ModuleFromAddress(PVOID pv) {
MEMORY_BASIC_INFORMATION mbi;
return((VirtualQuery(pv, &mbi, sizeof(mbi)) != 0)
? (HMODULE) mbi.AllocationBase : NULL);
}
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI LastMsgBoxInfo_HookAllApps(BOOL fInstall, DWORD dwThreadId) {
BOOL fOk;
if (fInstall) {
chASSERT(g_hhook == NULL); // повторная установка ловушки недопустима устанавливаем ловушку g_hhook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc,
ModuleFromAddress(LastMsgBoxInfo_HookAllApps), dwThreadId);
fOk = (g_hhook != NULL);
} else {
chASSERT(g_hhook != NULL); // нельзя снять ловушку, если она не установлена fOk = UnhookWindowsHookEx(g_hhook);
g_hhook = NULL;
}
return(fOk);
}
//////////////////////////////// Конец файла //////////////////////////////////
LastMsgBoxInfoLib.h
/******************************************************************************
Модуль: Автор Copyright (c) 2000, Джеффри Рихтер (Jeffrey Richter)
******************************************************************************/
#ifndef LASTMSGBOXINFOLIBAPI
см. след. стр.

574
Ч АС Т Ь I V
ДИНАМИЧЕСКИ ПОДКЛЮЧАЕМЫЕ БИБЛИОТЕКИ
Рис. 22-5.
продолжение
#define LASTMSGBOXINFOLIBAPI extern "C" __declspec(dllimport)
#endif
///////////////////////////////////////////////////////////////////////////////
LASTMSGBOXINFOLIBAPI BOOL WINAPI LastMsgBoxInfo_HookAllApps(BOOL fInstall,
DWORD dwThreadId);
//////////////////////////////// Конец файла //////////////////////////////////
APIHook.cpp
/******************************************************************************
Модуль: Автор Copyright (c) 2000, Джеффри Рихтер (Jeffrey Richter)
******************************************************************************/
#include "..\CmnHdr.h"
#include
#pragma comment(lib, "ImageHlp")
#include "APIHook.h"
#include "..\04 ProcessInfo\Toolhelp.h"
///////////////////////////////////////////////////////////////////////////////
// При выполнении приложения в Windows 98 под управлением отладчика последний записывает в раздел импорта модуля указатель на заглушку которая вызывает желательную функцию. Чтобы учесть это, придется выделывать сумасшедшие трюки, и для них понадобятся следующие переменные старший адрес закрытой памяти (только в Windows 98)
PVOID CAPIHook::sm_pvMaxAppAddr = NULL;
const BYTE cPushOpCode = 0x68; // код PUSH инструкции на платформе x86
///////////////////////////////////////////////////////////////////////////////
// заголовок связанного списка объектов CAPIHook
CAPIHook* CAPIHook::sm_pHead = NULL;
///////////////////////////////////////////////////////////////////////////////
CAPIHook::CAPIHook(PSTR pszCalleeModName, PSTR pszFuncName, PROC pfnHook,
BOOL fExcludeAPIHookMod) {
if (sm_pvMaxAppAddr == NULL) {
// функции с адресами выше lpMaximumApplicationAddress
// требуют особой обработки (только в Windows 98)
SYSTEM_INFO si;
GetSystemInfo(&si);
sm_pvMaxAppAddr = si.lpMaximumApplicationAddress;
}

575
Г ЛАВА 22
Внедрение DLL и перехват API-вызовов
Рис. 22-5.
продолжение
m_pNext = sm_pHead;
// этот узел был вверху списка sm_pHead = this;
// теперь вверху списка находится этот узел сохраняем информацию о перехватываемой функции m_pszCalleeModName = pszCalleeModName;
m_pszFuncName = pszFuncName;
m_pfnHook = pfnHook;
m_fExcludeAPIHookMod = fExcludeAPIHookMod;
m_pfnOrig = GetProcAddressRaw(
GetModuleHandleA(pszCalleeModName), m_pszFuncName);
chASSERT(m_pfnOrig != NULL); // такой функции нет if (m_pfnOrig > sm_pvMaxAppAddr) {
// адрес находится в общей DLL; его надо подправить pb = (PBYTE) m_pfnOrig;
if (pb[0] == cPushOpCode) {
// пропускаем команду PUSH и получаем истинный адрес pv = * (PVOID*) &pb[1];
m_pfnOrig = (PROC) pv;
}
}
// перехватываем эту функцию во всех загруженных модулях, m_pfnOrig, m_pfnHook,
m_fExcludeAPIHookMod);
}
///////////////////////////////////////////////////////////////////////////////
CAPIHook::
CAPIHook() {
// отменяем перехват этой функции во всех модулях, m_pfnHook, m_pfnOrig,
m_fExcludeAPIHookMod);
// удаляем этот объект из связанного списка p = sm_pHead;
if (p == this) { // удаляем верхний узел sm_pHead = p >m_pNext;
} else {
BOOL fFound = FALSE;
// проходим по списку сверху и исправляем указатели for (; !fFound && (p >m_pNext != NULL); p = p >m_pNext) {
if (p >m_pNext == this) {
// переадресуем узел с нашей функции наследующий узел p >m_pNext = p >m_pNext >m_pNext;
break;
}
}
см. след. стр.

576
Ч АС Т Ь I V
ДИНАМИЧЕСКИ ПОДКЛЮЧАЕМЫЕ БИБЛИОТЕКИ
Рис. 22-5.
продолжение
chASSERT(fFound);
}
}
///////////////////////////////////////////////////////////////////////////////
// Примечание эту функцию компилятор НЕ должен подставлять в конечный код CAPIHook::GetProcAddressRaw(HMODULE hmod, PCSTR pszProcName) {
return(::GetProcAddress(hmod, pszProcName));
}
///////////////////////////////////////////////////////////////////////////////
// возвращает HMODULE, содержащий указанный адрес памяти static HMODULE ModuleFromAddress(PVOID pv) {
MEMORY_BASIC_INFORMATION mbi;
return((VirtualQuery(pv, &mbi, sizeof(mbi)) != 0)
? (HMODULE) mbi.AllocationBase : NULL);
}
///////////////////////////////////////////////////////////////////////////////
void CAPIHook::ReplaceIATEntryInAllMods(PCSTR pszCalleeModName,
PROC pfnCurrent, PROC pfnNew, BOOL fExcludeAPIHookMod) {
HMODULE hmodThisMod = fExcludeAPIHookMod
? ModuleFromAddress(ReplaceIATEntryInAllMods) : NULL;
// получаем список модулей в данном процессе th(TH32CS_SNAPMODULE, GetCurrentProcessId());
MODULEENTRY32 me = { sizeof(me) };
for (BOOL fOk = th.ModuleFirst(&me); fOk; fOk = th.ModuleNext(&me)) {
// Примечание мы не перехватываем функции в собственном модуле if (me.hModule != hmodThisMod) {
// перехватываем данную функцию в этом модуле, pfnCurrent, pfnNew, me.hModule);
}
}
}
///////////////////////////////////////////////////////////////////////////////
void CAPIHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,
PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller) {
// получаем адрес раздела импорта модуля

577
Г ЛАВА 22
Внедрение DLL и перехват API-вызовов
Рис. 22-5.
продолжение
ULONG ulSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
ImageDirectoryEntryToData(hmodCaller, TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
if (pImportDesc == NULL)
return; // в этом модуле нет раздела импорта находим дескриптор раздела импорта со ссылками на функции DLL (вызываемого модуля (; pImportDesc >Name; pImportDesc++) {
PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc >Name);
if (lstrcmpiA(pszModName, pszCalleeModName) == 0)
break; // найден (pImportDesc >Name == 0)
return; // этот модуль не импортирует никаких функций изданной получаем таблицу адресов импорта (IAT) для функций DLL
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)
((PBYTE) hmodCaller + pImportDesc >FirstThunk);
// заменяем адреса исходных функций адресами своих функций for (; pThunk >u1.Function; pThunk++) {
// получаем адрес адреса функции ppfn = (PROC*) &pThunk >u1.Function;
// тали это функция, которая нас интересует fFound = (*ppfn == pfnCurrent);
if (!fFound && (*ppfn > sm_pvMaxAppAddr)) {
// Если это "не та" функция и ее адрес находится в общей DLL,
// то, вероятно, мы работаем под отладчиком в Windows 98.
// Тогда адрес указывает на инструкцию, в которой, может быть есть правильный адрес pbInFunc = (PBYTE) *ppfn;
if (pbInFunc[0] == cPushOpCode) {
// это инструкция PUSH; за ней следует истинный адрес функции ppfn = (PROC*) &pbInFunc[1];
// тали это функция, которая нас интересует = (*ppfn == pfnCurrent);
}
}
if (fFound) {
// адреса сходятся изменяем адрес в разделе импорта
см. след. стр.

578
Ч АС Т Ь I V
ДИНАМИЧЕСКИ ПОДКЛЮЧАЕМЫЕ БИБЛИОТЕКИ
Рис. 22-5.
продолжение
WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew,
sizeof(pfnNew), NULL);
return; // получилось выходим если мы попали сюда, значит, в разделе импорта нет ссылки на нужную функцию перехватываем LoadLibrary и GetProcAddress, чтобы наши ловушки работали корректно и при вызове этих функций CAPIHook::sm_LoadLibraryA ("Kernel32.dll", "LoadLibraryA",
(PROC) CAPIHook::LoadLibraryA, TRUE);
CAPIHook CAPIHook::sm_LoadLibraryW ("Kernel32.dll", "LoadLibraryW",
(PROC) CAPIHook::LoadLibraryW, TRUE);
CAPIHook CAPIHook::sm_LoadLibraryExA("Kernel32.dll", "LoadLibraryExA",
(PROC) CAPIHook::LoadLibraryExA, TRUE);
CAPIHook CAPIHook::sm_LoadLibraryExW("Kernel32.dll", "LoadLibraryExW",
(PROC) CAPIHook::LoadLibraryExW, TRUE);
CAPIHook CAPIHook::sm_GetProcAddress("Kernel32.dll", "GetProcAddress",
(PROC) CAPIHook::GetProcAddress, TRUE);
///////////////////////////////////////////////////////////////////////////////
void CAPIHook::FixupNewlyLoadedModule(HMODULE hmod, DWORD dwFlags) {
// если загружается новый модуль, его вызовы функций тоже перехватываются if ((hmod != NULL) && ((dwFlags & LOAD_LIBRARY_AS_DATAFILE) == 0)) {
for (CAPIHook* p = sm_pHead; p != NULL; p = p >m_pNext) {
ReplaceIATEntryInOneMod(p >m_pszCalleeModName,
p >m_pfnOrig, p >m_pfnHook, hmod);
}
}
}
///////////////////////////////////////////////////////////////////////////////
HMODULE WINAPI CAPIHook::LoadLibraryA(PCSTR pszModulePath) {
HMODULE hmod = ::LoadLibraryA(pszModulePath);
FixupNewlyLoadedModule(hmod, 0);
return(hmod);
}

579
Г ЛАВА 22
Внедрение DLL и перехват API-вызовов
Рис. 22-5.
продолжение
///////////////////////////////////////////////////////////////////////////////
HMODULE WINAPI CAPIHook::LoadLibraryW(PCWSTR pszModulePath) {
HMODULE hmod = ::LoadLibraryW(pszModulePath);
FixupNewlyLoadedModule(hmod, 0);
return(hmod);
}
///////////////////////////////////////////////////////////////////////////////
HMODULE WINAPI CAPIHook::LoadLibraryExA(PCSTR pszModulePath,
HANDLE hFile, DWORD dwFlags) {
HMODULE hmod = ::LoadLibraryExA(pszModulePath, hFile, dwFlags);
FixupNewlyLoadedModule(hmod, dwFlags);
return(hmod);
}
///////////////////////////////////////////////////////////////////////////////
HMODULE WINAPI CAPIHook::LoadLibraryExW(PCWSTR pszModulePath,
HANDLE hFile, DWORD dwFlags) {
HMODULE hmod = ::LoadLibraryExW(pszModulePath, hFile, dwFlags);
FixupNewlyLoadedModule(hmod, dwFlags);
return(hmod);
}
///////////////////////////////////////////////////////////////////////////////
FARPROC WINAPI CAPIHook::GetProcAddress(HMODULE hmod, PCSTR pszProcName) {
// получаем истинный адрес этой функции pfn = GetProcAddressRaw(hmod, pszProcName);
// относится ли эта функция к числу тех, которые мы хотим перехватывать p = sm_pHead;
for (; (pfn != NULL) && (p != NULL); p = p >m_pNext) {
if (pfn == p >m_pfnOrig) {
// возвращаем адрес перехватываемой функции pfn = p >m_pfnHook;
break;
}
}
return(pfn);
}
//////////////////////////////// Конец файла //////////////////////////////////
см. след. стр.
1   ...   53   54   55   56   57   58   59   60   ...   68


База данных защищена авторским правом ©nethash.ru 2019
обратиться к администрации

войти | регистрация
    Главная страница


загрузить материал