注入(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!
");
		return 0;
	}
	OutputDebugString(L"Inject Success!
");
    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!
");


	ModuleHandle = LoadLibrary(wzDllPath);
	if (!ModuleHandle)
	{
		OutputDebugString(L"[+] LoadLibrary error!
");
		goto Exit;
	}


	FunctionAddress = (DWORD)GetProcAddress(ModuleHandle, "MyMessageProc");
	if (!FunctionAddress)
	{
		OutputDebugString(L"[+] GetProcAddress error!
");
		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 !
");
		goto Exit;
	}

	OutputDebugString(L"[!] SetWinHKInject Exit!
");
	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);
}
原文地址:https://www.cnblogs.com/Toring/p/6628282.html