修复DLL劫持的问题

因为最后面DLL劫持的修复方法水了篇文章

DLL劫持

对于DLL劫持简单来说既是:

DLL劫持是一种通过利用某些 Windows 应用程序搜索和加载动态链接库 (DLL) 的方式将恶意代码注入应用程序的方法。

现在DLL加载最常见的搜索顺序如下:

  1. The directory from which the application loaded.
  2. The system directory. Use the GetSystemDirectory function to get the path of this directory.
  3. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
  4. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  5. The current directory.
  6. The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.

-- microsoft docs

具体加载顺序可以参考这里

所以将某些系统的DLL放置在可执行文件的同目录, 则会优先于原本需要加载的系统DLL搜索并加载.

系统缓解措施

大致分为三个阶段

在win xp sp2及以下

远古时期, 无缓解措施

在win7之前

添加了SafeDLLSearchMode注册表,将进程中%cd%这一当前目录的搜索优先级降级了. 本来是紧跟当前可执行文件所在目录后搜索, 如今变为了倒数第二位, 即%PATH%之前搜索

如今

在NT命名空间中存储了KnownDLLs这一列表, 其中所有的内容都仅能从%SystemRoot%\SYSTEM32这一目录下搜索
该项可使用winobj查看, 或者在注册表中查看HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs的值作为参考

但是也有问题, 即KnownDLLs项并不完整, 有些系统库反而不在该列表中. 如msimg32.DLL,Version.DLL 等等

修复

分动态加载与静态加载两种情况. 以下所有方法绝大多数均需要修改源码, 唯一一个不需要源码的可以是manifest的方法, 但是该方法需要patch相关的pe文件.

动态加载的修复

有多种方法

绝对路径加载

一目了然, 不言而喻.

1
LoadLibraryA("/path/to/library.DLL");

设置搜索路径

使用Set­DLL­Directory函数设置一个路径, 若传入路径为空, 则在DLL搜索路径中删去进程中%cd%这一当前目录.
实际上效果较低.

1
2
Set­DLL­Directory("")
LoadLibraryA("system_library.DLL")

hash校验

在装载DLL前, 先对文件的hash进行校验, 确认文件未被修改.

使用函数设置搜索行为

使用SetDefaultDLLDirectories函数来设置默认的行为, 其中若使用LOAD_LIBRARY_SEARCH_SYSTEM32这一参数, 则只搜索%SystemRoot%\SYSTEM32这一目录.

1
2
SetDefaultDLLDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32)
LoadLibraryA("system_library.DLL")

使用函数加载DLL

低版本不支持此函数, 该函数的flag可指定仅搜索%SystemRoot%\SYSTEM32这一目录.

1
LoadLibraryEx("system_library.DLL", 0, LOAD_LIBRARY_SEARCH_SYSTEM32)

导入表加载

搜索后得知也有多种方法, 已经在多个开源项目中使用. 这也是这篇文章的原因. 😀

嵌入manifest文件

在exe嵌入的manifest文件中设置文件的路径. 这个仅作为记录, 未测试.
该项唯一可在github上参考的是这个链接, 看来对非csharp编写可执行文件的也起作用.

1
2
3
4
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<file name="library.DLL" loadFrom="/path/to/ibrary.DLL" />
</assembly>

延迟加载

编辑link.exe的链接参数, 将所需DLL改为以参数/DELAYLOAD的形式链接.
同时在代码初始化的地方设置SetDefaultDLLDirectories, 这样延迟加载的DLL亦会收到前面所述函数的影响.

这里是某软件编译时使用延迟加载的方式去链接DLL
image.png

这里是同一软件初始化时使用SetDefaultDLLDirectories函数来设置DLL装载搜索路径默认的行为
image.png

参考资料

desktop-app/lib_base: Different useful utilities. (github.com)
Windows DLL Hijacking (Hopefully) Clarified | itm4n’s blog
Dynamic-Link Library Search Order - Win32 apps | Microsoft Docs
Windows: Add explicit manifest to Windows build · Issue #2326 · curl/curl (github.com)