Windows安全攻防-DDL全局钩子注入

admin 2026-01-05 18:01:26 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细解析了Windows系统中利用全局钩子进行DLL注入的原理与实现。文章阐述了钩子作为事件拦截机制的机制,指出全局钩子需借助DLL实现跨进程代码共享。通过SetWindowsHookExAPI及共享数据段技术,演示了如何编写DLL与加载器程序,将恶意DLL注入到目标进程中执行代码,从而实现权限维持或监控功能。 综合评分: 91 文章分类: 内网渗透,红队,安全开发


cover_image

Windows安全攻防-DDL全局钩子注入

原创

R0x7e

剑外思归客

2026年1月5日 00:01 江苏

By:whoami网络安全知识星球、R0x7e

钩子(Hooks)

Windows 系统中的 钩子(Hook) 是一种 事件拦截机制,允许应用程序监视或修改系统事件(如键盘输入、鼠标点击、窗口消息等) 钩子本质上是一个回调函数,当特定事件发生时,操作系统会调用这个函数。钩子可以拦截并处理以下内容:

  • 消息(如键盘、鼠标消息)
  • 系统事件(如窗口创建、焦点切换)
  • 特定线程或进程的执行

全局钩子和局部钩子

钩子可以分为全局钩子和局部钩子,局部钩子针对某一线程,全局钩子的作用域是整个系统的基于消息的应用,全局钩子需要使用DLL文件,并且在DLL文件中实现对于的钩子函数,局部钩子无需在DLL文件中实现每个进程在Windows中都有独立的地址空间,进程之间无法直接访问彼此的内存。如果钩子函数直接写在某个EXE文件中,其他进程无法直接调用该EXE的代码,因为它们的地址空间是隔离的。 DLL的设计初衷就是代码共享。当系统需要调用全局钩子时,会将包含钩子函数的DLL动态注入到目标进程的地址空间中。这样,所有需要处理钩子事件的进程都可以加载并调用同一个DLL中的钩子函数,从而实现跨进程的钩子功能。

  • Windows 的钩子机制是基于 线程(Thread) 的,而不是进程(Process)。
  • 每个线程有自己的消息队列,钩子需要绑定到具体的线程才能拦截消息。

钩子相关windows API

SetWindowsHookEx

安装一个钩子,监视指定类型的事件消息。

HHOOK SetWindowsHookEx(
int idHook, // 钩子类型(如 WH_KEYBOARD, WH_MOUSE)
HOOKPROC lpfn, // 钩子回调函数地址
HINSTANCE hmod, // 包含钩子函数的DLL模块句柄
DWORD dwThreadId // 线程ID(0表示全局钩子) );
  • idHook:钩子类型(如 WH_KEYBOARD_LL 表示低级键盘钩子)。
  • lpfn:钩子回调函数的地址(必须符合 HOOKPROC 签名)。
  • hmod必须为DLL模块句柄(全局钩子时)。
  • dwThreadId:目标线程ID(0表示全局钩子,影响所有线程)。

UnhookWindowsHookEx

卸载已安装的钩子

BOOL UnhookWindowsHookEx( HHOOK hhk  );// 由 SetWindowsHookEx 返回的钩子句柄

其他API

GetModuleHandle

获取当前进程或DLL的模块句柄。

HMODULE GetModuleHandle( LPCSTR lpModuleName // 模块名称(NULL 表示当前进程) );

应用场景:在 SetWindowsHookEx 中获取DLL模块句柄(全局钩子时)

钩子类型

| 钩子类型 | 描述 | | — | — | | WH_CALLWNDPROC | 监控发送到窗口的消息(局部钩子)。 | | WH_KEYBOARD | 监控键盘事件(仅限当前线程)。 | | WH_KEYBOARD_LL | 低级键盘钩子(全局钩子,需DLL支持)。 | | WH_MOUSE | 监控鼠标事件(仅限当前线程)。 | | WH_MOUSE_LL | 低级鼠标钩子(全局钩子,需DLL支持)。 | | WH_SHELL | 监控外壳事件(如任务栏操作)。 | | WH_CBT | 监控窗口创建、激活等事件。 | | WH_GETMESSAGE | 监控从消息队列获取消息的事件。 |

全局钩子实现DLL注入

这里通过WH_GETMESSAGE钩子实现,该钩子可以拦截所有 GUI 程序的消息(如键盘、鼠标、窗口消息),windows系统是基于消息驱动的,所有进程都会有一个消息队列,当有进程发送消息时,会触发该类型的钩子,实现DLL注入 DLL代码

#include "pch.h"
#include&nbsp;<windows.h>
#include&nbsp;<stdio.h>
#include&nbsp;<string>
#include&nbsp;<fstream>
#include&nbsp;<iostream>

// 共享数据段 (用于进程间通信)
#pragma&nbsp;data_seg(".shared")
HHOOK g_hHook =&nbsp;NULL;
#pragma&nbsp;data_seg()
#pragma&nbsp;comment(linker,&nbsp;"/SECTION:.shared,RWS")
// 目标PID
#define&nbsp;TARGET_PID 4960

// 全局保存DLL模块句柄
HMODULE g_hThisDll =&nbsp;NULL;

// DLL入口点
BOOL APIENTRY&nbsp;DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)&nbsp;{

&nbsp; &nbsp;&nbsp;switch&nbsp;(ul_reason_for_call) {
&nbsp; &nbsp;&nbsp;case&nbsp;DLL_PROCESS_ATTACH:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 禁用线程通知 (可选)
&nbsp; &nbsp; &nbsp; &nbsp; DisableThreadLibraryCalls(hModule);
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 如果不是目标PID,不加载此DLL
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;//if (currentPID != TARGET_PID)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;//{
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// &nbsp; &nbsp;return FALSE;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;//}

&nbsp; &nbsp; &nbsp; &nbsp; g_hThisDll = hModule;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 在这里可以执行恶意代码
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;//MessageBoxA(NULL, "DLL Injected Successfully!", "Hook DLL", MB_OK);
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break;

&nbsp; &nbsp;&nbsp;//case DLL_PROCESS_DETACH:
&nbsp; &nbsp;&nbsp;// &nbsp; &nbsp;// 清理代码
&nbsp; &nbsp;&nbsp;// &nbsp; &nbsp;if (g_hHook) {
&nbsp; &nbsp;&nbsp;// &nbsp; &nbsp; &nbsp; &nbsp;UnhookWindowsHookEx(g_hHook);
&nbsp; &nbsp;&nbsp;// &nbsp; &nbsp;}
&nbsp; &nbsp;&nbsp;// &nbsp; &nbsp;break;
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;return&nbsp;TRUE;
}

// 写入PID到文件的函数
void&nbsp;WritePidToFile()&nbsp;{
&nbsp; &nbsp;&nbsp;// 获取当前进程ID
&nbsp; &nbsp; DWORD pid = GetCurrentProcessId();

&nbsp; &nbsp;&nbsp;// 构造文件路径 - 使用临时目录避免权限问题
&nbsp; &nbsp;&nbsp;char&nbsp;path[MAX_PATH];
&nbsp; &nbsp; GetTempPathA(MAX_PATH, path);
&nbsp; &nbsp; strcat_s(path,&nbsp;"process_pids.log");

&nbsp; &nbsp;&nbsp;// 打开文件追加写入
&nbsp; &nbsp;&nbsp;std::ofstream outFile;
&nbsp; &nbsp; outFile.open(path,&nbsp;std::ios_base::app);

&nbsp; &nbsp;&nbsp;if&nbsp;(outFile.is_open()) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 写入PID和时间戳
&nbsp; &nbsp; &nbsp; &nbsp; SYSTEMTIME st;
&nbsp; &nbsp; &nbsp; &nbsp; GetLocalTime(&st);
&nbsp; &nbsp; &nbsp; &nbsp; outFile <<&nbsp;"PID: "&nbsp;<< pid <<&nbsp;" - "
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; << st.wYear <<&nbsp;"-"&nbsp;<< st.wMonth <<&nbsp;"-"&nbsp;<< st.wDay <<&nbsp;" "
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; << st.wHour <<&nbsp;":"&nbsp;<< st.wMinute <<&nbsp;":"&nbsp;<< st.wSecond <<&nbsp;"\n";
&nbsp; &nbsp; &nbsp; &nbsp; outFile.close();
&nbsp; &nbsp; }
}

// 钩子过程函数
LRESULT CALLBACK&nbsp;HookProc(int&nbsp;nCode, WPARAM wParam, LPARAM lParam)&nbsp;{
&nbsp; &nbsp;&nbsp;// 获取当前进程ID
&nbsp; &nbsp; DWORD currentPID = GetCurrentProcessId();
&nbsp; &nbsp;&nbsp;if&nbsp;(nCode >=&nbsp;0and&nbsp;currentPID== TARGET_PID) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 写入当前进程PID到文件
&nbsp; &nbsp; &nbsp; &nbsp; WritePidToFile();
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;// 调用下一个钩子
&nbsp; &nbsp;&nbsp;return&nbsp;CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

// 导出函数 - 设置钩子
extern"C"&nbsp;__declspec(dllexport)&nbsp;BOOL&nbsp;SetHook(DWORD threadId)&nbsp;{
&nbsp; &nbsp; g_hHook = SetWindowsHookEx(WH_GETMESSAGE, HookProc, g_hThisDll, threadId);
&nbsp; &nbsp;&nbsp;return&nbsp;g_hHook !=&nbsp;NULL;
}

// 导出函数 - 移除钩子
extern"C"&nbsp;__declspec(dllexport)&nbsp;BOOL&nbsp;RemoveHook()&nbsp;{
&nbsp; &nbsp;&nbsp;if&nbsp;(g_hHook) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;UnhookWindowsHookEx(g_hHook);
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;return&nbsp;FALSE;
}

加载DLL的程序代码

#include&nbsp;<windows.h>
#include&nbsp;<iostream>
#include&nbsp;<string>
#include&nbsp;<limits> &nbsp;// 添加这个头文件以使用numeric_limits

// 定义函数指针类型
typedef&nbsp;BOOL(*SET_HOOK_FUNC)(DWORD);
typedef&nbsp;BOOL(*REMOVE_HOOK_FUNC)();

// 加载DLL并获取函数指针
bool&nbsp;LoadDllFunctions(HMODULE& hDll, SET_HOOK_FUNC& SetHook, REMOVE_HOOK_FUNC& RemoveHook)&nbsp;{
&nbsp; &nbsp;&nbsp;// 加载DLL
&nbsp; &nbsp; hDll = LoadLibrary(TEXT("DLL2.dll"));
&nbsp; &nbsp;&nbsp;if&nbsp;(hDll ==&nbsp;NULL) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::cerr&nbsp;<<&nbsp;"LoadLibrary failed: "&nbsp;<< GetLastError() <<&nbsp;std::endl;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnfalse;
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;// 获取SetHook函数地址
&nbsp; &nbsp; SetHook = (SET_HOOK_FUNC)GetProcAddress(hDll,&nbsp;"SetHook");
&nbsp; &nbsp;&nbsp;if&nbsp;(SetHook ==&nbsp;NULL) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::cerr&nbsp;<<&nbsp;"GetProcAddress(SetHook) failed: "&nbsp;<< GetLastError() <<&nbsp;std::endl;
&nbsp; &nbsp; &nbsp; &nbsp; FreeLibrary(hDll);
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnfalse;
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;// 获取RemoveHook函数地址
&nbsp; &nbsp; RemoveHook = (REMOVE_HOOK_FUNC)GetProcAddress(hDll,&nbsp;"RemoveHook");
&nbsp; &nbsp;&nbsp;if&nbsp;(RemoveHook ==&nbsp;NULL) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::cerr&nbsp;<<&nbsp;"GetProcAddress(RemoveHook) failed: "&nbsp;<< GetLastError() <<&nbsp;std::endl;
&nbsp; &nbsp; &nbsp; &nbsp; FreeLibrary(hDll);
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnfalse;
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;returntrue;
}

// 显示菜单
void&nbsp;ShowMenu()&nbsp;{
&nbsp; &nbsp;&nbsp;std::cout&nbsp;<<&nbsp;"\n=== Hook 控制菜单 ==="&nbsp;<<&nbsp;std::endl;
&nbsp; &nbsp;&nbsp;std::cout&nbsp;<<&nbsp;"1. 设置钩子(SetHook)"&nbsp;<<&nbsp;std::endl;
&nbsp; &nbsp;&nbsp;std::cout&nbsp;<<&nbsp;"2. 移除钩子(RemoveHook)"&nbsp;<<&nbsp;std::endl;
&nbsp; &nbsp;&nbsp;std::cout&nbsp;<<&nbsp;"3. 退出程序"&nbsp;<<&nbsp;std::endl;
&nbsp; &nbsp;&nbsp;std::cout&nbsp;<<&nbsp;"请输入选择(1-3): ";
}

int&nbsp;main()&nbsp;{
&nbsp; &nbsp; HMODULE hDll =&nbsp;NULL;
&nbsp; &nbsp; SET_HOOK_FUNC SetHook =&nbsp;NULL;
&nbsp; &nbsp; REMOVE_HOOK_FUNC RemoveHook =&nbsp;NULL;

&nbsp; &nbsp;&nbsp;// 加载DLL和函数
&nbsp; &nbsp;&nbsp;if&nbsp;(!LoadDllFunctions(hDll, SetHook, RemoveHook)) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return1;
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;int&nbsp;choice =&nbsp;0;
&nbsp; &nbsp;&nbsp;bool&nbsp;running =&nbsp;true;

&nbsp; &nbsp;&nbsp;while&nbsp;(running) {
&nbsp; &nbsp; &nbsp; &nbsp; ShowMenu();
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::cin&nbsp;>> choice;

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 清除输入缓冲区
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::cin.clear();
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 添加NOMINMAX宏定义或者使用括号
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::cin.ignore((std::numeric_limits<std::streamsize>::max)(),&nbsp;'\n');

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;switch&nbsp;(choice) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case1:&nbsp;// 设置钩子
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(SetHook(0)) {&nbsp;// 0表示全局钩子
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::cout&nbsp;<<&nbsp;"钩子设置成功!"&nbsp;<<&nbsp;std::endl;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DWORD err = GetLastError();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::cerr&nbsp;<<&nbsp;"钩子设置失败! 错误代码: "&nbsp;<< err <<&nbsp;std::endl;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break;

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case2:&nbsp;// 移除钩子
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(RemoveHook()) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::cout&nbsp;<<&nbsp;"钩子移除成功!"&nbsp;<<&nbsp;std::endl;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DWORD err = GetLastError();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::cerr&nbsp;<<&nbsp;"钩子移除失败! 错误代码: "&nbsp;<< err <<&nbsp;std::endl;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break;

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case3:&nbsp;// 退出程序
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; running =&nbsp;false;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::cout&nbsp;<<&nbsp;"程序即将退出..."&nbsp;<<&nbsp;std::endl;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break;

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;default:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::cerr&nbsp;<<&nbsp;"无效输入,请重新选择!"&nbsp;<<&nbsp;std::endl;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;// 卸载DLL
&nbsp; &nbsp; FreeLibrary(hDll);

&nbsp; &nbsp;&nbsp;return0;
}

By:whoami网络安全知识星球、R0x7e


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:剑外思归客 R0x7e《Windows安全攻防-DDL全局钩子注入》

评论:0   参与:  0