如何在CGO加载库前调用SetDefaultDllDirectories防范DLL劫持?
问题描述
我需要保护Go应用免受DLL劫持威胁。当前应用存在漏洞:部分加载的DLL会优先从本地路径(./)查找系统DLL(如winmm.dll)。为解决该问题,我在main()函数开头调用了以下代码:
windows.SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32)
该调用对后续通过完整本地路径加载的DLL有效,但对CGO导入的库无效。通过Process Explorer观察到winmm.dll仍会从本地路径查找,推测CGO在main()执行前已完成该库的导入与加载。我通过以下方式在CGO中加载库:
#cgo LDFLAGS: -L . -lmylib #include <string.h> #include <stdlib.h> #include <mylib.h>
请问是否有办法让main()中的SetDefaultDllDirectories()调用对CGO加载的库生效?
解决方案
由于CGO依赖的库会在Go的main()函数执行前完成加载,因此main()中设置的DLL搜索路径无法覆盖这一阶段的加载行为。你需要在任何DLL加载之前设置默认搜索路径,以下是两种可行方案:
方案1:使用C构造函数提前设置路径
在CGO代码中添加一个带有__attribute__((constructor))标记的C函数,该函数会在程序启动初期(早于CGO依赖库加载、早于Go的main()执行)自动执行,从而提前设置DLL搜索路径:
#cgo LDFLAGS: -L . -lmylib #include <string.h> #include <stdlib.h> #include <mylib.h> #include <windows.h> #ifdef _WIN32 __attribute__((constructor)) void init_dll_search_path() { // 设置默认仅从System32目录查找系统DLL SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32); } #endif
这个构造函数会优先于所有依赖库的加载逻辑执行,确保winmm.dll这类系统DLL只会从系统目录加载,避免本地路径劫持。
方案2:延迟加载CGO依赖库(仅适用于动态链接库)
如果mylib是动态链接库(.dll文件),可以通过延迟加载的方式,让其在main()设置完路径后再加载:
- 修改CGO的链接选项,添加延迟加载标记:
#cgo LDFLAGS: -L . -lmylib -delayload:mylib.dll
- 在Go的
main()函数开头先设置DLL搜索路径,再手动触发mylib的加载:
import "syscall" import "unsafe" /* #cgo LDFLAGS: -L . -lmylib -delayload:mylib.dll #include <mylib.h> void trigger_load() {} */ import "C" func main() { windows.SetDefaultDllDirectories(windows.LOAD_LIBRARY_SEARCH_SYSTEM32) // 触发mylib的加载 C.trigger_load() // 后续业务逻辑 }
这种方式通过延迟加载机制,让DLL搜索路径设置生效后再加载依赖库,从而避免劫持风险。
内容的提问来源于stack exchange,提问作者Volker
相关产品推荐
相关产品推荐

