Win32 应用程序是不是自动链接到 ntdll.dll?

Posted

技术标签:

【中文标题】Win32 应用程序是不是自动链接到 ntdll.dll?【英文标题】:Are Win32 applications automatically linked against ntdll.dll?Win32 应用程序是否自动链接到 ntdll.dll? 【发布时间】:2017-09-22 21:04:15 【问题描述】:

我刚刚偶然发现这样做GetModuleHandle("ntdll.dll") 可以在没有之前调用LoadLibrary("ntdll.dll") 的情况下工作。

这意味着ntdll.dll 已经加载到我的进程中。

是否可以假设ntdll.dll 将始终加载到 Win32 应用程序上,从而无需调用 LoadLibrary

【问题讨论】:

这是一个可能会更改的实现细节。您应该不直接使用 ntdll.dll 中的任何内容。但只要您这样做,Microsoft 只能在您正确执行此操作的情况下为您提供帮助。避免 LoadLibrary() 是没有意义的。 ntdll.dll 总是在所有进程中加载​​。它一直是并且永远是肯定的 这样想……你调用了GetModuleHandle()。 GetModuleHandle() 在 kernel32.dll 中,因此您的应用程序必须链接到它。如果您查看 kernel32.dll 的依赖关系,您会发现它依赖于 ntdll.dll。因此,如果您的应用程序必须加载 kernel32,那么它也必须加载 ntdll。但是,对于 ntdll 来说,这不足为奇,因为它是任何 Win32 进程的根。 kernel32 中有几个/许多函数是 ntdll 中函数的包装器。 @JoeWillcoxson - ntdll.dll 加载 before kernel.32 或任何其他 dll 的原因很深。当进程启动时,它必须从用户模式下的哪个地址开始执行?当新线程开始时 - 再次从用户模式的哪一点开始?当内核将异常传递给用户模式时 - 到哪个地址?当 Apc 执行时-这是用户模式下的第一条指令?当任何 Windows 消息来处理 - 再次第一个用户模式指令在哪里? ntdll.dll 保存从内核到用户模式的入口点。以及当进程开始执行时 - 谁在初始化用户模式空间,加载附加 dll,等等 这一切都是 ntdll.dll 做的。一些进程根本不使用 kernel32.dll。但是 ntdll.dll 总是由内核映射到进程空间 【参考方案1】:

来自MSDN on LoadLibrary()(强调我的):

系统对所有加载的进程维护一个每个进程的引用计数 模块。调用 LoadLibrary 会增加引用计数。 调用 FreeLibrary 或 FreeLibraryAndExitThread 函数递减 参考计数。系统在其引用计数时卸载模块 达到零或进程终止时(无论 引用计数)。

换句话说,为了安全起见,继续调用 LoadLibrary() 并确保您得到ntdll.dll 的句柄 - 但系统几乎肯定会碰到引用计数,因为它应该已经加载了。

至于“它真的总是加载吗?”,请参阅Windows Internals on the Image Loader(简短的回答是肯定的,ntdll.dll 是加载器本身的一部分并且始终存在)。

相关段落是:

图像加载器位于用户模式系统 DLL Ntdll.dll 中,而不是内核库中。因此,它的行为与作为 DLL 一部分的标准代码一样,并且在内存访问和安全权限方面受到相同的限制。这段代码的特别之处在于保证它始终存在于运行进程中(Ntdll.dll 总是被加载),并且它是第一段在用户模式下运行的代码,作为一个新的应用程序。 (当系统构建初始上下文时,程序计数器或指令指针被设置为 Ntdll.dll 中的一个初始化函数。)

【讨论】:

以上是关于Win32 应用程序是不是自动链接到 ntdll.dll?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法让Windows 7 x64从本地目录加载ntdll.dll,而不是system32?

Delphi:如何确定应用程序是不是在 Win32 / Win64 下运行并在 64 位上自动启动 64 位版本?

WIN32对话框抛出异常[重复]

硬链接到带有 Win32 API 的符号链接?

将用户模式 ​​dll 中的高级函数映射到 NTDLL.dll

关于在WIN32调用一些Zw系列的文件操作函数