7-DLL劫持注入(涉及白加黑)
一、前言
本节内容涉及 白加黑 技术,白加黑并不是一个很新的技术,但是在红队攻防中应用非常广泛,且十分有效,究其原因是一个白程序(有数字签名的),能加载你的黑DLL,这样AV/EDR都得有所顾忌,不敢乱杀。
1.1 DLL简介
在Windows中,许多应用程序并不是一个完整的可执行文件,一个大型项目的许多功能被拆分成相对独立的动态链接库,即DLL文件(也是PE文件的一种)。当一个程序需要到一个DLL里面的函数或者数据时,就会将相应的DLL加载到自己的虚拟地址空间中。
一个DLL文件可以被多个应用程序直接使用,这样的DLL文件被称为共享DLL文件
1.2 DLL的加载顺序
当应用程序动态加载动态链接库而不指定完全限定的路径名称时,Windows 会尝试通过按特定顺序搜索一组定义完善的目录来查找 DLL。如果攻击者控制 DLL 搜索路径上的某个目录,则可以在该目录中放置 DLL 的恶意副本
DLL劫持技术利用的是Windows对DLL访问时查找DLL位置的一个漏洞,Windows对DLL的默认查找顺序(XP SP2及之后)如下:
官方文档: 1、 Dynamic-link library search order - Win32 apps | Microsoft Learn
2、动态链接库安全性 - Win32 apps | Microsoft Learn
从中加载应用程序的目录。
系统目录。
16 位系统目录。
Windows 目录。
当前目录。
PATH 环境变量中列出的目录。
当应用程序发出 LoadLibrary 调用时,系统会搜索 DLL,在当前目录中查找 DLL 的恶意副本,然后加载它。 然后,DLL 的恶意副本在应用程序中运行,并获取用户的权限。
说的有点啰嗦了,实际的劫持中我们排除某些KnownDlls,排除某些绝对路径加载的DLL,找到可以被劫持的DLL,然后将恶意的DLL放置到原始DLL的路径即可。
二、流程和代码实现
DLL的导出函数:在 C++ 中,导出函数(Export Functions)通常是为了创建动态链接库(DLL)或共享库,以便其他程序或模块可以调用这些函数
导出方式:
详见:C++开发基础之创建DLL的常见的6种导出函数(Export Functions)形式_c++ 导出函数-CSDN博客
⚠注意:DLL劫持注入中,恶意DLL应该与原始DLL某一个函数具有相同的导出函数声明,这样应用程序才能正确调用我们的恶意DLL里的函数。
2.1 DLL劫持测试
构造一个原始DLL
构造一个恶意DLL
构造一个应用程序exe
构造一个原始DLL
构造一个恶意DLL
应用程序代码


2.2 劫持特定函数接口型(Dll漏洞挖掘及白加黑利用)
寻找目标程序除微软DLL外的可被劫持的DLL
构造一个恶意DLL,并声明一个与原始DLL一样的导出函数声明
将恶意DLL放入到原始DLL目录中,并将恶意DLL的名称改为原始DLL的名称。
运行目标程序
现在有一个问题,就是我们如何知道被劫持的DLL里面的导出函数呢?手动去找不太现实,可以利用工具批量查找可利用的DLL。
工具:GitHub - HackerCalico/SkyShadow: Generate DLL Hijacking Payload in batches.
将其中的scan.py分成两部分,一个命名为:scan_MSDLL.py,另一个命名为:scan_DLLHijack.py,首先使用 scan_MSDLL.py 来搜寻微软的DLL,接着使用 scan_DLLHijack.py 来搜寻可以劫持的DLL。
判断了一下获取到的dll如果开头为API以及结尾为HELP或API直接丢弃掉,然后就是判断导出的dll如果大于1个那么也丢弃掉,因为白加黑只需要一个dll,如果导出来太多dll的话没啥用。
⚠注意:使用工具前,请将Tool目录添加到环境变量。
详见:白加黑详解
scan_MSDLL.py
使用默认搜寻路径 python .\scan_MSDLL.py

scan_DLLHijack.py
python .\scan_DLLHijack.py "C:\\"

随便打开一个输出结果的txt,看看里面的导出函数声明,然后将代码复制到VS编译成一个恶意DLL,将恶意DLL的名称修改为 chrome_elf.dll


来到原始DLL的路径 C:\Program Files\Google\Chrome\Application\131.0.6778.265。路径不一定相同,可以使用IDA PRO、windbg、x32/64dbg等工具去看 Chrome 真正加载的dll。
原始DLL:chrome_elf_old.dll 恶意DLL:chrome_elf.dll

来到Chrome.exe真正的目录 C:\Program Files\Google\Chrome\Application

点击运行exe,成功劫持

测试完之后,记得把恶意DLL chrome_elf.dll 给删除,原始DLL chrome_elf_old.dll 的名称修改为 chrome_elf.dll
2.3 DLL函数转发(也称DLL旁路加载)
寻找目标程序除微软DLL外的可被劫持的DLL
根据转发表,构造一个恶意DLL(用AheadLib工具)。
将恶意DLL放入到原始DLL目录中,并将恶意DLL的名称改为原始DLL的名称。
运行目标程序
可以看到上面的GIF图,我点击运行了Chrome,虽然成功执行了我们的恶意代码,但是Chrome并没有正常的执行。这样并不利于我们在实战中使用,所以在编写一个恶意DLL时,我们通常除了让dll的导出表与原dll一致,同时对函数进行向原dll的转发,这样我们就能在用户毫无察觉的情况下运行自定义的代码。

DLL函数转发:
A DLL,其导出函数有 funA,可以供主程序 exe 调用;
B DLL,其导出函数有 funB1, funB2,但是开发者开发时,标记了 funB2 函数实际调用的是 A DLL 的 funA 函数,那么主程序在调用的时候:exe -> funB2 -> funA,即 funB2 只是起到一个中转的作用,前面讲到,我们在调用 DLL 的导出函数时,需要将对应的 DLL 载入内存,获取到其导出函数的内存地址,才能进行调用,所以 exe 在调用 B DLL的 funB1 和 funB2 函数时,不仅需要将 B DLL 载入内存,而且还需要将 A DLL 载入内存。
这个知识点对我们后续开发恶意DLL有很重要的作用,比如说我们可以在dllmain函数中编写恶意代码,而不影响程序的正常执行。
转发函数的形式:
如果被劫持的DLL拥有多个导出函数,则我们就需要全部转发,那么怎么批量生成转发函数表呢?可以使用 AheadLib 工具:[下载] AheadLib修改 支持x64支持类/命名空间-编程技术-看雪-安全社区|安全招聘|kanxue.com
我这里选择的是直接转发函数,当然你也可以用即使调用函数,它们的原理不相同但是达到的效果差不多。
挑选一个可被劫持的DLL,如果要转发的函数太多了,选择一个合适的路径输出cpp文件。

dllmain和EvilFuntion的代码如下,然后将转发函数表代码复制到dllmain函数的下方中。

生成我们的恶意dll并改名,原始DLL改成以Org为后缀。

测试

可以看到,应用程序加载了恶意DLL和原始DLL,这样应用程序就能正常启动,达到隐蔽持久化的目的。

2.4 通用DLL劫持型
这是吾爱破解社区里面的一位大佬分享的技术。通用DLL劫持 ,这是一个 DLL 劫持的底层实现,主要通过直接操作 PEB(进程环境块)和 LDR(加载器)数据结构来替换已加载的 DLL。详细的原理介绍请看 参考文章-1
参考文章: 1、一种通用DLL劫持技术研究 - 吾爱破解 - 52pojie.cn
3、PEB (winternl.h) - Win32 apps | Microsoft Learn
4、PEB_LDR_DATA (winternl.h) - Win32 apps | Microsoft Learn
官方文档的数据结构中某些字段的含义并没有说明,详细字段含义请看参考文章-5。
数据结构定义
获取 PEB 数据结构的地址
⚠注意:
获取当前进程 PEB:使用
__readgsqword(0x60) 或(void*)__readfsdword(0x30)获取远程进程 PEB:使用上下文寄存器方法(
进程镂空注入(Process Hollowing Injection)有介绍)
获取 PEB 中的 Ldr 数据结构的地址
核心劫持函数
没成功,不过有些思路可以学习一下。
完整代码
Last updated