C++ 通过LoadLibrary()和GetModuleHandle()使用绝对路径加载系统DLL是否能更好地防止DLL劫持?

C++ 通过LoadLibrary()和GetModuleHandle()使用绝对路径加载系统DLL是否能更好地防止DLL劫持?,c++,windows,security,winapi,dll,C++,Windows,Security,Winapi,Dll,在许多情况下,要加载一些较新的API,需要使用如下构造: (FARPROC&)pfnZwQueryVirtualMemory = ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "ZwQueryVirtualMemory"); 但是,考虑到Dll被劫持的可能性,指定Dll的绝对路径是否更好。或者这只是一种过度的杀伤力 WCHAR buff[MAX_PATH]; buff[0] = 0; if(::GetSystemDirectory(

在许多情况下,要加载一些较新的API,需要使用如下构造:

(FARPROC&)pfnZwQueryVirtualMemory = ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "ZwQueryVirtualMemory");
但是,考虑到Dll被劫持的可能性,指定Dll的绝对路径是否更好。或者这只是一种过度的杀伤力

WCHAR buff[MAX_PATH];
buff[0] = 0;
if(::GetSystemDirectory(buff, MAX_PATH) &&
    ::PathAddBackslash(buff) &&
    SUCCEEDED(::StringCchCat(buff, MAX_PATH, L"ntdll.dll")))
{
    (FARPROC&)pfnZwQueryVirtualMemory = ::GetProcAddress(::GetModuleHandle(buff), "ZwQueryVirtualMemory");
}
else
{
    //Something went wrong
    pfnZwQueryVirtualMemory = NULL;
}

后一种方法的问题是,它并不总是适用于Comctl32.dll。

您不必对ntdll.dll和kernel32.dll执行任何特殊操作,因为它们将在您有机会执行任何操作之前加载,它们也在已知的dll列表中

dll劫持问题通常包括辅助库。以version.dll为例,它不再位于已知dll列表中,因此显式链接到它是有问题的,需要动态加载它

最好的解决方案是三件事的组合:

如果Win8+和更新的Win7可用,请调用。 在调用GetModuleHandle之前,使用完整路径GetSystemDirectory调用LoadLibrary。 不要显式链接到除kernel32、user32、gdi32、shlwapi、shell32、ole32、comdlg32和comctl32之外的任何内容。 如果SetDefaultDllDirectories不可用,那么如果不控制应用程序目录,就很难保护自己,因为各种Windows函数都会延迟加载dll,例如没有完整路径的shcore.dll,尤其是shell API。SetDllDirectory有助于解决当前/工作目录问题,但对于未修补的Win8之前的系统,没有很好的应用程序目录解决方案,您只需在WinMain的早期使用测试并手动加载有问题的库


应用程序目录是一个问题,因为有些用户只是将所有内容都放在下载文件夹中,然后从那里运行它。这意味着您的应用程序目录中可能会有一个恶意dll。

如果用户为您的应用程序启用了兼容模式,此方法也将失败。我个人的意见-这太麻烦了,收获很少。@Ari0nhh:我不同意。应用程序的Dll劫持将是一个非常糟糕的安全问题。但是,尽管如此,您能否解释一下,如果启用了兼容模式,为什么会失败呢。更多信息请点击@Anders,那又怎样?我真的不认为这是每个第三方应用程序的责任。我的应用程序不需要安装程序。它是一个独立的可执行文件,可以从任何位置运行。是的,它可以从下载文件夹、临时文件夹或其他任何地方运行。这就是我的担忧。谢谢。但在这种情况下,必须使用GetModuleHandle动态调出SetDefaultDllDirectory,除非您希望应用程序跳过对Windows 8之前版本的支持。这不是问题,直接链接到内核32并执行GetProcAddressLoadLibraryAKERNEL32,WinMain中的SetDefaultDllDirectories非常好。这带来了一个有趣的观点。显然,内核32.dll将在启动时加载到进程中。但是,如果一个名为kernel32.dll的恶意dll被注入到同一进程中,该怎么办。当我在存在2个kernel32.dll的情况下调用GetModuleHandle时会发生什么?真正的kernel32将是PEB模块列表中位于.exe和ntdll之后的第二个或第三个模块,如果加载时没有路径,它将位于另一个伪dll之前。当然,注入的代码可以在列表的早期插入自身,但如果代码可以注入自身,那么就已经丢失了。你应该注意不要从不安全的地方装载,不要防止注射,因为机器在那一点上已经损坏了。好的。我懂了。是否有一条规则定义GetModuleHandle如何选择首先加载哪个库?文档说,如果lpModuleName不包含路径,并且有多个加载的模块具有相同的基本名称和扩展名,则无法预测将返回哪个模块句柄。我猜SetDefaultDllDirectories甚至不会影响它。至于不从不安全的地方加载,就像我说的,它是一个独立的可执行文件。它可以从用户选择的任何位置运行。