全局钩子注入DLL

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("全局钩子加载成功! ");
         else{
             printf("全局钩子加载失败! ");
             break;
         }
         printf("按任意键卸载全局钩子! ");
         getchar();
         pfnUnloadHook();
         printf("全局钩子卸载完成! ");
     }while(FALSE);

    getchar();
     return 0;
}

注:为了简化出错处理,使用了 do-while(0) 结构

0x04 验证:

先打开PCHunter查看:

1

可以看到此时系统应用层没有任何全局消息钩子

为了方便观察,打开系统自带的Notepad,并使用调试器附加:

2

编译生成 TestDLL.dll 文件和调用程序放在同一路径下,并且执行调用程序:

3

可以发现已经成功将DLL注入到了当前系统的很多进程当中,用调试器附加的Notepad进程可以非常直观的看到结果

同时在PCHunter中也可以直观的看到结果:

4

原文地址:https://www.cnblogs.com/DarkBright/p/10835761.html