Tag Archive for 'CoInitialize'

[debugging tip] ole32!CRWLock::AcquireReaderLock == > GG

아래 내용의 덤프는 솔직히 현재 GG 상태 이지만 … 그래도 분석 했던 과정을 몇자 적습니다.(잘못된 분석일 수 있음)

. 0 Id: 6a4.1cc Suspend: 1 Teb: 7ffdf000 Unfrozen
# ChildEBP RetAddr Args to Child
00 0012da50 7c93e9c0 7c8025cb 00000350 00000000 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
01 0012da54 7c8025cb 00000350 00000000 00000000 ntdll!ZwWaitForSingleObject+0xc (FPO: [3,0,0])
02 0012dab8 7c802532 00000350 ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xa8 (FPO: [Non-Fpo])
03 0012dacc 769b4d8d 00000350 ffffffff 0012dbc8 kernel32!WaitForSingleObject+0×12 (FPO: [Non-Fpo])
04 0012db04 769915c0 00000001 0012dbc8 0012dbb4 ole32!CRWLock::AcquireReaderLock+0×120 (FPO: [Non-Fpo])
05 0012db40 76991524 00000001 0012dbc8 0012db7c ole32!CClassCache::GetClassObjectActivator+0×47 (FPO: [Non-Fpo])
06 0012db70 7698f9e9 0012dbc8 0012db54 02f5e8e0 ole32!CClassCache::SearchForLoadedClass+0×4a (FPO: [Non-Fpo])
07 0012dc54 7698faba 00557564 00000000 00000017 ole32!ICoCreateInstanceEx+0×15a (FPO: [Non-Fpo])
08 0012dc7c 7698fa89 00557564 00000000 00000017 ole32!CComActivator::DoCreateInstance+0×28 (FPO: [Non-Fpo])
09 0012dca0 7698faf7 00557564 00000000 00000017 ole32!CoCreateInstanceEx+0×1e (FPO: [Non-Fpo])
0a 0012dcd0 004f9ab4 00557564 00000000 00000017 ole32!CoCreateInstance+0×37 (FPO: [Non-Fpo])

Application Hang 상황에서 위와 같은 스택을 만난다면 굉장히 당황할 수 있습니다. 특히나 OLE 32와 같은 경우 거의 대부분의 내용이 Undocument 되어 있기때문에 사실상 Reversing 이외에는 방법이 없지요. WaitForSingleObject와 함께 발생하는 Application Hang이라면 WaitForSingleObject가 실행될 조건을 판단해 보는것이 분석에 꽤나 도움이 됩니다. ( 저 역시도 GG 입니다. )

ole32!CRWLock::AcquireReaderLock:
7698fc39 8bff mov edi,edi
7698fc3b 55 push ebp
7698fc3c 8bec mov ebp,esp
7698fc3e 83ec1c sub esp,1Ch
7698fc41 a16461a976 mov eax,dword ptr [ole32!gdwDefaultTimeout (76a96164)]
7698fc46 57 push edi
7698fc47 8bf9 mov edi,ecx
7698fc49 f6471801 test byte ptr [edi+18h],1
7698fc4d 897df0 mov dword ptr [ebp-10h],edi
7698fc50 8945e4 mov dword ptr [ebp-1Ch],eax
7698fc53 0f8458020700 je ole32!CRWLock::AcquireReaderLock+0×1c (769ffeb1)
ole32!CRWLock::AcquireReaderLock+0x20:
7698fc59 ff1580129776 call dword ptr [ole32!_imp__GetCurrentThreadId (76971280)]
7698fc5f 394710 cmp dword ptr [edi+10h],eax
7698fc62 0f8452020700 je ole32!CRWLock::AcquireReaderLock+0×2b (769ffeba)
일단 edi+10h와 GetCurrentThreadId를 비교하는 것으로 보아 edi+10h ( edi에는 ole32!CClassCache::_mxs 의 값이 있지요 ) 는 어떤 Thread의 ID가 있는 것으로 추정됩니다. 하지만 실제로 그 Thread는 존재하지 않습니다. ( 가장 아쉬운 부분 )

0:000> dd 76a96068+0x10
76a96078 00000794 00000178 00010001 00000001
76a96088 00000003 7697d2cc 00000000 00000000
76a96098 00000000 00000000 00000043 00000001
76a960a8 00000002 00000000 76a12cfb 7698cf29
76a960b8 7698cf29 76a12fcc 76a1304a 76a1313f
76a960c8 76a131e6 76a1326b 76a132f1 00000000
76a960d8 00000000 00000000 00000000 00000001
76a960e8 00000000 00000000 7697d7c0 00000021
0:000> ~*
. 0 Id: 6a4.1cc Suspend: 1 Teb: 7ffdf000 Unfrozen
Priority: 0 Priority class: 32
1 Id: 6a4.a7c Suspend: 1 Teb: 7ffdb000 Unfrozen
Priority: 0 Priority class: 32
2 Id: 6a4.d1c Suspend: 1 Teb: 7ffda000 Unfrozen
Priority: 0 Priority class: 32
3 Id: 6a4.d94 Suspend: 1 Teb: 7ffd9000 Unfrozen
Priority: 0 Priority class: 32
4 Id: 6a4.fd0 Suspend: 1 Teb: 7ffd8000 Unfrozen
Priority: 0 Priority class: 32
5 Id: 6a4.3d8 Suspend: 1 Teb: 7ffd7000 Unfrozen
Priority: 0 Priority class: 32
6 Id: 6a4.a58 Suspend: 1 Teb: 7ffd6000 Unfrozen
Priority: 0 Priority class: 32
7 Id: 6a4.6b8 Suspend: 1 Teb: 7ffd4000 Unfrozen
Priority: 0 Priority class: 32
8 Id: 6a4.f78 Suspend: 1 Teb: 7ffd3000 Unfrozen
Priority: 0 Priority class: 32
9 Id: 6a4.fc0 Suspend: 1 Teb: 7ff9f000 Unfrozen
Priority: 0 Priority class: 32
# 10 Id: 6a4.85c Suspend: 1 Teb: 7ffde000 Unfrozen
Priority: 0 Priority class: 32

이 Thread가 존재했다면 좀더 정확한 원인을 찾았을꺼라 생각이되는데 …

ole32!CRWLock::AcquireReaderLock+0x3a:
7698fc68 8b07 mov eax,dword ptr [edi]
7698fc6a 53 push ebx
7698fc6b 56 push esi
7698fc6c 8d4de8 lea ecx,[ebp-18h]
7698fc6f 51 push ecx
7698fc70 8bcf mov ecx,edi
7698fc72 ff5008 call dword ptr [eax+8] // GetTLSLockData
7698fc75 85c0 test eax,eax
7698fc77 8945fc mov dword ptr [ebp-4],eax
7698fc7a 0f8cae510200 jl ole32!CRWLock::AcquireReaderLock+0×256 (769b4e2e)
ole32!CRWLock::AcquireReaderLock+0x52:
7698fc80 8b4de8 mov ecx,dword ptr [ebp-18h]
7698fc83 33c0 xor eax,eax
7698fc85 668b01 mov ax,word ptr [ecx]
7698fc88 6685c0 test ax,ax
7698fc8b 0f8538020700 jne ole32!CRWLock::AcquireReaderLock+0×5f (769ffec9)
ole32!CRWLock::AcquireReaderLock+0x68:
7698fc91 8365fc00 and dword ptr [ebp-4],0
7698fc95 8365f400 and dword ptr [ebp-0Ch],0
7698fc99 8b770c mov esi,dword ptr [edi+0Ch]

ole32!CRWLock::AcquireReaderLock+0×73: <==
7698fc9c b8ff030000 mov eax,3FFh
7698fca1 3bf0 cmp esi,eax
7698fca3 8975ec mov dword ptr [ebp-14h],esi
7698fca6 0f83ba4f0200 jae ole32!CRWLock::AcquireReaderLock+0×83 (769b4c66)

0:000> dd 76a96068+0×0C
76a96074 00803000 00000794 00000178 00010001
76a96084 00000001 00000003 7697d2cc 00000000
76a96094 00000000 00000000 00000000 00000043
76a960a4 00000001 00000002 00000000 76a12cfb
76a960b4 7698cf29 7698cf29 76a12fcc 76a1304a
76a960c4 76a1313f 76a131e6 76a1326b 76a132f1
76a960d4 00000000 00000000 00000000 00000000
76a960e4 00000001 00000000 00000000 7697d7c0

WaitSingle Object를 타기위해서는 위에 있는 769b4c66 으로 Jump를 해야합니다.  그런 조건이라면 esi 의 값이 0×3FFh 의 값보다 컷어야 한다는 것이지요 ..  0×3FF와 비교 해야하는 값에 의미를 파악하지 할 수 있다면 더없이 좋을것으로 일단 생각 됩니다.

ole32!CRWLock::AcquireReaderLock+0x1f9:
7698fcac 56 push esi
7698fcad 46 inc esi
7698fcae 56 push esi
7698fcaf 8d470c lea eax,[edi+0Ch]
7698fcb2 50 push eax
7698fcb3 ff1540129776 call dword ptr [ole32!_imp__InterlockedCompareExchange (76971240)]
7698fcb9 8bf0 mov esi,eax
7698fcbb 3b75ec cmp esi,dword ptr [ebp-14h]
ole32!CRWLock::AcquireReaderLock+0x20b:
7698fcbe 0f85f04f0200 jne ole32!CRWLock::AcquireReaderLock+0x20d (769b4cb4)
ole32!CRWLock::AcquireReaderLock+0x27f:
7698fcc4 837dfc00 cmp dword ptr [ebp-4],0
7698fcc8 0f8c60510200 jl ole32!CRWLock::AcquireReaderLock+0×256 (769b4e2e)

ole32!CRWLock::AcquireReaderLock+0×285:
7698fcce 8b45e8 mov eax,dword ptr [ebp-18h]
7698fcd1 66c7000100 mov word ptr [eax],1

ole32!CRWLock::AcquireReaderLock+0×277:
7698fcd6 5e pop esi
7698fcd7 5b pop ebx

ole32!CRWLock::AcquireReaderLock+0×279:
7698fcd8 8b45fc mov eax,dword ptr [ebp-4]
7698fcdb 5f pop edi
7698fcdc c9 leave
7698fcdd c3 ret

ole32!CRWLock::AcquireReaderLock+0×83:
769b4c66 b900040000 mov ecx,400h
769b4c6b 85f1 test ecx,esi
769b4c6d 0f8591010000 jne ole32!CRWLock::AcquireReaderLock+0×8c (769b4e04)

ole32!CRWLock::AcquireReaderLock+0xad:
769b4c73 8bd6 mov edx,esi
769b4c75 23d0 and edx,eax
769b4c77 3bd0 cmp edx,eax
769b4c79 0f84ddb20400 je ole32!CRWLock::AcquireReaderLock+0×1e5 (769fff5c)

ole32!CRWLock::AcquireReaderLock+0xb9:
769b4c7f b800e07f00 mov eax,7FE000h
769b4c84 8bd6 mov edx,esi
769b4c86 23d0 and edx,eax
769b4c88 3bd0 cmp edx,eax
769b4c8a 0f84ccb20400 je ole32!CRWLock::AcquireReaderLock+0×1e5 (769fff5c)

ole32!CRWLock::AcquireReaderLock+0xca:
769b4c90 8bc6 mov eax,esi
769b4c92 25000c0000 and eax,0C00h
769b4c97 3bc1 cmp eax,ecx
769b4c99 0f84bdb20400 je ole32!CRWLock::AcquireReaderLock+0×1e5 (769fff5c)

ole32!CRWLock::AcquireReaderLock+0xd9: <==
769b4c9f ff45f4 inc dword ptr [ebp-0Ch]
769b4ca2 8b45f4 mov eax,dword ptr [ebp-0Ch]
769b4ca5 3b05bc64a976 cmp eax,dword ptr [ole32!gdwDefaultSpinCounu t (76a964bc)]
769b4cab 0f87a3000000 ja ole32!CRWLock::AcquireReaderLock+0xeb (769b4d54)

ole32!CRWLock::AcquireReaderLock+0×1f4:
769b4cb1 8b770c mov esi,dword ptr [edi+0Ch]

ole32!CRWLock::AcquireReaderLock+0×20d:
769b4cb4 817dfc1f010180 cmp dword ptr [ebp-4],8001011Fh
769b4cbb 0f84afb20400 je ole32!CRWLock::AcquireReaderLock+0×216 (769fff70)

ole32!CRWLock::AcquireReaderLock+0×24c:
769b4cc1 837dfc00 cmp dword ptr [ebp-4],0
769b4cc5 0f8dd1affdff jge ole32!CRWLock::AcquireReaderLock+0×73 (7698fc9c)

ole32!CRWLock::AcquireReaderLock+0×256:
769b4ccb e95e010000 jmp ole32!CRWLock::AcquireReaderLock+0×256 (769b4e2e)

ole32!CRWLock::AcquireReaderLock+0xeb:
769b4d54 56 push esi
769b4d55 81c600200000 add esi,2000h
769b4d5b 56 push esi
769b4d5c 8d470c lea eax,[edi+0Ch]
769b4d5f 50 push eax
769b4d60 ff1540129776 call dword ptr [ole32!_imp__InterlockedCompareExchange (76971240)]
769b4d66 8bf0 mov esi,eax
769b4d68 3b75ec cmp esi,dword ptr [ebp-14h]
769b4d6b 0f8543ffffff jne ole32!CRWLock::AcquireReaderLock+0×20d (769b4cb4)

ole32!CRWLock::AcquireReaderLock+0×108:
769b4d71 8bcf mov ecx,edi
769b4d73 e8bdffffff call ole32!CRWLock::GetReaderEvent (769b4d35)
769b4d78 85c0 test eax,eax
769b4d7a 8945f8 mov dword ptr [ebp-8],eax
769b4d7d 0f844fb10400 je ole32!CRWLock::AcquireReaderLock+0×124 (769ffed2)

ole32!CRWLock::AcquireReaderLock+0×116:
769b4d83 ff75e4 push dword ptr [ebp-1Ch]
769b4d86 50 push eax
769b4d87 ff15b8129776 call dword ptr [ole32!_imp__WaitForSingleObject (769712b8)]

769b4d8d 8bd8 mov ebx,eax

ole32!CRWLock::AcquireReaderLock+0xd9지점을 거져서 Default Time Out Count를 가지고 WaitForSingleObject를 호출하게 되죠 ..  그렇다면 왜 hang이 걸려 있나 ??  일단 확인 가능한 정보로는 Default Time Out Count 의 값이 INFINITE라는 점, 그리고 알 수 없는 Thread의 ID 있다는 점을 미루어 보면 그 알 수 없는 Thread ID를 가지는 Thread에서 SetEvent를 해줄 것 같다는 불길한 생각이 듭니다. 그럼 그 Thread는 과연 어디로 살아진것일까 ???

정말 궁금합니다.. 재현이 안되니 아쉬움도 많이 남는 ㅜ.ㅜ  흑흑….

이 덤프 분석 가능하다 ==> 리플 고고싱
이 덤프 예전에 봤었다 ==> 리플 고고싱
이 덤프 원인은 모르지만 해결가능하다 ==> 리플 고고싱

[tip]ShellExecuteEx==> CoCreateInstance.. 주의 해야할점..

사내 Dump를 분석하던 중 CoInitialize를 호출해줬는데도 불구하고 CoCreateInstance를 실패하는 경우가 있었다. 무슨 원인일까 참 고민을 많이 했었는데 ShellExecuteEx라는 녀석이 문제의 원인이라는것을 찾은 적이 있다.

0:000> uf SHELL32!ShellExecuteExW
SHELL32!ShellExecuteExW:
7d5e17db 8bff mov edi,edi
7d5e17dd 55 push ebp
7d5e17de 8bec mov ebp,esp
7d5e17e0 51 push ecx
7d5e17e1 56 push esi
7d5e17e2 57 push edi
7d5e17e3 e88900ffff call SHELL32!SHCoInitialize (7d5d1871)
7d5e17e8 8b7508 mov esi,dword ptr [ebp+8]
7d5e17eb 6a3c push 3Ch
7d5e17ed 56 push esi
7d5e17ee 8945fc mov dword ptr [ebp-4],eax
7d5e17f1 ff1594145a7d call dword ptr [SHELL32!_imp__IsBadReadPtr (7d5a1494)]
7d5e17f7 85c0 test eax,eax
7d5e17f9 0f8549b20000 jne SHELL32!ShellExecuteExW+0xb2 (7d5eca48)
… 생략
SHELL32!ShellExecuteExW+0xb8:
7d5e1850 837dfc00 cmp dword ptr [ebp-4],0
7d5e1854 7c06 jl SHELL32!ShellExecuteExW+0xc4 (7d5e185c)
SHELL32!ShellExecuteExW+0xbe:
7d5e1856 ff1528e2797d call dword ptr [SHELL32!_imp__CoUninitialize (7d79e228)]

SHELL32!ShellExecuteExW+0xc4:
7d5e185c 85ff test edi,edi
7d5e185e 0f85a3900400 jne SHELL32!ShellExecuteExW+0xc8 (7d62a907)
… 생략

SHELL32!ShellExecuteExW+0xb2:
7d5eca48 6a05 push 5
7d5eca4a 5f pop edi
7d5eca4b 897e20 mov dword ptr [esi+20h],edi
7d5eca4e e9fd4dffff jmp SHELL32!ShellExecuteExW+0xb8 (7d5e1850)
… 생략
SHELL32!ShellExecuteExW+0xc8:
7d62a907 57 push edi
7d62a908 ff15e0155a7d call dword ptr [SHELL32!_imp__SetLastError (7d5a15e0)]
7d62a90e e9516ffbff jmp SHELL32!ShellExecuteExW+0xcf (7d5e1864)

ShellExecuteEx 함수는 내부에서 CoInitialize를 호출하고 문제가 발생해서 종료 될 경우 SetLastError를 호출한 뒤 CoUninitialize를 호출하고 종료한다. 그러한 이유에서 COM Object를 사용하기 위해서 COM 초기화를 한 상태라도 ShellExecuteEx 함수 호출 후 COM 초기화가 해제되는 경우가 있어 COM Object 생성을 실패하는 경우가 있다.

00 0013dd50 77e7937c 0013e20c 00000000 00000401 ole32!CoCreateInstance (FPO: [Non-Fpo])
01 0013dd78 7d5d4926 0013e20c 00000000 00000401 SHLWAPI!SHCoCreateInstanceAC+0×3a (FPO: [Non-Fpo])
02 0013e15c 7d5cfac8 0013e20c 00000000 00000401 SHELL32!_SHCoCreateInstance+0×127 (FPO: [Non-Fpo])
03 0013e19c 7d5cfa87 00000000 0013e20c 00000000 SHELL32!SHExtCoCreateInstance2+0×41 (FPO: [Non-Fpo])
04 0013e1bc 7d5d2ba2 00000000 0013e20c 00000000 SHELL32!SHExtCoCreateInstance+0×1e (FPO: [Non-Fpo])
05 0013e220 7d5cb96c 001767e8 0016ffd0 7d5a6efc SHELL32!CRegFolder::_CreateAndInit+0×106 (FPO: [Non-Fpo])
06 0013e248 7d620e71 001767e8 0016ffd0 7d5a6efc SHELL32!CRegFolder::_BindToItem+0×55 (FPO: [Non-Fpo])
07 0013e26c 7d620e37 001767e8 00000000 0016ffd0 SHELL32!CRegFolder::_ParseThroughItem+0×1d (FPO: [Non-Fpo])
08 0013e2d4 7d5cddad 0017bae0 00000000 0016ffd0 SHELL32!CRegFolder::ParseDisplayName+0×15a (FPO: [Non-Fpo])
09 0013e30c 7d5e1abb 00000000 70c50008 00000000 SHELL32!SHParseDisplayName+0xa3 (FPO: [Non-Fpo])
0a 0013e33c 7d5e190f 0013e358 0016ff08 00190008 SHELL32!CShellExecute::_PerfPidl+0×4e (FPO: [Non-Fpo])
0b 0013e350 7d5e18a6 00000000 0016ff08 0013e398 SHELL32!CShellExecute::ExecuteNormal+0×46 (FPO: [Non-Fpo])
0c 0013e364 7d5e1842 0013e398 00000000 0016ff08 SHELL32!ShellExecuteNormal+0×30 (FPO: [Non-Fpo])
0d 0013e380 7d620cc2 0013e398 00000000 0013f554 SHELL32!ShellExecuteExW+0×8d (FPO: [Non-Fpo])
0e 0013f42c 0041363b 0013f508 0013f858 00163f98 SHELL32!ShellExecuteExA+0×203 (FPO: [Non-Fpo])

…생략
0:000> dt ntdll!_GUID 0013e20c
{871c5380-42a0-1069-a2ea-08002b30309d}
+0×000 Data1 : 0×871c5380
+0×004 Data2 : 0×42a0
+0×006 Data3 : 0×1069
+0×008 Data4 : [8] “???”

0:000> !dreg hkcr\CLSID\{871c5380-42a0-1069-a2ea-08002b30309d}\InProcServer32\!*
Value: “” - REG_EXPAND_SZ: “%SystemRoot%\system32\SHDOCVW.DLL”
expanded = “C:\WINDOWS\system32\SHDOCVW.DLL”
————————————————————————
Value: “ThreadingModel” - REG_SZ: “Apartment”
————————————————————————

ShellExecuteEx를 호출하게 되면 내부적으로 COM Object를 사용하고 있고 그러한 이유에서 COM 초기화나 해제에 대한 Code가를 구현하고 있는것 으로 생각된다. ShellExecuteEx 호출에 조심해야 할 부분인것 같다.