欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于系统搜索某个DLL的路径

程序员文章站 2023-12-26 23:08:45
...

引言

我们可以使用LoadLibrary()LoadLibraryEx()来显式地加载某个dll,在我们未提供dll全路径或调用SetDefaultDllDirectories和 AddDllDirectory两个API对DLL路径进行设置时,系统依然会尝试着在某些目录下寻找我们想要的DLL文件,在寻找DLL时,Windows系统会按一定的顺序在不同的目录下查找.


Windows查找DLL的顺序

在以前的Windows版本(Windows xp sp2之前),系统在寻找某个DLL时,会按照以下顺序搜索:

  1. 应用程序EXE所在的路径。
  2. 当前目录(可通过SetCurrentDirectory设置,GetCurrentDirectory获取)
  3. 系统目录(通常是C:\Windows\System32,WOW64程序也会重定向到C:\Windows\SysWOW64目录,可以通过GetSystemDirectory获取)
  4. 16位系统目录(通常是,C:\Windows\System)
  5. Windows目录(通常是,C:\Windows,可以通过GetWindowsDirectory获取)
  6. PATH环境变量指定的目录

由于很多恶意程序利用这一机制,在程序的当前目录放置与程序欲加载的DLL同名的假DLL文件,导致程序加载了错误的DLL(这一过程又叫DLL劫持),在Windows xp sp2之后,WIndows系统默认开启了一种名为安全DLL搜索模式(SafeDllSearchMode)的机制,该机制将使系统按如下模式搜索DLL:

  1. 应用程序EXE所在的路径。
  2. 系统目录。
  3. 16位系统目录
  4. Windows目录
  5. 当前目录
  6. PATH环境变量指定的目录

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager目录下的键值SafeDllSearchMode的值设置为0时将关闭该机制,win7win10没找到该键值但验证下来的确开启了该机制

验证SafeDllSearchMode

我们可以验证这一机制,具体做法为:

  • 编写一个dll
  • 在dllmain中输出调用GetModuleFileName输出当前dll所在目录
  • 将该dll在上面提到的所有路径中都放置一个dll的副本
  • 使用我们的程序加载该dll(仅传入dll名字)
  • 这样输出的值就是系统搜索dll的第一个路径
  • 删除该路径下的dll,输出下一搜索路径
  • 验证完毕

下面是DLL的代码:

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        char szDllPath[MAX_PATH] = { 0 };
        GetModuleFileNameA(hModule, szDllPath, MAX_PATH);//输出dll所在路径
        cout << "DLL PATH: " << szDllPath << endl;
    }
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

exe的代码:

int main()
{
    HMODULE hModuel = LoadLibraryA("mydll");
    if (hModuel == NULL)
    {
        printf("LOADFAILED");
    }
    MessageBox(NULL, NULL, NULL, NULL);
    return 0;
}

下面是输出结果(这里当前目录为G\Git\cmd,环境变量里也有G\Git\cmd这一项(第一个输出结果是多余的,操作失误了一下):
关于系统搜索某个DLL的路径

可以看见,SafeDllSearchMode的确在起作用

DLL重定向

将一个DLL名称字符串解析成一个文件前,加载器LDR将利用Dll名称重定向来扩展或者改变DLL名字空间的某些部分
对于应用程序,规则有:

  • MinWin API集重定向

  • .LOCAL重定向:
    在没有清单文件时(一般默认都有),将某个特定DLL基本名称的所有加载操作(就算指明了全路径)都重定向至EXE所在路径下的本地副本上,假设exe名称为Myapp.exe存放于Myapp\目录下,则重定向的路径为Myapp\Myapp.exe.local\MyLibrary.dll
    在Win7WIn10中,欲开启该规则,需要将HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\Current Version\Image File Execution Options下添加一个dword键DevOverrideEnable,并设置值为1,重启电脑方可起效

  • Fusion(Side by side,并行程序集,SxS)

  • 已知DLL重定向 (KnownDlls):
    计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs存放着一些(不带扩展名的)dll名字的键值,在加载这些DLL时,系统将直接去SYSTEM 32目录下加载这些DLL,然后才按上述路径搜索
    在计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager下有一键值叫ExcludeFromKnownDLLs,在其中加入指定dll则系统不会对其启用已知DLL重定向

DLL重定向一旦生效,系统将不会去按刚才说的搜索路径去搜索DLL,关于KnownDlls重定向有不少可说的,这里暂且放下

相关标签: DLL

上一篇:

下一篇: