DllMain中不当操作导致死锁问题的分析--加载卸载DLL与DllMain死锁的关系
2014-03-18 15:47
204 查看
(转载于breaksoftware的csdn博客)
前几篇文章一直没有在源码级证明:DllMain在收到DLL_PROCESS_ATTACH和DLL_PROCESS_DETACH时会进入临界区。这个论证非常重要,因为它是使其他线程不能进入临界区从而导致死锁的关键。我构造了在DLL被映射到进程地址空间的场景,请看死锁时加载DLL的线程的堆栈
如果仔细看过《DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子2》,应该得知第14步就是进入临界区的点。
我们可以看到LdrLoadDll内部调用了LdrLockLoaderLock。LdrLockLoaderLock内部进入临界区,我们用IDA查看LdrLoadDll函数
[cpp]
view plaincopy
int __stdcall LdrLoadDll(int a1, int a2, int a3, int a4)
{
……
LdrLockLoaderLock(1, 0, &v10);
……
v6 = LdrpLoadDll(v9, a1, a2, v17, a4, 1);
……
if ( v8 >= 0 )
{
ms_exc.disabled = -1;
sub_7C936587(ebp0, v7);
v6 = 0;
goto LABEL_6;
}
}
int __usercall sub_7C936587<eax>(int a1<ebp>, int a2<esi>)
{
LdrpTopLevelDllBeingLoaded = a2;
return LdrUnlockLoaderLock(1, *(_DWORD *)(a1 - 572));
}
我们看到在LdrpLoadDll是在临界区中执行的。其实在LdrpLoadDll中也会进入该临界区,但是我们不必关注了。因为只要一次没出临界区就可以满足死锁的条件了。
我们再看下卸载DLL时发生的进入临界区场景,请看堆栈
我们将关注FreeLibrary和LdrpCallInitRoutine之间的代码逻辑。我们用IDA查看LdrUnLoadDll
[cpp]
view plaincopy
int __stdcall LdrUnloadDll(int a1)
{
……
v73 = 0;
v70 = *(_DWORD *)(*MK_FP(__FS__, 24) + 48);
v71 = 0;
ms_exc.disabled = 0;
if ( !LdrpInLdrInit )
RtlEnterCriticalSection(&LdrpLoaderLock);
++LdrpActiveUnloadCount;
if ( !LdrpShutdownInProgress )
{
if ( LdrpCheckForLoadedDllHandle(a1, (int)&v78) )
{
if ( *(_WORD *)(v78 + 56) != -1 )
{
……
if ( (unsigned __int8)LdrpActiveUnloadCount <= 1u )
{
……
v15 = (int *)LdrpUnloadHead;
v77 = (int *)LdrpUnloadHead;
while ( v15 != &LdrpUnloadHead )
{
……
LdrpCallInitRoutine((int (__stdcall *)(_DWORD, _DWORD, _DWORD))v20, *(_DWORD *)(v78 + 24), 0, 0);
……
v15 = (int *)LdrpUnloadHead;
v77 = (int *)LdrpUnloadHead;
ms_exc.disabled = 0;
v3 = 0;
}
……
}
}
}
else
{
v71 = 0xC0000135u;
}
}
ms_exc.disabled = -1;
sub_7C937424();
……
return v71;
}
int __cdecl sub_7C937424()
{
int result; // eax@3
--LdrpActiveUnloadCount;
if ( !LdrpInLdrInit )
result = RtlLeaveCriticalSection(&LdrpLoaderLock);
return result;
}
我们看到LdrUnloadDll几乎所有操作都是在临界区执行的。 以上两段从源码级证明了加载和卸载DLL导致的DllMain的调用(以及不调用)都是在临界区中完成的。
前几篇文章一直没有在源码级证明:DllMain在收到DLL_PROCESS_ATTACH和DLL_PROCESS_DETACH时会进入临界区。这个论证非常重要,因为它是使其他线程不能进入临界区从而导致死锁的关键。我构造了在DLL被映射到进程地址空间的场景,请看死锁时加载DLL的线程的堆栈
如果仔细看过《DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子2》,应该得知第14步就是进入临界区的点。
我们可以看到LdrLoadDll内部调用了LdrLockLoaderLock。LdrLockLoaderLock内部进入临界区,我们用IDA查看LdrLoadDll函数
[cpp]
view plaincopy
int __stdcall LdrLoadDll(int a1, int a2, int a3, int a4)
{
……
LdrLockLoaderLock(1, 0, &v10);
……
v6 = LdrpLoadDll(v9, a1, a2, v17, a4, 1);
……
if ( v8 >= 0 )
{
ms_exc.disabled = -1;
sub_7C936587(ebp0, v7);
v6 = 0;
goto LABEL_6;
}
}
int __usercall sub_7C936587<eax>(int a1<ebp>, int a2<esi>)
{
LdrpTopLevelDllBeingLoaded = a2;
return LdrUnlockLoaderLock(1, *(_DWORD *)(a1 - 572));
}
我们看到在LdrpLoadDll是在临界区中执行的。其实在LdrpLoadDll中也会进入该临界区,但是我们不必关注了。因为只要一次没出临界区就可以满足死锁的条件了。
我们再看下卸载DLL时发生的进入临界区场景,请看堆栈
我们将关注FreeLibrary和LdrpCallInitRoutine之间的代码逻辑。我们用IDA查看LdrUnLoadDll
[cpp]
view plaincopy
int __stdcall LdrUnloadDll(int a1)
{
……
v73 = 0;
v70 = *(_DWORD *)(*MK_FP(__FS__, 24) + 48);
v71 = 0;
ms_exc.disabled = 0;
if ( !LdrpInLdrInit )
RtlEnterCriticalSection(&LdrpLoaderLock);
++LdrpActiveUnloadCount;
if ( !LdrpShutdownInProgress )
{
if ( LdrpCheckForLoadedDllHandle(a1, (int)&v78) )
{
if ( *(_WORD *)(v78 + 56) != -1 )
{
……
if ( (unsigned __int8)LdrpActiveUnloadCount <= 1u )
{
……
v15 = (int *)LdrpUnloadHead;
v77 = (int *)LdrpUnloadHead;
while ( v15 != &LdrpUnloadHead )
{
……
LdrpCallInitRoutine((int (__stdcall *)(_DWORD, _DWORD, _DWORD))v20, *(_DWORD *)(v78 + 24), 0, 0);
……
v15 = (int *)LdrpUnloadHead;
v77 = (int *)LdrpUnloadHead;
ms_exc.disabled = 0;
v3 = 0;
}
……
}
}
}
else
{
v71 = 0xC0000135u;
}
}
ms_exc.disabled = -1;
sub_7C937424();
……
return v71;
}
int __cdecl sub_7C937424()
{
int result; // eax@3
--LdrpActiveUnloadCount;
if ( !LdrpInLdrInit )
result = RtlLeaveCriticalSection(&LdrpLoaderLock);
return result;
}
我们看到LdrUnloadDll几乎所有操作都是在临界区执行的。 以上两段从源码级证明了加载和卸载DLL导致的DllMain的调用(以及不调用)都是在临界区中完成的。
相关文章推荐
- cvSVM及trainSVM参数详解
- DllMain中不当操作导致死锁问题的分析--DisableThreadLibraryCalls对DllMain中死锁的影响
- DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子2
- DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子
- DllMain中不当操作导致死锁问题的分析--进程对DllMain函数的调用规律的研究和分析
- DllMain中不当操作导致死锁问题的分析--死锁介绍
- SVN中 “containing working copy admin area is missing” 问题 .
- main函数argc,argv操作
- rsync: failed to connect to X.X.X.X: No route to host (113)
- Codeforces-298b H Sail
- 提升Email邮件营销转化效率方法分享
- 什么是RAID
- 什么是RAID
- MIME协议及源邮件格式分析
- hdu1983 dfs+bfs Kaitou Kid - The Phantom Thief
- 更改amazon ec2 key-pair最佳实践
- AirPnP,厕所版AirBnB
- AfxGetMainWnd()函数用法
- usaco 总结
- ORA-21561: OID generation failed