天道酬勤,学无止境

Loading/calling ntdll from DllMain

One should not use functions other than those in kernel32.dll from DllMain:

From MS documentation:

Because Kernel32.dll is guaranteed to be loaded in the process address space when the entry-point function is called, calling functions in Kernel32.dll does not result in the DLL being used before its initialization code has been executed. Therefore, the entry-point function can call functions in Kernel32.dll that do not load other DLLs. For example, DllMain can create synchronization objects such as critical sections and mutexes, and use TLS. Unfortunately, there is not a comprehensive list of safe functions in Kernel32.dll.
...
Calling functions that require DLLs other than Kernel32.dll may result in problems that are difficult to diagnose. For example, calling User, Shell, and COM functions can cause access violation errors, because some functions load other system components. Conversely, calling functions such as these during termination can cause access violation errors because the corresponding component may already have been unloaded or uninitialized.

My question:
But the documentation does not mention ntdll.dll. - Can I call LoadLibrary for "ntdll" and use functions in ntdll from DllMain:
1) during DLL_PROCESS_ATTACH (load and use functions of ntdll)?
2) during DLL_PROCESS_DETACH (use functions of previously loaded ntdll)?


Also, please, would somebody with 1500+ reputation like to create a new tag titled "dllmain" ?

评论

The answer to the question "is it safe in DllMain" always defaults to "no". In this case, calling LoadLibrary is never okay.

Generally speaking, calling anything in ntdll.dll is not recommended even places where it is safe to do so.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • C++11 std::mutex in Visual Studio 2012 deadlock when locked from DllMain()
    I am seeing a deadlock with std::mutex when the mutex is locked from DllMain() Below is a minimal DLL test case that exhibits the problem for me. My actual code does the mutex locking because it uses member functions that are also usable outside initialization during normal function. I think that the problem is a deadlock between the scheduler as seen in the call stack of main() thread and the other thread (probably) spawned by the scheduler. The deadlock seems to happen before main() is actually executed. I would appreciate any advice as to how to fix/resolve the deadlock. Simple DLL: static
  • windbg crash dump analysis, high cpu usage -
    My application(web api) is suffering with high cpu, while analyzing dump, I see my most of the threads have this !dumpstack -: Child-SP RetAddr Caller, Callee 00000030497bec00 00007ffbb19e1118 KERNELBASE!WaitForSingleObjectEx+0x94, calling ntdll!NtWaitForSingleObject 00000030497beca0 00007ffba8375dda clr!CLRSemaphore::Wait+0xee, calling kernel32!WaitForSingleObjectEx 00000030497becd0 00007ffba837345d clr!GCCoop::GCCoop+0xe, calling clr!GetThread 00000030497bed60 00007ffba8375842 clr!ThreadpoolMgr::WorkerThreadStart+0x482, calling clr!CLRSemaphore::Wait 00000030497bee00 00007ffba8393e1e clr
  • windbg 故障转储分析,cpu 使用率高 -(windbg crash dump analysis, high cpu usage -)
    问题 我的应用程序(web api)受到高 CPU 的影响,在分析转储时,我看到我的大部分线程都有这个 !dumpstack -: Child-SP RetAddr Caller, Callee 00000030497bec00 00007ffbb19e1118 KERNELBASE!WaitForSingleObjectEx+0x94, calling ntdll!NtWaitForSingleObject 00000030497beca0 00007ffba8375dda clr!CLRSemaphore::Wait+0xee, calling kernel32!WaitForSingleObjectEx 00000030497becd0 00007ffba837345d clr!GCCoop::GCCoop+0xe, calling clr!GetThread 00000030497bed60 00007ffba8375842 clr!ThreadpoolMgr::WorkerThreadStart+0x482, calling clr!CLRSemaphore::Wait 00000030497bee00 00007ffba8393e1e clr!Thread::intermediateThreadProc+0x7d 00000030497bee30
  • 我们可以从 ExitInstance 调用 FreeLibrary(Can we call FreeLibrary from ExitInstance)
    问题 从MSDN文档中我们可以看出,在DllMain入口点函数中不应该调用LoadLibrary/FreeLibrary。 入口函数应该只执行简单的初始化或终止任务。 它不能调用 LoadLibrary 或 LoadLibraryEx 函数(或调用这些函数的函数),因为这可能会在 DLL 加载顺序中创建依赖循环。 这可能导致在系统执行其初始化代码之前使用 DLL。 类似地,入口函数在进程终止期间不得调用 FreeLibrary 函数(或调用 FreeLibrary 的函数),因为这可能导致在系统执行其终止代码后使用 DLL。 我的问题是:我们可以从 ExitInstance() 调用 FreeLibrary 吗? 例如: Test.exe - 主要可执行文件 HINSTANCE hDllMFC = LoadLibrary(L"TestApp.dll"); if (hDllMFC != NULL) { FreeLibrary(hDllMFC); } while unload the hDllMFC, the call stack looks like: TestApp.dll!CTestAppApp::ExitInstance() Line 42 C++ TestApp.dll!InternalDllMain() Line 155 C++ TestApp.dll!DllMain()
  • 是否有来自 kernel32.dll 或 ntdll.dll 等低级库的 wsprintf() 类型的函数?(Is there a wsprintf()-type function from a low-level library such as kernel32.dll or ntdll.dll?)
    问题 我正在编写一个低级记录器函数,它将文本字符串附加到文本(日志)文件的末尾。 要求是此函数不应从进程可能尚不可用的 DLL 中调用任何 WinAPI,例如当它从 DllMain 处理程序调用时。 换句话说,它不能使用除了保证加载到任何用户模式进程的库之外的任何库,即kernel32.dll或ntdll.dll 。 我只使用CreateFile 、 WriteFile 、 CloseHandle 、 HeapAlloc 、 HeapFree等都来自kernel32.dll就可以很好地解决问题。 问题是格式化输出字符串。 例如,我需要添加一些额外的(自动生成的)的详细信息,诸如当前时间,过程ID,会话ID等我通常会使用wsprintf型函数,该函数,或StringCchPrintf准确的说,因为这样: StringCchPrintf(buffer, buffer_size, L"%04u-%02u-%02u %02u:%02u:%02u pid=0x%x, sessID=%d, %s\r\n", /* parameters */ ); 但是这些 API 违反了我上面提到的规则。 有谁知道是否有可用的低级printf类型格式化 API? 回答1 所有版本的ntdll.dll 都支持最小 next(from xp) 字符串格式化函数: _snprintf _snwprintf
  • std::thread cause deadlock in DLLMain
    So, this is what I'm talking about: std is complex. In VS2013 this simple program will cause a deadlock. #include <thread> #include <windows.h> void foo() { } void initialize() { std::thread t(foo); } BOOL APIENTRY DllMain(HMODULE, DWORD reason, LPVOID) { switch (reason) { case DLL_PROCESS_ATTACH: initialize(); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: break; } return TRUE; } Create a thread in DLLMain is totally wrong ? It's not true. From the document "Best Practices for Creating DLLs" of Microsoft: "Creating a thread can work if you do not
  • Can we call FreeLibrary from ExitInstance
    From the MSDN document, we can see that, we should not call LoadLibrary/FreeLibrary in the DllMain entry point function. The entry-point function should perform only simple initialization or termination tasks. It must not call the LoadLibrary or LoadLibraryEx function (or a function that calls these functions), because this may create dependency loops in the DLL load order. This can result in a DLL being used before the system has executed its initialization code. Similarly, the entry-point function must not call the FreeLibrary function (or a function that calls FreeLibrary) during process
  • 检测何时卸载模块 (DLL)(Detect when a Module (DLL) is unloaded)
    问题 有没有办法以编程方式检测模块(特别是 DLL)何时从进程中卸载? 我没有 DLL 源,所以我无法更改它的 DLL 入口点。 我也不能轮询当前是否加载了 DLL,因为 DLL 可能会在轮询之间被卸载然后重新加载。 结果: 我最终使用了绕过 dll 入口点并捕获 DLL_PROCESS_DETACH 的 jimharks 解决方案。 我发现绕道 FreeLibrary() 也可以工作,但必须添加代码以检测模块何时实际卸载或引用计数是否正在减少。 Necrolis 关于查找引用计数的链接对于这样做的方法很方便。 我应该注意的是,如果 MSDetours 中存在绕道,则我在使用 MSDetours 时实际上不会从内存中卸载模块。 回答1 也许比 Necrolis 更糟糕的方法是使用 Microsoft Research 的 Detours 包来挂钩 dll 的入口点以监视 DLL_PROCESS_DETACH 通知。 您可以使用以下函数找到给定 HMODULE(由 LoadLibrary 返回)的入口点: #include <windows.h> #include <DelayImp.h> PVOID GetAddressOfEntryPoint(HMODULE hmod) { PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)hmod
  • std::thread 导致 DLLMain 中的死锁(std::thread cause deadlock in DLLMain)
    问题 所以,这就是我要说的:std 很复杂。 在 VS2013 中,这个简单的程序会导致死锁。 #include <thread> #include <windows.h> void foo() { } void initialize() { std::thread t(foo); } BOOL APIENTRY DllMain(HMODULE, DWORD reason, LPVOID) { switch (reason) { case DLL_PROCESS_ATTACH: initialize(); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: break; } return TRUE; } 在 DLLMain 中创建线程是完全错误的吗? 这不是真的。 来自 Microsoft 的文档“Best Practices for Creating DLLs”:“如果不与其他线程同步,则创建线程可以工作”。 所以 CreateThread 有效,_beginthreadex 有效,boost::thread 有效,但 std::thread 无效。 这是调用堆栈: ntdll.dll!_NtWaitForSingleObject@12()
  • cl.exe 在通过 MSBuild 调用时无限期挂起(cl.exe hangs indefinitely while being invoked via MSBuild)
    问题 我正在尝试在我的(主要是 C++)项目上运行 MSBuild(想象一下一个非常庞大的代码库)。 Visual Studio 2015 是有问题的工具集( Windows 7 SP1 和 VS 2015 Update 2 )。 即使使用 /m:1 (从而迫使它只使用一个处理器),我也发现一些完全随机的项目在编译阶段经常挂起。 例如,当这个问题发生时,如果我查看有问题的项目及其包含的文件,我可以看到已为每个翻译单元成功创建了 .obj 文件。 然而,系统永远不会进入链接阶段。 我看到两个 cl.exe 实例闲置在任务管理器上,什么也不做。 也许在 30 分钟左右后,当我杀死其中一个实例时,我会得到类似的信息: cl : Command line error D8040: error creating or communicating with child process [Path_To_The_Project_Where_The_Compiler_Was_Stuck.vcxproj] 在此之后,令人惊讶的是,编译器只是继续从它停止的地方开始。 有没有人遇到过类似的事情? 在过去的几周里,这让我很不爽! 更新了 IInspectable 查询的答案: 这看起来有点毛茸茸的。 拜托,有更好的编辑技巧的人,你能帮我以更好的方式格式化它,这样人们就不会瞪大眼睛吗? 0:002> ~
  • cl.exe hangs indefinitely while being invoked via MSBuild
    I am trying to run MSBuild on my (mostly C++) projects (imagine a really humongous code base). Visual Studio 2015 is the toolset in question (Windows 7 SP1 and VS 2015 Update 2). Even with /m:1 (and thereby forcing it to use only one processor) I am finding some completely random project constantly hanging at the compile phase. For example, when this issue happens, if I look at the offending project and the files it comprises of, I can see that the .obj files have been created successfully for every translation unit. However the system just never moves on to the link phase. I see two instances
  • 挂钩线程的创建/终止(Hooking thread creation/termination)
    问题 是否可以在Windows上挂接到线程终止? IOW,如果进程内的一个线程(对其他进程及其线程不感兴趣)已终止(通常是-或更重要的是-强制终止),我想得到通知。 另外,也可以加入线程创建。 原理:我有一个基于每个线程管理某些信息的库(可以将其视为某些信息的整个进程的每个线程缓存)。 当线程终止时,我必须从缓存中删除所有特定于线程的信息。 [使用线程ID实现缓存关联,该ID可能会在以后的线程中重用。] “正常”执行顺序没有问题,因为库用户将从库中分离当前线程,这将清除状态。 如果有人杀死拥有缓存资源的线程,就会开始出现问题。 回答1 您可以使用Detours之类的工具来对Win32 API(例如TerminateThread)进行API级别的挂钩。 不过,我不明白您为什么需要这样做。 听起来好像您需要在线程死亡时清除该线程的关联缓存,以便在出现另一个具有相同ID的线程时可以重新使用该插槽。 这样对吗? 如果是这样,当您收到DLL_THREAD_ATTACH事件时,是否不能仅清除DllMain的缓存关联? 这实际上是您的新线程通知。 在这一点上,您知道您有一个新线程,那么清除现有的关联缓存不是安全的吗? 另一个可行的替代方法是线程本地存储(TLS)。 您可以使用Win32 API(例如TlsAlloc / TlsSetValue)来存储特定于线程的信息。 您还可以使用_
  • How to set breakpoint at the very beginning of program execution
    How can I stop the program before loading any of the linked DLLs? I've tried to set LoadLibraryExW function in the Break At Function debugging option and it stops at that function, but before that I have the following in Visual Studio output windows: 'test.exe': Loaded 'C:\Windows\System32\ntdll.dll', Symbols loaded (source information stripped). 'test.exe': Loaded 'C:\Windows\System32\kernel32.dll', Symbols loaded (source information stripped). 'test.exe': Loaded 'C:\Windows\System32\KernelBase.dll', Symbols loaded (source information stripped). 'test.exe': Loaded 'C:\Windows\System32\uxtheme
  • wine 无法加载我的自定义内置 dll 并报告“调用未实现的函数”(wine can't load my custom build-in dll and report "call to unimplemented function")
    问题 我无法登录 WINEHQ Bugzilla,所以我在这里问,这是要求: 我们有一个 Windows 应用程序,我们有 exe 源代码,它使用 ATL。 exe 依赖的 dll 需要一些特殊的设备,但大多数情况下它们都有 linux 版本。 现在我们需要将 windows 应用程序移植到 linux。 我最后的尝试:写一个中间dll来包装一些已经是跨平台的lib,exe会调用新的中间dll,我将中间dll命名为“WINE自定义内置dll”。 CUSTOM 意味着我编译这个 dll.so 由酿酒师独立。 一切都很好,直到在 wine64 下运行它,linux shell 中的命令行: wine64 portsome.exe 这是输出: wine: Call from 0x7bc5eeec to unimplemented function wrapsome.dll.wrap_SOME_GetVersion, aborting Backtrace: =>0 0x000000007bc5eeec stub_entry_point+0x5c(dll=<is not available>, name=<is not available>, ret_addr=<is not available>) [/home/root0/src/wine/build/dlls/ntdll/../../
  • Windows 上 PE 文件 (exe) 的最小文件大小是多少? 以及最小的内存分配? [复制](What is the minimum file size of a PE file (exe) on Windows? And the minimal memory allocation? [duplicate])
    问题 这个问题在这里已经有了答案: 最小的 Windows (PE) 可执行文件是什么? (2 个回答) 5年前关闭。 Windows 上 PE 文件 (exe) 的最小文件大小是多少? 以及最小的内存分配? 我组装了(使用 VS 10 附带的 MASM (ml.exe) 和 link.exe)以下代码:我不能省略 kernel32.lib 和 ExitProcess,如果我这样做,程序会崩溃。 ; Assmebly options .386 .MODEL FLAT, STDCALL option casemap:none ; Include Libs includelib kernel32.lib ; Imported symbols ExitProcess PROTO :Dword Sleep PROTO :Dword ; Code .CODE start: invoke Sleep, 10000 invoke ExitProcess, 0 END start 包含 Sleep 命令只是为了能够在程序结束之前读取内存使用情况。 现在我测量以下内容:.exe 文件的大小正好是 2.5 KB(如果我包含 user32.lib 和 MessageBoxA,它的大小变为 3 KB --> 块?)并且应用程序在运行时使用 136 KB RAM(Vista 32 位)。
  • 从dll载入dll?(Loading a dll from a dll?)
    问题 从DLL加载DLL的最佳方法是什么? 我的问题是我无法在process_attach上加载dll,也无法从主程序加载dll,因为我无法控制主程序源。 因此,我也不能调用非dllmain函数。 回答1 在评论中进行了所有辩论之后,我认为最好以“真实”的答案概括我的立场。 首先,仍然不清楚为什么需要使用LoadLibrary在DllMain中加载dll。 这绝对是一个坏主意,因为你的DllMain被另一个LoadLibrary调用,其持有加载程序锁,由DllMain中的文档解释中运行: 在初始进程启动期间或在调用LoadLibrary之后,系统会扫描该进程的已加载DLL列表。 对于尚未使用DLL_PROCESS_ATTACH值调用的每个DLL,系统将调用DLL的入口点函数。 该调用是在导致进程地址空间发生变化的线程(例如,进程的主线程或称为LoadLibrary的线程)的上下文中进行的。 系统在整个过程中对入口点的访问进行序列化。 DllMain中的线程持有加载程序锁,因此无法动态加载或初始化其他DLL。 入口点功能应仅执行简单的初始化或终止任务。 它一定不能调用LoadLibrary或LoadLibraryEx函数(或调用这些函数的函数) ,因为这可能会以DLL加载顺序创建依赖关系循环。 这可能会导致在系统执行其初始化代码之前使用DLL。 同样
  • 如何正确取消初始化OpenSSL(How to properly uninitialize OpenSSL)
    问题 在我的OpenSSL客户端中,我遇到的问题是,当我选择静态链接libeay32和ssleay32而不是动态链接的那一刻,我从Visual Leak Detector收到了大量内存泄漏错误。 我在该线程中从OP复制了命令,但仍然剩下6个。 然后我添加了sk_SSL_COMP_free(SSL_COMP_get_compression_methods()); 正如4LegsDrivenCat在同一线程中建议的那样,仅剩下4个,所有这些显然都与加载受信任的证书有关,我使用该证书来与服务器的证书进行比较。 我使用Visual Studio 2013 Express,OpenSSL 1.0.1L(32位和64位),VLD 2.4RC2,并且我的PC是Windows 7 64位。 在安全模式下,下面的调用堆栈是来自VLD的64位。 在32位中,VLD在安全模式下崩溃(尽管它在快速模式下工作,但不会产生像样的调用堆栈)。 我删除了引用我自己的函数以及十六进制数据的调用堆栈部分。 Visual Leak Detector Version 2.4RC2 installed. WARNING: Visual Leak Detector detected memory leaks! ---------- Block 5671 at 0x000000000097E9B0: 180 bytes ---
  • 首先调用的是 DllMain() 还是全局静态对象构造函数?(Which is called first, DllMain() or global static object constructor?)
    问题 我正在编写一个定义全局静态对象的 DLL。 在对象的构造函数中,我正在做一些可能会成功也可能不会成功的初始化。 是否可以在 DllMain() 中表示初始化过程的成功或失败? 两者中的哪一个先被调用? 谢谢你。 回答1 MSDN 的 DllMain 文档说: 如果您的 DLL 与 C 运行时库 (CRT) 链接,则 CRT 提供的入口点会调用全局和静态 C++ 对象的构造函数和析构函数。 因此,对 DllMain 的这些限制也适用于构造函数和析构函数以及从它们调用的任何代码。 由于 DllMain 中的代码可能使用静态对象,因此静态对象必须在 DllMain 为 DLL_PROCESS_ATTACH 运行之前构造,并在 DLL_PROCESS_DETACH 运行后销毁。 您可以使用一个简单的测试 exe 和测试 dll 来验证这一点。 可执行程序: int _tmain(int argc, _TCHAR* argv[]) { wprintf(L"Main, loading library\n"); HMODULE h = LoadLibrary(L"Test.dll"); if (h) { wprintf(L"Main, freeing library\n"); FreeLibrary(h); } wprintf(L"Main, exiting\n"); return 0;
  • 如何在 DLLMain 中启动线程?(How to start a thread in DLLMain?)
    问题 如何在 DLLMain 中启动线程意味着 std::thread - 从根本上说。 No 表示 WinApi,STL 表示。 当我在流程中运行该函数时,我崩溃了从这个 DLL 调用的应用程序。 先感谢您。 此代码获取文件 (exe) 上的哈希和并将其写入文件。 (* 。文本)。 但是应用程序崩溃 void initialize() { string buffer; thread t(calclulateHash, ref(buffer)); t.detach(); } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: { initialize(); break; } } return true; } 回答1 DllMain() 有一些限制。 您不应该在 DllMain 中进行任何阻塞调用,因为它是从 OS 加载程序调用的。 锁定加载程序可能会阻止某些线程启动,并且通常会导致不好的事情。 任何形式的锁定。 如果您试图获取当前由需要 OS 加载程序锁(您在从它执行时持有)的线程持有的锁,在最佳情况下您将死锁。 不允许启动线程,因为当你启动线程时.. 你通过操作系统加载器再次调用这个
  • 错误LNK2005:_DllMain @ 12已在MSVCRT.lib中定义(error LNK2005: _DllMain@12 already defined in MSVCRT.lib)
    问题 我收到此链接器错误。 mfcs80.lib(dllmodul.obj):错误LNK2005:_DllMain @ 12已在MSVCRT.lib(dllmain.obj)中定义 请告诉我消除此错误的正确方法。 我在Microsoft支持网站上阅读了有关此bug的解决方案,但并没有太大帮助。 我正在将VS 2005与Platform SDK一起使用 回答1 如果您彻底阅读了链接器错误并应用了一些知识,则可以自己解决: 链接器将许多已编译的对象和库链接在一起以获得二进制文件。 每个对象/库描述 它期望在其他对象中出现什么符号它定义了什么符号 如果两个对象定义了相同的符号,则将出现此链接器错误。 在您的情况下,mfcs80.lib和MSVCRT.lib都定义_DllMain @ 12符号。 摆脱错误: 找出您实际需要的两个库中的哪个了解如何告诉链接器不要使用另一个链接器(例如,使用James Hopkin的技巧) 回答2 我有相同的错误消息,但是这里没有答案可以为我解决。 因此,如果在创建使用MFC的DLL项目时遇到此问题,则可以通过输入以下行来解决: extern "C" { int _afxForceUSRDLL; } 到定义了DllMain的cpp文件。 然后使用您自己的DllMain实现,而不是dllmain.obj中的实现。 当我们尝试使用MFC库时