安全编程技术-消息 Hook实验

消息Hook实验

Windows系统建立在事件驱动机制上,整个系统通过消息传递实现的。在Windows系统里,消息Hook就是一个Windows消息的拦截机制,可以拦截单个进程的消息(线程钩子),也可以拦截所有进程的消息(系统钩子),也可以对拦截的消息进行自定义的处理:

  • 如果对于同一事件(如鼠标消息)既安装了线程Hook又安装了系统Hook,那么系统会自动先调用线程Hook,然后调用系统Hook(类似栈)。
  • 对于同一事件消息可安装多个Hook处理过程,这些Hook处理过程形成了Hook链,后加入的有优先控制权。

在Windows中,利用SetWindowsHookEx函数创建钩子(Hooks)可以实现DLL注入,本实验使用消息Hook实现dll注入,实现类似插桩的效果。

  • 编制键盘消息的Hook函数一KeyHook.dll中的KeyboardProc函数
  • 通过SetWindowsHookEx创建键盘消息钩子实现DLL注入(执行DLL内部代码)

实验环境:Win xp sp3、vc6.0


  1. 编写DLL文件:
    在VC 6中新建一个Win32 Dynamic-Link Library项目,Project name: KeyHook
    image-20250509220139270
    创建一个空的DLL项目
    image-20250509220254476

添加一个代码文件KeyHook.cpp
image-20250509220558685

#include "stdio.h"
#include "windows.h"
#define DEF_PROCESS_NAME		"notepad.exe"  //定义hook进程名称
HINSTANCE g_hInstance = NULL;
HHOOK g_hHook = NULL;
HWND g_hWnd = NULL;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved){
	switch( dwReason )
	{
        case DLL_PROCESS_ATTACH:
			g_hInstance = hinstDLL;
			break;

        case DLL_PROCESS_DETACH:
			break;	
	}
	return TRUE;
}

//Hook函数(自定义的键盘消息处理函数)
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{//这里对第二个参数lParam进行了处理
	char szPath[MAX_PATH] = {0,};
	char *p = NULL;

	if( nCode >= 0 ){
		// lParam 第31位bit: 0 => key press, 1 => key release
		if( !(lParam & 0x80000000) )	{	//当按键被释放时
			GetModuleFileNameA(NULL, szPath, MAX_PATH);
			p = strrchr(szPath, '\\');

       //比较当前进程名称,若为notepad.exe,则消息不会继续传递
			if( !_stricmp(p + 1, DEF_PROCESS_NAME) )
				return 1;		//丢弃该Keyboard消息
		}
	}
      //若不为notepad.exe,调用CallNextHookEx()函数将消息传递给下一个“钩子”或应用程序
	return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

#ifdef __cplusplus  //这里定义了两个导出函数HookStart()、HookStop(),允许外部调用
extern "C" {
#endif
	__declspec(dllexport) void HookStart()
	{
		g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
	}

	__declspec(dllexport) void HookStop()
	{
		if( g_hHook )
		{
			UnhookWindowsHookEx(g_hHook);
			g_hHook = NULL;
		}
	}
#ifdef __cplusplus
}
#endif

得到项目文件夹下的KeyHook.dll文件

image-20250509221648471

  1. 编写DLL注入功能的可执行文件
    新建一个VC6的控制台程序,添加源文件HookMain.cpp如下:

    #include "stdio.h"
    #include "conio.h"
    #include "windows.h"
    
    #define	DEF_DLL_NAME		"KeyHook.dll"//定义一些宏
    #define	DEF_HOOKSTART	    "HookStart"
    #define	DEF_HOOKSTOP		"HookStop"
    
    typedef void (*PFN_HOOKSTART)();//用于指向动态链接库的两个函数
    typedef void (*PFN_HOOKSTOP)();
    void main()
    {
    	HMODULE	hDll = NULL;
    	PFN_HOOKSTART	HookStart = NULL;
    	PFN_HOOKSTOP	HookStop = NULL;
    	char		ch = 0;
    	hDll = LoadLibraryA(DEF_DLL_NAME); // 加载KeyHook.dll (这里为相对路径,dll与exe要位于同一路径下)
    
    	if( hDll == NULL ){
    		 printf("LoadLibrary(%s) failed!!! [%d]", DEF_DLL_NAME, GetLastError());
    		 return;
    	}
    
        // 获取导出函数地址
    	HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART);//获得特定函数地址
    	HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP);
    
    	HookStart(); // 开始Hook
    
        // 等待直到用户输入'q'
    	printf("press 'q' to quit!\n");
    	while( _getch() != 'q' )	;
    
    	HookStop(); // 结束Hook 	
    	FreeLibrary(hDll); // 卸载KeyHook.dll
    }
    
    

    将HookMain.exe和KeyHook.dll放在相同目录下,运行HookMain.exe安装键盘消息Hook后,将实现notepad.exe进程的键盘消息拦截,使之无法显示在记事本中。直到输入“q”才可停止键盘Hook。

    结果:

    • 在记事本中无法输入
    • 在其他程序中可以正常输入
    • 输入q结束HookMain.exe后,记事本中也可以正常输入
posted @ 2025-05-10 09:49  踏雪xun槑  阅读(24)  评论(0)    收藏  举报