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;
}
}