1. 程式人生 > >注入(4)--訊息鉤子注入(SetWindowsHookEX)

注入(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);
}