调试环境:WIN7 32bit SP1
调试工具:windbg+IDA
影响版本:瑞星杀毒软件2011 hookhelp.sys版本25.0.0.9
调试目的:解决自己遇到的问题,同时学习相应方法和知识。
近一个月来,我两台刚刚更新了WIN7 SP1系统的电脑(一台实验室用的PC,一台宿舍用的笔记本)多次出现死锁情况,现象表现为突然整个图形界面没响应,只有鼠标可以动,有时鼠标有忙的图标(蓝圈),有时没有,同时可以听到CPU风扇声明显增大。这种现象经常出现在系统长期待机后唤醒进入登录界面后几秒,后来在正在使用过程中时不时也出现。
我十分头疼,觉得应该是系统底层哪里死锁了,不得已设置了CrashOnCtrlScroll键,希望遇到的时候可以用它来BSOD掉然后分析dmp。
昨晚在宿舍的电脑上又给我碰上,这次是重启后刚登录后,过了登录界面将要出来桌面之前,刚好屏幕一片黑的时候,就又停在那里了。用右边Ctrl键+两次ScrollLock键手动BSOD,重启后选正常启动系统,用windbg加载保存下来的核心内存转储文件,开始找原因。
以前调dmp文件都是有比较明确目标的,比如一个出异常的用户态程序,或者导致BSOD的驱动,那样只要在出异常或BSOD的当前线程进行栈回溯就比较容易发现问题了,这次则不然,因为BSOD是人工触发的,跟真正的死锁原因无关,所以找原因要麻烦得多。由于这块确实不熟,调了N久,中间有很多无用功,发帖的时候就只贴有用的部分了。
代码:
0: kd> !analyze -v ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* MANUALLY_INITIATED_CRASH (e2) The user manually initiated this crash dump. Arguments: Arg1: 00000000 Arg2: 00000000 Arg3: 00000000 Arg4: 00000000 Debugging Details: ------------------ BUGCHECK_STR: MANUALLY_INITIATED_CRASH DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT PROCESS_NAME: System CURRENT_IRQL: 6 LAST_CONTROL_TRANSFER: from 945df160 to 83318f20 STACK_TEXT: 83362c0c 945df160 000000e2 00000000 00000000 nt!KeBugCheckEx+0x1e 83362c3c 945df768 00105d30 000000c6 00000000 i8042prt!I8xProcessCrashDump+0x251 83362c88 832747ad 88ab4a00 86105c78 83362cb4 i8042prt!I8042KeyboardInterruptService+0x2ce 83362c88 832b1e1a 88ab4a00 86105c78 83362cb4 nt!KiInterruptDispatch+0x6d 83362d24 00000000 0000000e 00000000 00000000 nt!KiIdleLoop+0x1a
看到网上有文章说查deadlock可以先用!locks命令看看哪些lock是在held的状态,就先试试了。
代码:
0: kd> !locks **** DUMP OF ALL RESOURCE OBJECTS **** KD: Scanning for held locks........................................................................................................................................................ ....................................................................................................... 8159 total locks
用!stacks看一看各个线程的情况(部分省略):
代码:
0: kd> !stacks Proc.Thread .Thread Ticks ThreadState Blocker [85404020 System] 4.00001c 85429850 0000923 Blocked nt!AlpcpSignalAndWait+0x7b 4.000028 85424020 0000923 Blocked nt!AlpcpSignalAndWait+0x7b 4.000034 85424798 0001178 Blocked nt!AlpcpSignalAndWait+0x7b 4.000044 85423a70 0000923 Blocked nt!AlpcpSignalAndWait+0x7b 4.00005c 8542a5f8 0000031 Blocked nt!MiModifiedPageWriter+0x39 4.000074 85427a28 0000001 Blocked nt!CcQueueLazyWriteScanThread+0x4a 4.000080 8541f5a8 0003751 Blocked nt!AlpcpReceiveMessagePort+0x245 4.000084 85435d48 0000041 Blocked nt!EtwpLogger+0xd0 4.000088 854357b0 0000001 Blocked nt!EtwpLogger+0xd0 4.00008c 85449d48 0000001 Blocked nt!EtwpLogger+0xd0 4.000090 854497b0 0000001 Blocked nt!EtwpLogger+0xd0 4.000098 85c94540 0000001 Blocked nt!EtwpLogger+0xd0 ...... [88ab53d0 svchost.exe] 48c.000490 a27caa88 00038c4 Blocked nt!KiFastCallEntry+0x12a 48c.0004a8 a27e43b0 000017f Blocked nt!ObpWaitForMultipleObjects+0x262 48c.0004b0 a27e7868 00031e0 Blocked nt!KiAcquireFastMutex+0x56 48c.0004c0 a15fdd48 00004ce Blocked nt!ObpWaitForMultipleObjects+0x262 48c.0004f8 a27f07e0 0000804 Blocked nt!ObpWaitForMultipleObjects+0x262 48c.0004fc a27fd030 0003797 Blocked nt!ObpWaitForMultipleObjects+0x262 48c.000500 a27ffc18 0003817 Blocked nt!ObpWaitForMultipleObjects+0x262 48c.000548 a2d8d548 00038d2 Blocked nt!IoRemoveIoCompletion+0x23 48c.000560 a2d96388 0003081 Blocked nt!KiAcquireFastMutex+0x56 48c.0005b8 a2d89a10 00036fc Blocked nt!KiAcquireFastMutex+0x56 48c.0005d4 a2db6380 0002db7 Blocked nt!KiAcquireFastMutex+0x56 48c.000674 a2df87b8 0003e84 Blocked nt!ObpWaitForMultipleObjects+0x262 48c.000ff8 b6c4dc50 0003675 Blocked nt!KiAcquireFastMutex+0x56 48c.000858 b6cc0910 00031e0 Blocked nt!KiAcquireFastMutex+0x56 48c.000728 85542030 0003534 Blocked nt!KiAcquireFastMutex+0x56 48c.0002dc 854a75f8 0003cab Blocked nt!ObpWaitForMultipleObjects+0x262 48c.000744 854a7a60 0003cb0 Blocked nt!IoRemoveIoCompletion+0x23 48c.000554 8554d4c0 00038c3 Blocked nt!ObpWaitForMultipleObjects+0x262 48c.001004 a15e6690 0003014 Blocked nt!KiAcquireFastMutex+0x56 48c.00105c 85639a08 0002ee7 Blocked nt!KiAcquireFastMutex+0x56 48c.001060 85639720 0002ee7 Blocked nt!KiAcquireFastMutex+0x56 48c.0010a8 a15e6358 0002e8e Blocked nt!KiAcquireFastMutex+0x56 48c.0010ac 855a9030 0002e57 Blocked nt!KiAcquireFastMutex+0x56 48c.0010b8 8560c568 0002dc6 Blocked nt!KiAcquireFastMutex+0x56 48c.0010c0 85568880 0002a4f Blocked nt!KiAcquireFastMutex+0x56 48c.0010fc 855b5030 0002a4f Blocked nt!KiAcquireFastMutex+0x56 48c.001100 855b5d48 0001274 Blocked nt!AlpcpSignalAndWait+0x7b 48c.001194 85585030 000017f Blocked nt!IoRemoveIoCompletion+0x23 48c.0011a8 85584a60 000017f Blocked nt!IoRemoveIoCompletion+0x23 ...... [855a4d40 explorer.exe] 71c.0008b4 855c3030 00035ee Blocked nt!KiAcquireFastMutex+0x56 71c.000adc b6cd7d48 0003069 Blocked nt!ObpWaitForMultipleObjects+0x262 71c.000cb0 b6cdc920 00037c0 Blocked nt!KiFastCallEntry+0x12a 71c.000480 854a4ad8 00034bc Blocked nt!KiFastCallEntry+0x12a 71c.00056c 8556ed48 000282e Blocked nt!KiFastCallEntry+0x12a 71c.000c80 854f14f0 0002889 Blocked nt!KiAcquireFastMutex+0x56 71c.000cfc 854e1ad8 00036f9 Blocked nt!KiAcquireFastMutex+0x56 71c.000070 85667030 0003790 Blocked nt!ObpWaitForMultipleObjects+0x262 71c.0001a4 8543dd48 000372c Blocked nt!ObpWaitForMultipleObjects+0x262 71c.000128 8560f030 00034a9 Blocked nt!KiAcquireFastMutex+0x56 71c.000de0 8560e970 0003719 Blocked nt!ObpWaitForMultipleObjects+0x262 71c.000e60 855c05f8 00036fc Blocked nt!ExfAcquirePushLockExclusive+0x100 71c.000ae8 85626030 0003743 Blocked nt!ObpWaitForMultipleObjects+0x262 71c.000a00 854fbbe0 0002800 Blocked nt!KiFastCallEntry+0x12a 71c.0009e4 856267f0 00034ac Blocked nt!KiFastCallEntry+0x12a 71c.000830 855bad48 000372c Blocked win32k!xxxRealSleepThread+0x1d7 71c.00099c 854fa380 0000a18 Blocked win32k!xxxRealSleepThread+0x1d7 71c.000814 8562f838 00036fc Blocked nt!KiAcquireFastMutex+0x56 71c.000568 8556f030 0003700 Blocked nt!KiFastCallEntry+0x12a 71c.000cdc 85632d48 0003069 Blocked nt!ExfAcquirePushLockExclusive+0x100 ...... [8562cd40 dllhost.exe] d00.000d0c 85633030 00036fc Blocked nt!KiAcquireFastMutex+0x56 [856166a0 IMSCMIG.EXE] bf8.0001b0 8564b640 00064ea ???? nt!KiThreadStartup
那么先应该找到那个FastMutex。比如看dllhost.exe的这个线程:
代码:
0: kd> !thread 85633030 THREAD 85633030 Cid 0d00.0d0c Teb: 7ffdf000 Win32Thread: fe52c7e0 WAIT: (WrFastMutex) KernelMode Non-Alertable 86e15014 SynchronizationEvent Not impersonating DeviceMap c14ef898 Owning Process 8562cd40 Image: dllhost.exe Attached Process N/A Image: N/A Wait Start TickCount 11758 Ticks: 14076 (0:00:03:39.587) Context Switch Count 16 UserTime 00:00:00.000 KernelTime 00:00:00.015 Win32 Start Address 0x00661609 Stack Init b5e47fd0 Current b5e47198 Base b5e48000 Limit b5e45000 Call 0 Priority 9 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5 ChildEBP RetAddr Args to Child b5e471b0 832b869d 85633030 00000000 83365d20 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4]) b5e471e8 832b74f7 856330f0 85633030 86e15014 nt!KiSwapThread+0x266 b5e47210 832b10cf 85633030 856330f0 00000000 nt!KiCommitThreadWait+0x1df b5e47288 8326b08e 86e15014 00000022 00000000 nt!KeWaitForSingleObject+0x393 b5e472b0 832ce55b 85633030 8e015390 8ece16c7 nt!KiAcquireFastMutex+0x56 b5e472bc 8ece16c7 8615c440 00000000 b5e47304 nt!ExAcquireFastMutex+0x1e (FPO: [0,0,2]) WARNING: Stack unwind information not available. Following frames may be wrong. b5e47b0c 834a939c a1583d40 00000d00 b5e47b5c HOOKHELP!RisingInlineUnHook+0x1467 b5e47b34 8349127f a1583d40 00000d00 8337cb88 nt!PsCallImageNotifyRoutines+0x62 b5e47be8 83481d4a a1581ca0 8562cd40 b5e47ce4 nt!MiMapViewOfImageSection+0x670 b5e47c58 83481e3a 8562cd40 b5e47ce4 00000000 nt!MiMapViewOfSection+0x22e b5e47c88 83482599 c4cb0360 8562cd40 b5e47ce4 nt!MmMapViewOfSection+0x2a b5e47d04 832781ea 0000005c ffffffff 0007f4b0 nt!NtMapViewOfSection+0x204 b5e47d04 779970b4 0000005c ffffffff 0007f4b0 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ b5e47d34) 0007f41c 00000000 00000000 00000000 00000000 0x779970b4
代码:
0: kd> dd nt!PspLoadImageNotifyRoutine 8337cb80 8a334e77 8a36505f 8e015393 bb0a1e4f 8337cb90 00000000 00000000 00000000 00000000 8337cba0 00000004 00000000 00000000 00000000 8337cbb0 00000000 00000000 00000000 00000000 8337cbc0 8a38fa63 bb0f0ca7 00000000 00000000 8337cbd0 00000000 00000000 00000000 00000000 8337cbe0 00000000 00000000 00000000 00000000 8337cbf0 00000000 00000000 00000000 00000000
代码:
0: kd> dd 8e015390 8e015390 00000010 8ece1690 00000000 7d52504c 8e0153a0 06700203 6666744e 00f00702 01000a48 8e0153b0 00005756 00010000 00000000 00000001 8e0153c0 00000000 00000000 8e01565c 8e01565c 8e0153d0 8e0154e0 8e0154e0 00000000 be89a9b8 8e0153e0 86bf70d8 86d28690 86d28714 429eb9ca 8e0153f0 01ca040f 42a105b0 01ca040f 13e98a58 8e015400 01caa6ba 429eb9ca 01ca040f 00009000 0: kd> u 8ece1690 HOOKHELP!RisingInlineUnHook+0x1430: 8ece1690 55 push ebp 8ece1691 8bec mov ebp,esp 8ece1693 81ec48080000 sub esp,848h 8ece1699 c745f800000000 mov dword ptr [ebp-8],0 8ece16a0 837d1000 cmp dword ptr [ebp+10h],0 8ece16a4 0f849e030000 je HOOKHELP!RisingInlineUnHook+0x17e8 (8ece1a48) 8ece16aa 8b4510 mov eax,dword ptr [ebp+10h] 8ece16ad 8b08 mov ecx,dword ptr [eax]
代码:
0: kd> u 8ece1690 HOOKHELP!RisingInlineUnHook+0x1430: 8ece1690 55 push ebp 8ece1691 8bec mov ebp,esp 8ece1693 81ec48080000 sub esp,848h 8ece1699 c745f800000000 mov dword ptr [ebp-8],0 8ece16a0 837d1000 cmp dword ptr [ebp+10h],0 8ece16a4 0f849e030000 je HOOKHELP!RisingInlineUnHook+0x17e8 (8ece1a48) 8ece16aa 8b4510 mov eax,dword ptr [ebp+10h] 8ece16ad 8b08 mov ecx,dword ptr [eax] 0: kd> u HOOKHELP!RisingInlineUnHook+0x144f: 8ece16af c1e908 shr ecx,8 8ece16b2 83e101 and ecx,1 8ece16b5 0f858d030000 jne HOOKHELP!RisingInlineUnHook+0x17e8 (8ece1a48) 8ece16bb 8b0d1845ce8e mov ecx,dword ptr [HOOKHELP!RisingInlineUnHook+0x42b8 (8ece4518)] 8ece16c1 ff150453ce8e call dword ptr [HOOKHELP!RisingInlineUnHook+0x50a4 (8ece5304)] 8ece16c7 8d550c lea edx,[ebp+0Ch] 8ece16ca 52 push edx 8ece16cb 8b0d1845ce8e mov ecx,dword ptr [HOOKHELP!RisingInlineUnHook+0x42b8 (8ece4518)] 0: kd> dds 8ece5304 8ece5304 832ce53d nt!ExAcquireFastMutex 8ece5308 00000000 ...(省略无关部分)
代码:
0: kd> dd 8ece4518 8ece4518 86e15008 00000000 cf396c68 6952c38e 8ece4528 676e6973 6b6f6f48 00007845 4b2ea300 8ece4538 00000083 00000000 00000000 00000000 8ece4548 00000000 00000000 00000000 00000000 8ece4558 00000000 00000000 00000000 00000000 8ece4568 00000000 00000000 00000000 00000000 8ece4578 00000000 00000000 00000000 00000000 8ece4588 00000000 00000000 00000000 00000000 0: kd> dt _FAST_MUTEX 86e15008 hal!_FAST_MUTEX +0x000 Count : 0n1200 +0x004 Owner : 0x855c05f8 _KTHREAD +0x008 Contention : 0x4f5 +0x00c Event : _KEVENT +0x01c OldIrql : 0
于是关键就是其Owner线程为什么没Release它。看一下Owner线程是哪一个:
代码:
0: kd> !thread 855c05f8 THREAD 855c05f8 Cid 071c.0e60 Teb: 7ffd3000 Win32Thread: fe53e170 WAIT: (WrPushLock) KernelMode Non-Alertable bd82e310 SynchronizationEvent Not impersonating DeviceMap c14ef898 Owning Process 855a4d40 Image: explorer.exe Attached Process N/A Image: N/A Wait Start TickCount 11758 Ticks: 14076 (0:00:03:39.587) Context Switch Count 124 UserTime 00:00:00.015 KernelTime 00:00:00.062 Win32 Start Address 0x75bc42ed Stack Init bd82ffd0 Current bd82e1e0 Base bd830000 Limit bd82d000 Call 0 Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5 ChildEBP RetAddr Args to Child bd82e1f8 832b869d 855c05f8 00000000 807c6120 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4]) bd82e230 832b74f7 855c06b8 855c05f8 bd82e310 nt!KiSwapThread+0x266 bd82e258 832b10cf 855c05f8 855c06b8 00000000 nt!KiCommitThreadWait+0x1df bd82e2d4 832ccc8d bd82e310 0000001c 00000000 nt!KeWaitForSingleObject+0x393 bd82e344 83466cdc 984ad368 bd82e44c bd82e4dc nt!ExfAcquirePushLockExclusive+0x100 bd82e42c 832781ea ffffffff bd82e514 00000000 nt!NtAllocateVirtualMemory+0x127a bd82e42c 832758e1 ffffffff bd82e514 00000000 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ bd82e44c) bd82e4bc 8ece0d4a ffffffff bd82e514 00000000 nt!ZwAllocateVirtualMemory+0x11 (FPO: [6,0,0]) WARNING: Stack unwind information not available. Following frames may be wrong. bd82e650 8ece1011 00000bf8 bd82ee98 00000208 HOOKHELP!RisingInlineUnHook+0xaea bd82f0c0 834a276c 0000071c 00000bf8 00000001 HOOKHELP!RisingInlineUnHook+0xdb1 bd82f178 834aa799 8564b640 016166a0 bd82f1d4 nt!PspInsertThread+0x5c0 bd82f884 8eceebf4 0463e6dc 0463e6b8 02000000 nt!NtCreateUserProcess+0x742 bd82fd00 832781ea 0463e6dc 0463e6b8 02000000 Hooksys+0x7bf4 bd82fd00 779970b4 0463e6dc 0463e6b8 02000000 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ bd82fd34) 0463e9fc 00000000 00000000 00000000 00000000 0x779970b4
找一下这个Routine的位置:
代码:
0: kd> dd nt!PspCreateProcessNotifyRoutine 8337cce0 8a204bb7 8a24116f 8b2020df 8a31a2ff 8337ccf0 8a332a67 8a306e27 8a3219d6 b9a9c077 8337cd00 9972f5af 00000000 00000000 00000000 8337cd10 00000000 00000000 00000000 00000000 8337cd20 00000000 00000000 00000000 00000000 8337cd30 00000000 00000000 00000000 00000000 8337cd40 00000000 00000000 00000000 00000000 8337cd50 00000000 00000000 00000000 00000000 ...(一个一个EX_CALLBACK结构地看)... 0: kd> dd 8a3219d0 8a3219d0 00000010 8ece0f50 00000000 8b200078 8a3219e0 06080203 6646744e 0024005c 00780045 8a3219f0 00650074 0064006e 0024005c 006d0052 8a321a00 0065004d 00610074 00610064 00610074 8a321a10 0024005c 00780054 004c0066 0067006f 8a321a20 06060208 69446350 8e0f3520 8787377c 8a321a30 6994ad04 11d093ef a000cca3 963122c9 8a321a40 010e010c 8eaa50d8 885e05e8 01000000 0: kd> u 8ece0f50 HOOKHELP!RisingInlineUnHook+0xcf0: 8ece0f50 55 push ebp 8ece0f51 8bec mov ebp,esp 8ece0f53 81ec580a0000 sub esp,0A58h 8ece0f59 57 push edi 8ece0f5a 8b4508 mov eax,dword ptr [ebp+8] 8ece0f5d 8945e8 mov dword ptr [ebp-18h],eax 8ece0f60 8b4d0c mov ecx,dword ptr [ebp+0Ch] 8ece0f63 894dec mov dword ptr [ebp-14h],ecx
代码:
.text:00011F50 ; =============== S U B R O U T I N E ======================================= .text:00011F50 .text:00011F50 ; Attributes: bp-based frame .text:00011F50 .text:00011F50 ; void __stdcall CreateProcessNotifyRoutine(HANDLE, HANDLE, BOOLEAN) .text:00011F50 CreateProcessNotifyRoutine proc near ; DATA XREF: sub_11840+B8o .text:00011F50 ; sub_11840+DDo ... .text:00011F50 .text:00011F50 var_A58 = dword ptr -0A58h .text:00011F50 P = dword ptr -0A54h .text:00011F50 var_A50 = dword ptr -0A50h .text:00011F50 var_A4C = dword ptr -0A4Ch .text:00011F50 var_A48 = word ptr -0A48h .text:00011F50 var_83C = dword ptr -83Ch .text:00011F50 var_838 = word ptr -838h .text:00011F50 var_438 = word ptr -438h .text:00011F50 var_230 = dword ptr -230h .text:00011F50 var_22C = dword ptr -22Ch .text:00011F50 ProcessFileNameBuffer= word ptr -228h .text:00011F50 var_226 = byte ptr -226h .text:00011F50 var_1C = byte ptr -1Ch .text:00011F50 ParentId1 = dword ptr -18h .text:00011F50 ProcessId1 = dword ptr -14h .text:00011F50 var_10 = dword ptr -10h .text:00011F50 var_C = dword ptr -0Ch .text:00011F50 var_8 = dword ptr -8 .text:00011F50 var_4 = dword ptr -4 .text:00011F50 ParentId = dword ptr 8 .text:00011F50 ProcessId = dword ptr 0Ch .text:00011F50 Create = byte ptr 10h .text:00011F50 .text:00011F50 push ebp .text:00011F51 mov ebp, esp .text:00011F53 sub esp, 0A58h .text:00011F59 push edi .text:00011F5A mov eax, [ebp+ParentId] .text:00011F5D mov [ebp+ParentId1], eax .text:00011F60 mov ecx, [ebp+ProcessId] .text:00011F63 mov [ebp+ProcessId1], ecx .text:00011F66 mov [ebp+var_8], 0 .text:00011F6D mov [ebp+var_4], 0 .text:00011F74 cmp [ebp+ProcessId], 0 .text:00011F78 jnz short loc_11F7F .text:00011F7A jmp loc_122B6 .text:00011F7F ; --------------------------------------------------------------------------- .text:00011F7F .text:00011F7F loc_11F7F: ; CODE XREF: CreateProcessNotifyRoutine+28j .text:00011F7F mov [ebp+var_10], 0 .text:00011F86 mov [ebp+var_C], 0 .text:00011F8D mov [ebp+var_1C], 0 .text:00011F91 movzx edx, [ebp+Create] .text:00011F95 test edx, edx .text:00011F97 jz loc_12084 .text:00011F9D mov ecx, ds:FastMutex ; FastMutex .text:00011FA3 call ds:ExAcquireFastMutex .text:00011FA9 mov ecx, ds:FastMutex .text:00011FAF add ecx, 40h .text:00011FB2 call sub_135A0 .text:00011FB7 cmp eax, 2710h .text:00011FBC jnb loc_12073 .text:00011FC2 lea eax, [ebp+ProcessId] .text:00011FC5 push eax .text:00011FC6 mov ecx, ds:FastMutex .text:00011FCC add ecx, 40h .text:00011FCF call sub_13B00 .text:00011FD4 test eax, eax .text:00011FD6 jnz loc_12073 .text:00011FDC mov [ebp+ProcessFileNameBuffer], 0 .text:00011FE5 mov ecx, 81h .text:00011FEA xor eax, eax .text:00011FEC lea edi, [ebp+var_226] .text:00011FF2 rep stosd .text:00011FF4 stosw .text:00011FF6 push 208h ; Size .text:00011FFB lea ecx, [ebp+ProcessFileNameBuffer] .text:00012001 push ecx ; Buffer .text:00012002 mov edx, [ebp+ProcessId] .text:00012005 push edx ; ProcessId .text:00012006 mov ecx, ds:FastMutex .text:0001200C call GetProcessFileName
代码:
.text:00011F9D mov ecx, ds:FastMutex ; FastMutex .text:00011FA3 call ds:ExAcquireFastMutex
该CreateProcessNotifyRoutine在获得这个_FAST_MUTEX之后,获取新创建的进程的映像文件路径:
代码:
.text:00011C60 .text:00011C60 ; =============== S U B R O U T I N E ======================================= .text:00011C60 .text:00011C60 ; Attributes: bp-based frame .text:00011C60 .text:00011C60 ; int __stdcall GetProcessFileName(int ProcessId, void *Buffer, int Size) .text:00011C60 GetProcessFileName proc near ; CODE XREF: CreateProcessNotifyRoutine+BCp .text:00011C60 .text:00011C60 var_170 = dword ptr -170h .text:00011C60 len = dword ptr -16Ch .text:00011C60 ImagePathBuffer = dword ptr -168h .text:00011C60 ImagePathName = dword ptr -164h .text:00011C60 ProcessPeb = dword ptr -160h .text:00011C60 ProcessInformation= PROCESS_BASIC_INFORMATION ptr -15Ch .text:00011C60 ProcessParameters= dword ptr -144h .text:00011C60 FreeSize = dword ptr -140h .text:00011C60 BaseAddress = dword ptr -13Ch .text:00011C60 var_138 = byte ptr -138h .text:00011C60 var_137 = byte ptr -137h .text:00011C60 status = dword ptr -2Ch .text:00011C60 ObjectAttributes= OBJECT_ATTRIBUTES ptr -28h .text:00011C60 Handle = dword ptr -10h .text:00011C60 ClientId = CLIENT_ID ptr -0Ch .text:00011C60 var_4 = dword ptr -4 .text:00011C60 ProcessId = dword ptr 8 .text:00011C60 Buffer = dword ptr 0Ch .text:00011C60 Size = dword ptr 10h .text:00011C60 .text:00011C60 push ebp .text:00011C61 mov ebp, esp .text:00011C63 sub esp, 170h .text:00011C69 push edi .text:00011C6A mov [ebp+var_170], ecx .text:00011C70 mov [ebp+var_4], 0 .text:00011C77 mov [ebp+Handle], 0 .text:00011C7E mov [ebp+ClientId.UniqueProcess], 0 .text:00011C85 xor eax, eax .text:00011C87 mov [ebp+ClientId.UniqueThread], eax .text:00011C8A cmp [ebp+Buffer], 0 .text:00011C8E jnz short loc_11C97 .text:00011C90 xor eax, eax .text:00011C92 jmp loc_11F17 .text:00011C97 ; --------------------------------------------------------------------------- .text:00011C97 .text:00011C97 loc_11C97: ; CODE XREF: GetProcessFileName+2Ej .text:00011C97 mov [ebp+ObjectAttributes.Length], 18h .text:00011C9E mov [ebp+ObjectAttributes.RootDirectory], 0 .text:00011CA5 mov [ebp+ObjectAttributes.Attributes], 0 .text:00011CAC mov [ebp+ObjectAttributes.ObjectName], 0 .text:00011CB3 mov [ebp+ObjectAttributes.SecurityDescriptor], 0 .text:00011CBA mov [ebp+ObjectAttributes.SecurityQualityOfService], 0 .text:00011CC1 mov ecx, [ebp+ProcessId] .text:00011CC4 mov [ebp+ClientId.UniqueProcess], ecx .text:00011CC7 lea edx, [ebp+ClientId] .text:00011CCA push edx ; ClientId .text:00011CCB lea eax, [ebp+ObjectAttributes] .text:00011CCE push eax ; ObjectAttributes .text:00011CCF push 1F0FFFh ; DesiredAccess .text:00011CD4 lea ecx, [ebp+Handle] .text:00011CD7 push ecx ; ProcessHandle .text:00011CD8 call ds:ZwOpenProcess .text:00011CDE mov [ebp+status], eax .text:00011CE1 cmp [ebp+status], 0 .text:00011CE5 jl loc_11F14 .text:00011CEB mov edx, ds:FastMutex .text:00011CF1 cmp dword ptr [edx+104h], 0 .text:00011CF8 jz loc_11F0A .text:00011CFE mov [ebp+var_138], 0 .text:00011D05 mov ecx, 40h .text:00011D0A xor eax, eax .text:00011D0C lea edi, [ebp+var_137] .text:00011D12 rep stosd .text:00011D14 stosw .text:00011D16 stosb .text:00011D17 mov [ebp+BaseAddress], 0 .text:00011D21 mov [ebp+FreeSize], 1000h .text:00011D2B push PAGE_READWRITE ; Protect .text:00011D2D push MEM_COMMIT ; AllocationType .text:00011D32 lea eax, [ebp+FreeSize] .text:00011D38 push eax ; AllocationSize .text:00011D39 push 0 ; ZeroBits .text:00011D3B lea ecx, [ebp+BaseAddress] .text:00011D41 push ecx ; BaseAddress .text:00011D42 push 0FFFFFFFFh ; ProcessHandle .text:00011D44 call ds:ZwAllocateVirtualMemory .text:00011D4A mov [ebp+status], eax .text:00011D4D cmp [ebp+status], 0 .text:00011D51 jl loc_11F0A .text:00011D57 mov [ebp+ProcessPeb], 0 .text:00011D61 push 0 ; ReturnLength .text:00011D63 push 18h ; ProcessInformationLength .text:00011D65 lea edx, [ebp+ProcessInformation] .text:00011D6B push edx ; ProcessInformation .text:00011D6C push 0 ; ProcessInformationClass .text:00011D6E mov eax, [ebp+Handle] .text:00011D71 push eax ; ProcessHandle .text:00011D72 call ds:ZwQueryInformationProcess .text:00011D78 test eax, eax .text:00011D7A jl short loc_11D88 .text:00011D7C mov ecx, [ebp+ProcessInformation.PebBaseAddress] .text:00011D82 mov [ebp+ProcessPeb], ecx .text:00011D88 .text:00011D88 loc_11D88: ; CODE XREF: GetProcessFileName+11Aj .text:00011D88 cmp [ebp+ProcessPeb], 0 .text:00011D8F jz short loc_11DDB .text:00011D91 push 0 .text:00011D93 push 4 .text:00011D95 mov edx, [ebp+BaseAddress] .text:00011D9B push edx .text:00011D9C mov eax, [ebp+ProcessPeb] .text:00011DA2 add eax, 10h .text:00011DA5 push eax .text:00011DA6 mov ecx, [ebp+Handle] .text:00011DA9 push ecx .text:00011DAA mov edx, ds:FastMutex .text:00011DB0 call dword ptr [edx+104h] ; NtReadVirtualMemory .text:00011DB6 mov [ebp+status], eax .text:00011DB9 cmp [ebp+status], 0 .text:00011DBD jnz short loc_11DCF .text:00011DBF mov eax, [ebp+BaseAddress] ; ProcessParameters .text:00011DC5 mov ecx, [eax] ; _RTL_USER_PROCESS_PARAMETERS .text:00011DC7 mov [ebp+ProcessParameters], ecx .text:00011DCD jmp short loc_11DD9 .text:00011DCF ; --------------------------------------------------------------------------- .text:00011DCF .text:00011DCF loc_11DCF: ; CODE XREF: GetProcessFileName+15Dj .text:00011DCF mov [ebp+ProcessParameters], 20000h .text:00011DD9 .text:00011DD9 loc_11DD9: ; CODE XREF: GetProcessFileName+16Dj .text:00011DD9 jmp short loc_11DE5 .text:00011DDB ; --------------------------------------------------------------------------- .text:00011DDB .text:00011DDB loc_11DDB: ; CODE XREF: GetProcessFileName+12Fj .text:00011DDB mov [ebp+ProcessParameters], 20000h .text:00011DE5 .text:00011DE5 loc_11DE5: ; CODE XREF: GetProcessFileName:loc_11DD9j .text:00011DE5 mov edx, [ebp+ProcessParameters] .text:00011DEB add edx, RTL_USER_PROCESS_PARAMETERS.ImagePathName .text:00011DEE mov [ebp+ImagePathName], edx .text:00011DF4 push 0 .text:00011DF6 push 8 .text:00011DF8 mov eax, [ebp+BaseAddress] .text:00011DFE push eax .text:00011DFF mov ecx, [ebp+ImagePathName] .text:00011E05 push ecx .text:00011E06 mov edx, [ebp+Handle] .text:00011E09 push edx .text:00011E0A mov eax, ds:FastMutex .text:00011E0F call dword ptr [eax+104h] ; NtReadVirtualMemory .text:00011E15 mov [ebp+status], eax .text:00011E18 cmp [ebp+status], 0 .text:00011E1C jl loc_11EEF .text:00011E22 mov ecx, [ebp+BaseAddress] .text:00011E28 mov edx, [ecx+4] .text:00011E2B mov [ebp+ImagePathBuffer], edx .text:00011E31 mov eax, [ebp+BaseAddress] .text:00011E37 movzx ecx, word ptr [eax] .text:00011E3A mov [ebp+len], ecx .text:00011E40 mov edx, [ebp+ImagePathBuffer] .text:00011E46 cmp edx, [ebp+ProcessParameters] .text:00011E4C jnb short loc_11E60 .text:00011E4E mov eax, [ebp+ImagePathBuffer] .text:00011E54 add eax, [ebp+ProcessParameters] .text:00011E5A mov [ebp+ImagePathBuffer], eax .text:00011E60 .text:00011E60 loc_11E60: ; CODE XREF: GetProcessFileName+1ECj .text:00011E60 cmp [ebp+len], 0FFFh .text:00011E6A jbe short loc_11E76 .text:00011E6C mov [ebp+len], 0FFFh .text:00011E76 .text:00011E76 loc_11E76: ; CODE XREF: GetProcessFileName+20Aj .text:00011E76 push 0 .text:00011E78 mov ecx, [ebp+len] .text:00011E7E push ecx .text:00011E7F mov edx, [ebp+BaseAddress] .text:00011E85 push edx .text:00011E86 mov eax, [ebp+ImagePathBuffer] .text:00011E8C push eax .text:00011E8D mov ecx, [ebp+Handle] .text:00011E90 push ecx .text:00011E91 mov edx, ds:FastMutex .text:00011E97 call dword ptr [edx+104h] .text:00011E9D mov [ebp+status], eax .text:00011EA0 cmp [ebp+status], 0 .text:00011EA4 jl short loc_11EEF .text:00011EA6 mov eax, [ebp+len] .text:00011EAC add eax, 2 .text:00011EAF cmp eax, [ebp+Size] .text:00011EB2 jbe short loc_11EB8 .text:00011EB4 xor eax, eax .text:00011EB6 jmp short loc_11F17 .text:00011EB8 ; --------------------------------------------------------------------------- .text:00011EB8 .text:00011EB8 loc_11EB8: ; CODE XREF: GetProcessFileName+252j .text:00011EB8 mov ecx, [ebp+len] .text:00011EBE push ecx ; size_t .text:00011EBF mov edx, [ebp+BaseAddress] .text:00011EC5 push edx ; void * .text:00011EC6 mov eax, [ebp+Buffer] .text:00011EC9 push eax ; void * .text:00011ECA call memcpy .text:00011ECF add esp, 0Ch .text:00011ED2 mov ecx, [ebp+Buffer] .text:00011ED5 push ecx ; wchar_t * .text:00011ED6 call ConvertToNormalPath .text:00011EDB mov edx, [ebp+Buffer] .text:00011EDE push edx ; wchar_t * .text:00011EDF call ds:_wcsupr .text:00011EE5 add esp, 4 .text:00011EE8 mov [ebp+var_4], 1 .text:00011EEF .text:00011EEF loc_11EEF: ; CODE XREF: GetProcessFileName+1BCj .text:00011EEF ; GetProcessFileName+244j .text:00011EEF push 8000h ; FreeType .text:00011EF4 lea eax, [ebp+FreeSize] .text:00011EFA push eax ; FreeSize .text:00011EFB lea ecx, [ebp+BaseAddress] .text:00011F01 push ecx ; BaseAddress .text:00011F02 push 0FFFFFFFFh ; ProcessHandle .text:00011F04 call ds:ZwFreeVirtualMemory .text:00011F0A .text:00011F0A loc_11F0A: ; CODE XREF: GetProcessFileName+98j .text:00011F0A ; GetProcessFileName+F1j .text:00011F0A mov edx, [ebp+Handle] .text:00011F0D push edx ; Handle .text:00011F0E call ds:ZwClose .text:00011F14 .text:00011F14 loc_11F14: ; CODE XREF: GetProcessFileName+85j .text:00011F14 mov eax, [ebp+var_4] .text:00011F17 .text:00011F17 loc_11F17: ; CODE XREF: GetProcessFileName+32j .text:00011F17 ; GetProcessFileName+256j .text:00011F17 pop edi .text:00011F18 mov esp, ebp .text:00011F1A pop ebp .text:00011F1B retn 0Ch .text:00011F1B GetProcessFileName endp .text:00011F1B
于是从栈回溯结果可以推断,NtAllocateVirtualMemory里的ExfAcquirePushLockExclusive获取某个PushLock的时候处在等待状态,从而导致HOOKHELP.sys中其他需要获取这个HOOKHELP.sys的全局Fast Mutex的线程都只能等待了。
这个ZwAllocateVirtualMemory的问题,我自己遇到过,曾经在LoadImageNotifyRoutine中调用ZwAllocateVirtualMemory,结果那个线程死锁了。
网上有debugman的帖子http://www.debugman.com/discussion/1110/关于zwallocatevirtualmemory/p1,询问关于这个问题,但是没有结果。
搜了一下又发现OSR里有一篇:http://www.osronline.com/cf.cfm?PageURL=showThread.CFM?link=183262,其中提到:
代码:
> Well i think i've found the reason of the deadlock. I've assumed the > callback function is always executed at PASSIVE IRQL LEVEL. However > after first two loaded modules, IRQL raises to APC LEVEL :-( This is a known limitation. For user image loads the callback is invoked with the process address space lock held, so you can't call any APIs which might directly or indirectly try to acquire the same lock.
代码:
...... 6,如果不是new created process,例如是随后的dll导致的callback,或者是父进程导致的exe的callback,堆栈如下(x86 win7): 8bb01b3c 83c9abc6 nt!PsCallImageNotifyRoutines+0x62 8bb01be8 83cb3979 nt!MiMapViewOfImageSection+0x7fd 8bb01c58 83cc4241 nt!MiMapViewOfSection+0x22e 8bb01c88 83cc416c nt!MmMapViewOfSection+0x2a 8bb01d04 83a8844a nt!NtMapViewOfSection+0x204 8bb01d04 76eb64f4 nt!KiFastCallEntry+0x12a ...... 8,场景不同有什么意义? 第一种场景下,可以调用ZwQueryVirtualMemory等函数 第二种场景下,这些函数都不能调用。原因是在第二种场景下,系统在进入load image callback之前,在MmMapViewOfSection中会调用 #define LOCK_ADDRESS_SPACE(PROCESS) \ ExAcquireFastMutex( &((PROCESS)->AddressCreationLock))获得Mutex。 (以上#define来自win2k src code,如果是2k3以上,不是fast mutex,而是push lock,但类似。不同os获得的锁不尽相同,但总之都需要获得锁,并且锁都是不可递归获取的) 并且在load image callback结束后回到MmMapViewOfSection才释放。 9,有什么影响? ZwQueryVirtualMemory/Allocate/Protect同样会获得这个mutex或者push lock。因此,如果是第二种场景,在load image callback中调用ZwQueryVirtualMemory将导致deadlock 。win2k的代码是LOCK_WS_AND_ADDRESS_SPACE。 ...... 此问题在create process/thread callback中不存在。因为这2个callback不涉及map view/memory,所以很容易理解。 ...... 引自http://huyuguang1976.spaces.live.com/(原文链接已失效)
代码:
NtAllocateVirtualMemory的相应位置: 0: kd> u 83466cc5 nt!NtAllocateVirtualMemory+0x1263: 83466cc5 8b4de4 mov ecx,dword ptr [ebp-1Ch];EPROCESS pointer 83466cc8 81c100010000 add ecx,100h;_EPROCESS.AddressCreationLock 83466cce 8bc1 mov eax,ecx 83466cd0 f00fba2800 lock bts dword ptr [eax],0 83466cd5 7305 jae nt!NtAllocateVirtualMemory+0x127a (83466cdc) 83466cd7 e8b15ee6ff call nt!ExfAcquirePushLockExclusive (832ccb8d) 83466cdc 808b8902000002 or byte ptr [ebx+289h],2 83466ce3 8b45e4 mov eax,dword ptr [ebp-1Ch]
代码:
bd82e42c 832781ea ffffffff bd82e514 00000000 nt!NtAllocateVirtualMemory+0x127a bd82e42c就是进入NtAllocateVirtualMemory后的ebp 0: kd> dd bd82e42c-1c bd82e410 855a4d40 bd82e34c 8ec7821f ffffffff bd82e420 832f9ccd a6e177ec fffffffe bd82e44c bd82e430 832781ea ffffffff bd82e514 00000000 bd82e440 bd82e510 00001000 00000000 bd82e650 bd82e450 832758e1 badb0d00 bd82e4c4 ba000d00 bd82e460 bd82e4cc 83001703 00000000 bd82ee00 bd82e470 807c6120 bd82e484 00000000 00010022 bd82e480 00000000 bd82e4c4 bd82fd34 832b48c6
代码:
0: kd> dt -r _EPROCESS 855a4d40 nt!_EPROCESS ... +0x100 AddressCreationLock : _EX_PUSH_LOCK +0x000 Locked : 0y1 +0x000 Waiting : 0y1 +0x000 Waking : 0y0 +0x000 MultipleShared : 0y0 +0x000 Shared : 0y1100010100011111011010101011 (0xc51f6ab) +0x000 Value : 0xc51f6ab3 +0x000 Ptr : 0xc51f6ab3 Void
但是问题是,这个NtAllocateVirtualMemory调用是在CreateProcessNotifyRoutine里面做的,按理应该不会有这样的问题了才对。也就是说很可能不是这个线程本身先锁定了AddressCreationLock,而是被另一个线程先锁定了,那另一个线程又怎么会不解锁呢?
再在explorer.exe里找找,结果发现了这个线程:
代码:
THREAD 8562f838 Cid 071c.0814 Teb: 7ff9a000 Win32Thread: fe5121d8 WAIT: (WrFastMutex) KernelMode Non-Alertable 86e15014 SynchronizationEvent Not impersonating DeviceMap c14ef898 Owning Process 855a4d40 Image: explorer.exe Attached Process N/A Image: N/A Wait Start TickCount 11758 Ticks: 14076 (0:00:03:39.587) Context Switch Count 42 UserTime 00:00:00.000 KernelTime 00:00:00.000 Win32 Start Address 0x0025ad5f Stack Init c51ebfd0 Current c51eb198 Base c51ec000 Limit c51e9000 Call 0 Priority 9 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5 ChildEBP RetAddr c51eb1b0 832b869d nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4]) c51eb1e8 832b74f7 nt!KiSwapThread+0x266 c51eb210 832b10cf nt!KiCommitThreadWait+0x1df c51eb288 8326b08e nt!KeWaitForSingleObject+0x393 c51eb2b0 832ce55b nt!KiAcquireFastMutex+0x56 c51eb2bc 8ece16c7 nt!ExAcquireFastMutex+0x1e (FPO: [0,0,2]) WARNING: Stack unwind information not available. Following frames may be wrong. c51ebb0c 834a939c HOOKHELP!RisingInlineUnHook+0x1467 c51ebb34 8349127f nt!PsCallImageNotifyRoutines+0x62 c51ebbe8 83481d4a nt!MiMapViewOfImageSection+0x670 c51ebc58 83481e3a nt!MiMapViewOfSection+0x22e c51ebc88 83482599 nt!MmMapViewOfSection+0x2a c51ebd04 832781ea nt!NtMapViewOfSection+0x204 c51ebd04 779970b4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ c51ebd34) 04e6f948 00000000 0x779970b4 0: kd> .thread 8562f838 Implicit thread is now 8562f838 0: kd> kb *** Stack trace for last set context - .thread/.cxr resets it ChildEBP RetAddr Args to Child c51eb1b0 832b869d 8562f838 00000000 83365d20 nt!KiSwapContext+0x26 c51eb1e8 832b74f7 8562f8f8 8562f838 86e15014 nt!KiSwapThread+0x266 c51eb210 832b10cf 8562f838 8562f8f8 00000000 nt!KiCommitThreadWait+0x1df c51eb288 8326b08e 86e15014 00000022 00000000 nt!KeWaitForSingleObject+0x393 c51eb2b0 832ce55b 8562f838 8e015390 8ece16c7 nt!KiAcquireFastMutex+0x56 c51eb2bc 8ece16c7 8615c480 00000000 c51eb304 nt!ExAcquireFastMutex+0x1e WARNING: Stack unwind information not available. Following frames may be wrong. c51ebb0c 834a939c a2dae2e0 0000071c c51ebb5c HOOKHELP!RisingInlineUnHook+0x1467 c51ebb34 8349127f a2dae2e0 0000071c 8337cb88 nt!PsCallImageNotifyRoutines+0x62 c51ebbe8 83481d4a a1baa568 855a4d40 c51ebce4 nt!MiMapViewOfImageSection+0x670 c51ebc58 83481e3a 855a4d40 c51ebce4 00000000 nt!MiMapViewOfSection+0x22e c51ebc88 83482599 c4d32150 855a4d40 c51ebce4 nt!MmMapViewOfSection+0x2a c51ebd04 832781ea 000006a0 ffffffff 04e6f9dc nt!NtMapViewOfSection+0x204 c51ebd04 779970b4 000006a0 ffffffff 04e6f9dc nt!KiFastCallEntry+0x12a 04e6f948 00000000 00000000 00000000 00000000 0x779970b4 0: kd> dc a2dae2e0 a2dae2e0 0078003c b54556f8 00000000 00000000 <.x..VE......... a2dae2f0 00000000 00000000 00000000 00040001 ................ a2dae300 00000000 a2dae304 a2dae304 00040000 ................ a2dae310 00000000 a2dae314 a2dae314 00000000 ................ a2dae320 00000000 a2dae324 a2dae324 00000000 ....$...$....... a2dae330 04080017 ee657645 00000000 00000040 ....Eve.....@... a2dae340 00000000 00000000 00000001 00000001 ................ a2dae350 00000000 0008000c 83370cc0 00000000 ..........7..... 0: kd> dc b54556f8 b54556f8 0057005c 006e0069 006f0064 00730077 \.W.i.n.d.o.w.s. b5455708 0053005c 00730079 00650074 0033006d \.S.y.s.t.e.m.3. b5455718 005c0032 00750041 00690064 0053006f 2.\.A.u.d.i.o.S. b5455728 00730065 0064002e 006c006c 548d0000 e.s...d.l.l....T b5455738 f28bff12 f63302eb 850ff685 fffff5dd ......3......... b5455748 3bf2508b 7d74f251 0ff2b60f 2bf251b6 .P.;Q.t}.....Q.+ b5455758 331574f2 0ff685d2 548dc29f f28bff12 .t.3.......T.... b5455768 850ff685 fffff5b5 00010210 e24e4d43 ............CMN.
但是重点是,如上面所提到的,这个线程在PsCallImageNotifyRoutines前,在MiMapViewOfSection中已经锁定了explorer.exe进程的AddressCreationLock:
代码:
PAGE:00647C86 loc_647C86: ; CODE XREF: MiMapViewOfSection(x,x,x,x,x,x,x,x,x,x,x,x)+15Ej PAGE:00647C86 8B 03 mov eax, [ebx] PAGE:00647C88 64 8B 3D 24 01 00 00 mov edi, large fs:124h PAGE:00647C8F 89 44 24 14 mov [esp+40h+var_2C], eax PAGE:00647C93 8B 45 08 mov eax, [ebp+Eprocess] PAGE:00647C96 39 47 50 cmp [edi+50h], eax PAGE:00647C99 74 16 jz short loc_647CB1 PAGE:00647C9B 8D 4C 24 28 lea ecx, [esp+40h+var_18] PAGE:00647C9F 51 push ecx ; int PAGE:00647CA0 50 push eax ; Eprocess PAGE:00647CA1 E8 0B 41 E5 FF call _KeStackAttachProcess@8 ; KeStackAttachProcess(x,x) PAGE:00647CA6 8B 45 08 mov eax, [ebp+Eprocess] PAGE:00647CA9 C7 44 24 10 01 00 00+ mov [esp+40h+var_30], 1 PAGE:00647CB1 PAGE:00647CB1 loc_647CB1: ; CODE XREF: MiMapViewOfSection(x,x,x,x,x,x,x,x,x,x,x,x)+17Dj PAGE:00647CB1 66 FF 8F 86 00 00 00 dec word ptr [edi+86h] PAGE:00647CB8 8D 88 00 01 00 00 lea ecx, [eax+100h];AddressCreationLock PAGE:00647CBE 89 4C 24 20 mov [esp+40h+var_20], ecx PAGE:00647CC2 8B D1 mov edx, ecx PAGE:00647CC4 F0 0F BA 2A 00 lock bts dword ptr [edx], 0 PAGE:00647CC9 73 08 jnb short loc_647CD3 PAGE:00647CCB E8 BD AE E4 FF call @ExfAcquirePushLockExclusive@4 ; ExfAcquirePushLockExclusive(x)
于是整个过程清晰了:
0. 系统启动时,瑞星的HOOKHELP.sys这个内核dll加载,hooksys.sys通过调用它进行底层HOOK和挂NotifyRoutine的工作。HOOKHELP.sys初始化了一个全局性的Fast Mutex(我称为HookHelpMutex)。其实这个Fast Mutex后部还放了一些HOOKHELP.sys自定义的内容。
1. 在本例中,explorer.exe进程启动过程中,其中一个线程加载AudioSes.dll的时候,在MiMapViewOfSection中调用ExfAcquirePushLockExclusive,获取了explorer.exe进程的
AddressCreationLock。
2. 与1大概同时,explorer.exe进程的另一个线程执行启动微软输入法IMSCMIG.EXE进程的过程中,进入了HOOKHELP.sys的CreateProcessNotifyRoutine,后者调用ExAcquireFastMutex获取了HookHelpMutex。
3. 随后,加载AudioSes.dll的线程进入了HOOKHELP.sys的LoadImageNotifyRoutine,同样调用ExAcquireFastMutex试图获取HookHelpMutex,由于此时HookHelpMutex已被创建IMSCMIG.EXE进程的线程获取,加载AudioSes.dll的线程只能等待。
4. 最终,创建IMSCMIG.EXE进程的线程调用了ZwAllocateVirtualMemory,后者调用ExfAcquirePushLockExclusive试图获取explorer.exe进程的AddressCreationLock,由于它已被加载AudioSes.dll的线程获取并且未释放,创建IMSCMIG.EXE进程的线程也只能等待。
加载AudioSes.dll的线程的继续,依赖于创建IMSCMIG.EXE进程的线程释放HookHelpMutex,然而后者请求的explorer.exe进程的AddressCreationLock又已被前者获取,因此两个线程之间形成了deadlock。
如果只是这两个线程之间deadlock,影响不大,但是由于HookHelpMutex对于HOOKHELP.sys来说是全局性的,HOOKHELP.sys中大量系统底层HOOK的函数要通过它进行同步,因此它的被死锁导致了很大一部分线程一进入系统底层调用就停在ExAcquireFastMutex中。只有那些不跳进HOOKHELP.sys的线程,比如进入win32k.sys的线程,由于瑞星2011似乎没有做SSDT Shadow HOOK而幸免于难,所以鼠标还能动,但是点什么什么没反应……
分析到此结束,我能想到的建议,是希望瑞星改进一下这个全局Fast Mutex的设置,比如对LoadImageNotifyRoutine做特殊处理等,保证这个回调尽量不要被其他例程锁住,要不然这种死锁就会有几率性地出现。