什么是HOOK呢?其实很简单,HOOK就是对Windows消息进行拦截检查处理的一个函数。在Windows的消息机制中,当用户产生消息时,应用程序通过调用GetMessage函数取出消息,然后把消息放入到消息队列,再使用消息调度函数DispatchMessage函数讲消息调度给系统,Windows系统会调用创建窗口类时制定的窗口过程中进行次消息的处理。而HOOK函数的话,就可以对此消息进行拦截。经过此HOOK函数的处理后,再决定是屏蔽掉此消息,还是继续往下传递。至于为什么叫“钩子”,可能就是因为它可以像钩子一样把消息给钩住。话说四川话里面的“钩子”却是屁股的意思...哈哈,四川的同学读钩子肯定多了几份趣味

  钩子函数的实现分为以下步骤:

  1 安装钩子函数

  安装钩子函数是通过函数SetWindowHookEx来实现的:

  

HHOOK WINAPI SetWindowsHookExW(__in int idHook,  __in HOOKPROC lpfn,__in_opt HINSTANCE hmod,  __in DWORD dwThreadId);

  此函数的第一个参数idHook指定将要安装的钩子过程的类型,如果我们安装键盘钩子,则设为WH_KEYBOARD,鼠标钩子则设为WH_MOUSE。 lpfn指向了相应的钩子函数,如果dwThreadId为0,或者指定了一个其他进程创建的线程之标识符,则lpfn必须指向一个位于某动态链接库中的钩子函数。如果为进程外钩子,hMod指向的是钩子函数所在的DLL的句柄,如果为进程内钩子,则设为NULL。dwThreadId指定与钩子过程相关的线程表示,为0表示与所有线程相关。函数成功返回所安装的钩子函数的句柄,否则返回NULL。PS:最后安装的钩子函数总是排在钩子链的最前面。

  

  2 添加全局变量

HHOOK g_hMouse = NULL;
HHOOK g_hKeyboard = NULL;
HWND g_hWnd = NULL;

全局句柄g_hMouse、g_hKeyboard分别代表我们所要安装的鼠标钩子和键盘钩子过程的句柄,g_hWnd用来保存当前的窗口句柄。

  3 声明钩子函数

  如果想要监视鼠标消息,需要定义相应的鼠标钩子过程。同样,要监视键盘消息,也需要定义相应的键盘钩子过程。该钩子函数的形式必须如下:

LRESULT CALLBACK  HookProc(int nCode, WPARAM wParam, LPARAM lParam);

  在当前钩子函数中处理完信息后,如果想把信息继续传递给下一个钩子函数,可以调用CallNextHookEx函数来实现:

LRESULT
WINAPI CallNextHookEx( __in_opt HHOOK hhk, __in int nCode, __in WPARAM wParam, __in LPARAM lParam

  CallNextHookEx函数的第一个参数是钩子的句柄,就是我们调用SetWindowHookEx函数返回的句柄,其他几个参数和HookProc中是一样的。

  4 卸载钩子函数

  当我们不需要再使用钩子函数的时候,可以将其卸载,调用函数:

  

BOOL WINAPI UnhookWindowsHookEx(  __in HHOOK hhk);

  函数的唯一参数便为钩子函数的句柄。

  说一千道一万,不如一个程序来的实在。下面便是一个实现进程内钩子函数的MFC例子。步骤如下:

  1 新建一个名字CInnerHookDlg的MFC工程。

  2 在CInnerHookDlgDlg.cpp中添加钩子的全局变量和当前句柄

  

HHOOK g_hMouse = NULL;
HHOOK g_hKeyboard = NULL;
HWND g_hWnd = NULL;

  3 然后再分别实现键盘和鼠标钩子函数,我们在键盘钩子函数中显示出当前按下去的键盘。而在鼠标钩子函数中,当我们双击右键时候,会显示出对话框。

//鼠标钩子函数
LRESULT CALLBACK MouseProc( int nCode, WPARAM wParam, LPARAM lParam )
{
...
} //键盘钩子函数
LRESULT CALLBACK KeyBoardProc( int nCode, WPARAM wParam, LPARAM lParam )
{
...
}

  4 在CCInnerHookDlgDlg的OnInitDialog()中设置钩子,添加如下代码

  

//设置鼠标钩子
g_hMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, NULL,GetCurrentThreadId()); //设置键盘钩子
g_hKeyboard = SetWindowsHookEx(WH_KEYBOARD, KeyBoardProc, NULL, GetCurrentThreadId()); //获取当前句柄
g_hWnd = m_hWnd;

  5 最后在CCInnerHookDlgDlg的OnSysCommand()中卸载钩子,添加如下代码:

UnhookWindowsHookEx(g_hMouse);
UnhookWindowsHookEx(g_hKeyboard);

  下面是所有的代码啦!

// CInnerHookDlgDlg.cpp : 实现文件
// #include "stdafx.h"
#include "CInnerHookDlg.h"
#include "CInnerHookDlgDlg.h" #ifdef _DEBUG
#define new DEBUG_NEW
#endif HHOOK g_hMouse = NULL;
HHOOK g_hKeyboard = NULL;
HWND g_hWnd = NULL; // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialog
{
public:
CAboutDlg(); // 对话框数据
enum { IDD = IDD_ABOUTBOX }; protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现
protected:
DECLARE_MESSAGE_MAP()
}; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
} void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
} BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP() // CCInnerHookDlgDlg 对话框
CCInnerHookDlgDlg::CCInnerHookDlgDlg(CWnd* pParent /*=NULL*/)
: CDialog(CCInnerHookDlgDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
} void CCInnerHookDlgDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
} BEGIN_MESSAGE_MAP(CCInnerHookDlgDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
END_MESSAGE_MAP() //鼠标钩子函数
LRESULT CALLBACK MouseProc( int nCode, WPARAM wParam, LPARAM lParam )
{
LPMOUSEHOOKSTRUCT pMouseHook = (MOUSEHOOKSTRUCT*)(lParam); if (nCode >= 0)
{
//双击右键弹出当前窗口的窗口名
if (wParam == WM_RBUTTONDBLCLK)
{
HWND hWnd = pMouseHook->hwnd; //鼠标所在的窗口
HWND hParent; //获取顶层窗口
while(hWnd != NULL)
{
hParent = GetParent(hWnd);
if (hParent == NULL)
break;
hWnd = hParent;
} if (hWnd != NULL)
{
//得到窗口名
TCHAR strDlgName[MAX_PATH] = {0};
GetWindowText(hWnd,strDlgName, MAX_PATH);
AfxMessageBox( strDlgName );
}
}
} return CallNextHookEx(g_hMouse,nCode, wParam, lParam);
} //键盘钩子函数
LRESULT CALLBACK KeyBoardProc( int nCode, WPARAM wParam, LPARAM lParam )
{
LRESULT lReturnValue;
lReturnValue = CallNextHookEx(g_hKeyboard, nCode, wParam, lParam); //键盘按键是否已经松动
if ( (lParam & 0x80000000) && (HC_ACTION == nCode))
{
char c = (char) lParam;
CString strText(_T("按下了键"));
strText += c;
AfxMessageBox(strText); //显示当前的按键
} //如果按下F4,则退出程序
if (wParam == VK_F4)
{
SendMessage(g_hWnd, WM_CLOSE,0,0);
} return lReturnValue;
} // CCInnerHookDlgDlg 消息处理程序 BOOL CCInnerHookDlgDlg::OnInitDialog()
{
CDialog::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
} // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 //设置鼠标钩子
g_hMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, NULL,GetCurrentThreadId()); //设置键盘钩子
g_hKeyboard = SetWindowsHookEx(WH_KEYBOARD, KeyBoardProc, NULL, GetCurrentThreadId()); //获取当前句柄
g_hWnd = m_hWnd; return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CCInnerHookDlgDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
} UnhookWindowsHookEx(g_hMouse);
UnhookWindowsHookEx(g_hKeyboard);
} // 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。 void CCInnerHookDlgDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), ); // 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + ) / ;
int y = (rect.Height() - cyIcon + ) / ; // 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
} //当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CCInnerHookDlgDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}

  

    

HOOK函数(一)——进程内HOOK的更多相关文章

  1. 钩子编程(HOOK) 安装进程内键盘钩子 (1)

    摘要:钩子能够监视系统或进程中的各种事件消息.截获发往目标窗体的消息并进行处理.这样,我们就能够在系统中安装自己定义的钩子,监视系统中特定事件的发生.完毕特定的功能,比方截获键盘.鼠标的输入.屏幕取词 ...

  2. Linux进程内消息总线设计

    文章目录 Windows平台进程内消息总线 如果没有消息总线,会产生什么问题 死循环包含关系 高耦合.低内聚 消息总线 结构图 原理 生产者与总线的关系 总线与消费者的关系 Linux进程内消息总线设 ...

  3. [Hook] 免root,自己进程内,startActivity hook的几种姿势

    首先关于startActivity 我们平时会经常使用到 在activity内 直接startActivity(intent) 其实这里还有一种start方式 我们可能没怎么用过 getApplica ...

  4. ZeroMQ接口函数之 :zmq_inproc – ØMQ 本地进程内(线程间)传输方式

    ZeroMQ API 目录 :http://www.cnblogs.com/fengbohello/p/4230135.html ——————————————————————————————————— ...

  5. 利用Objective-C运行时hook函数的三种方法

    版权声明:转载请注明出处:http://blog.csdn.net/hursing 方法一,hook已有公开头文件的类: 首先写一个Utility函数: #import <objc/runtim ...

  6. [PyTorch 学习笔记] 5.2 Hook 函数与 CAM 算法

    本章代码: https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson5/hook_fmap_vis.py https://gi ...

  7. HOOK API (一)——HOOK基础+一个鼠标钩子实例

    HOOK API (一)——HOOK基础+一个鼠标钩子实例 0x00 起因 最近在做毕业设计,有一个功能是需要实现对剪切板的监控和进程的防终止保护.原本想从内核层实现,但没有头绪.最后决定从调用层入手 ...

  8. HOOK API(三)—— HOOK 所有程序的 MessageBox

    HOOK API(三) —— HOOK 所有程序的 MessageBox 0x00 前言 本实例要实现HOOK MessageBox,包括MessageBoxA和MessageBoxW,其实现细节与H ...

  9. HOOK API(二)—— HOOK自己程序的 MessageBox

    HOOK API(二) —— HOOK自己程序的 MessageBox 0x00 前言 以下将给出一个简单的例子,作为HOOK API的入门.这里是HOOK 自己程序的MessageBox,即将自己程 ...

随机推荐

  1. Setting Up the ADT Bundle

    Setting Up the ADT Bundle The ADT Bundle provides everything you need to start developing apps, incl ...

  2. SR4000自带软件修改(二)

    /*----------------------------------------------------------------------------- *   *   版权声明: *   可以 ...

  3. NOIP2000 进制转换

    题一   进制转换              (18分)  问题描述      我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减1)为指数,以10为底数的幂之 ...

  4. iOS开发——View的透明属性hidden、alpha、opaque

    Hidden.Alpha.Opaque的区别 在iOS中,每个View都有Hidden.Alpha.Opaque三个关于透明的属性,官方文档介绍如下: 1. @property(nonatomic) ...

  5. Azure VM对远程桌面登录的支持-示例

    我们在开发Windows Azure的应用程序,虽然在大部分的情况下都可以使用Azure Emulator模拟器来模拟在云端计算节点(Azure VM)的执行结果,但是并不能100%模拟真正在Azur ...

  6. java项目中eclipse控制台输出log4j的信息

    最近做的一个hadoop项目中,用MR实现了一个比较复杂的问题,其中的日志信息都是使用的是log4j来处理的.但不知怎么控制台不输出日志信息,只能输出System.out.println()信息,这个 ...

  7. python —print

    今天开始学python了,“装X”安装了最新版本python 3.4.1 然后,print “hello world!" 就出错了... 一搜原来... python v3.0以后的版本pr ...

  8. 教程-Delphi 调用控制面板设置功能

    应用程序运行时,有时需要对系统环境有特殊要求.例如,在Delphi数据库应用程序中可能需要进行BDE(Borland Database Engine)或ODBC数据源名称(DSN:Data Sourc ...

  9. STM32F103 与 STM32F407引脚兼容问题

    ===========突袭网收集的解决方案如下=========== 解决方案1: STM32F103有的功能407都有,并且这些功能的引脚完全兼容,只是程序不同而已...而STM32F407有的功能 ...

  10. Android:从程序员到架构师之路Ⅰ

    一般而言,人们大多先学开发(代码)的技术,随后才学(架构)设计的方法.然而,在实际做事时,却是先设计,随后才写出代码来.敏捷过程则让设计与写码迭代循环下去,一直到完成为止.在本课程里,就遵循敏捷的迭代 ...