注入(4)--消息钩子注入(SetWindowsHookEX)
SetWindowsHookEx函数是微软提供给程序开发人员进行消息拦截的一个API。不过,他的功能不仅可以用作消息拦截,还可以进行DLL注入。
SetWindowsHookEx原型声明如下:
WINUSERAPI HHOOK WINAPI SetWindowsHookExW( _In_ int idHook, _In_ HOOKPROC lpfn, _In_opt_ HINSTANCE hmod, _In_ DWORD dwThreadId);
idHook:指示将要安装的挂钩处理过程的类型。例如,idHook为“WH_CALLWNDPROC”时代表安装一个挂钩处理过程,在系统将消息发送至目标窗口处理过程之前对该消息进行监视。
lpfn:指向相应的挂钩处理过程。
hmod:指示了一个DLL句柄。该DLL包含参数lpfn所指向的挂钩处理过程
dwThreadId:指示了一个线程标示符,挂钩处理过程与线程相关。若此参数值为0,则该挂钩处理过程与所有现存的线程相关。
如果去掉消息钩子,可以用UnhookWindowsHookEx函数
Windows消息处理流程:
插入SetWindowsHookEx之后流程:
下面来看代码:
// MessageHook.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <Windows.h> #include <Tlhelp32.h> BOOL SetWinHookInject(WCHAR * wzDllPath, WCHAR * wzProcessName); UINT32 GetTargetThreadIdFromProcessName(WCHAR *ProcessName); int main() { WCHAR wzProcessName[0x20] = L"Target.exe"; WCHAR wzDllFullPath[0x20] = L"MessageHookDll.dll"; if (!SetWinHookInject(wzDllFullPath, wzProcessName)) { OutputDebugString(L"Set Hook Unsuccess!\r\n"); return 0; } OutputDebugString(L"Inject Success!\r\n"); return 0; } // //利用Windows API SetWindowsHookEx实现注入DLL // BOOL SetWinHookInject(WCHAR * wzDllPath, WCHAR * wzProcessName) { HMODULE ModuleHandle = NULL; BOOL bOk = FALSE; DWORD FunctionAddress = NULL; UINT32 dwThreadId = 0; HHOOK g_hHook = NULL; PVOID pShareM = NULL; OutputDebugString(L"[+] SetWinHKInject Enter!\n"); ModuleHandle = LoadLibrary(wzDllPath); if (!ModuleHandle) { OutputDebugString(L"[+] LoadLibrary error!\n"); goto Exit; } FunctionAddress = (DWORD)GetProcAddress(ModuleHandle, "MyMessageProc"); if (!FunctionAddress) { OutputDebugString(L"[+] GetProcAddress error!\n"); goto Exit; } dwThreadId = GetTargetThreadIdFromProcessName(wzProcessName); if (!dwThreadId) goto Exit; //设消息钩子 g_hHook = SetWindowsHookEx( WH_GETMESSAGE,//WH_KEYBOARD,//WH_CALLWNDPROC, (HOOKPROC)FunctionAddress, ModuleHandle, dwThreadId ); if (!g_hHook) { OutputDebugString(L"[-] SetWindowsHookEx error !\n"); goto Exit; } OutputDebugString(L"[!] SetWinHKInject Exit!\n"); bOk = TRUE; Exit: if (ModuleHandle) FreeLibrary(ModuleHandle); return bOk; } //通过进程名获得线程ID UINT32 GetTargetThreadIdFromProcessName(WCHAR *ProcessName) { PROCESSENTRY32 pe; HANDLE SnapshotHandle = NULL; HANDLE ProcessHandle = NULL; BOOL Return, ProcessFound = FALSE; UINT32 pTID, ThreadID; SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (SnapshotHandle == INVALID_HANDLE_VALUE) { MessageBox(NULL, L"Error: unable to create toolhelp snapshot", L"Loader", NULL); return FALSE; } pe.dwSize = sizeof(PROCESSENTRY32); Return = Process32First(SnapshotHandle, &pe); while (Return) { if (_wcsicmp(pe.szExeFile, ProcessName) == 0) { ProcessFound = TRUE; break; } Return = Process32Next(SnapshotHandle, &pe); pe.dwSize = sizeof(PROCESSENTRY32); } CloseHandle(SnapshotHandle); //通过fs寄存器获取TID _asm { mov eax, fs:[0x18] add eax, 36 mov[pTID], eax } ProcessHandle = OpenProcess(PROCESS_VM_READ, FALSE, pe.th32ProcessID); ReadProcessMemory(ProcessHandle,(LPCVOID)pTID, &ThreadID, 4, NULL); CloseHandle(ProcessHandle); return ThreadID; }
// dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "stdafx.h" #include <Windows.h> #pragma data_seg(SHARD_SEG_NAME) static HHOOK g_hHook; #pragma data_seg() BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { // //加入你想在目标进程空间HOOK的代码 // MessageBox(NULL, L"Inject Success!", L"Message", 0); } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } __declspec(dllexport)LRESULT MyMessageProcess(int Code, WPARAM wParam, LPARAM lParam) { // //你自己对消息的处理 // return CallNextHookEx(g_hHook, Code, wParam, lParam); }