0x00 原理說明:
Windows系統基於消息驅動,每個進程都有各自的消息隊列,每個進程都會GetMessage
調用WIN32API SetWindowsHookEx 可以在系統的鈎子鏈中安裝一個指定的鈎子
如果使用 SetWindowsHookEx 安裝 WH_GETMESSAGE 類型的鈎子,並且鈎子過程函數放在DLL中,就可以實現全局的DLL注入
0x01 關鍵API說明:
實現全局鈎子注入DLL最核心的API:
HHOOK WINAPI SetWindowsHookEx( _In_ int idHook, _In_ HOOKPROC lpfn, _In_ HINSTANCE hMod, _In_ DWORD dwThreadId );
參數說明:
1、 idHook:鈎子類型,此處填寫WH_GETMESSAGE
2、 lpfn:鈎子的過程函數,也就是鈎子觸發的時候要執行的代碼
3、 hMod:鈎子過程函數所在的DLL模塊句柄,在DLL初始化的獲得(DllMain的第一個參數)
4、 dwThreadId:與鈎子程序關聯的線程ID,此處填0,表示關聯系統中的所有線程
返回值:
鈎子句柄
0x02 編寫需要注入的DLL:
DLL大致需要實現以下內容:
1、 設置鈎子
2、 取消鈎子
3、 鈎子過程函數
4、 導出相關函數
DLL的主要實現代碼如下:
#include "pch.h"
HHOOK g_hHook;
HMODULE g_hModule;LRESULT CALLBACK GetMsgProc(
_In_ int code,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
return CallNextHookEx(g_hHook, code, wParam, lParam);
}BOOL LoadHook(void)
{
g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hModule, 0);
if (g_hHook){
MessageBox(NULL, TEXT("鈎子加載成功!"), TEXT("提示"), MB_OK);
return TRUE;
}
else
return FALSE;
}VOID UnloadHook(void)
{
if(g_hHook)
UnhookWindowsHookEx(g_hHook);
}BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hModule = hModule;
MessageBox(NULL, TEXT("加載DLL!"), TEXT("提示"), MB_OK);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
新建def文件導出相關函數:
LIBRARY
EXPORTS
LoadHook
UnloadHook
編譯生成 TestDLL.dll 文件
0x03 編寫調用程序:
DLL不能主動執行,因此需要編寫調用程序:
#include <windows.h>
#include <stdio.h>#define DLL_NAME "TestDLL.dll"
int main(int argc, char* argv[])
{
do{
HMODULE hModule = LoadLibraryA(DLL_NAME);
if(hModule == NULL)
break;
FARPROC pfnLoadHook = GetProcAddress(hModule, "LoadHook");
FARPROC pfnUnloadHook = GetProcAddress(hModule, "UnloadHook");
if(pfnLoadHook==NULL || pfnUnloadHook==NULL)
break;
if (pfnLoadHook())
printf("全局鈎子加載成功!\r\n");
else{
printf("全局鈎子加載失敗!\r\n");
break;
}
printf("按任意鍵卸載全局鈎子!\r\n");
getchar();
pfnUnloadHook();
printf("全局鈎子卸載完成!\r\n");
}while(FALSE);getchar();
return 0;
}
注:為了簡化出錯處理,使用了 do-while(0) 結構
0x04 驗證:
先打開PCHunter查看:
可以看到此時系統應用層沒有任何全局消息鈎子
為了方便觀察,打開系統自帶的Notepad,並使用調試器附加:
將編譯生成 TestDLL.dll 文件和調用程序放在同一路徑下,並且執行調用程序:
可以發現已經成功將DLL注入到了當前系統的很多進程當中,用調試器附加的Notepad進程可以非常直觀的看到結果
同時在PCHunter中也可以直觀的看到結果: