《Windows核心编程系列》谈谈Windows钩子-2

上一篇 / 下一篇  2012-09-03 14:25:25 / 个人分类:杂谈

~'g9j4Y#c0u7O!OY0  首先要实现DLL:

M1W"IlG8TIYD:h/S0

R#g E,@wT&z0  在dll内实现钩子函数这是毫无疑问的。而安装钩子和卸载钩子的函数既可以写在主程序内,也可以写在DLL内。写在主程序内时只可以在主程序内 安装钩子。而在dll内实现则可以让所有载入该dll的程序安装钩子。如当某进程将该DLL载入的时候,可以在DllMain中创建一个线程,让他调用安 装钩子的函数,实现为此进程内的线程安装钩子的目的。为了拓展程序的功能,实现代码重用,最好是将钩子函数写在DLL内。另外这也可以实现模块化。一旦需 求发生更改可以只修改DLL内的代码,而不需要改变主程序。

s9ym.B8e tJ7t S9@0

;PuS@!D*oQ.d t0  当钩子函数被调用的时候,也就是我们被拦截的消息已被触发,如何让主程序得到这个通知呢 ?51Testing软件测试网 utd0Vt^/~;t"vj

51Testing软件测试网S1J5z$a,B7l

  我们可以在其他进程内的钩子函数内给主程序的窗口发送消息。但如何发送呢?51Testing软件测试网1VVcDxb)\ a(`

51Testing软件测试网 m X W t G1PA!L

  PostMessage可以实现这个功能。51Testing软件测试网Tq8G)[^`r

51Testing软件测试网*M-t4c KL(K

  看原型:51Testing软件测试网yF H K \a\

Q:z L2cu/z,s0

;j?j^8A0
    BOOL WINAPI PostMessage(HWND hWnd,UINT Msg,WPARAM wparam,LPARAM lParam);
51Testing软件测试网j!WZ@fk

  hWnd即为要接受消息的窗口句柄。51Testing软件测试网+R&FH M!~@

51Testing软件测试网Wbm6nsY fS:a~6v a(C

  Msg为要发送的消息。51Testing软件测试网:t/s&lm e

1g;F(gu?&eQ0  wParam和lParam为消息的附加参数。

k ?m It/R0

8|`'y:kWI;W rq0  虽然可以使用PostMessage实现向主程序的窗口发送消息,但是我们如何获得主程序的窗口句柄呢?我们知道钩子函数是在DLL内实现的,而DLL会被加载到各个进程内。在其他进程要想得到主程序的窗口句柄这是一个问题。51Testing软件测试网.rp%Aw?p e

\~(aB/g^0  在《windows核心编程系列》谈谈内存映射文件中,我们谈到了在可执行文件内使用共享段,可以实现同一个可执行文件的多个实例共享共享段内 的数据的目的。那么在DLL使用共享段呢?哈哈,或许你已经猜出来了,由于DLL被映射到了各个进程,将数据放在DLL的共享段,可以实现在各个进程内共 享DLL内共享段数据的目的。

O Owmj,U] T U!`?0

_"NU7o/p4xC5N0  我们的解决方法就是:在DLL内建立共享段,将主程序的窗口句柄放在共享段中。在主程序调用安装钩子的函数时可以将共享段内的窗口句柄赋为主程 序的窗口句柄。从而达到在各个进程内共享数据的目的。到此,我们又学习一种在进程间共享数据的方法,另一种方法是利用内存映射文件。

+nr2aj.hG7}/Zu0

1b@7I q4aZ5R0

\m;M0}.@}4r)U0

P"f#~F"Do y0<SPAN style="FONT-SIZE: 18px"> #pragma data_seg("shared")51Testing软件测试网 zd }7f!p$])`"c)d;M]3IE
  HWND hWnd=NULL;
e$b|FB?!A5}q0  HHOOK hHook=NULL;
51Testing软件测试网#~/|aG-Y1U

51Testing软件测试网:kdR*R yd

 #pragma data_seg()

K:jxZ/xs(R051Testing软件测试网f5d!s"E L$qo$_f;Y

#pragma comment(linker,"/SECTION:shared,RWS")51Testing软件测试网5n]1Q/iB5VM

9\uKia`0</SPAN>

Wk)Av9E~6~(ax-e0

k$@E2CdM~9\_3\0  怎么多了个hHook,hHook是创建的钩子的句柄。由于在钩子函数中会调用CallNextHookEx将消息传给钩子链的下一结点。二者都是在其他进程调用的,因此我们也必须把钩子的句柄设为共享。

!S+^ZT+fyj"[7r7^[051Testing软件测试网/kPQ-x o.vx^

  DLL内创建钩子的代码:

`1W8a3Jc!@2i0

q"k4t c4[4q1sk@0

~ xZ+C6n/AH(vNx3c0
<SPAN style="FONT-SIZE: 18px">    KEYHOOKDLL_API bool SetHook(</SPAN>

LP'x"RR051Testing软件测试网\L hVN$Xc;B4{0N5e

<SPAN style="FONT-SIZE: 18px">                            bool IsInstall,//true表示安装钩子,false表示卸载钩子。</SPAN>

(|*e:F5D,kU X0

]:bL~1@0
<SPAN style="FONT-SIZE: 18px">                            HWND hWnd,     //主程序窗口句柄,用于在主程序内传入设置。</SPAN>
51Testing软件测试网-o2X1AgP{'F/RC$Og[

Lj/`S} J4H0
<SPAN style="FONT-SIZE: 18px">                              int ThreadId)//要安装钩子的线程。
\*E5?*Zy!d(B0   {51Testing软件测试网Z%HTf2Ay)]X*h
 ::hWnd=hWnd;//将当前窗口句柄赋给DLL共线段内的窗口句柄。51Testing软件测试网2h6gZ3KF[a"h
 if(IsInstall)
@1hs(q ft5~8^;u0 {
`-a/ab6tHf(X0  hHook=SetWindowsHookEx( WH_KEYBOARD,KeyHookProc,GetModuleHandle  </SPAN>
51Testing软件测试网g(P D(U.Z0LA

51Testing软件测试网{cZ ox9u

*TY0}&W9?0<SPAN style="FONT-SIZE: 18px">                                           ("keyhookdll"),ThreadId);
GNtmbK0  return true;

T5C~1w{0

\'P9p2LS{\0 }51Testing软件测试网#b%P.o4^h`
 else51Testing软件测试网P ? b]}r _6bW
 {51Testing软件测试网PDi Xp#[
  UnhookWindowsHookEx(hHook);51Testing软件测试网fJv/x*x wa4?7Q
  return true;

|LY [1m9W)y0

3U-U5~ ukk\0 }51Testing软件测试网wj,r`U Qd

51Testing软件测试网} \Y;O2R[$@

}</SPAN>

m0\Z%L^lX0
51Testing软件测试网(y ubHN

  创建的钩子类型为WH_KEYBOARD,他可以拦截WM_KEYDOWN 和WM_KEYUP 消息。51Testing软件测试网3~ W~4I8s!A5R(T'u

?U.m}rP0  创建钩子函数功能很简单,仅仅安装钩子和设置共享段内的数据。Thread为要安装钩子的线程。主程序在调用时传入0,表示为所有线程安装钩子。51Testing软件测试网L ?.acfYd]

&a9A^ N,n Rk+m0 再看钩子函数:

6R2QuPV051Testing软件测试网a8y$c$s J6?8iV

51Testing软件测试网Ft R^^F

LRESULT CALLBACK KeyHookProc(int nCode ,WPARAM wParam,LPARAM lParam)
sY(f8lD;JL R0{51Testing软件测试网p_7QBI.P
 if(nCode<0||nCode==HC_NOREMOVE)
"T}*[M7X!Y0 {51Testing软件测试网&}5x,}|6u fLJ
  return CallNextHookEx(hHook,nCode,wParam,lParam);
iO*]y M!P'Vf0 }
X%\4YP[L`0 if(lParam&0x40000000)//只对WM_DOWN进行响应。51Testing软件测试网 at*@4vh,p T OX
&nbsp;     {51Testing软件测试网 \0A-lBe/r*C(v
&nbsp;&nbsp;&nbsp;     PostMessage(hWnd,WM_KEYDOWN,wParam,lParam);
*Z)?e'cjSK0&nbsp;     } 

#\b*Pp+S1]-q051Testing软件测试网4?"V f.y!Ye8N#U

J5WP:x?0O0        return CallNextHookEx(hHook,nCode,wParam,lParam);51Testing软件测试网0R y2P"PXu:b1CN

51Testing软件测试网#Q0G8L_,Y9m0iI

}51Testing软件测试网7@ X[2B)t0Q-X;m

51Testing软件测试网'A+v`{K;am2\p

  在钩子函数中首先判断nCode的值,当他小于零时应该直调用CallNextHookEx,除此之外它也可以有以下取值:51Testing软件测试网m\B;s0wqU|q

|~hb%cz0  ACTION:说明wParam和lParam包含按键消息的信息,可以处理。

t#x uN|3Dy0

+Wby$AM6n5Hn Tsgc0  HC_NOREMOVE:说明wParam和lParam包含按键消息的信息,但该消息没有被从消息队列中移除。即程序是调用PeekMessage来查询消息队列内的消息的。51Testing软件测试网8E0uc bSdudZ

J:o _ k8E H2Ko/OJ0  (与GetMessage的区别与联系:他们都从消息队列内查询消息,有消息时将此消息发送出去,GetMessage在消息队列没有消息时会一直等待,直到有消息到达时才返回。而PeekMessage无论消息队列中是否有消息都立即返回。)

5G'rTG-T+A/_~;X]051Testing软件测试网XZbix$j |iXN

  因此当检测到nCode小于0或者为WH_NOREMOVE时不能对消息进行处理而要直接调用CallNextHookEx。lParam的第 30位为1时说明此时键被按下,为零时说明键被弹起。此处进行了判断,仅在键被按下时向窗口发送消息。防止消息每次击键发送两次消息。51Testing软件测试网#a!y8n*[#~ @2]

M6x.v BTb(Pk)Y0  当某消息到达时我们给主程序窗口发送的消息为用户自定义消息:WM_KEY

4d gfj-G051Testing软件测试网u%cC6ok)k7e X

  他被定义为#define WM_KEY  WM_USER+1

+R q9v5K9I:|oD0

^w[V8^l(n#Ww(@fs0  在主程序内我们必须自己实现相应此消息的消息处理函数。

\s*p(@R0

4OhL%b/bh` Iu0  原型为:51Testing软件测试网;S&f^6MdZ,L

#w&Xx&jB$rp051Testing软件测试网%Ze*v `&M"e.iY-KG

    afx_msg LRESULT OnKey(WPARAM wParam,LPARAM lParam);
51Testing软件测试网d7HLyO1~

  实现:

wzG knb0

nbl2j8D w$Q0

,g_ p-Eg-o M_z3]0
      char keyname[100];
&XPp+n*};|0 ::GetKeyNameText(lParam,keyname,100);//获得按键的键名。51Testing软件测试网$yt.Nj.A N1F/J
 CString a;51Testing软件测试网;[#C"Tb6Vp$qVxO5Y
 a.Format("用户按键:%s\r\n",keyname);
Z c+_ r|0 m_output+=a;
{M {a`j!|7\0 UpdateData(false);51Testing软件测试网5q!@5]4f(L'Pg xS Z
 ::MessageBeep(MB_OK);51Testing软件测试网.jl'iZ^K|)X
 CEdit *edit=(CEdit*)GetDlgItem(IDC_EDIT_OUTPUT);51Testing软件测试网+bwEaJ:o)H:[
 edit->LineScroll(edit->GetLineCount());
GKlbj3P0 return 0;
51Testing软件测试网4G x^J`"i5S

  到此为止各主要函数都介绍完毕,剩下都是如何创建dll。此处不再介绍。51Testing软件测试网-ab&jZ6ZY-Gl!reU

51Testing软件测试网(t|.z2|ET5UX

  总结:以上程序花了近三个小时实现,此程序看似容易但一旦自己动手实现各种问题接踵而至。所以以后要经常动 手实现一些看似容易的程序,不要眼高手低。打这些字的时候键盘监控程序仍在工作,显示着我按下的每一个键。有明显的电脑感觉速度比平常慢了不少,看来使用 钩子,尤其是系统范围内的钩子会导致很大的overhead。

K G7Om]iD0

TAG:

 

评分:0

我来说两句

Open Toolbar