HOOK学习
HOOK学习
Hook技术又叫钩子函数,在系统没有调用该函数之前,钩子程序就先获取该消息,钩子函数先得到控制权,这时钩子函数既可以加工处理该函数的执行行为,还可以强制结束消息的传递。
Hook分类
Hook分为应用层(Ring3)Hook和内核层(Ring0)Hook,应用层Hook适用于x86和x64,而内核层Hook一般仅在x86平台适用。
应用层Hook:
- 消息Hook
- 注入Hook
- 调试Hook
消息Hook
技术原理
当发生键盘输入事件时,WM_KEYDOWN消息被添加到[OS message queue]。
OS判断哪个应用程序中发生了事件,然后从[OS message queue]取出消息,添加到相应应用程序的[application message queue]中
应用程序监视自身的[application message queue],发现新添加的WM_KEYDOWN消息后,调用相应的事件处理程序处理。
所以,只需要在[OS message queue]和[application message queue]之间安装钩子即可窃取键盘消息,并实现恶意操作。
Windows函数SetWindowsHookEx()用于设置消息Hook,只需要调用该API就能简单地实现消息Hook。
SetWindowsHookEx(
WH_KEYBOARD, //键盘消息
KeyboardProc,//钩子函数
hInstance,//钩子函数所在DLL的handle
0 //该参数用于设定要Hook得线程ID,为0时表示监视所有线程)
钩子的类型,表示在什么时机调用钩子。
-
WH_CALLWNDPROC(4):安装一个挂钩处理过程,在系统消息发送至目标窗口处理过程之前,对该消息进行监视。WH_CALLWNDPROC钩子监视SendMessage消息的传递,不管是系统内部调用的SendMessage()函数还是用户进程中调用的SendMessage函数。
SendMessage()把消息直接交给窗口过程WndProc()来处理,WndProc()处理完消息后SendMessage()函数才返回。
如果设置了WH_CALLWNDPROC类型的钩子,则当SendMessage()把消息交给WndProc时,在WndProc尚未执行前,系统调用CallWndProc钩子函数,钩子函数执行后才执行窗口过程WndProc。
WH_CALLWNDPROC只能监视消息而不能修改
-
WH_CALLWNDPROCRET(12):安装一个挂钩处理过程,它对已被目标窗口处理过程处理过的消息进行监视。
-
WH_CBT(5):安装一个挂钩处理过程,接受对CBT应用程序有用的消息。
在窗口激活、创建、销毁、最小化、最大化、移动或改变尺寸的前一刻。系统会调用WH_CBT钩子过程,钩子过程的返回值决定了系统是允许或阻止这些操作。WB_CBT钩子主要用于基于计算机的教学应用。
-
WH_DEBUG(9):安装一个挂钩处理过程以便对其它挂钩处理过程进行调试。
在调用与系统中的其它钩子关联的钩子过程前,系统会调用WH_DEBUG钩子过程。可以用这个钩子来决定是否允许系统调用其它类型钩子的钩子函数。
-
WH_FOREGROUNDIDLE(11):安装一个钩子处理过程,该处理过程当应用程序的前台线程即将进入空闲状态时被调用,它有助于在空闲时间内执行低优先级的任务。
-
WH_GETMESSAGE(3):安装一个钩子处理过程对发送至消息队列的消息进行监视。让应用能够监视将要被GetMessage或PeekMessage函数返回的消息。可以使用WH_GETMESSAGE钩子来监视鼠标键盘输入,以及其它投递到消息队列的消息。
-
WH_JOURNALPLAYBACK(1):安装一个钩子处理过程,对此前由WH_JOURNALRECORD挂钩处理过程记录的消息进行寄送。
-
WH_JOURNALRECORD(0):安装一个钩子处理过程,对寄送至系统消息队列的输入消息进行记录。
-
WH_KEYBOARD(2):安装一个钩子处理过程对键盘消息进行监视。
-
WH_KEYBOARD_LL(13):此钩子只能在Windows NT中被安装,用来对底层的键盘输入事件进行监视。
-
WH_MOUSE(7):安装一个钩子处理过程,对鼠标消息进行监视。
-
WH_MOUSE_LL(4):此钩子只能安装在Windows NT中,用来对底层的鼠标输入事件进行监视。
-
WH_MSGFILTER(-1):监视由对话框、消息框、菜单栏、或滚动条中输入事件引发的消息。
-
WH_SHELL(10):接收对外壳应用程序有用的通知。
核心函数:SetWindowsHookEx(),UnhookWindowsHookEx(),CallNextHookEx()
示例:
#include "msg.h"
#include<Windows.h>
#include<iostream>
using namespace std;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lParam);
//钩子处理函数
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParan, LPARAM lParam);
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParan, LPARAM lParam);
HHOOK mouseHook;
HHOOK keyHook;
HWND g_hwnd;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int cmdShow)
{
TCHAR szAppClassName[] = TEXT("DunKaiEDU张三");
WNDCLASS wc = { 0 };
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
wc.hCursor = ::LoadCursor(nullptr, IDC_ARROW);
wc.hIcon = nullptr;
wc.hInstance = hInstance;
wc.lpfnWndProc = WindowProc;
wc.lpszClassName = szAppClassName;
wc.lpszMenuName = nullptr;
wc.style = CS_HREDRAW | CS_VREDRAW;
// 注册窗口类
RegisterClass(&wc);
HWND hwnd = ::CreateWindow(szAppClassName, TEXT("福州成"), WS_OVERLAPPEDWINDOW, 100, 100, 800, 600, nullptr, nullptr, hInstance, nullptr);
::g_hwnd = hwnd;
::ShowWindow(hwnd, SW_SHOW);
::UpdateWindow(hwnd);
//消息循坏
//WIndows应用程序时通过消息机制驱动运行
MSG msg = { 0 };
while (GetMessage(&msg, nullptr, 0, 0))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE://窗口创建消息
//::mouseHook = SetWindowsHookEx(WH_MOUSE, MouseProc, nullptr, ::GetCurrentThreadId());
::keyHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, nullptr, ::GetCurrentThreadId());
break;
case WM_LBUTTONDOWN://鼠标按下消息
{
MessageBox(hwnd, L"hell", L"sdf", MB_YESNO);
}
break;
case WM_KEYDOWN:
MessageBox(nullptr, L"sdf", L"dsfs", MB_OK);
break;
case WM_MOUSEMOVE:
{
//根据鼠标当前的位置
int x = LOWORD(lParam);
int y = HIWORD(lParam);
TCHAR str[255] = { 0 };
wsprintf(str, L"当前鼠标坐标(%d,%d)", x, y);
::SetWindowText(hwnd, str);
}
break;
case WM_CLOSE:
{
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
}
return ::DefWindowProc(hwnd, uMsg, wparam, lParam);
}
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
return ::CallNextHookEx(::mouseHook, nCode, wParam, lParam);//传递给下一个钩子函数
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (wParam == VK_F2)
{
//卸载所有钩子
::UnhookWindowsHookEx(::keyHook);
return 1;
}
else
{
return 1;
}
}