DllMain中不当操作导致死锁问题的分析——DllMain中要谨慎写代码(完结...

DllMain中不当操作导致死锁问题的分析——DllMain中要谨慎写代码(完结...

2023年8月1日发(作者:)

DllMain中不当操作导致死锁问题的分析——DllMain中要谨慎写代码(完结篇)之前⼏篇⽂章主要介绍和分析了为什么会在DllMain做出⼀些不当操作导致死锁的原因。本⽂将总结以前⽂章的结论,并介绍些DllMain中还有哪些操作会导致死锁等问题。( )

DllMain的相关特性

⾸先列出中论证的11个特性:1.

Dll的加载不会导致之前创建的线程调⽤其DllMain函数。2.

线程创建后会调⽤已经加载了的DLL的DllMain,且调⽤原因是DLL_THREAD_ATTACH。(DisableThreadLibraryCalls会导致该过程不被调⽤)3.

TerminateThread⽅式终⽌线程是不会让该线程去调⽤该进程中加载的Dll的DllMain。4.

线程正常退出时,会调⽤进程中还没卸载的DLL的DllMain,且调⽤原因是DLL_THREAD_DETACH。5.

进程正常退出时,会调⽤(不⼀定是主线程)该进程中还没卸载的DLL的DllMain,且调⽤原因是DLL_PROCESS_DETACH。6.

加载DLL进⼊进程空间时(和哪个线程LoadLibrary⽆关),加载它的线程会调⽤DllMain,且调⽤原因是DLL_PROCESS_ATTACH。7.

DLL从进程空间中卸载出去前,会被卸载其的线程调⽤其DllMain,且调⽤原因是DLL_PROCESS_DETACH。8.

TerminateProcess 将导致线程和进程在退出时不对未卸载的DLL进⾏DllMain调⽤。9.

ExitProcess将导致主线程意外退出,⼦线程对未卸载的DLL进⾏了DllMain调⽤,且调⽤原因是DLL_PROCESS_DETACH。10.

ExitThread是最和平的退出⽅式,它会让线程退出前对未卸载的DLL调⽤DllMain。11.

线程的创建和退出不会对调⽤了DisableThreadLibraryCalls的DLL调⽤DllMain。不要在DllMain中做的事情A直接或者间接调⽤LoadLibrary(Ex)假如我们在中的DllMain收到DLL_PROCESS_ATTACH时,加载了;⽽中的DllMain在收到DLL_PROCESS_ATTACH时⼜去加载。则产⽣了循环依赖。但是注意不要想当然认为这个过程是的DllMain调⽤了的DllMain,的DllMain再调⽤了的DllMain这样的死循环。即使不出现循环依赖,如果出现中第三个例⼦的情况,也会死锁的。

B使⽤CoInitializeEx在CoInitializeEx底层会调⽤LoadLibraryEx,原因同A。

C使⽤CreateProcessCreateProcess在底层执⾏了加载DLL的操作。我⽤IDA查看Kernel32中的CreateProcess可以发现其底层调⽤的CreateProcessInternalW中有

D使⽤User32或Gdi32中的函数User32和Gdi32中部分函数在调⽤的底层会加载其他DLL。

E使⽤托管代码运⾏托管代码需要加载其他DLL。

F与其他线程同步执⾏由、和《》可知,进程创建和销毁以及DLL的加载都要进⼊PEB的LoadLock临界区。如果占⽤了LoaderLock临界区的线程在等待⼀个需要经过临界区才能结束的线程时,就发⽣了死锁。以上3篇博⽂中均有案例。

G同步对象如果该同步对象的释放需要获得PEB中的LoaderLock,⽽占⽤该临界区的线程⼜要去等待这个同步对象,则会死锁。其实F中的线程也算是个同步对象。案例详见中例⼦。

H使⽤CreateThread理由同F。

I使⽤ExitThread理由同F。

J寄希望于DisableThreadLibraryCalls解决死锁问题由可知。DisableThreadLibraryCalls的实现逻辑是:找到PEB结构中⽤于保存加载器信息的结构体对象Ldr。Ldr对象的InMemoryOrderModuleList⽤户保存已经加载的DLL的链表。它遍历这个链表,找到调⽤DisableThreadLibraryCalls的DLL的信息,将该信息中的Flags字段设置或上0x40000。

⽽创建线程在底层将调⽤LdrpInitializeThread(详见)。该函数⼀开始便进⼊了PEB中LoaderLock临界区,在该临界区中根据PEB中LDR的InMemoryOrderModuleList遍历加载的DLL,然后判断该DLL信息的Flags字段是否或上了0x40000。如果或上了,就不调⽤DllMain。如果没或上,就调⽤DllMain。这说明DisableThreadLibraryCalls对创建线程时是否进⼊临界区⽆关。在退出线程时底层将调⽤LdrShutdownThread(详见)。该函数逻辑和LdrpInitializeThread相似,只是在调⽤DllMain时传的是DLL_THREAD_DETACH。所以DisableThreadLibraryCalls对LdrShutdownThread是否进⼊临界区也是没有影响的。

发布者:admin,转转请注明出处:http://www.yc00.com/news/1690875436a452488.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信