"钩子"敲门砖

对钩子的理解

说起钩子,很多人都想起它的形状,根据形状去想象windows的钩子,会陷入误区。Windows的钩子,是没有形状的,之所以叫钩子,并不是说它的形状象钩子,而是它的作用和钩子一样:就是用来“挂靠”的。比如有个包工头想去接个项目,但是他没有公司,拿不出相关的证件,怎么办呢?那就得找个公司挂靠,成立个子公司(subclass技术)之类,让那个公司帮他出资源,出相关的证件之类......windows的钩子和这很相似。比如我们常常想访问另一个进程的一些资源(常见的获取编辑框的密码),怎么办呢?用钩子来做挂靠,成为另一个进程的一个分子,那样你就可以在一定规则下(挂靠的当然都会有限制了)访问、控制该进程的资源了。钩子不但可以挂靠别的进程,本进程也可以用钩子去“挂靠”和控制。

 

有关钩子的API

(有关API的更详细和权威的介绍,请参考MSDN

1、安装钩子的APISetWindowsHookEx(),要使用钩子,首先得安装钩子。任何一个钩子都由系统来维护一个指针列表(钩子链表),其指针指向钩子的各个处理函数。最近安装的钩子放在链的开始,最早安装的钩子则放在最后,当钩子监视的消息出现时,操作系统调用链表开始处的第一个钩子处理函数进行处理,也就是说最后加入的钩子优先获得控制权。呵呵,最后这句话就是提示我们怎么反钩子的。

 

HHOOK SetWindowsHookEx(int idHook,

HOOKPROC lpfn,

HINSTANCE hMod,

DWORD dwThreadId)

 

其中:参数idHook 指定了钩子的类型,总共有如下13种:

WH_CALLWNDPROC 系统将消息发送到指定窗口之前的"钩子"

WH_CALLWNDPROCRET 消息已经在窗口中处理的"钩子"

WH_CBT 基于计算机培训的"钩子"

WH_DEBUG 差错"钩子"

WH_FOREGROUNDIDLE 前台空闲窗口"钩子"

WH_GETMESSAGE 接收消息投递的"钩子"

WH_JOURNALPLAYBACK 回放以前通过WH_JOURNALRECORD"钩子"记录的输入消息

WH_JOURNALRECORD 输入消息记录"钩子"

WH_KEYBOARD 键盘消息"钩子"

WH_MOUSE 鼠标消息"钩子"

WH_MSGFILTER 对话框、消息框、菜单或滚动条输入消息"钩子"

WH_SHELL 外壳"钩子"

WH_SYSMSGFILTER 系统消息"钩子"

       这样,你就可以用各种各样的钩子去做挂靠访问了,比如你可以用鱼勾去钓鱼,用衣服钩子去钩衣服,但不要用错……

参数lpfn为指向钩子处理函数的指针,即回调函数的首地址;参数hMod则标识了钩子处理函数所处模块的句柄;第四个参数dwThreadId 指定被监视的线程,如果明确指定了某个线程的ID就只监视该线程,此时的钩子即为线程钩子;如果该参数被设置为0,则表示此钩子为监视系统所有线程的全局钩子。此函数在执行完后将返回一个钩子句柄。

对于全局钩子,要使用动态连接库来实现,因为你的钩子需要被其他进程和系统调用,如果放在你的进程中,估计别的进程也得产生个钩子来访问你的钩子了J,对于一些线程钩子,虽然不是全局钩子,建议也使用动态连接库。

2、传递钩子的APICallNextHookEx( )。在安装钩子以后,钩子会对相关的资源进行访问控制,如果希望自己处理完相应的事物后,将系统交还给系统和原来的进程,就需要调用CallNextHookEx( )。一些反钩子的代码常常不调用该函数,这样外挂程序安装的钩子就不会被运行。

 

LRESULT CallNextHookEx(HHOOK hhk,int nCode,WPARAM wParam,LPARAM lParam);

 

其中,参数hhk为由SetWindowsHookEx()函数返回的当前钩子句柄;参数nCode为传给钩子过程的事件代码;参数wParamlParam 则为传给钩子处理函数的参数值,其具体含义同设置的钩子类型有关。

3、卸载钩子的APISetWindowsHookEx()。由于钩子对系统的性能有影响,在安装使用完钩子以后,就需要把钩子卸载。

 

BOOL UnhookWindowsHookEx(HHOOK hhk);

 

其中hhk是使用SetWindowsHookEx()安装钩子时产生的返回值。

 

注意:windows的钩子为了提高系统的性能,采用了“copy-on-write”的技术,在SetWindowsHookEx()调用后并不马上安装钩子。比如在设置WH_CALLWNDPROC钩子时,钩子并不马上生效,而要在系统将消息发送到指定窗口的时候才会正式安装钩子,才会把钩子挂靠在进程内(实际上不只是挂靠钩子过程,还会把整个dll影射到进程内),才能访问进程的资源,否则是个假钩子,徒有虚名而已。

 

钩子的简单应用

这个例子不是我写的,在网上找的,是个键盘钩子。通过这个例子可以对钩子和钩子的有关API有比较深刻的认识。原来的连接在http://www.pconline.com.cn/pcedu/empolder/gj/vc/0403/340480.html可以找到,但是代码编译有问题。我作了些修改。

附代码如下:

 

// test.cpp : Defines the entry point for the console application.

//

#include "stdafx.h"

#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

 

DWORD   g_main_tid  = 0;

HHOOK   g_kb_hook   = 0;

#define _WIN32_WINNT    0x0400

 

BOOL CALLBACK con_handler (DWORD)

{

 

     PostThreadMessage (g_main_tid, WM_QUIT, 0, 0);

     return TRUE;

 

};

//--add by pdg

#define WH_KEYBOARD_LL     13

typedef struct tagKBDLLHOOKSTRUCT {

     DWORD   vkCode;

     DWORD   scanCode;

     DWORD   flags;

     DWORD   tim e;

     ULONG_PTR dwExtraInfo;

} KBDLLHOOKSTRUCT, FAR *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

//--add by pdg ,由于编译时认不到这两个定义,因此此次重新做了定义

LRESULT CALLBACK kb_proc (int code, WPARAM w, LPARAM l)

{

     PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)l;

     const char *info = NULL;

     if (w == WM_KEYDOWN)

         info = "key dn";

     else if (w == WM_KEYUP)

         info = "key up";

     else if (w == WM_SYSKEYDOWN)

         info = "sys key dn";

     else if (w == WM_SYSKEYUP)

         info = "sys key up";

 

     printf ("%s - vkCode [%04x], scanCode [%04x]/n",

         info, p->vkCode, p->scanCode);

 

     //  always call next hook

     return CallNextHookEx (g_kb_hook, code, w, l);

};

 

 

int _tmain(int argc, _TCHAR* argv[])

{

     g_main_tid = GetCurrentThreadId ();

     SetConsoleCtrlHandler (&con_handler, TRUE);

     g_kb_hook = SetWindowsHookEx (

         WH_KEYBOARD_LL,

         &kb_proc,

         GetModuleHandle (NULL), // 不能为NULL,否则失败

         0);

 

     if (g_kb_hook == NULL)

     {

         fprintf (stderr,

              "SetWindowsHookEx failed with error %d/n",

              ::GetLastError ());

         return 0;

     };

     //  消息循环是必须的,想知道原因可以查msdn

     MSG msg;

 

     while (GetMessage (&msg, NULL, 0, 0))

     {

         TranslateMessage (&msg);

         DispatchMessage (&msg);

     };

     UnhookWindowsHookEx (g_kb_hook);

     return 0;

}

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值