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
#include
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
#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);
}