Dll注入:Windows消息鈎子注入


SetWindowsHook() 是Windows消息處理機制的一個平台,應用程序可以在上面設置子程以監視指定窗口的某種消息,而且所監視的窗口可以是其他進程所創建的。當消息到達后,在目標窗口處理函數之前處理它。

鈎子機制允許應用程序截獲處理window消息或特定事件。

HHOOK WINAPI SetWindowsHookEx(
__in int idHook, \\鈎子類型
__in HOOKPROC lpfn, \\回調函數地址
__in HINSTANCE hMod, \\實例句柄
__in DWORD dwThreadId); \\線程ID

使用API函數SetWindowsHookEx()把一個應用程序定義的鈎子子程安裝到鈎子鏈表中。 SetWindowsHookEx函數總是在Hook鏈的開頭安裝Hook子程。當指定類型的Hook監視的事件發生時,系統就調用與這個Hook關聯的 Hook鏈的開頭的Hook子程。每一個Hook鏈中的Hook子程都決定是否把這個事件傳遞到下一個Hook子程。Hook子程傳遞事件到下一個 Hook子程需要調用CallNextHookEx函數。

系統鈎子

SetWindowsHookEx()函數的最后一個參數決定了此鈎子是系統鈎子還是線程鈎子。

線程鈎子

線程勾子用於監視指定線程的事件消息。線程勾子一般在當前線程或者當前線程派生的線程內。
 
系統勾子監視系統中的所有線程的事件消息。因為系統勾子會影響系統中所有的應用程序,所以勾子函數必須放在獨立的動態鏈接庫(DLL) 中。系統自動將包含"鈎子回調函數"的DLL映射到受 鈎子函數影響的所有進程的 地址空間中,即將這個DLL注入了那些進程。
 
如果對於同一事件(如鼠標消息)既安裝了線程鈎子又安裝了 系統鈎子,那么系統會自動先調用線程鈎子,然后調用系統鈎子。
 
對同一事件消息可安裝多個鈎子處理過程,這些勾子處理過程形成了鈎子鏈。當前鈎子處理結束后應把鈎子信息傳遞給下一個 鈎子函數
 
每一種類型的Hook可以使應用程序能夠監視不同類型的 系統消息處理機制。下面描述所有可以利用的Hook類型。
1、WH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks
WH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks使你可以監視發送到窗口過程的消息。系統在消息發送到接收窗口過程之前調用WH_CALLWNDPROC Hook子程,並且在窗口過程處理完消息之后調用WH_CALLWNDPROCRET Hook子程。
WH_CALLWNDPROCRET Hook傳遞 指針到CWPRETSTRUCT結構,再傳遞到Hook子程。
CWPRETSTRUCT結構包含了來自處理消息的窗口過程的返回值,同樣也包括了與這個消息關聯的消息參數。
2、WH_CBT Hook
在以下事件之前,系統都會調用WH_CBT Hook子程,這些事件包括:
1)激活,建立,銷毀,最小化,最大化,移動,改變尺寸等窗口事件;
2)完成系統指令;
3)來自系統消息隊列中的移動鼠標,鍵盤事件;
4)設置 輸入焦點事件;
5)同步系統消息隊列事件。
Hook子程的返回值確定系統是否允許或者防止這些操作中的一個。
3、WH_DEBUG Hook
系統調用系統中與其他Hook關聯的Hook子程之前,系統會調用WH_DEBUG Hook子程。你可以使用這個Hook來決定是否允許系統調用與其他Hook關聯的Hook子程。
4、WH_FOREGROUNDIDLE Hook
當應用程序的前台 線程處於空閑狀態時,可以使用WH_FOREGROUNDIDLE Hook執行低優先級的任務。當應用程序的前台線程大概要變成空閑狀態時,系統就會調用WH_FOREGROUNDIDLE Hook子程。
5、WH_GETMESSAGE Hook
應用程序使用WH_GETMESSAGE Hook來監視從GetMessage or PeekMessage函數返回的消息。你可以使用WH_GETMESSAGE Hook去監視鼠標和鍵盤輸入,以及其他發送到 消息隊列中的消息。
6、WH_JOURNALPLAYBACK Hook
WH_JOURNALPLAYBACK Hook使應用程序可以插入消息到系統消息隊列。可以使用這個Hook回放通過使用WH_JOURNALRECORD Hook記錄下來的連續的鼠標和鍵盤事件。只要WH_JOURNALPLAYBACK Hook已經安裝,正常的鼠標和鍵盤事件就是無效的。
WH_JOURNALPLAYBACK Hook是全局Hook,它不能象線程特定Hook一樣使用。
WH_JOURNALPLAYBACK Hook返回超時值,這個值告訴系統在處理來自回放Hook當前消息之前需要等待多長時間(毫秒)。這就使Hook可以控制實時事件的回放。
WH_JOURNALPLAYBACK是system-wide local hooks,它們不會被注射到任何行程位址空間。
7、WH_JOURNALRECORD Hook
WH_JOURNALRECORD Hook用來監視和記錄輸入事件。典型的,可以使用這個Hook記錄連續的鼠標和鍵盤事件,然后通過使用WH_JOURNALPLAYBACK Hook來回放。
WH_JOURNALRECORD Hook是全局Hook,它不能象線程特定Hook一樣使用。
WH_JOURNALRECORD是system-wide local hooks,它們不會被注射到任何行程位址空間。
8、WH_KEYBOARD Hook
在應用程序中,WH_KEYBOARD Hook用來監視WM_KEYDOWN and WM_KEYUP消息,這些消息通過GetMessage or PeekMessage function返回。可以使用這個Hook來監視輸入到 消息隊列中的鍵盤消息。
9、WH_KEYBOARD_LL Hook
WH_KEYBOARD_LL Hook監視輸入到線程消息隊列中的鍵盤消息。
10、WH_MOUSE Hook
WH_MOUSE Hook監視從GetMessage 或者 PeekMessage 函數返回的鼠標消息。使用這個Hook監視輸入到 消息隊列中的鼠標消息。
11、WH_MOUSE_LL Hook
WH_MOUSE_LL Hook監視輸入到線程消息隊列中的鼠標消息。
12、WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks
WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我們可以監視菜單,滾動條, 消息框,對話框消息並且發現用戶使用ALT+TAB or ALT+ESC 組合鍵切換窗口。WH_MSGFILTER Hook只能監視傳遞到菜單,滾動條,消息框的消息,以及傳遞到通過安裝了Hook子程的應用程序建立的對話框的消息。WH_SYSMSGFILTER Hook監視所有應用程序消息。
WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我們可以在模式循環期間過濾消息,這等價於在主 消息循環中過濾消息。
通過調用CallMsgFilter function可以直接的調用WH_MSGFILTER Hook。通過使用這個函數,應用程序能夠在模式循環期間使用相同的代碼去過濾消息,如同在主消息循環里一樣。
13、WH_SHELL Hook
外殼應用程序可以使用WH_SHELL Hook去接收重要的通知。當外殼應用程序是激活的並且當頂層窗口建立或者銷毀時, 系統調用WH_SHELL Hook子程。
WH_SHELL 共有5鍾情況:
1)只要有個top-level、unowned 窗口被產生、起作用、或是被摧毀;
2)當Taskbar需要重畫某個按鈕;
3)當系統需要顯示關於Taskbar的一個程序的最小化形式;
4)當如今的 鍵盤布局狀態改變;
5)當使用者按Ctrl+Esc去執行Task Manager(或相同級別的程序)。
 
使用鍵盤鈎子實現注入的一個Demo
實現過程:
1.在動態庫里導出一個自己的函數MyMessageProcess,在這里面可是實現自己對消息的處理。
2.輸入所需要注入的進程ID,並獲得線程ID
3.SetWindowsHookEx(WH_KEYBOARD, MyMessageProcess , DllModule, ThreadID);
4.在注入的進程內輸入鍵盤消息 會觸發Dll內的MyMessageProcess,實現鈎子注入
cpp部分:
#include "stdafx.h"
#include <Windows.h>
#include<TlHelp32.h>
#include<iostream>

using namespace std;

BOOL InjectDllBySetWindowsHook(ULONG32 ulTargetProcessID);
DWORD getThreadID(ULONG32 ulTargetProcessID);
int main()
{

    ULONG32 ulTargetProcessID;
    cout << "請輸入目標進程ID:";
    cin >> ulTargetProcessID;

    if (!InjectDllBySetWindowsHook(ulTargetProcessID))
    {
        cout << "Set Hook Unsuccess!\r\n" << endl;
        return 0;
    }
    cout << "Inject Success!\r\n" << endl;
    return 0;
    return 0;
}


BOOL InjectDllBySetWindowsHook(ULONG32 ulTargetProcessID)
{
    HANDLE  TargetProcessHandle = NULL;
    TargetProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ulTargetProcessID);

    if (NULL == TargetProcessHandle)
    {
        printf("Couldn't get Target Process Handle\r\n");
        return FALSE;
    }

    HMODULE DllModule = LoadLibrary(L"Dll.dll");

    if (DllModule == NULL)
    {
        printf("cannt find dll\r\n");
        return FALSE;
    }

    //獲取Dll中導出的函數的地址
    HOOKPROC   Sub_1Address = NULL;
    Sub_1Address = (HOOKPROC)GetProcAddress(DllModule, "MyMessageProcess");
    if (Sub_1Address == NULL)
    {
        printf("cannt found MyMessageProcess");
        return FALSE;
    }

    DWORD ThreadID = getThreadID(ulTargetProcessID);

    HHOOK Handle = SetWindowsHookEx(WH_KEYBOARD,
        Sub_1Address, DllModule, ThreadID);

    if (Handle == NULL)
    {
        printf("cannt hook\r\n");
        return FALSE;
    }
    printf("hook success\r\n");
    getchar();
    getchar();
    getchar();
    UnhookWindowsHookEx(Handle);

    FreeLibrary(DllModule);
}


DWORD getThreadID(ULONG32 ulTargetProcessID)
{
    HANDLE Handle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if (Handle != INVALID_HANDLE_VALUE)
    {
        THREADENTRY32 te;
        te.dwSize = sizeof(te);
        if (Thread32First(Handle, &te))
        {
            do
            {
                if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID))
                {
                    if (te.th32OwnerProcessID == ulTargetProcessID)
                    {
                        HANDLE hThread = OpenThread(READ_CONTROL, FALSE, te.th32ThreadID);
                        if (!hThread)
                        {
                            printf("Couldn't get thread handle\r\n");
                        }
                        else
                        {
                            return te.th32ThreadID;
                        }
                    }
                }
            } while (Thread32Next(Handle, &te));
        }
    }
    CloseHandle(Handle);
    return (DWORD)0;
}

Dll部分:

#pragma data_seg(SHARD_SEG_NAME)  
static HHOOK g_hHook;
#pragma data_seg()

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        MessageBox(NULL, L"Inject Success!", L"1", 0);
    }
    
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

extern "C"

__declspec(dllexport)LRESULT MyMessageProcess(int Code, WPARAM wParam, LPARAM lParam)
{
    //  
    //你自己對消息的處理  
    //  
    MessageBox(NULL, L"GetMessage!", L"Message", 0);
    return CallNextHookEx(g_hHook, Code, wParam, lParam);
}

可參考百度百科


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM