DLL劫持
DLL劫持已经是一个很古老成熟对技术了,以前就有看到有许多人用来做游戏外挂(2008年左右甚至更早以前),近期我了解到现在还有许多对人使用DLL劫持做权限维持,因为之前只是一直知道这个技术原理但是却没有实际使用过,并且最近看到有人开源了一份非常不错的检测工具,于是就打算动手做一下相关对分析研究。
DLL劫持简介
DLL全称dynamic-link library,即动态链接库,是一个包含可以由多个程序同时使用的代码和数据的库。比如,windows操作系统中的Comdlg32.dll 包含常见的对话框相关导出函数,当我们在程序中加载该DLL后,就能使用该DLL中的函数来实现“打开”对话框。
用大白话解释,每一个DLL都有一些特定的功能,包含该DLL即可使用这些功能。
而DLL劫持其实就是在不破坏目标DLL的功能的情况下,增加一些恶意代码,使程序执行恶意代码。有两种思路,第一种是编写恶意DLL做函数转发,大致流程如下所示
第二种思路是直接将恶意代码写入到正常DLL中。
另外,还有一类利用思路也归并到DLL劫持当中。
遗弃DLL劫持方式
这种方式个人感觉最方便,只需要一个免杀的DLL即可(当然免杀也不简单),所以优先讲这个。但在介绍利用函数转发方式的DLL劫持方法之前,必须要先介绍一下Windows对于指定DLL的搜索方式。
DLL搜索顺序
当在代码中使用LoadLibrary(“hello.dll”)函数来加载DLL时,操作系统便会开始搜索DLL。
在系统搜索DLL之前,它会检查以下内容:
1、如果已在内存中加载具有相同模块名称的DLL,则系统将使用加载的DLL,无论它在哪个目录中,系统不搜索DLL。
2、如果DLL位于KnownDLLs列表中,则系统将使用其已知DLL(以及已知DLL的相关DLL,如果有),系统不搜索DLL。
默认情况下启用安全DLL搜索模式。要禁用此功能则需要创建HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager \SafeDllSearchMode注册表值并将其设置为0。
默认开启的SafeDllSearchMode搜索顺序如下: 1、进程对应的应用程序所在目录 2、系统目录(使用GetSystemDirectory函数获取此目录的路径) 3、16位系统目录(c:\windows\system没有函数可以获取此目录的路径,但会搜索它) 4、Windows目录(使用GetWindowsDirectory函数获取此目录的路径) 5、当前工作目录(Current Directory) 6、PATH环境变量中列出的目录
禁用SafeDllSearchMode后的搜索顺序如下: 1、进程对应的应用程序所在目录 2、当前工作目录(Current Directory) 3、系统目录(使用GetSystemDirectory函数获取此目录的路径) 4、16位系统目录(c:\windows\system没有函数可以获取此目录的路径,但会搜索它) 5、Windows目录(使用GetWindowsDirectory函数获取此目录的路径) 6、PATH环境变量中列出的目录
注: KnownDLLs
注册表位置:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs。
KnownDLLs注册表项下包含一系列常见的系统dll,如usp10.dll、lpk.dll、shell32.dll、user32.dll
如果创建注册表项
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager\ExcludeFromKnownDlls
并指定具体dll名称,可以使KnownDLLs列表中同名的dll保护失效,修改后需要重启才能生效。
产生原因
程序或者服务尝试加载系统中不存在的DLL
那么怎么知道哪些不存在的DLL是程序或者服务会去尝试加载的呢?这里就必须要推荐一下国外大牛的开源工具–DLLSPY,利用该工具的静态检测方法就可以找到遗弃DLL,该工具用法十分简单,github上写得很清楚。
利用方法
由于程序或者服务会根据名称在系统中搜索指定DLL,那么利用方式十分简单,直接将恶意DLL文件修改为程序搜索或者服务尝试加载的DLL名称,然后将该恶意DLL放在任意的DLL搜索目录下即可。可以使用cobaltstrike生成的becaon.dll进行测试,当程序或者服务加载该DLL后即可得到Beacon(需关闭Defender)。
函数转发的DLL劫持方式
这种方式已经是很传统的方法了,说存在了十几年也不是太夸张的说法。这还可以理解成一种MITM Attack(中间人攻击)。
产生原因
程序没有对加载的DLL进行校验。
利用方法
先介绍怎么用DLLHijcker完成这件事 1、下载脚本安装了相关的依赖后,运行该脚本,参数为要劫持的目标DLL文件,然后会在当前目录下生成一个VS2019的项目。 2、打开该项目后修改Hijack函数的函数体,可以只是修改shellcode,也可以修改加载shellcode的方式(该加载方式来自于MSF,特征明显,无法绕过Defender),修改后编译该DLL文件。 3、将原始DLL文件移动到搜索顺序优先级低的文件夹底下。 4、将恶意DLL移动至目标DLL的文件下。
再介绍一下手工的利用方法,利用IDA查看DLL的导出表,记录每个导出函数的函数名以及参数类型,然后自己再新建一个DLL项目,编写相关的代码。
注意x86与x64的函数转发实现方式是不同的。手工的方式就不仔细叙述了,感兴趣的话可以利用DLLHijacker生成x86与x64的DLL文件,自己理解一下相关代码(其实代码逻辑很简单),有不懂的可以去看雪查看相关资料。
篡改正常DLL的劫持方式
这种方式最好的利用方式就是使用The Backdoor Factory(BDF),该工具最初于2014年发布,最后一次更新是在2017年。至于为什么最好等利用方式是这个呢,原因是我自己目前还没有花时间来完整手工复现一次…,这里立一个Flag,等以后手工复现完后再来更新这一小节。
产生原因
程序没有对加载的DLL进行校验。
利用方法
1、下载BDF,用-f指定要篡改的目标DLL,-s指定SHELLCODE。
2、将目标DLL修改为.bak后缀(保险措施)。
3、将篡改后的DLL文件移动至目标DLL目录下。
SUMMARY
其实还有另一种方法可以做DLL劫持,即在恶意DLL文件中篡改程序使用LoadLibrary的句柄返回,将原先要返回恶意DLL的句柄修改为返回原始DLL的句柄,这种方式是通过修改LDR_DATA_TABLE_ENTRY结构体中的BaseAddress来实现的,具体可以看一下看雪的帖子。我在实际复现的时候也遇到了很多问题,最后的解决方法也蛮奇怪的,将vs2017升级成vs2019后编译即可解决加载的程序一直崩溃的问题。等以后有时间的时候我再深入研究一下,该方法较传统的劫持是否存在什么优势。
另外,在做相关的分析研究的时候,踩了不少坑。
比如x86与x64的函数转发方式是不相同的,一开始没找到x64该怎么做劫持,后来问来问去总算是理解了其中的原因并找到可用的方法。然后在加载shellcode的时候又出现各种各样导致程序崩溃的bug,厚着脸请教大牛并用windbg一步一步调试,最后总算是解决了问题(虽然加载方式不能免杀)。
又比如利用函数转发的方式劫持某个程序的DLL时,发现该程序在加载了恶意DLL后直接崩溃,利用Process Monitor 定位问题,发现是程序不会再次搜索该DLL所在的目录(普通用户权限可修改的目录),只会按照系统搜索路径来搜索DLL,即使我在恶意DLL中用绝对路径去加载正常的DLL也不行,于是只能将原始DLL放到系统搜索目录下(这一步需要管理员权限)。文章来源:https://www.toymoban.com/news/detail-851161.html
Win10虚拟机下的DLL搜索情况,注意到当前工作目录最后才搜索,与MSDN描述不太一样。文章来源地址https://www.toymoban.com/news/detail-851161.html
到了这里,关于白加黑(dll劫持)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!