HOOK编程 ----全局钩子

同样的,全局钩子也是用SetWindowHookEx来实现,只不过后面两个参数有些变化,并且一定要在一个DLL中实现钩子才能达到全局钩子的效果.

 

我们先新建一个项目,选择WIN32  DLL工程,先创建3个全局变量,再写一个钩子函数,之后分别实现他们的钩子子程序。

GetModuleHandle()函数是获取一个应用程序或动态链接库的模块句柄 。

 

HHOOK g_mouseHook;
HHOOK g_keyboardHook;

HWND g_hwnd=NULL;

 

LRESULT CALLBACK MouseProc(
  int nCode,      // hook code
  WPARAM wParam,  // message identifier
  LPARAM lParam   // mouse coordinates
) //鼠标钩子过程
{
 return 1;
}

 

 

LRESULT CALLBACK KeyboardProc(
  int code,       // hook code
  WPARAM wParam,  // virtual-key code
  LPARAM lParam   // keystroke-message information
)//键盘钩子过程
{
 if(VK_F2==wParam)
 {
  ::SendMessage(g_hwnd,WM_CLOSE,0,0);
  ::UnhookWindowsHookEx(g_mouseHook);
  ::UnhookWindowsHookEx(g_keyboardHook);
 }
 else
  return 1;
}

void SetHook(HWND hwnd)
{
 g_hwnd=hwnd;
 g_mouseHook=::SetWindowsHookEx(WH_MOUSE,MouseProc,::GetModuleHandle(_T("dll_hook.dll")),0); 
 g_keyboardHook=::SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,::GetModuleHandle(_T("dll_hook.dll")),0);
}

之后我们添加def文件

LIBRARY "dll_hook"
EXPORTS
SetHook

 

编译下,编译通过之后可以看到 hook_dll.dll  和  hook_dll.lib文件。

 

接着我们写一个测试程序,新建MFC工程 选择对话框程序.

拷贝hook_dll.dll  和  hook_dll.lib到工程目录下,在链接器命令行加上  hook_dll.lib.

在OnInitDialog()函数之前 定义DLL函数:

_declspec(dllimport) void SetHook(HWND hwnd);

在OnInitDialog()内添加

SetHook(this->m_hWnd);

 

编译下,执行程序.

HOOK编程 ----全局钩子_第1张图片

 

HOOK编程 ----全局钩子_第2张图片


切换到其他程序下比如我的电脑 QQ 之类的任何程序发现点击鼠标或者按键盘都不起作用了,是的,所有的进程都被屏蔽了,只有我们留的后门F2键可以解除这种状态,然后我们会发现一个问题,就是当hookDll_test窗口为激活状态的时候按F2键才能解除这种状态,当hookDll_test不是活动状态的时候按下F2键没有任何反映。这是因为操作系统为了保护DLL中的共享数据设置的一种机制,

先看一下DLL与进程之间的工作方式  如图: (自己用WINDOWS自带的画图程序写的,不要鄙视 -.-)

HOOK编程 ----全局钩子_第3张图片

当两个进程同时读同一份DLL中的数据时DLL中的数据不变,假设DLL中数据页1的内容为一个指针变量,进程二试图改变这个指针,但如果改变了这个指针进程一可能会崩溃,其实我们大可以放心,进程1永远不会崩溃,因为当进程2试图改变数据页1的时候并不会直接改变数据页1,而是在新页面中拷贝数据页1,也就是进程二改变的是新页面中的值,根本不会影响到进程一的使用。

如图:

HOOK编程 ----全局钩子_第4张图片

知道了这个原因我们再来分析刚才的问题,显然dllHook中的g_hwnd即为这个被更改的数据,当我们在dllHoook_test测试程序中测试的时候改变了这个值但在DLL内部,改变的是上图中 新数据页1中的内容,而其他进程仍然使用的是数据页1中的内容,所以当dllHook_test窗口没在活动状态时,我们按F2键是没有用的.

 

知道原因之后就容易解决这个问题了,我们可以在dllHook.dll中自己写一个节 (section)。

方法:

在写全局变量g_hwnd的时候在前后加上如下代码,(具体#pragma的用法可以在msdn中查到)

#pragma data_seg("MySec");  //起名的时候最多为8个字符,否则取前8个字符
HWND g_hwnd=NULL;
#pragma data_seg()

#pragma comment(linker,"/section:MySec,RWS")   //设置链接器,使MySec节拥有属性为 RWS (READ WRITE SHARED )

这时在编译下,成功之后重新在把hook_dll.dll  和  hook_dll.lib拷贝到测试工程目录下,再编译dllHook_test,启动程序会发现

之前的问题已经解决了,无论在任何窗口下按F2键都可以退出这个钩子程序,使得鼠标和键盘变为可用状态。

 

最后我加上一些代码让它变成一个我们常遇到的愚人节程序(就是占着满屏幕,不能动鼠标不能动键盘,只能重启)。

仍然是用这个DLL ,和这个DLL测试程序,加上如下代码:

在OnInitDialog()函数中写入:

int cxScreen,cyScreen;
 cxScreen=::GetSystemMetrics(SM_CXSCREEN); //获取屏幕宽度 (以像素为单位)
 cyScreen=::GetSystemMetrics(SM_CYSCREEN);//获取高度
 
 SetWindowPos(&wndTopMost,0,0,cxScreen,cyScreen,SWP_SHOWWINDOW);//设置窗口占满整个屏幕
 SetHook(this->m_hWnd); //钩子函数

 

在OnPaint中写入:

CClientDC dc(this);
 CFont font;
 font.CreatePointFont(500,_T("宋体"),NULL);
 CFont *oldFont=dc.SelectObject(&font);
 dc.TextOutW(200,300,_T("Blue236146祝大家愚人节快乐!"));
 dc.SelectObject(oldFont);

 

现在就完成了,运行程序如图:

HOOK编程 ----全局钩子_第5张图片

HOOK编程 ----全局钩子_第6张图片

因为我们无形之中把现在计算机运行的所有进程都注入了我们的DLL,这是病毒和木马经常做的事情,所以360会提示警告,我们可以无视之。

 关掉360之后我们会发现屏幕一直被这个窗口占着,无法看到任何东西,鼠标和键盘都无法关闭这个窗口,当然我们留了后门F2键可以关闭这个窗口。 按下F2键退出程序。 计算机又可以正常工作了。

 

写到这吧,1点多了,睡觉! 

你可能感兴趣的:(HOOK编程 ----全局钩子)