什么是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. 查询显示MSSQL表结构 [转]

    SELECT 表名 = Case When A.colorder= Then D.name Else '' End, 表说明 = Case When A.colorder= Then isnull(F ...

  2. 关于NSLocalizedString(@"Foo %@",nil)

    NSLocalizedString(@"Foo %@",nil) 这句话实际上是在多语言文件中寻找一个key为“Foo %@”的文字,千万不要把这个和[NSString strin ...

  3. JDK1.5新特性(三)……Varargs

    援引 Varargs - This facility eliminates the need for manually boxing up argument lists into an array w ...

  4. bzoj 3926 [Zjoi2015]诸神眷顾的幻想乡(SAM)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3926   [题意]   给定一棵树,每个节点都有相应的颜色,且保证叶子数不超过20,问 ...

  5. 选择一个 HTTP 状态码不再是一件难事 – Racksburg

    原文链接:http://racksburg.com/choosing-an-http-status-code/ 打开双语对照阅读 有什么能比 HTTP 响应状态码更简单呢?页面渲染了吗?好极了,返回  ...

  6. Learning JavaScript Design Patterns The Constructor Pattern

    In classical object-oriented programming languages, a constructor is a special method used to initia ...

  7. advanced dom scripting dynamic web design techniques Part One DOM SCRIPTING IN DETAIL CHAPTER 1 DO IT RIGHT WITH BEST PRACTICES

    You’re excited; your client is excited. All is well. You’ve just launched the client’s latest websit ...

  8. java request判断微信客户端访问

    微信客户端访问时候user-agent信息如下: Mozilla/5.0 (Linux; Android 5.0.1; M040 Build/LRX22C) AppleWebKit/537.36 (K ...

  9. 虚机分配静态IP地址

    在为虚机分配静态IP地址池的IP时,如果报错“没有从与 VMSubnet 相关的 IP 池中为虚拟网络适配器 9i [MAC: 001DD8B71C17] 分配 CA (客户地址)” 使用“动态获取” ...

  10. HTTPResponse.read([amt]):只能read一次

    业务需要:我要写个tanx模拟器,给DSP发竞价请求. 下面是部分代码: def PostDataToDSP(self,url,postdata): headers = { 'Content-Type ...