Некоторое время назад я писал вводную статью о хуках (что это, зачем нужно, Hello world). Статья задумывалась простой, минималистичной и, вроде бы, такой и получилась. Единственный упрёк, который я услышал в комментариях — «Зачем же брать библиотеку Microsoft Detours, которая для коммерческого использования стоит 10 000$ ?». Замечание справедливое. В этой статье я приведу тот же пример с использованием другой библиотеки ценой примерно в 20 раз меньше (что уже вполне себе в рамках разумного) — madCodeHook.
Для лучшего понимания данной статьи рекомендуется сначала прочитать первую часть.
madCodeHook
Библиотека с богатым прошлым. Первая её версия вышла в далёком 2000-ом году, предназначалась для использования под Delphi и мало что умела. Тем ни менее за последующие годы автор весьма неплохо её развивал: сделал SDK для С++, внедрил поддержку 64-битных систем, всех версий Windows от 9х до Win 8.1, реализовал драйвер для внедрения хуков во все новосозданные процессы, ну и вообще достаточно активно работал над проектом (апдейты и сейчас выходят регулярно). По ходу дела из-из нежелания быть подмогой вирусописателям библиотека потеряла бесплатную версию, однако цены, начинающиеся от 349 евро делают её реальной альтернативой и нереально дорогой Microsoft Detours, и малоудобной mhook, и нестабильной (по моему опыту) EasyHook.
Ограничения evaluation-версии
- Нет исходников
- Нет возможности статической линковки
- Должно быть вручную запущено входящее в комплект приложение mchEvaluation.exe
- Библиотека madCHook.dll должна быть предварительно скопирована в System32
В общем, для изучения — ничего критически мешающего. Для коммерческого продукта в любом случае нужно покупать лицензию.
Вспоминаем нашу задачу
В первой части статьи мы использовали хуки для того, чтобы заставить браузер Mozilla Firefox при заходе на Хабр писать в своём заголовке «Привет!». Во-первых, мне лень придумывать новую задачу, а во-вторых даже правильнее будет реализовать снова тоже самое на базе другой библиотеки — можно сравнить скорость разработки, объём и сложность кода. Кроме того, в первой части мы уже разобрались куда и какие хуки нужно вешать, так что сэкономим на этом немного времени.
Практика
1. Качаем последнюю версию madCodeHook, устанавливаем.
2. Создаём в Visual Studio (я использую VS 2010, но вы можете взять и другую) solution c двумя проектами. Первый — библиотека с кодом хука, которую мы будем инжектить в процесс браузера. Второй — приложение инжектора, его задача — забросить библиотеку в адресное пространство браузера.
- Для создания первого проекта: File->New->Project. Тип Visual C++ -> Win32 -> Win32 Project. В диалоге создания проекта указываем тип «Dll»
- Для создания второго проекта: File->Add->New Project. Тип Visual C++ -> Win32 -> Win32 Console Application.
4. Подкидываем в наши проекты заголовочный файл и lib-файл из SDK madCodeHook. При установке библиотеки по-умолчанию они находятся по адресу C:Program Files (x86)madCollectionmadCodeHookDll. В evaluation-версии нам доступна только динамическая линковка, так что забираем файлы madCHook — dynamic.h и madCHook — dynamic — microsoft.lib, можно их для краткости переименовать в madCHook.h и madCHook.lib.
5. Пишем код. Ключевые моменты:
#include "stdafx.h"
#include <conio.h>
#include "windows.h"
#include "madCHook.h"
#include <tlhelp32.h>
HANDLE GetProcessByName(PCWSTR name)
{
DWORD pid = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 process;
ZeroMemory(&process, sizeof(process));
process.dwSize = sizeof(process);
if (Process32First(snapshot, &process))
{
do
{
if (_wcsicmp(process.szExeFile, name) == 0)
{
pid = process.th32ProcessID;
break;
}
} while(Process32Next(snapshot, &process));
}
CloseHandle(snapshot);
if (pid != 0)
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
return NULL;
}
int _tmain(int argc, _TCHAR* argv[])
{
InjectLibraryW((DWORD)GetProcessByName(L"firefox.exe"), L"HookLib.dll");
_getch();
UninjectLibraryW((DWORD)GetProcessByName(L"firefox.exe"), L"HookLib.dll");
}
#include "stdafx.h"
#include "madCHook.h"
LRESULT (WINAPI * TrueSendMessageW)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) = SendMessageW;
__declspec(dllexport) LRESULT WINAPI MySendMessageW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (Msg == WM_SETTEXT && wcsstr((LPCTSTR)lParam, L"Хабрахабр"NULL)
return TrueSendMessageW(hWnd, Msg, wParam, (LPARAM)L"Привет!");
return TrueSendMessageW(hWnd, Msg, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
HookAPI("User32.dll", "SendMessageW", MySendMessageW, (PVOID*) &TrueSendMessageW);
}
return TRUE;
}
6. Компилируем, запускаем Firefox, запускаем mchEvaluation.exe, запускаем инжектор, в браузере переходим на Хабр. Результат:
Выводы
В плане удобства работы с evaluation-версией madCodeHook немного проигрывает Microsoft Detours, полнофункциональные версии в этом плане примерно равны. Кода писать madCodeHook требует даже меньше. В составе madCodeHook есть драйвер для внедрения библиотек на общесистемном уровне (во все существующие и новые процессы), в Detours эту задачу нужно решать собственным сервисом или драйвером. По скорости и стабильности библиотеки показались мне аналогичными. madCodeHook не вызывает ощущения «энтерпрайзности», как продукт Microsoft, что одновременно и хорошо и плохо: автора легко можно поймать на форуме (что хорошо), но там же написано «я могу уйти в отпуск на 6 недель в любое время года» (что плохо). Сообщество madCodeHook сосредоточено на их форуме, сообщество Microsoft Detours как-то раскидано по Stackoverflow, wasm.ru, форумам MSDN и ощущения целостности не создаёт.
В общем, библиотека madCodeHook оставляет хорошее впечатление, можно пользоваться.
Автор: tangro