SetWindowsHookEx實現對目標進程注入Dll

MSDN官方文檔給出的定義:

HHOOK SetWindowsHookEx(  int idHook,        // hook type
  HOOKPROC lpfn,     // hook procedure
  HINSTANCE hMod,    // handle to application instance
  DWORD dwThreadId   // thread identifier);

idHook:掛鉤類型,即處理的消息類型;我此處測試的是WH_KEYBOARD
lpfn:掛鉤函數的地址指針。如果是全局鉤子,即dwThreadId爲0或者Hook的進程不是當前進程,那麼lpfn必須指向DLL中的掛鉤函數。除此之外,lpfn可指向當前進程的一段掛鉤函數代碼。當鉤到消息後,執行此函數。爲適用性起見,我在代碼中用的是從DLL中導出的函數地址。
hMod:應用程序的的實例句柄,指向包含lpfn指針的DLL。
dwThreadId:如果爲0,則表示該鉤子與所有線程相關聯,爲全局掛鉤。
函數失敗,返回NULL,成功返回鉤子句柄。
實現思路:

  • 從控制檯得到想要實施注入的目標進程名字
  • 得到當前進程所在的目錄(GetCurrentDirectory),並保存
  • 得到當前進程的位數 (IsWow64Process)
  • 根據進程名字得到當前進程的Id
  • 根據進程Id得到當前進程的完整路徑
  • 通過進程完整路徑對PE文件解析得到目標進程位數
  • 目標與當前進程的位數進行匹配,決定加載哪一個dll(x86 or x64)
  • 根據當前進程目錄,得到dll完整路徑
  • 通過目標進程Id返回目標進程中所有線程的Id
  • 通過LoadLibrary加載目標動態庫,得動態庫模塊句柄
  • GetProcAddress得到導出函數的函數指針
  • SetWindowsHookEx實施對某個線程的注入
  • 收尾工作,卸載鉤子
#include"SetWindowsHookEx.h"
#include"Helper.h"



int _tmain(int argc, TCHAR* argv[], TCHAR *envp[])
{
	//控制檯識別中文
	setlocale(LC_ALL, "Chinese-simplified");

	TCHAR ProcessImageName[MAX_PATH] = { 0 };//保存進程名字

	TCHAR CurrentFullPath[MAX_PATH] = { 0 }; //當前進程的完整路徑

	TCHAR TargetProcessFullPath[MAX_PATH] = { 0 };//目標進程的完整路徑
	ULONG_PTR TargetProcessPathLength = MAX_PATH;

	ULONG ProcessId = 0;//目標進程Id
	vector<HANDLE>   ThreadId;//線程ID

	HANDLE ProcessHandle = INVALID_HANDLE_VALUE;//進程句柄


	HMODULE ModuleBase = NULL;//Dll模塊句柄
	FARPROC InjectFunction = NULL;//接導出函數的指針
	HHOOK HookHandle = NULL;//SetWindowsHookEx返回值

	BOOL  IsOk = FALSE;

	//注入的啓動程序和目標程序的位數
	BOOL  SourceIsWow64 = FALSE;
	BOOL  TargetIsWow64 = FALSE;


	_tprintf(_T("輸入一個進程ImageName\r\n"));


	TCHAR RcceiveChar = _gettchar();//接受字符串
	int i = 0;//用來偏移ProcessName字符數組
	while (RcceiveChar != '\n')
	{
		ProcessImageName[i++] = RcceiveChar;
		RcceiveChar = _gettchar();

	}

	GetCurrentDirectory(MAX_PATH, CurrentFullPath);//保存當前進程的完整路徑

	IsWow64Process(GetCurrentProcess(), &SourceIsWow64);//得到當前進程位數

	ProcessId = KtGetProcessIdentify(ProcessImageName);//通過進程名得到進程Id

	if (ProcessId == 0)
	{
		return 0;
	}
	IsOk = KtGetProcessFullPath(TargetProcessFullPath,
		&TargetProcessPathLength, ProcessId, FALSE);

	if (IsOk == FALSE)
	{
		return 0;
	}
	//判斷目標進程位數
	KtIsWow64Process(TargetProcessFullPath, &TargetIsWow64);
	if (SourceIsWow64 == TRUE && TargetIsWow64 == TRUE)
	{
		_tcscat_s(CurrentFullPath, _T("\\Dll.dll"));
	}
	else if (SourceIsWow64 == FALSE && TargetIsWow64 == FALSE)
	{
		_tcscat_s(CurrentFullPath, _T("\\Dll.dll"));
	}

	//_tcscat_s(CurrentFullPath, _T("\\Dll.dll"));虛擬機測試
	//KtGetThreadIdentify我自己封裝的內部使用CreateToolhelp32Snapshot系列的函數處理的
	if (KtGetThreadIdentify((HANDLE)ProcessId, ThreadId) == FALSE)
	{
		goto Exit;
	}
	//加載動態庫
	ModuleBase = LoadLibrary(CurrentFullPath);
	if (ModuleBase == NULL)
	{
		goto Exit;
	}
	//獲得導出函數指針
	InjectFunction = GetProcAddress(ModuleBase, "InjectFunction");
	if (InjectFunction == NULL)
	{
		goto Exit;
	}
	for (int i = 0; i < ThreadId.size(); ++i)
	{
	//對其中的某個線程實施注入
		HookHandle = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)InjectFunction, ModuleBase, (DWORD)ThreadId[i]);
		if (HookHandle != NULL)
		{
			//只要有一個線程注入成功,就退出
			break;
		}
	}
	_tprintf(_T("Input AnyKey To Exit"));
	getchar();
Exit:
	if (HookHandle != NULL)
	{
	//卸載鉤子
		UnhookWindowsHookEx(HookHandle);
		HookHandle = NULL;
	}
	if (!!(ThreadId.size()))
	{
		vector<HANDLE>().swap(ThreadId);
	}
	if (ModuleBase != NULL)
	{
		FreeLibrary(ModuleBase);
		ModuleBase = NULL;
	}
}

注入成功截圖:按鍵就會產生彈窗效果
在這裏插入圖片描述
64位測試截圖:
在這裏插入圖片描述
卸載之後我也進行了鍵盤按鍵,不會彈出來了。

不忘初心,方得始終

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章