街角_祝福

导航

HOOK技术--键盘鼠标钩子实例

1.首先创建一个DLL项目,用以生成自定义的DLL文件,在DLL文件中对外有两个接口,安装钩子的函数SetHook和卸载钩子函数UnSetHook函数,对于

   这些函数由于需要导出,所以在工程项目的.h文件中需要声明这些函数需要导出。

//MouseKeyboardHook.h
#ifdef MOUSEKEYBOARDHOOK_EXPORTS
#define MOUSEKEYBOARDHOOK_API __declspec(dllexport)
#else
#define MOUSEKEYBOARDHOOK_API __declspec(dllimport)
#endif

extern "C" MOUSEKEYBOARDHOOK_API int SetHook( DWORD dwThreadId  );
extern "C" MOUSEKEYBOARDHOOK_API int UnSetHook(void);

    这里只有安装钩子函数有参数,该参数是线程ID号,这里需要注意,如果在调用DLL时发现找不到函数地址,那就需要加extern “C” 说明了,当时我就是没有加郁闷了很久才找到这个问题。我思考了一下,应该是DLL中我采用的是C编程语言,而我的调用该DLL的应用程序默认是C++,但是由于C和C++的OBJ的函数名格式不同,所以才会出现找不到函数地址的问题。是对于DLL的头文件按照这个格式就可以导出函数了。

//MouseKeyboardHook.cpp文件

#include "stdafx.h"
#include "MouseKeyboardHook.h"
#include "stdio.h"


//共享内存变量
#pragma data_seg("MouseKeyboardHook")
HHOOK g_hMouseHook = NULL;
HHOOK g_hKeyboardHook = NULL;
#pragma data_seg()
// 这是导出变量的一个示例
MOUSEKEYBOARDHOOK_API int nMouseKeyboardHook=0;

// 这是导出函数的一个示例。
int UnSetHook(void);
int fnMouseKeyboardHook(void);
int SetHook( DWORD dwThreadId  );
//注意:钩子函数的格式必须是 LRESULT CALLBACK 函数名( int 钩子类型, WPARAM wParam, LPARAM lParam );
LRESULT CALLBACK MouseHookProc( int nCode, WPARAM wParam, LPARAM lParam );//处理鼠标的钩子函数
LRESULT CALLBACK KeyboardHookProc( int nCode, WPARAM wParam, LPARAM lParam );//处理键盘的钩子函数
HMODULE WINAPI ModuleFromAddress(PVOID pv) ;//这个是获取DLL的内存地址,可以重复使用,当做模版


MOUSEKEYBOARDHOOK_API int fnMouseKeyboardHook(void)//这个是项目自己生成的没多大用
{
	return 42;
}

LRESULT CALLBACK KeyboardHookProc( int nCode, WPARAM wParam, LPARAM lParam )
{
	if( wParam=='Q' && lParam>0 )//当只有按下Q键的时候才会退出钩子函数。其他其他的话都屏蔽
	{
		MessageBox( NULL, "卸载钩子中...", "卸载钩子", MB_OK );
		UnSetHook();
	}
	else return TRUE;
	return ::CallNextHookEx(g_hKeyboardHook, nCode, wParam, lParam);
}

LRESULT CALLBACK MouseHookProc( int nCode, WPARAM wParam, LPARAM lParam )//我这里屏蔽所有鼠标消息
{
	return ::CallNextHookEx(g_hMouseHook, nCode, wParam, lParam);
}
// 这是已导出类的构造函数。
// 有关类定义的信息,请参阅 MouseKeyboardHook.h

CMouseKeyboardHook::CMouseKeyboardHook()
{
	return;
}

MOUSEKEYBOARDHOOK_API int SetHook( DWORD dwThreadId  )//安装钩子函数
{
	g_hMouseHook = ::SetWindowsHookEx( WH_MOUSE, MouseHookProc, ModuleFromAddress(MouseHookProc), 0 );
	g_hKeyboardHook = ::SetWindowsHookEx( WH_KEYBOARD, KeyboardHookProc, ModuleFromAddress(KeyboardHookProc), 0 );
	return 0;
}

MOUSEKEYBOARDHOOK_API int UnSetHook(void)//卸载钩子函数,不过这个例子有问题,卸载不了,不知道为什么
{

	BOOL b1 = ::UnhookWindowsHookEx( g_hMouseHook );
	BOOL b2 = ::UnhookWindowsHookEx( g_hKeyboardHook );
	if( b1==FALSE || b2==FALSE )
		MessageBox( NULL, "卸载钩子失败!", "", MB_OK );
	return 0;
}

HMODULE WINAPI ModuleFromAddress(PVOID pv) 
{
	MEMORY_BASIC_INFORMATION mbi;
	if(::VirtualQuery(pv, &mbi, sizeof(mbi)) != 0)
	{
		return (HMODULE)mbi.AllocationBase;
	}
	else
	{
		return NULL;
	}
}



这里要注意的地方是钩子函数的格式,其他的话应该问题不大。同时,因为在头文件中已经声明了导出函数,所以这里不需要再次声明了,按照正常函数写即可。

不过不知道为什么我的钩子卸载时失败了,真心不懂!


2.创建加载该DLL的应用程序

    因为需要监视整个计算机,所以SetHook函数传参是0,代表监视整个计算机。

   在本实例中,对于DLL的加载方式是动态加载的。

   具体流程是:加载DLL文件-->获取导出函数地址-->调用钩子安装函数-->卸载钩子

   程序主要源码如下:

BOOL bInstall = FALSE;//用来指示是否已经安装了钩子
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
//需要声明导出函数指针
typedef int ( *pSetHook)(DWORD * );//声明函数类型
typedef int ( *pUnsetHook)(void);

void CKeyMouseHookAppDlg::OnBnClickedButton1()//程序是按下按钮动态加载DLL的
{
	
	HMODULE hModule = ::LoadLibrary( "MouseKeyboardHook.dll" );//加载DLL库
	if( hModule!=NULL )
	{
		if( bInstall==FALSE )
		{
			pSetHook mpSetHook;
			mpSetHook = (pSetHook)::GetProcAddress( hModule, "SetHook" );//获取导出函数地址
			if( mpSetHook!=NULL )
			{
				mpSetHook( 0 );//安装全局钩子
				bInstall = TRUE;
				GetDlgItem( IDC_BUTTON1 )->SetWindowText( "卸载DLL" );
			}
			else MessageBox( "获取函数地址失败!" );
		}
		else
		{
			pUnsetHook mpUnsetHook;
			mpUnsetHook = (pUnsetHook)::GetProcAddress( hModule, "UnSetHook" );
			if( mpUnsetHook!=NULL )
			{
				mpUnsetHook();//卸载钩子
				bInstall = FALSE;
				GetDlgItem( IDC_BUTTON1 )->SetWindowText( "加载DLL" );
			}
			else MessageBox( "获取函数地址失败!" );
			::FreeLibrary( hModule );//释放加载的DLL库
		}
	}
	else MessageBox( "加载DLL失败!" );
}


posted on 2012-06-24 01:24  街角_祝福  阅读(853)  评论(0编辑  收藏  举报