進程注入之全局鈎子注入


全局鈎子注入

Windows中大部分的應用程序都是基於消息機制的,它們都有一個消息過程函數比如SetWindowsHookEx函數

,根據不同的消息完成不同的功能。

消息鈎子是windows提供的一種消息過濾和預處理機制,可以用來截獲和監視系統中的消息。

按照鈎子作用范圍不同,又可以分為局部鈎子和全局鈎子。局部鈎子是針對某個線程的,而全局鈎子是作用於整個系統的基於消息的應用。全局鈎子需要使用DLL文件,在DLL文件中實現相應的鈎子函數。

核心函數介紹

HHOOK WINAPI SetWindowsHookExW(
_In_ int idHook,
_In_ HOOKPROC lpfn,
_In_opt_ HINSTANCE hmod,
_In_ DWORD dwThreadId);

1.idHook 要安裝的鈎子(HOOK)的類型,它決定了HOOKPROC被調用的時機,可選參數如下。

WH_MSGFILTER = -1 線程級,截獲用戶與控件交互的消息
WH_JOURNALRECORD = 0 系統級,記錄所有消息隊列送出的輸入消息
WH_JOURNALPLAYBACK = 1 系統級,回放由WH_JOURNALRECORD記錄的消息
WH_KEYBOARD = 2 系統級或線程級,截獲鍵盤消息
WH_GETMESSAGE = 3 系統級或線程級,截獲從消息隊列送出的消息
WH_CALLWNDPROC = 4 系統級或線程級,截獲發送到目標窗口的消息
WH_CBT = 5 系統級或線程級,截獲系統基本消息 例如:窗口的創建,激活,關閉,最大/最小化,移動等
WH_SYSMSGFILTER = 6 系統級,截獲系統范圍內用戶與控件交互的消息
WH_MOUSE = 7 系統級或線程級,截獲鼠標消息
WH_HARDWARE = 8 系統級或線程級,截獲非標准硬件(非鼠標,鍵盤)的消息
WH_DEBUG = 9 系統級或線程級,在其它鈎子調用前調用,用於調試鈎子
WH_SHELL = 10 系統級或線程級,截獲發給外殼應用程序的消息
WH_FOREGROUNDIDLE = 11 系統級或線程級,在程序前台線程空閑時調用
WH_CALLWNDPROCRET = 12 系統級或線程級,截獲目標窗口處理完的消息 在SendMessage被調用后發生
WH_KEYBOARD_LL = 13 系統級,截獲全局鍵盤消息
WH_MOUSE_LL = 14 系統級,截獲全局鼠標消息

2.lpfn指向鈎子回調函數的指針。如果最后一個參數dwThreadId為0或者是其它進程創建的線程標識符,則lpfn參數必須指向DLL中的鈎子回調函數,即HOOKPROC函數必須在DLL中實現。否則,lpfn 可以指向與當前進程相關聯的代碼中的鈎子過程。

3.hmod包含由lpfn參數指向的鈎子回調函數的DLL句柄。如果dwThreadId參數指定由當前進程創建線程,並且鈎子回調函數位於當前進程關聯的代碼中,則hmod參數必須設置為NULL

4.dwThreadId與鈎子程序關聯的線程標識符(指定要HOOK的線程 ID)。如果此參數為0,則鈎子過程與系統中所有線程相關聯,即全局消息鈎子

實現原理

通過SetWindowsHookExW函數安裝一個用於過濾特定類型消息的鈎子函數(鈎子WH_GETMESSAGE可以立即被觸發,而某些類型的鈎子需要在處理指定類型的消息時才能被觸發),當其它進程中產生了我們過濾的消息,就會調用HOOKPROC,如果發現目標DLL(HOOKPROC實現的DLL)尚未加載,就會使用KeUserModeCallback函數回調User32.dll__ClientLoadLibrary() 函數,由User32.dll把這個DLL加載到目標進程中(低級鍵盤和鼠標鈎子的加載有所不同),從而實現DLL注入其它進程的目的。

代碼及其實現過程

首先新建一個dll項目

image-20220224221831169

pch.h中聲明這幾個我們定義的函數都是裸函數,由我們自己平衡堆棧

extern "C" _declspec(dllexport) int SetHook();
extern "C" _declspec(dllexport) LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam);
extern "C" _declspec(dllexport) BOOL UnsetHook();

image-20220224222046446

pch.cpp里面寫入三個函數並創建共享內存(進程通信的方法有很多,比如自定義消息、管道、dll共享節、共享內存等等,這里就用共享內存來實現進程通信)

#include "pch.h"
#include <windows.h>
#include <stdio.h>


extern HMODULE g_hDllModule;

// 共享內存
#pragma data_seg("mydata")
HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:mydata,RWS")

//鈎子回調函數
LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam) {
	return ::CallNextHookEx(g_hHook, code, wParam, lParam);
}

// 設置鈎子
BOOL SetHook() {
	g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllModule, 0);
	if (NULL == g_hHook) {
		return FALSE;
	}
	return TRUE;
}
//這里第二個參數是回調函數,那么我們還需要寫一個回調函數的實現,這里就需要用到CallNextHookEx這個api,主要是第一個參數,這里傳入鈎子的句柄的話,就會把當前鈎子傳遞給下一個鈎子,若參數傳入0則對鈎子進行攔截

// 卸載鈎子
BOOL UnsetHook() {
	if (g_hHook) {
		UnhookWindowsHookEx(g_hHook);//UnhookWindowsHookEx這個api是來卸載鈎子的
	}
	return TRUE;
}

image-20220224222240772

dllmain.cpp設置DLL_PROCESS_ATTACH,然后編譯生成Dll1.dll

// dllmain.cpp : 定義 DLL 應用程序的入口點。
#include "pch.h"
HMODULE g_hDllModule = NULL;
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
	{
		g_hDllModule = hModule;
		break;
	}
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

image-20220224222424391

之后再創建一個控制台項目

image-20220224222618491

LoadLibrabryW加載dll,生成inject2.cpp文件

// inject2.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//

#include <iostream>
#include <Windows.h>

int main()
{
	typedef BOOL(*typedef_SetGlobalHook)();
	typedef BOOL(*typedef_UnsetGlobalHook)();
	HMODULE hDll = NULL;
	typedef_SetGlobalHook SetGlobalHook = NULL;
	typedef_UnsetGlobalHook UnsetGlobalHook = NULL;
	BOOL bRet = FALSE;

	do
	{
		hDll = ::LoadLibraryW(TEXT("D:\\vs2017project\\Dll1\\Debug\\Dll1.dll"));
		if (NULL == hDll)
		{
			printf("LoadLibrary Error[%d]\n", ::GetLastError());
			break;
		}

		SetGlobalHook = (typedef_SetGlobalHook)::GetProcAddress(hDll, "SetHook");
		if (NULL == SetGlobalHook)
		{
			printf("GetProcAddress Error[%d]\n", ::GetLastError());
			break;
		}

		bRet = SetGlobalHook();
		if (bRet)
		{
			printf("SetGlobalHook OK.\n");
		}
		else
		{
			printf("SetGlobalHook ERROR.\n");
		}

		system("pause");

		UnsetGlobalHook = (typedef_UnsetGlobalHook)::GetProcAddress(hDll, "UnsetHook");
		if (NULL == UnsetGlobalHook)
		{
			printf("GetProcAddress Error[%d]\n", ::GetLastError());
			break;
		}
		UnsetGlobalHook();
		printf("UnsetGlobalHook OK.\n");

	} while (FALSE);

	system("pause");
	return 0;
}

執行測試

編譯inject2.cpp生成inject2.exe並運行

image-20220224223314059

打開進程工具,搜索Dll1.dll是否加載,發現在大多數進程中都得到了加載

image-20220224223458548

嘗試卸載鈎子

image-20220224223607471

進程中的Dll1.dll已經被卸載

image-20220224223746445


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM