恶意程序研究之DLL劫持
郑重声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,如果您不同意请关闭该页面!任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!
DLL劫持
DLL劫持一直深受黑客们的喜欢,利用此技术可以实现启动木马后门,游戏外挂插件的注入,绕过UAC等操作。
全文约定:全文中系统盘所在的位置默认为C盘
DLL加载顺序
DLL是以文件的形式存在在硬盘中,那么应用程序又是如何索引所需的DLL呢?其实,Microsoft已在此处完整记录了DLL搜索顺序。
微软的DLL劫持分为三个阶段
- 无保护阶段:Windows XP SP2之前
- 保护阶段:Windows XP SP2之后,Windows 7之前
- 进一步保护阶段:Windows 7之后
Windows XP SP2之前
- 进程对应的应用程序所在目录;
- 加载 DLL 时所在的当前目录;
- 系统目录即 SYSTEM32 目录(通过 GetSystemDirectory 获取);
- 16位系统目录即 SYSTEM 目录;
- Windows目录(通过 GetWindowsDirectory 获取);
- PATH环境变量中的各个目录;
Windows XP SP2之后
微软为了防止DLL劫持漏洞的产生,在XP SP2之后,添加了一个SafeDllSearchMode的注册表属性。注册表路径如下:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SafeDllSearchMode |
当SafeDllSearchMode的值设置为1,即安全DLL搜索模式开启时,查找DLL的目录顺序如下:
- 应用程序所在目录;
- 系统目录SYSTEM32 目录;
- 16位系统目录即SYSTEM 目录。该项只是为了向前兼容的处理,可以不考虑;
- Windows目录。通常是C:\Windows;
- 加载 DLL 时所在的当前目录;
- 环境变量PATH中所有目录。需要注意的是,这里不包括App Paths注册表项指定的应用程序路径。
PS:"安全DLL查找模式"默认是启用的
Windows 7之后
微软为了更进一步的防御系统的DLL被劫持,将一些容易被劫持的系统DLL写进了一个注册表项中,那么凡是此项下的DLL文件就会被禁止从EXE自身所在的目录下调用,而只能从系统目录即SYSTEM32目录下调用。注册表路径如下:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs |
Windows 10中的如下
如何寻找DLL劫持
劫持系统DLL
要分析一个应用程序是否存在劫持系统DLL的漏洞,需要这么几个步骤
- 启动应用程序
- 使用Process Explorer等类似软件查看该应用程序启动后加载的动态链接库。
- 从该应用程序已经加载的DLL列表中,查找在上述“KnownDLLs注册表项”中不存在的DLL。
- 编写从上一步获取到的DLL的劫持DLL。
- 将编写好的劫持DLL放到该应用程序目录下,重新启动该应用程序,检测是否劫持成功。
如果对以上步骤都没问题还是没有实现劫持的话,具体可能有一下情况
- DLL不在KnownDLLs注册表中但是已经被微软做了保护,比如ntdll.dll等系统核心dll
- 宿主进程在调用LoadLibrary函数时使用了“绝对路径”
- 宿主进程对调用的DLL进行了校检,比如文件MD5、HASH等值
- 宿主调用DLL时使用了SetDllDirectory函数把当前目录从DLL的搜索顺序列表中删除
劫持应用DLL
劫持这个DLL就方便多了,只要宿主没有对自己的DLL做校检的话就可以进行劫持替换
手动寻找
由于Windows 10做了很多限制,我们使用Windows 7来测试会方便很多,如果是新的Windows 7系统需要打个补丁,不然用不了Process Monitor
https://www.microsoft.com/en-us/download/confirmation.aspx?id=46148 |
利用NDP461-KB3102438-Web.exe
程序进行进行测试
#微软下载地址 |
然后使用Process Monitor做如下设置
Include the following filters: |
设置Exclude Result is SUCCESS后会只显示NAME NOT FOUND项,也就是只查看未成功加载的dll项,即KnownDLLs的列表中不包含的dll名称,可用于查找存在漏洞的dll路径
可以看到NDP461-KB3102438-Web.exe
在启动的过程中会加载下图中框起来的DLL,并且DLL的路径和这个进程在相同文件夹,同时显示NAME NOT FOUND
,表示无法找到该文件,加载失败,这就说明这几个DLL是可以进行劫持的
劫持测试
既然发现了劫持的DLL,我们就可以进程初步演示了,搞一个执行计算器的DLL然后把它改名为CRYPTSP.dll,接着运行程序即可达到劫持的作用
实战化利用
如果动手过的小伙伴可以发现,如果我们吧CRYPTSP.dll的名称改成VERSION.dll的时候用来劫持的话,会发现报错。
主要的原因是测试DLL只有一个加载的时候执行计算器的函数,而并没有劫持目标上面的所有导出函数,所以当我们找到了一个可以劫持的DLL的时候,需要用脚本一键生成劫持cpp文件后进行编译,以下是对系统中的twain_32的一键生成方式的演示
导出后我们就可以把免杀代码放到这个位置然后编译即可
参考文章
https://github.com/sensepost/rattler |