安全加载库 | MSRC博客
动态加载库到应用程序中如果未正确保护可能导致漏洞。在本博客文章中,我们讨论使用LoadLibraryEx() API加载库,并利用其选项确保安全。
了解默认设置
传递给LoadLibrary() / LoadLibraryEx()调用的库文件名不需要包含扩展名。如果未指定扩展名,则使用默认库文件扩展名.DLL。由于此特性,如果传递null作为库名称,它会尝试加载“.DLL”,这可能被通过在搜索路径中放置“.DLL”文件来利用。
传递给LoadLibrary()/ LoadLibraryEx()调用的库文件名不需要指定目录路径。如果指定了路径,则仅从指定路径加载库。否则,使用以下默认DLL搜索顺序:
- 当前进程映像文件目录,应用程序目录
- 系统目录
- 16位系统目录
- Windows目录
- 当前工作目录
- PATH环境变量中列出的目录
Windows维护一个已知DLL列表,这些基本上是系统DLL集合,当指定绝对名称时,始终保证从系统目录加载。
加载库到内存后,会调用已加载库中的DllMain()函数。
控制DLL搜索顺序
有多种选项可以修改加载库时的搜索顺序,与提供绝对名称时的默认搜索顺序不同。
以下是一些可以通过LoadLibraryEx()影响DLL搜索顺序/路径的API:
- SetDllDirectory():将目录添加到用于定位应用程序DLL的搜索路径中
- SetDefaultDllDirectories():将目录添加到进程DLL搜索路径
- AddDllDirectory():将目录添加到进程DLL搜索路径
- RemoveDllDirectory():移除通过AddDllDirectory()添加到进程DLL搜索路径的目录
- SearchPath():在指定路径中搜索指定文件
- SetSearchPathMode():设置SearchPath()函数在定位文件时使用的每进程模式
- SetCurrentDirectory():更改当前进程的当前目录
- DefaultDllImportSearchPathsAttribute:对于托管应用程序,使用此属性指定平台调用期间搜索DLL的路径
LoadLibraryEx()提供了许多可用于更改默认搜索顺序的标志。下表列出了大多数标志,并描述了每个标志遵循的DLL搜索顺序。某些选项甚至考虑了使用上述API设置的路径。
以非可执行方式加载库
并不总是需要将库作为可执行映像加载。LoadLibraryEx()可以使其作为数据文件或图像资源加载。为此,它支持以下不同选项:
- LOAD_LIBRARY_AS_DATAFILE
- LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
- LOAD_LIBRARY_AS_IMAGE_RESOURCE
- DONT_RESOLVE_DLL_REFERENCES
这些选项有助于将文件视为普通数据文件而不是可执行模块。使用此选项加载不会调用DLLMain(),并且加载的DLL数据的内存空间都不会标记为可执行。
阻止库加载
有时可能需要阻止库或非法库加载到应用程序中。查看以下设施来帮助实现:
AppLocker
AppLocker是一种基于策略的机制,用于阻止DLL加载到应用程序中。这些策略可以通过组策略推送。AppLocker可以控制可执行文件、脚本和安装程序。
当新DLL加载时,会向AppLocker发送通知以验证是否允许加载该DLL。AppLocker调用应用程序标识组件来计算文件属性。它复制现有的进程令牌,并用加载的DLL的属性替换复制的令牌中的那些应用程序标识属性。AppLocker然后评估此DLL的策略,并丢弃复制的令牌。根据此检查的结果,系统要么继续加载DLL,要么停止进程。
AppLocker可以根据路径、发布者或文件哈希阻止DLL。
代码签名
Microsoft Authenticode技术可用于对DLL进行签名,即将数字签名附加到DLL以保证其真实性和完整性。
总结讨论
为确保安全加载库:
- 使用适当的DLL搜索顺序
- 当库位置固定时,始终指定完全限定路径
- 需要时作为数据文件加载
- 利用代码签名基础设施或AppLocker
我们常见的一些攻击向量:
-
应用程序目录攻击,特别是从临时互联网或下载文件夹的角度。特别是当应用程序是安装程序时,人们通常会将安装程序下载到默认目录并从那里执行。考虑到攻击者可以在默认目录中放置恶意文件,可以利用应用程序目录加载DLL。在这种情况下也可以使用清单和.local重定向。
-
从内存加载DLL以及PowerShell DLL注入。恶意软件可以使用这些方法来避免检测恶意DLL的加载。
-
从远程位置加载库时的TOCTOU攻击。
-
Swamy Shivaganga Nagaraju,MSRC工程团队