关于hook!

wushunhui 2002-05-31 12:24:11
小弟至今未能理解hook有什么用途,谁能给我一点信息,有哪方面的书籍啊?
...全文
43 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
brapler 2002-05-31
  • 打赏
  • 举报
回复
hook是用来分流消息到特定的处理过程的,看操作系统方面的书.
Badwood 2002-05-31
  • 打赏
  • 举报
回复
既生瑜何生亮
bright5 2002-05-31
  • 打赏
  • 举报
回复
怎样编写一个全局勾子勾住系统中的API ?
这里有两个函数,是用来勾住DLL中函数的,可以参照一下,只要把函数名换一下即可。bool HookFunc (BYTE* pbCodeBuffer, DWORD& dwBufLen)
{
// ole libraries probably have been initialized, just get the handle
HMODULE hModule = GetModuleHandle (_T ("ds_avc.dll"));
if (hModule == NULL)
{
hModule = LoadLibrary (_T ("ds_avc.dll"));
}

// get address of the original CLSIDFromProgID
PVOID pfnOrg = (PVOID) GetProcAddress (hModule, "AvcCmdSetStreamState");

HANDLE hProcess = GetCurrentProcess ();

DWORD dwRead = 0;

// calculate offset from the original procedure to our;
// it doesn't matter the base address of our DLL, since "CPU" jumps always forward;
// notice dwJmpInstructionLen - the offset is calculated from next instruction
DWORD dwHookOffest = (DWORD)FuncProc -
((DWORD) pfnOrg + 5);//dwJmpInstructionLen);

if (!ReadProcessMemory (hProcess,
pfnOrg,
pbCodeBuffer,
dwJmpInstructionLen,
&dwRead))
{
// should be zero in this case
dwBufLen = 0;
return false;
}

// will be used to restore the original code during UnHook
dwBufLen = dwRead;

DWORD dwWritten = 0;

// write the jmp instruction. NT will perform copy-on-write, therefore no
// process will be affected by the change

if (!WriteProcessMemory (hProcess,
pfnOrg, // write at start of CLSIDFromProgID
(LPVOID) &bJmpCode, // jmp code 0xE9
sizeof (bJmpCode),
&dwWritten) && dwWritten != 0)
{
return false;
}

dwWritten = 0;
// write the offset to CLSIDProgIDProc
return (WriteProcessMemory (hProcess,
(LPVOID)((DWORD) pfnOrg + 1), // from the next byte
&dwHookOffest, // offset calculated before
sizeof (DWORD), &dwWritten) &&
dwWritten != 0);
}

bool HookFunc2 (BYTE* pbCodeBuffer, DWORD& dwBufLen)
{
// ole libraries probably have been initialized, just get the handle
HMODULE hModule = GetModuleHandle (_T ("ds_avc.dll"));
if (hModule == NULL)
{
hModule = LoadLibrary (_T ("ds_avc.dll"));
}

// get address of the original CLSIDFromProgID
PVOID pfnOrg = (PVOID) GetProcAddress (hModule, "AvcCmdGetVideoInputLumaSatGainThresh");

HANDLE hProcess = GetCurrentProcess ();

DWORD dwRead = 0;

// calculate offset from the original procedure to our;
// it doesn't matter the base address of our DLL, since "CPU" jumps always forward;
// notice dwJmpInstructionLen - the offset is calculated from next instruction
DWORD dwHookOffest = (DWORD)FuncProc2 -
((DWORD) pfnOrg + 5);//dwJmpInstructionLen);

if (!ReadProcessMemory (hProcess,
pfnOrg,
pbCodeBuffer,
dwJmpInstructionLen,
&dwRead))
{
// should be zero in this case
dwBufLen = 0;
return false;
}

// will be used to restore the original code during UnHook
dwBufLen = dwRead;

DWORD dwWritten = 0;

// write the jmp instruction. NT will perform copy-on-write, therefore no
// process will be affected by the change

if (!WriteProcessMemory (hProcess,
pfnOrg, // write at start of CLSIDFromProgID
(LPVOID) &bJmpCode, // jmp code 0xE9
sizeof (bJmpCode),
&dwWritten) && dwWritten != 0)
{
return false;
}

dwWritten = 0;
// write the offset to CLSIDProgIDProc
return (WriteProcessMemory (hProcess,
(LPVOID)((DWORD) pfnOrg + 1), // from the next byte
&dwHookOffest, // offset calculated before
sizeof (DWORD), &dwWritten) &&
dwWritten != 0);
}

// restore the previously saved code
void UnHookFunc (BYTE* pbCodeBuffer, DWORD dwBufLen)
{
HMODULE hModule = GetModuleHandle (_T ("ds_avc.dll"));
if (hModule != NULL)
{
// the ole32.DLL must be in memory
// get address of the original CLSIDFromProgID
PVOID pfnOrg = (PVOID) GetProcAddress (hModule, "AvcCmdSetStreamState");

HANDLE hProcess = GetCurrentProcess ();

DWORD dwWritten = 0;
WriteProcessMemory (hProcess,
pfnOrg,
pbCodeBuffer,
dwBufLen,
&dwWritten);

}
}

//-----------------------------------------------------------------------------------//
// the actual hook code
//-----------------------------------------------------------------------------------//

UINT _cdecl FuncProc (PVOID,PVOID, UINT state,UINT options)
{

TRACE("state options :0x%x,0x%x\n",state,options);

return options;
}
UINT _cdecl FuncProc2 (PVOID, UINT *gain)
{

TRACE("FuncProc2\n");
*gain = 0;

return 0;
}


bright5 2002-05-31
  • 打赏
  • 举报
回复
一些相关资料,千万不要头晕

Q:如何在WIN98下锁住鼠标和键盘。
A:贴一篇关于钩子的文章(转载):

WINDOWS键盘事件的挂钩监控原理及其应用技术

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

一、在WINDOWS键盘事件上挂接监控函数的方法

WINDOW下可进行挂接的过滤函数包括11种:
H_CALLWNDPROC 窗口函数的过滤函数
H_CBT 计算机培训过滤函数
H_DEBUG 调试过滤函数
H_GETMESSAGE 获取消息过滤函数
H_HARDWARE 硬件消息过滤函数
H_JOURNALPLAYBACK 消息重放过滤函数
H_JOURNALRECORD 消息记录过滤函数
H_MOUSE 鼠标过滤函数
H_MSGFILTER 消息过滤函数
H_SYSMSGFILTER 系统消息过滤函数
H_KEYBOARD 键盘过滤函数

键盘过滤函数是最常用最有用的过滤函数类型,不管是哪一种类型的过滤函数,其挂接的基本方法都是相同的。WINDOW调用挂接的反调函数时总是先调用挂接链首的那个函数,因此必须将键盘挂钩函数利用函数SetWindowsHookEx()将其挂接在函数链首。至于消息是否传递给函数链的下一个函数是由每个具体函数功能确定的,如果消息需要传统给下一个函数,可调用API函数的CallNextHookEx()来实现,如果不传递直接返回即可。挂接函数可以是用来监控所有线程消息的全局性函数,也可以是单独监控某一线程的局部性函数。如果挂接函数是局部函数,可以将它放到一个.DLL动态链接库中,也可以放在一个局部模块中;如果挂接函数是全局的,那么必须将其放在一个.DLL动态链接库中。挂接函数必须严格按照下述格式进行声明,以键盘挂钩函数为例:
nt FAR PASCAL KeyboardProc(
nt nCode,WORD wParam,DWORD lParam)
中KeyboardProc为定义挂接函数名,该函数必须在模块定义文件中利用EXPORTS命令进行说明;nCode决定挂接函数是否对当前消息进行处理;wParam和lParam为具体的消息内容。

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

程序中可以利用函数SetWindowsHookEx()来挂接过滤函数,在挂接函数时必须指出该挂接函数的类型、函数的入口地址以及函数是全局性的还是局部性的,挂接函数的具体调用格式如下:
etWindowsHookEx(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、利用本文提供的方法设置自己的应用程序功能按键,在保证程序功能按键不会与其它系统发生冲突的同时,有效地利用了系统中现有资源,而且在实现应用程序功能的同时灵活应用了系统中提供的各种功能调用。

16,467

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧