钩子的使用

来源:互联网 发布:java软件系统技术合同 编辑:程序博客网 时间:2024/04/30 17:27
  钩子函数的用法和作用?

http://topic.csdn.net/t/20020625/10/827891.html

WINDOW的消息处理机制为了能在应用程序中监控系统的各种事件消息,提供了挂接各种反调函数(HOOK)的功能。这种挂钩函数(HOOK)类似扩充中断驱动程序,挂钩上可以挂接多个反调函数构成一个挂接函数链。系统产生的各种消息首先被送到各种挂接函数,挂接函数根据各自的功能对消息进行监视、修改和控制等,然后交还控制权或将消息传递给下一个挂接函数以致最终达到窗口函数。WINDOW系统的这种反调函数挂接方法虽然会略加影响到系统的运行效率,但在很多场合下是非常有用的,通过合理有效地利用键盘事件的挂钩函数监控机制可以达到预想不到的良好效果。   
一、在WINDOWS键盘事件上挂接监控函数的方法 
WINDOW下可进行挂接的过滤函数包括11种: 
WH_CALLWNDPROC   窗口函数的过滤函数 
WH_CBT   计算机培训过滤函数 
WH_DEBUG   调试过滤函数 
WH_GETMESSAGE   获取消息过滤函数 
WH_HARDWARE   硬件消息过滤函数 
WH_JOURNALPLAYBACK   消息重放过滤函数 
WH_JOURNALRECORD   消息记录过滤函数 
WH_MOUSE   鼠标过滤函数 
WH_MSGFILTER   消息过滤函数 
WH_SYSMSGFILTER   系统消息过滤函数 
WH_KEYBOARD   键盘过滤函数 
其中键盘过滤函数是最常用最有用的过滤函数类型,不管是哪一种类型的过滤函数,其挂接的基本方法都是相同的。WINDOW调用挂接的反调函数时总是先调用挂接链首的那个函数,因此必须将键盘挂钩函数利用函数SetWindowsHookEx()将其挂接在函数链首。至于消息是否传递给函数链的下一个函数是由每个具体函数功能确定的,如果消息需要传统给下一个函数,可调用API函数的CallNextHookEx()来实现,如果不传递直接返回即可。 
挂接函数可以是用来监控所有线程消息的全局性函数,也可以是单独监控某一线程的局部性函数。如果挂接函数是局部函数,可以将它放到一个.DLL动态链接库中,也可以放在一个局部模块中;如果挂接函数是全局的,那么必须将其放在一个.DLL动态链接库中。挂接函数必须严格按照下述格式进行声明,以键盘挂钩函数为例: 
int   FAR   PASCAL   KeyboardProc

int   nCode,WORD  wParam,DWORD   lParam) 

其中KeyboardProc为定义挂接函数名,该函数必须在模块定义文件中利用EXPORTS命令进行说明;nCode决定挂接函数是否对当前消息进行处理;wParamlParam为具体的消息内容。 

二、键盘事件挂接函数的安装与下载 

在程序中可以利用函数SetWindowsHookEx()来挂接过滤函数,在挂接函数时必须指出该挂接函数的类型、函数的入口地址以及函数是全局性还是局部性的,挂接函数的具体调用格式如下: 
SetWindowsHookEx(iType,iProc,hInst,iCode) 
其中iType为挂接函数类型,键盘类型为WH_KEYBOARD,iProc挂接函数地址hInst挂接函数链接库实例句柄iCode为监控代码0表示全局性函数。如果挂接函数需要将消息传递给下一个过滤函数,则在该挂接函数返回前还需要调用一次CallNextHookEx()函数,当需要下载挂接函数时,只要调用一次UnhookWindowsHookEx(iProc)函数即可实现。如果函数是全局性的,那么它必须放在一个.DLL动态链接库中,这时该函数调用方法可以和其它普通.DLL函数一样有三种: 
1.DEF定义文件中直接用函数名或序号说明: 
EXPORTS 
WEP   @1   RESIDENTNAME 
InitHooksDll   @2 
InstallFilter   @3 
KeyboardProc   @4 
用序号说明格式为:链接库名.函数名(如本例中说明方法为KEYDLL.KeyboardProc)。 
2.在应用程序中利用函数直接调用: 
首先在应用程序中利用LoadLibrary(LPSTR   "链接库名 ")将动态链接库装入,并取得装载库模块句柄hInst,然后直接利用GetProcAddress(HINSTANCE  hInst,LPSTR   "函数过程名 ")获取函数地址,然后直接调用该地址即可,程序结束前利用函数FreeLibrary(   )释放装入的动态链接库即可。 
3.利用输入库.LIB方法 
利用IMPLIB.EXE程序在建立动态链接库的同时建立相应的输入库.LIB,然后直接在项目文件中增加该输入库。   
三、WINDOWS挂钩监控函数的实现步骤 
WINDOWS挂钩函数只有放在动态链接库DLL中才能实现所有事件的监控功能。在.DLL中形成挂钩监控函数基本方法及其基本结构如下: 
1、首先声明DLL中的变量和过程; 
2、然后编制DLL主模块LibMain(),建立模块实例; 
3、建立系统退出DLL机制WEP()函数; 
4、完成DLL初始化函数InitHooksDll(),传递主窗口程序句柄; 
5、编制挂钩安装和下载函数InstallFilter(); 
6、编制挂钩函数KeyboardProc(),在其中设置监控功能,并确定继续调下一个钩子函数还是直接返回WINDOWS应用程序。 
7、在WINDOWS主程序中需要初始化DLL并安装相应挂钩函数,由挂接的钩子函数负责与主程序通信; 
8、在不需要监控时由下载功能卸掉挂接函数。 
四、WINDOWS下键盘挂钩监控函数的应用技术  
    目前标准的104   键盘上都有两个特殊的按键,其上分别用WINDOW程序徽标和鼠标下拉列表标识,本文暂且分别称为Micro左键和Micro右键,前者用来模拟鼠标左键激活开始菜单,后者用来模拟鼠标右键激活属性菜单。这两个特殊按键只有在按下后立即抬起即完成   CLICK过程才能实现其功能,并且没有和其它按键进行组合使用。 
   由于WINDOWS  系统中将按键划分得更加详细,使应用程序中很难灵活定义自己的专用快捷键,比如在开发.IME等应用程序时很难找到不与WORD8.0等其它应用程序冲突的功能按键。如果将标准104键盘中的这两个特殊按键作为模拟CTRL和ALT   等专用按键,使其和其它按键组合,就可以在自己的应用程序中自由地设置专用功能键,为应用程序实现各种功能快捷键提供灵活性。正常情况下WINDOWS   键盘事件驱动程序 
并不将这两个按键的消息进行正常解释,这就必须利用键盘事件的挂钩监控函数来实现其特定的功能。其方法如下:
1、首先编制如下一个简单动态链接库程序,并编译成DLL文件。 
#include   "windows.h " 
int   FAR   PASCAL  LibMain(HANDLE   hModule,UINT   wDataSeg, 
UINT   cbHeapSize,LPSTR  lpszCmdLine); 
int   WINAPI   WEP(int  bSystemExit); 
int   WINAPI   InitHooksDll(HWND  hwndMainWindow); 
int   WINAPI   InstallFilter(BOOL  nCode); 
LRESULT   CALLBACK   KeyHook(int  nCode,WORD   wParam,DWORD   lParam); 
static   HANDLE   hInstance;   //  全局句柄 
static   HWND   hWndMain;   //  主窗口句柄 
static   int   InitCalled=0;   //  初始化标志 
static   HHOOK   hKeyHook; 
FARPROC   lpfnKeyHook=(FARPROC)KeyHook; 
BOOL   HookStates=FALSE; 
int   FAR   PASCAL   LibMain( 
HANDLE   hModule, 
UINT   wDataSeg, 
UINT   cbHeapSize, 
LPSTR   lpszCmdLine) 

if   (cbHeapSize!=0)   UnlockData(0); 
hInstance   =   hModule; 
return   1; 

int   WINAPI   WEP   (int  bSystemExit) 
{   return   1;} 
int   WINAPI   InitHooksDll(HWND  hwndMainWindow) 
{   hWndMain   =  hwndMainWindow; 
InitCalled   =   1; 
return   (0); 

int   WINAPI   InstallFilter(BOOL  nCode) 
{   if   (InitCalled==0)   return  (-1); 
if   (nCode==TRUE)   { 
hKeyHook=SetWindowsHookEx(WH_KEYBOARD, 
(HOOKPROC)lpfnKeyHook,hInstance,0); 
HookStates=TRUE; 
}   else   { 
UnhookWindowsHookEx(hKeyHook); 
HookStates=FALSE; 

return(0); 

LRESULT   CALLBACK   KeyHook(int  nCode,WORD   wParam,DWORD   lParam) 

static   BOOL   msflag=FALSE; 
if(nCode> =0)   { 
if(HookStates==TRUE){ 
if((wParam==0xff)||   //WIN3.X下按键值 
(wParam==0x5b)||(wParam==0x5c)){//WIN95下按键值 
if((i==0x15b)||(i==0x15c)){   //按键按下处理 
msflag=TRUE; 
PostMessage(hWndMain,0x7fff,0x1,0x3L); 
}   else  if((i==0xc15b)||(i==0xc15c)){//按键抬起处理 
msflag=FALSE; 
PostMessage(hWndMain,0x7fff,0x2,0x3L); 




return((int)CallNextHookEx(hKeyHook,nCode,wParam,lParam)); 

该程序的主要功能是监控键盘按键消息,将两个特殊按键Micro按下和抬起消息转换成自定义类型的消息,并将自定义消息发送给应用程序主窗口函数。 
2、在应用程序主函数中建立窗口后,调用InitHooksDll()函数来初始化动态链接库,并将应用程序主窗口句柄传递给链接库,然后调用InstallFilter()函数挂接键盘事件监控回调函数。 
InitHooksDll(hIMEWnd);   //初始化DLL 
InstallFilter(TRUE);   //安装键盘回调函数 
3、在应用程序主窗口函数处理自定义消息时,保存Micro按键的状态,供组合按键处理时判断使用。 
switch   (iMessage)   { 
case   0x7fff:   //自定义消息类型 
if(lParam==0x3L){//设置Micro键的状态 

if(wParam==0x1)   MicroFlag=TRUE; 
else   if(wParam==0x2)  MicroFlag=FALSE; 

break; 
4、在进行按键组合处理时,首先判断Micro键是否按下,然后再进行其它按键的判断处理。 
case   WM_KEYDOWN:   //   按键按下处理 
if(MicroFlag==TRUE){//Micro键按下 
if((BYTE)HIBYTE(wParam)==0x5b){ 
//Micro+ "[ "组合键 
......//按键功能处理 
}   else  if((BYTE)HIBYTE(wParam)==0x5d){ 
//Micro+ "] "组合键 
......//按键功能处理 


break; 
5、当应用程序退出时应注意下载键盘监控函数,即调用InstallFilter(FALSE)函数一次。 
6、利用本文提供的方法设置自己的应用程序功能按键,在保证程序功能按键不会与其它系统发生冲突的同时,有效地利用了系统中现有资源,而且在实现应用程序功能的同时灵活应用了系统中提供的各种功能调用。

http://hi.baidu.com/anwyo/blog/item/882c858276107bb96d811925.html

HOOK的认识[转载]

20080926日星期五下午 3:40

本文将试图以下面的顺序讲解HOOK的大部分内容:

1 WINDOWS的消息机制
2
HOOK介绍
3
HOOK
4
HOOK钩子的作用范围
5
HOOK类型
6
、回调函数
7
HOOK钩子的安装与卸载
8
HOOK实例演示

+++++++++++++++++++
WINDOWS
的消息机制
+++++++++++++++++++
Windows
系统是以消息处理为其控制机制,系统通过消息为窗口过程(windows 
procedure
)传递输入。系统和应用两者都可以产生消息。对于每个输入事件,例如用
户按下了键盘上的某个键、移动了鼠标、单击了一个控件上的滚动条,等等,系统都
将产生一系列消息。此外,对于应用带给系统的变化,如字体资源的改变、应用本身
窗口的改变,系统都将通过消息以响应这种变化。应用通过产生消息指示应用的窗口
完成特定的任务,或与其他应用的窗口进行通信。
每个窗口都有一个处理Windows系统发送消息的处理程序,称为窗口程序。它是
隐含在窗口背后的一段程序脚本,其中包含对事件进行处理的代码。
Windows
系统为每条消息指定了一个消息编号,例如当一个窗口变为活动窗口时,它事
实上是收到一条来自Windows系统的WM_ACTIVATE消息,该消息的编号为6,它对
应于VB窗口的Activate事件。对于窗口来说,诸如OpenActivateMouseDownResize
等事件,实际上对应的是窗口内部的消息处理程序,这些程序对于用户来讲是不可见的。
类似地,命令按钮也有消息处理程序,它的处理程序响应诸如WM_LBUTTONDOWN
WM_RBUTTONDOWN之类的消息,即激活命令按钮的MouseDown事件。

WINDOWS的消息处理机制为了能在应用程序中监控系统的各种事件消息,提供
了挂接各种回调函数(HOOK)的功能。这种挂钩函数(HOOK)类似扩充中断驱动程序,
挂钩上可以挂接多个反调函数构成一个挂接函数链。系统产生的各种消息首先被送
到各种挂接函数,挂接函数根据各自的功能对消息进行监视、修改和控制等,然后交
还控制权或将消息传递给下一个挂接函数以致最终达到窗口函数。WINDOW系统的
这种反调函数挂接方法虽然会略加影响到系统的运行效率,但在很多场合下是非常有
用的,通过合理有效地利用键盘事件的挂钩函数监控机制可以达到预想不到的良好效
果。

+++++++++++
hook
介绍
+++++++++++

Hook(钩子)是WINDOWS提供的一种消息处理机制平台,是指在程序正常运
行中接受信息之前预先启动的函数,用来检查和修改传给该程序的信息,(钩子)实
际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,
在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这
时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还
可以强制结束消息的传递。
注意:安装钩子函数将会影响系统的性能。监测系统范围事件的系统钩子特
别明显。因为系统在处理所有的相关事件时都将调用您的钩子函数,这样您的系统将
会明显的减慢。所以应谨慎使用,用完后立即卸载。还有,由于您可以预先截获其它
进程的消息,所以一旦您的钩子函数出了问题的话必将影响其它的进程。记住:功能
强大也意味着使用时要负责任。

+++++++++++++
HOOK

+++++++++++++

WINDOWS提供了14种不同类型的HOOKS;不同的HOOK可以处理不同的消
息。例如,WH_MOUSE HOOK用来监视鼠标消息。
WINDOWS
为这几种HOOKS维护着各自的HOOK链表。HOOK链表是一串由
应用程序定义的回调函数(CALLBACK Function)队列,当某种类型的消息发生时,

WINDOWS向此种类型的HOOK链的第一个函数(HOOK链的顶部)发送该消息,
在第一函数处理完该消息后由该函数向链表中的下一个函数传递消息,依次向下。如
果链中某个函数没有向下传送该消息,那么链表中后面的函数将得不到此消息。(对
于某些类型的HOOK,不管HOOK链中的函数是否向下传递消息,与此类型HOOK
联系的所有HOOK函数都会收到系统发送的消息)一些Hook子过程可以只监视消息,
或者修改消息,或者停止消息的前进,避免这些消息传递到下一个Hook子过程或者
目的窗口。最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加
入的先获得控制权。

+++++++++++++++++
钩子的作用范围
++++++++++++++++

一共有两种范围(类型)的钩子:局部的和远程的。
一、局部钩子仅钩挂您自己进程的事件。
二、远程的钩子还可以将钩挂其它进程发生的事件。
远程的钩子又有两种:
1
、基于线程的它将捕获其它进程中某一特定线程的事件。简言之,就是可
以用来观察其它进程中的某一特定线程将发生的事件。
2
、系统范围的将捕捉系统中所有进程将发生的事件消息。

+++++++++++++
HOOK
类型
+++++++++++++

Windows共有14HOOKS,每一种类型的Hook可以使应用程序能够监视不同
类型的系统消息处理机制。下面描述所有可以利用的Hook类型的发生时机。(这些常
数值均可以API浏览器里查到)

1WH_CALLWNDPROCWH_CALLWNDPROCRET Hooks

WH_CALLWNDPROCWH_CALLWNDPROCRET Hooks使你可以监视发送到
窗口过程的消息。系统在消息发送到接收窗口过程之前调用WH_CALLWNDPROC
Hook
子过程,并且在窗口过程处理完消息之后调用WH_CALLWNDPROCRET Hook
子过程。

WH_CALLWNDPROCRET Hook传递指针到CWPRETSTRUCT结构,再传递到
Hook
子过程。CWPRETSTRUCT结构包含了来自处理消息的窗口过程的返回值,同
样也包括了与这个消息关联的消息参数。

2WH_CBT Hook

在以下事件之前,系统都会调用WH_CBT Hook子过程,这些事件包括:
1.
激活,建立,销毁,最小化,最大化,移动,改变尺寸等窗口事件;
2.
完成系统指令;
3.
来自系统消息队列中的移动鼠标,键盘事件;
4.
设置输入焦点事件;
5.
同步系统消息队列事件。

Hook子过程的返回值确定系统是否允许或者防止这些操作中的一个。

3WH_DEBUG Hook

在系统调用系统中与其它Hook关联的Hook子过程之前,系统会调用
WH_DEBUG Hook
子过程。你可以使用这个Hook来决定是否允许系统调用与其它
Hook
关联的Hook子过程。

4WH_FOREGROUNDIDLE Hook

当应用程序的前台线程处于空闲状态时,可以使用WH_FOREGROUNDIDLE
Hook
执行低优先级的任务。当应用程序的前台线程大概要变成空闲状态时,系统就
会调用WH_FOREGROUNDIDLE Hook子过程。

5WH_GETMESSAGE Hook

应用程序使用WH_GETMESSAGE Hook来监视从GetMessage or PeekMessage
数返回的消息。你可以使用WH_GETMESSAGE Hook去监视鼠标和键盘输入,以及
其它发送到消息队列中的消息。

6WH_JOURNALPLAYBACK Hook

WH_JOURNALPLAYBACK Hook使应用程序可以插入消息到系统消息队列。可
以使用这个Hook回放通过使用WH_JOURNALRECORD Hook记录下来的连续的鼠
标和键盘事件。只要WH_JOURNALPLAYBACK Hook已经安装,正常的鼠标和键盘
事件就是无效的。WH_JOURNALPLAYBACK Hook全局Hook,它不能象线程特定
Hook
一样使用。WH_JOURNALPLAYBACK Hook返回超时值,这个值告诉系统在处
理来自回放Hook当前消息之前需要等待多长时间(毫秒)。这就使Hook可以控制实
时事件的回放。WH_JOURNALPLAYBACKsystem-wide local hooks,它们不会被
注射到任何行程地址空间。

7WH_JOURNALRECORD Hook

WH_JOURNALRECORD Hook用来监视和记录输入事件。典型的,可以使用这
Hook记录连续的鼠标和键盘事件,然后通过使用WH_JOURNALPLAYBACK Hook
来回放。WH_JOURNALRECORD Hook全局Hook,它不能象线程特定Hook一样
使用。WH_JOURNALRECORDsystem-wide local hooks,它们不会被注射到任何行
程地址空间。

8WH_KEYBOARD Hook

在应用程序中,WH_KEYBOARD Hook用来监视WM_KEYDOWN and
WM_KEYUP
消息,这些消息通过GetMessage or PeekMessage function返回。可以使
用这个Hook来监视输入到消息队列中的键盘消息。

9WH_KEYBOARD_LL Hook

WH_KEYBOARD_LL Hook监视输入到线程消息队列中的键盘消息。

10WH_MOUSE Hook

WH_MOUSE Hook监视从GetMessage或者 PeekMessage函数返回的鼠标消息。
使用这个Hook监视输入到消息队列中的鼠标消息。

11WH_MOUSE_LL Hook

WH_MOUSE_LL Hook监视输入到线程消息队列中的鼠标消息。

12WH_MSGFILTER WH_SYSMSGFILTER Hooks

WH_MSGFILTER WH_SYSMSGFILTER Hooks使我们可以监视菜单,滚动
条,消息框,对话框消息并且发现用户使用ALT+TAB or ALT+ESC组合键切换窗口。
WH_MSGFILTER Hook
只能监视传递到菜单,滚动条,消息框的消息,以及传递到通
过安装了Hook子过程的应用程序建立的对话框的消息。WH_SYSMSGFILTER Hook
监视所有应用程序消息。

WH_MSGFILTER WH_SYSMSGFILTER Hooks使我们可以在模式循环期间
过滤消息,这等价于在主消息循环中过滤消息。

通过调用CallMsgFilter function可以直接的调用WH_MSGFILTER Hook。通过使用这
个函数,应用程序能够在模式循环期间使用相同的代码去过滤消息,如同在主消息循
环里一样。

13WH_SHELL Hook

外壳应用程序可以使用WH_SHELL Hook去接收重要的通知。当外壳应用程序是
激活的并且当顶层窗口建立或者销毁时,系统调用WH_SHELL Hook子过程。
WH_SHELL
共有5钟情况:
1.
只要有个top-levelunowned窗口被产生、起作用、或是被摧毁;
2.
Taskbar需要重画某个按钮;
3.
当系统需要显示关于Taskbar的一个程序的最小化形式;
4.
当目前的键盘布局状态改变;
5.
当使用者按Ctrl+Esc去执行Task Manager(或相同级别的程序)。

按照惯例,外壳应用程序都不接收WH_SHELL消息。所以,在应用程序能够接
WH_SHELL消息之前,应用程序必须调用SystemParametersInfo function注册它自
己。


++++++++++++++++++++++++++
回调函数(HOOK处理子过程)
++++++++++++++++++++++++++

为了拦截和处理特定的消息,你可以使用SetWindowsHookEx函数(下面将具体
说明这些函数的声明及各种参数)在该类型的HOOK链中安装你自己的处理HOOK
的子过程(回调函数)。只要您安装的钩子的消息事件类型发生,WINDOWS就将调
用钩子函数。譬如您安装的钩子是WH_MOUSE类型,那么只要有一个鼠标事件发生
时,该钩子函数就会被调用。不管您安装的是那一类型钩子,钩子函数的原型都时是
一样的,语法如下:

public function MyHook(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam
As Long) as long

处理代码

end function

其中MyHook可以随便命名,其它不能变。该函数必须放在模块段。
参数说明:
nCode
指定HOOK传入的信息类型。Hook子过程使用这个参数来确定任务。这个
参数的值依赖于Hook类型,每一种Hook都有自己的Hook代码特征字符集。
wParam
:短整型参数。
lParam
:长整型参数。
wParam,iParam
的取值随nCode不同而不同,它代表了某种类型的HOOK的某个特
定的动作。它们的典型值是包含了关于发送或者接收消息的信息。
至于以上的几个参数及返回值的具体含义,各种类型的钩子都不相同,所以您必

须查询WIN32 API指南来得到不同类型钩子参数的详细定义以及它们返回值的意
义。(如果哪位朋友有时间和兴趣的话,请整理一下贴出来,顺便发给我一份,我的邮箱:
wlclass163.com

譬如:
WH_CALLWNDPROC
nCode
只能是HC_ACTION,它代表有一个消息发送给了一个窗口
wParam
如果非0,代表正被发送的消息
lParam
指向CWPSTRUCT型结构体变量的指针
return value:
未使用,返回0
WH_MOUSE
nCode
HC_ACTION HC_NOREMOVE
wParam
包含鼠标的事件消息
lParam
指向MOUSEHOOKSTRUCT型结构体变量的指针
return value:
如果不处理返回0,否则返回非0

++++++++++++++++++++++++++
钩子的安装/卸载
++++++++++++++++++++++++++

现在我们知道了一些基本的理论,接下来开始讲解如何安装和卸载一个钩子。


安装钩子

使用SetWindowsHookEx函数(API函数),指定一个HOOK类型、自己的HOOK
过程是全局还是局部HOOK,同时给出HOOK过程的进入点,就可以轻松的安装你
自己的HOOK过程。
SetWindowsHookEx
总是将你的HOOK函数放置在HOOK链的顶端。你可以使用
CallNextHookEx
函数将系统消息传递给HOOK链中的下一个函数。
[
注意]对于某些类型的HOOK,系统将向该类的所有HOOK函数发送消息,这时,
HOOK
函数中的CallNextHookEx语句将被忽略。

全局(远程钩子)HOOK函数可以拦截系统中所有线程的某个特定的消息,为了
安装一个全局HOOK过程,必须在应用程序外建立一个DLL,并将该HOOK函数封
装到其中,应用程序在安装全局HOOK过程时必须先得到该DLL模块的句柄。将DLL
名传递给LoadLibrary函数,就会得到该DLL模块的句柄;得到该句柄后,使用
GetProcAddress
函数可以得到HOOK过程的地址。最后,使用SetWindowsHookEx
HOOK
过程的首址嵌入相应的HOOK链中,SetWindowsHookEx传递一个模块句柄,
它为HOOK过程的进入点,线程标识符置为0,指出:该HOOK过程同系统中的所
有线程关联。如果是安装局部HOOK此时该HOOK函数可以放置在DLL中,也可以
放置在应用程序的模块段。

建议只在调试时使用全局HOOK函数。全局HOOK函数将降低系统效率,并且
会同其它使用该类HOOK的应用程序产生冲突。

SetWindowsHookEx函数的VB声明及参数解释:

Public Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA"
(ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId
As Long) As Long

SetWindowHookEx函数参数说明:
idHook
:代表是何种Hook(也就是上面讲的14Hook

lpfn:代表处理Hook的过程所在的Address,这是一个CallBack Fucnction(也就是上
面讲的回调函数),当挂上某个Hook时,我们便得定义一个Function来当作某个信
息产生时,来处理它的Function。因这个参数是一个 FunctionAddress所以我们
固定将Hook Function放在.Bas中,并以AddressOf HookFunc传入

hmod:代表.DLLhInstance,如果是Local Hook,该值可以是Null(VB中可传0
进去),而如果是Remote Hook,则可以使用GetModuleHandle(".dll名称")来传入。

dwThreadId:代表执行这个HookThreadId(线程ID),如果不设定是那个Thread
(线程)来做,则传0,而VBLocal Hook一般可传App.ThreadId进去ThreadID
是您安装该钩子函数后想监控的线程的ID号。该参数可以决定该钩子是局部的还
是系统范围的。如果该值为NULL,那么该钩子将被解释成系统范围内的,那它就
可以监控所有的进程及它们的线程。如果您指定了您自己进程中的某个线程ID号,
那该钩子是一个局部的钩子。如果该线程ID是另一个进程中某个线程的ID,那该
钩子是一个全局的远程钩子。这里有两个特殊情况:WH_JOURNALRECORD
WH_JOURNALPLAYBACK
总是代表局部的系统范围的钩子,之所以说是局部,是
因为它们没有必要放到一个DLL中。WH_SYSMSGFILTER总是一个系统范围内
的远程钩子。其实它和WH_MSGFILTER钩子类似,如果把参数ThreadID设成0
的话,它们就完全一样了。

SetWindowHookEx函数回值:如果SetWindowsHookEx()成功,它会传回一个值,
代表目前的HookHandle,否则返回NULL。您必须保存该句柄,因为后面我们
还要它来卸载钩子。

CallNextHookEx函数的VB声明及参数解释:

Declare Function CallNextHookEx Lib "user32" Alias "CallNextHookEx" (ByVal hHook
As Long, ByVal ncode As Long, ByVal wParam As Long,lParam As Any) As Long

hHook值是SetWindowsHookEx()的传回值,nCode, wParam, lParam则是回调函数
中的三个参数。

在钩子子程中调用得到控制权的钩子函数在完成对消息的处理后,如果想要该消
息继续传递,那么它必须调用另外一个API函数CallNextHookEx来传递它,以执行
钩子链表所指的下一个钩子子过程。这个函数成功时返回钩子链中下一个钩子过程的
返回值,返回值的类型依赖于钩子的类型。

卸载钩子

要卸载一个钩子非常简单,只需要使用UnhookWindowsHookEx函数来卸载创建
的钩子。
函数声明:

Declare Function UnhookWindowsHookEx Lib "user32" Alias "UnhookWindowsHookEx"
(ByVal hHook As Long) As Long

参数说明:
hHook
:是SetWindowsHookEx()的传回值,上面告诉过你要记下来嘛。^_^

2 实例句柄

http://zhidao.baidu.com/question/83275743.html

3  DLL入门浅析(1)——如何建立DLL

http://www.cppblog.com/suiaiguo/archive/2009/07/20/90619.html

    初学DLL,结合教程,总结一下自己的所得,希望对DLL初学者们有所帮助。
    动态链接库(DLL)是从C语言函数库和Pascal库单元的概念发展而来的。所有的C语言标准库函数都存放在某一函数库中。在链接应用程序的过程中,链接器从库文件中拷贝程序调用的函数代码,并把这些函数代码添加到可执行文件中。这种方法同只把函数储存在已编译的OBJ文件中相比更有利于代码的重用。但随着Windows这样的多任务环境的出现,函数库的方法显得过于累赘。如果为了完成屏幕输出、消息处理、内存管理、对话框等操作,每个程序都不得不拥有自己的函数,那么Windows程序将变得非常庞大。Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝。动态链接库就是在这种情况下出现的。动态链接库不用重复编译或链接,一旦装入内存,DLL函数可以被系统中的任何正在运行的应用程序软件所使用,而不必再将DLL函数的另一拷贝装入内存。
   下面我们一步一步来建立一个DLL。
   一、建立一个DLL工程
   新建一个工程,选择Win32控制台项目(Win32 Console Application),并且在应用程序设置标签(the advanced tab)上,选择DLL和空项目选项。
   二、声明导出函数
   这里有两种方法声明导出函数:一种是通过使用__declspec(dllexport),添加到需要导出的函数前,进行声明;另外一种就是通过模块定义文件(Module-Definition File即.DEF)来进行声明。
   第一种方法,建立头文件DLLSample.h,在头文件中,对需要导出的函数进行声明。

#ifndef _DLL_SAMPLE_H
#define _DLL_SAMPLE_H

// 如果定义了C++编译器,那么声明为C链接方式
#ifdef __cplusplus
extern "C" {
#endif

// 通过宏来控制是导入还是导出
#ifdef _DLL_SAMPLE
#define DLL_SAMPLE_API __declspec(dllexport)
#else
#define DLL_SAMPLE_API __declspec(dllimport)
#endif

// 导出/导入函数声明
DLL_SAMPLE_API void TestDLL(int);

#undef DLL_SAMPLE_API

#ifdef __cplusplus
}
#endif

#endif

   这个头文件会分别被DLL和调用DLL的应用程序引入,当被DLL引入时,在DLL中定义_DLL_SAMPLE宏,这样就会在DLL模块中声明函数为导出函数;当被调用DLL的应用程序引入时,就没有定义_DLL_SAMPLE,这样就会声明头文件中的函数为从DLL中的导入函数。 
  
   第二种方法:模块定义文件是一个有着.def文件扩展名的文本文件。它被用于导出一个DLL的函数,和__declspec(dllexport)很相似,但是.def文件并不是Microsoft定义的。一个.def文件中只有两个必需的部分:LIBRARY和 EXPORTS。

LIBRARY DLLSample
DESCRIPTION "my simple DLL"
EXPORTS
        TestDLL @1  ;@1表示这是第一个导出函数

   第一行,''LIBRARY''是一个必需的部分。它告诉链接器(linker)如何命名你的DLL。下面被标识为''DESCRIPTION''的部分并不是必需的。该语句将字符串写入 .rdata 节,它告诉人们谁可能使用这个DLL,这个DLL做什么或它为了什么(存在)。再下面的部分标识为''EXPORTS''是另一个必需的部分;这个部分使得该函数可以被其它应用程序访问到并且它创建一个导入库。当你生成这个项目时,不仅是一个.dll文件被创建,而且一个文件扩展名为.lib的导出库也被创建了。除了前面的部分以外,这里还有其它四个部分标识为:NAME, STACKSIZE, SECTIONS, 和VERSION。另外,一个分号(;)开始一个注解,如同''//''在C++中一样。定义了这个文件之后,头文件中的__declspec(dllexport)就不需要声明了。
   三、编写DllMain函数和导出函数
   DllMain函数是DLL模块的默认入口点。当Windows加载DLL模块时调用这一函数。系统首先调用全局对象的构造函数,然后调用全局函数DLLMain。DLLMain函数不仅在将DLL链接加载到进程时被调用,在DLL模块与进程分离时(以及其它时候)也被调用。

#include "stdafx.h"
#define _DLL_SAMPLE

#ifndef _DLL_SAMPLE_H
#include "DLLSample.h"
#endif

#include "stdio.h"

//APIENTRY声明DLL函数入口点
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
 switch (ul_reason_for_call)
 {
  case DLL_PROCESS_ATTACH:
  case DLL_THREAD_ATTACH:
  case DLL_THREAD_DETACH:
  case DLL_PROCESS_DETACH:
   break;
 }
 return TRUE;
}

void TestDLL(int arg)
{
  printf("DLL output arg %d\n", arg);
}

   如果程序员没有为DLL模块编写一个DLLMain函数,系统会从其它运行库中引入一个不做任何操作的缺省DLLMain函数版本。在单个线程启动和终止时,DLLMain函数也被调用。
   然后,F7编译,就得到一个DLL了。

4  基本概念

  钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。

  钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。

运行机制

  1、钩子链表和钩子子程:

  每一个Hook都有一个与之相关联的指针列表,称之为钩子链表,由系统来维护。这个列表的指针指向指定的,应用程序定义的,被Hook子程调用的回调函数,也就是该钩子的各个处理子程。当与指定的Hook类型关联的消息发生时,系统就把这个消息传递到Hook子程。一些Hook子程可以只监视消息,或者修改消息,或者停止消息的前进,避免这些消息传递到下一个Hook子程或者目的窗口。最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。

  Windows 并不要求钩子子程的卸载顺序一定得和安装顺序相反。每当有一个钩子被卸载,Windows 便释放其占用的内存,并更新整个Hook链表。如果程序安装了钩子,但是在尚未卸载钩子之前就结束了,那么系统会自动为它做卸载钩子的操作。

  钩子子程是一个应用程序定义的回调函数(CALLBACK Function),不能定义成某个类的成员函数,只能定义为普通的C函数。用以监视系统或某一特定类型的事件,这些事件可以是与某一特定线程关联的,也可以是系统中所有线程的事件。

钩子回调函数必须按照以下的语法

  LRESULT CALLBACK HookProc

  (

  int nCode,

  WPARAM wParam,

  LPARAM lParam

  );

  HookProc是回调函数名。

  nCode参数是Hook代码,Hook子程使用这个参数来确定任务。这个参数的值依赖于Hook类型,每一种Hook都有自己的Hook代码特征字符集

wParam和lParam参数的值依赖于Hook代码,但是它们的典型值是包含了关于发送或者接收消息的信息。

5  HHOOK 类型

 类型: HHOOK句柄函数参数的类型

如:

BOOL WINAPIUnhookWindowsHookEx( __in HHOOK hhk);

Appliesto: desktopapps only:适用于:桌面应用程序

Removesa hook procedure installed in a hook chain by the SetWindowsHookEx function.

删除一个钩子过程安装在一个钩子链的SetWindowsHookEx函数。

HHOOK WINAPI SetWindowsHookEx(

  __inint idHook,    

  __inHOOKPROC lpfn,

  __inHINSTANCE hMod,

__inDWORD dwThreadId);

 

BOOL WINAPI UnhookWindowsHookEx(

  __in  HHOOK hhk

);

参数:

  hhk [in]

  类型: HHOOK

  要删除的钩子的句柄。这个参数是上一个函数SetWindowsHookEx的返回值.

返回值:

  类型: BOOL

  如果函数成功,返回值为非零值。

  如果函数失败,返回值为零。要获得更多的错误信息,调用GetLastError函数.

6  KeyboardProc

键盘钩子处理函数:

首先键盘钩子处理函数的函数名是可以自定义的,例如:MyKeyboardProc()

  函数原型:

  LRESULTCALLBACK KeyboardProc( int code,

  WPARAMwParam,

  LPARAMlParam

);

code:

  根据这个数值决定怎样处理消息

如果code 小于0,则必须让KeyboardProc()函数返回CallNextHookEx()

code可以是下列值:

  HC_ACTION:wParam和lParam包含按键消息

HC_NOREMOVE:wParam和lParam包含按键消息,并且按键消息不能从消息队列中移除(一个被PeekMessage函数调用的请求,指定 PM_NOREMOVE标志)

wParam:

  按键的虚拟键值消息,例如:VK_F1

  lParam:

32位内存,内容描述包括:指定扩展键值,扫描码,上下文,重复次数。

7 CallNextHookEx()

Appliesto: desktopapps only

Passesthe hook information to the next hook procedure in the current hook chain. Ahook procedure can call this function either before or after processing thehook information.

适用于桌面应用程序:
钩子信息传递给下一个钩子程序,在当前的钩链。一个钩子程序可以调用这个函数之前或钩子信息处理后。

Winapi:调用下一个钩子

  CallNextHookEx(

  hhk:HHOOK; {当前钩子的句柄}

  nCode:Integer; {钩子代码; 就是给下一个钩子要交待的}

  wParam:WPARAM; {要传递的参数; 由钩子类型决定是什么参数}

  lParam:LPARAM {要传递的参数; 由钩子类型决定是什么参数}

  ):LRESULT; {会返回下一个钩子执行后的返回值; 0 表示失败}

  //参数nCode 的可选值:

  HC_ACTION= 0; {}

  HC_GETNEXT= 1; {}

  HC_SKIP= 2; {}

  HC_NOREMOVE= 3; {}

  HC_NOREM= HC_NOREMOVE; {}

  HC_SYSMODALON= 4; {}

  HC_SYSMODALOFF = 5; {}

 

8       SetWindowsHookEx()

Unicode and ANSI names

SetWindowsHookExW (Unicode) and SetWindowsHookExA (ANSI)

#ifdef UNICODE

#defineSetWindowsHookEx SetWindowsHookExW

#else

#defineSetWindowsHookEx SetWindowsHookExA

#endif// !UNICODE

 

http://edu.qudong.com/program/C/shilijiexi/20080512/11946.html

http://blog.csdn.net/djyangmaowei/article/details/4536667

HHOOK WINAPI SetWindowsHookEx(

  __inint idHook,

  __inHOOKPROC lpfn,

  __inHINSTANCE hMod,

__inDWORD dwThreadId);

 

HHOOKSetWindowsHookEx(                                   //装载一个钩子        

   int idHook,                                        //描述被装载的钩子的类型,参数见下面

   HOOKPROC lpfn,                    //钩子回调函数的地址,如果 dwThreadId 0 那么这个回调函数会在不同的进程中创建,它必须写在在DLL

   HINSTANCE hMod,                                      //DLL的句柄

   DWORD dwThreadId                                   //描述要钩住的线程ID,如果这个参数为0,则会钩住桌面上的所有线程

);    

idhook:装入钩子的类型.
lpfn: 钩子进程的入口地址
hMod: 应用程序的事件句柄
dwThreadId: 装入钩子的线程

参数:
idHook:
这个参数可以是以下值:
WH_CALLWNDPROC、WH_CALLWNDPROCRET、WH_CBT、WH_DEBUG、WH_FOREGROUNDIDLE、WH_GETMESSAGE、WH_JOURNALPLAYBACK、WH_JOURNALRECORD、WH_KEYBOARD、WH_KEYBOARD_LL、WH_MOUSE、WH_MOUSE_LL、WH_MSGFILTER、WH_SHELL、WH_SYSMSGFILTER。
对于这些参数,我不想一一加以解释,因为MSDN中有关于他们的详细注解。我只挑选其中的几个加以中文说明。 

9       clearAllHook ()清除钩子
10  HINSTANCE,HWND和ID值的用法及意义和区别

HINSTANCE;应用程序实例句柄,它是一个唯一用来标识程序进程的32位的变量, 

HWND:是窗口句柄,有很多种句柄,还有HBRUSH,HFONT,HMENU等等 
ID:是一些控件或是选项的标识符,在程序中用到对他们的操作时可以用这个ID来访问这个控件或是其他什么

HINSTANCE和HMODULE这两种类型的句柄,用法不同么?

hmodule是代表应用程序载入的模块,win32系统下通常是被载入模块的线性地址,比如exe, dll等模块等。

hinstance在win32下与hmodule是相同的东西,在win32下还存在主要是因为win16程序使用hinstance来区别task
HINSTANCE是应用程序的实例句柄  
  获取方法 HINSTANCEAfxGetInstanceHandle( );  
  或者AfxGetApp( );
  得到一个CWINAPP类的指针

11 使用DEF 文件从 DLL 导出

模块定义(.def) 文件是包含一个或多个描述DLL 各种属性的Module 语句的文本文件。如果不使用 __declspec(dllexport) 关键字导出DLL 的函数,则DLL 需要.def 文件。

.def 文件必须至少包含下列模块定义语句:

文件中的第一个语句必须是LIBRARY语句。此语句将.def 文件标识为属于DLL。LIBRARY语句的后面是DLL 的名称。链接器将此名称放到DLL 的导入库中。

EXPORTS语句列出名称,可能的话还会列出DLL 导出函数的序号值。通过在函数名的后面加上@ 符和一个数字,给函数分配序号值。当指定序号值时,序号值的范围必须是从1 到N,其中N 是DLL 导出函数的个数。如果希望按序号导出函数,请参见按序号而不是按名称从 DLL 导出函数以及本主题。

例如,包含实现二进制搜索树的代码的DLL 看上去可能像下面这样:

12 DLL 中 .DEF文件的使用

DLL中导出函数的声明有两种方式:一种为在函数声明中加上__declspec(dllexport),这里不再举例说明;另外一种方式是采用模块定义(.def) 文件声明,.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。

首先创建一个DLL程序,.cpp中

int__stdcall Add(int numa, int numb)

{

return(numa + numb);

}

 

int__stdcall Sub(int numa, int numb)

{

return(numa - numb);

}

然后创建一个.def的文件,在里面加上

;DllTestDef.lib: 导出DLL函数

;作者:----

LIBRARYDllTestDef

EXPORTS

Add@ 1

Sub@ 2

最后创建一个测试程序:.cpp文件如下:

#include<iostream>

#include<windows.h>

 

usingnamespace std;

 

typedefint (__stdcall *FUN)(int, int);

HINSTANCEhInstance;

FUN   fun;

 

intmain()

{

hInstance= LoadLibrary("DLLTestDef.dll");

if(!hInstance)

cout<<"Not Find this Dll" << endl;

fun= (FUN)GetProcAddress(hInstance, MAKEINTRESOURCE(1));

if(!fun)

       {

cout<<"not find this fun" << endl;

       }

cout<<fun(1, 2) << endl;

FreeLibrary(hInstance);

return0;

}

说明:

.def文件的规则为:

  (1)LIBRARY语句说明.def文件相应的DLL;

  (2)EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数名后加@n,表示要导出函数的序号为n(在进行函数调用时,这个序号将发挥其作用);

(3).def 文件中的注释由每个注释行开始处的分号 (;) 指定,且注释不能与语句共享一行。

13 关于什么是句柄(经典)

句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WINDOWS使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等。WINDOWS句柄有点象C语言中的文件句柄

从上面的定义中的我们可以看到,句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样,每个人都会有一个,不同的人的姓名不一样,但是,也可能有一个名字和你一样的人。从数据类型上来看它只是一个16位的无符号整数。应用程序几乎总是通过调用一个WINDOWS函数来获得一个句柄,之后其他的WINDOWS函数就可以使用该句柄,以引用相应的对象。

如果想更透彻一点地认识句柄,我可以告诉大家,句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是住留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,我们该到哪里去找该对象呢?

为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。

句柄地址(稳定)记载着对象在内存中的地址────对象在内存中的地址(不稳定)实际对象

本质:WINDOWS程序中并不是用物理地址来标识一个内存块,文件,任务或动态装入模块的,相反的,WINDOWSAPI给这些项目分配确定的句柄,并将句柄返回给应用程序,然后通过句柄来进行操作。

但是必须注意的是程序每次从新启动,系统不能保证分配给这个程序的句柄还是原来的那个句柄,而且绝大多数情况的确不一样的。假如我们把进入电影院看电影看成是一个应用程序的启动运行,那么系统给应用程序分配的句柄总是不一样,这和每次电影院售给我们的门票总是不同的一个座位是一样的道理。

受M$的帮助文档以及很多Windows编程书籍的影响,大家对局柄比较普遍的认识是:句柄是一个整数,用以标识Windows对象,句柄不是一个指针……

而实际上,这些不过是M$进行数据封装的幌子而已,下面我们一起来分析一下HANDLE到底是什么。

请先到Windef.h找绝大多数句柄的定义:

DECLARE_HANDLE(HWND);

DECLARE_HANDLE(HHOOK);

……

DECLARE_HANDLE(HGDIOBJ);

DECLARE_HANDLE(HBITMAP);

DECLARE_HANDLE(HBRUSH);

……

typedef HANDLE         HGLOBAL;

typedefHANDLE          HLOCAL;

……

OK, 现在大家跟我一起翻到Winnt.h,看看DECLARE_HANDLE和HANDLE到底是什么:

#ifdef STRICT

typedef void *HANDLE;

#define DECLARE_HANDLE(name) structname##__ { int unused; }; typedef struct name##__ *name

#else

typedef PVOID HANDLE;

#define DECLARE_HANDLE(name) typedefHANDLE name

#endif

typedef HANDLE *PHANDLE;

哈哈,现在知道了吧,HANDLE就是PVOID,也就是无类型指针,

而DECLARE_HANDLE(HWND);就是:

struct HWND__ {

   int unused;};

typedef struct HWND__ *HWND;

现在实际上都清楚啦,这些Handles都不过是指向struct的指针,至于这个struct的用处,连M$都说unused了,^o^

现在解释下M$这么做的意义,这就是所谓数据封装,你可以在你的程序中把M$的内部结构指针传来传去,可是你却不知道它到底指向的内容是什么,而且可以编个句柄的瞎话防止大家的质疑:)。而M$的程序大可以这么写:

#include <windows.h> //这个和大家用的一样

#include "windows_in.h" //这个是M$自用的,外人别想看到^o^

HSOMETHINGELSE DoSomething(HSOMETHINGhSomething) {

   struct RealSomething* p =(struct RealSomething*)hSomething; //先强制类型转换成内部结构指针

   ……do something……

   return(HSOMETHINGELSE)pRealSomethingElse;//强制类型逆转换

14  WH_GETMESSAGE和WH_CALLWNDPROC这两个钩子的区别
首先
1.WH_GETMESSAGE专门勾的是通过postmessage发送到目标程序的消息。
2.WH_CALLWNDPROC则是勾的sendmessage发送到目标程序的消息。
3.postmessage 是将消息寄送到消息队列而不管其是否返回,sendmessage则是将消息发送到目标程序并等待返回。
4.最重要一点也是我犯错的地方,WH_GETMESSAGE中的lparam指向的是一个MSG结构体。
WH_CALLWNDPROC中的lparam指向的则是CWPSTRUCT结构体!如果再写回调函数的时候结构体弄错了那可就什么消息都截获不到了因为你要截获的消息根本就没有存在在这个结构体中。

15 HC_ACTION  0

ThelParam parameter is apointer to an EVENTMSG structure containing information about a messageremoved from the system queue. The hook procedure must record the contents ofthe structure by copying them to a buffer or file.

lParam参数是一个指针一个EVENTMSG结构包含从系统队列中删除消息的信息。钩子过程必须记录复制到一个缓冲区或文件的内容结构。

16 回调函数 

使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。 

17 VC++加载动态库和静态库

一. 静态库包括.lib和.h文件,在工程中使用静态库分为3步:

<1>在工程中加入静态库,有两种方法:

**方法一:项目设置中引用.lib,project-> setting->link-> object/library modules中添加.lib;(需要在tools/options/Directories设置正确的引用路径)

**方法二:在项目中直接加入lib,project-> add to project->files,选择正确的.lib。

<2>在工程中包括.h文件;(可能需要在tools/options设置正确的引用路径)

<3>在工程中使用静态库中的函数;

二. 动态链接库一般包括.lib(导出函数),.h,.dll文件,使用动态库有两种情况:

a.隐式链接,同使用静态库相似,分为三步:引用.lib(#pragmacomment(lib, "##/##/mine.lib")或者项目设置中引用.lib,project-> setting->link-> object/library modules中添加.lib),包含头文件,使用导出函数;

b.动态加载,直接使用LoadLibrary 加载所需的动态库,然后指定所需的导出函数,效率最高!

三.关于lib文件:

开发DLL的时候,就会生成两个文件:LIB静态库文件(接口文件)、DLL动态库文件(程序文件).

LIB是提供DLL接口的文件,供编译器使用.

#pragmacomment(lib, "##/##/mine.lib")
是使本工程加入mine.dll动态链表库的接口库文件,让本工程可以使用mine.dll中的函数

Windows用来定位 DLL 的搜索路径

通过隐式和显式链接,Windows 首先搜索“已知 DLL”,如 Kernel32.dll 和 User32.dll。Windows 然后按下列顺序搜索 DLL: 
1. 当前进程的可执行模块所在的目录(包含 EXE 文件的目录)。 
2. 当前目录(进程的当前工作目录)。 
3. Windows 系统目录。GetSystemDirectory 函数检索此目录的路径。 
4. Windows 目录。GetWindowsDirectory 函数检索此目录的路径。 
5. PATH 环境变量中列出的目录。

18 Win32 多线程程序设计(线程完全手册)

Threads(线程)是比processes进程更小的执行单元,CPU的调度与时间分配皆以threads为对象。

19  消息钩子

钩子是WINDOWS中消息处理机制的一个要点,通过安装各种钩子,应用程序能够设置相应的子例程来监视系统里的消息传递以及在这些消息到达目标窗口程序之前处理它们。钩子的种类很多,每种钩子可以截获并处理相应的消息,如键盘钩子可以截获键盘消息,鼠标钩子可以截获鼠标消息,外壳钩子可以截获启动和关闭应用程序的消息,日志钩子可以监视和记录输入事件。

若在dll中使用SetWindowsHookEx设置一全局钩子,系统会将其加载入使用user32的进程中,因而它也可被利用为无进程木马的进程注入手段。

20 wParamlParam用法总结: 

使用LPARAM传递地址,而WPARAM传递其他参数。

lp一般指指针


wparam
的定义:
typedef unsigned int  UINT;
typedef UINT WPARAM;


lparam
的定义
typedef long LONG;
typedef LONG LPARAM;

1. WM_PAINT
消息,LOWORD(lParam)是客户区的宽,HIWORD(lParam)是客户区的高
2.
滚动条WM_VSCROLLWM_HSCROLL消息,LOWORD(wParam)指出了鼠标对滚动条的操作。比如上、下、左、右、翻页、移动等。
3.
击键消息,有WM_SYSKEYDOWNWM_SYSKEYUPWM_KEYUPWM_KEYDOWN,其中wParam是虚拟键代码,lParam是包含属于击键的其他信息。lParam消息参数分为6个域,有重复计数、环境代码、键的先前状态等。
4.
字符消息WM_CHARWM_DEADCHARWM_SYSCHARWM_SYSDEADCHARlParam消息参数跟击键消息的lParam消息参数内容相同,wParam参数是ANSIUnicode字符代码
5.
客户区鼠标消息WM_LBUTTONDOWNWM_LBUTTONUPWM_RBUTTONDOWNWM_RBUTTONUP WM_MBUTTONDOWNWM_MBUTTONUP,lParam参数的低位是鼠标的客户区x坐标,高位是客户区y坐标。wParam参数是指示鼠标键及ShiftCtrl键的状态。wParam&MK_SHIFTMK_CTRL,如果返回TRUE就意味着有按下ShiftCtrl键。
6.
非客户区消息,wParam参数指明移动或者单击鼠标键的非客户区位置,以HT开头,lParam参数低位指出了鼠标所在屏幕坐标的x坐标,高位指出了鼠标所在屏幕坐标的y坐标。
7.
鼠标轮滚动消息,WM_MOUSEWHEEL消息,lParam将获得鼠标的屏幕位置(坐标),wParam参数的低位表明鼠标键和ShiftCtrl键的状态。wParam高位有一个“delta”值,该值可正可负,指出了滚轮导致屏幕滚动几行,120表示向上3行。
8.
计时器消息WM_TIMERwParam参数等于计时器的ID值,lParam0
9.
按钮子窗口的WM_COMMAND消息,wParam参数的低位是子窗口ID,高位是通知码, lParam参数是接收消息的子窗口的句柄。
10.
焦点消息,对于正在失去焦点的窗口,会收到WM_KILLFOCUS消息,其wParam参数是即将接收输入焦点的窗口的句柄。对于即将获取焦点的窗口,会收到WM_SETFOCUS消息,其wParam参数是正在失去焦点的窗口的句柄。
11.
编辑控制的WM_COMMAND消息,wParam参数的低位是子窗口ID,高位是通知码, lParam参数是子窗口句柄。
12.
列表框的WM_COMMAND消息,wParam参数的低位是子窗口ID,高位是通知码, lParam参数是子窗口句柄。
13.
菜单消息1WM_INITMENUwParam是主菜单句柄,lParam0.
14.
菜单消息2WM_MENUSELECT,菜单跟踪消息,指针移到菜单的某一些,就会发送这个消息给窗口过程,其wParam参数的低位是选中项菜单的 ID或者弹出式菜单的句柄,高位是选择标识,lParam参数是包含选中项的菜单句柄。
15.
菜单消息3WM_INITMENUPOPUP,准备显示一个弹出式菜单时产生的消息,wParam参数是弹出式菜单的句柄,lParam的低位是弹出式菜单的索引,如果该菜单是系统菜单,那么高位是1,否则为0.
16.
菜单消息4WM_COMMAND,选中菜单后产生,wParam低位是击中菜单的ID,高位是0lParam参数也是0.
17.
菜单消息5WM_SYSCOMMAND,表示用户从系统菜单中选择一个启用的菜单项,其wParam参数是菜单的ID lParam0.如果该消息是由按鼠标产生的,那么lParam参数是鼠标的屏幕坐标。
18.
加速键消息,WM_COMMAND消息,wParam低位是加速键ID,高位是1 lParam0.
19.
控制项着色消息,WM_CTLCOLORBTN消息,wParam是按钮的设备描述表句柄,lParam是按钮的窗口句柄.

22  GetModuleFileName

得到全路径
TCHAR exeFullPath[MAX_PATH]; // MAX_PATH
GetModuleFileName(NULL,exeFullPath,MAX_PATH);//得到程序模块名称,全路径
也就是当前运行程序的全路径
利用方法一的解析路径的方法,即可得到程序所在路径。

GetModuleFileName函数原型
DWORD GetModuleFileName(
   HMODULE hModule,     // handle to module。将要得到的模块的句柄。如果是当前模块,NULL
   LPTSTR lpFilename,   // path buffer   得到的文件名。
   DWORD nSize         // size of buffer   一般MAX_PATH就可以了

原创粉丝点击