HN 日本語サマリー

← 一覧へ戻る
プログラミング

正式にはアンロードされていないのにメモリ上に存在しないDLL

DLL that was not present in memory despite not being formally unloaded (devblogs.microsoft.com)

111 pointsby ibobev39 コメント

要約

shell32.dllチームは、サードパーティ製プログラムでの多数のクラッシュバグを調査しました。クラッシュダンプから、スタックオーバーフローによる再帰的な例外処理の無限ループが明らかになりました。根本原因はcombase!CoTaskMemFreeで発生した非実行可能アドレスへのアクセス違反であり、本来メモリにロードされているはずのcombase.dllが、何らかの理由でメモリからアンロードされているか、あるいは不正な状態になっていたことが判明しました。

全文翻訳

shell32.dllを担当するチームは、あるサードパーティ製プログラムで多数のクラッシュが発生しているというバグを受け取りました。クラッシュダンプを開くと、スタックオーバーフローの明確な兆候が見られました。 # Child-SP RetAddr Call Site 00 000000ba`92851098 00007ff9`fed521c1 ntdll!_chkstk+0x37 01 000000ba`928510b0 00007ff9`feea5ace ntdll!RtlDispatchException+0x2d1 02 000000ba`92851300 00007ff9`fed4e02d ntdll!KiUserExceptionDispatch+0x2e 03 000000ba`92852060 00007ff9`fed5222f ntdll!RtlLookupFunctionEntry+0x8d 04 000000ba`928520b0 00007ff9`feea5ace ntdll!RtlDispatchException+0x33f 05 000000ba`92852800 00007ff9`fed4e02d ntdll!KiUserExceptionDispatch+0x2e 06 000000ba`92853560 00007ff9`fed5222f ntdll!RtlLookupFunctionEntry+0x8d 07 000000ba`928535b0 00007ff9`feea5ace ntdll!RtlDispatchException+0x33f 08 000000ba`92853d00 00007ff9`fed4e02d ntdll!KiUserExceptionDispatch+0x2e 09 000000ba`92854a60 00007ff9`fed5222f ntdll!RtlLookupFunctionEntry+0x8d 0a 000000ba`92854ab0 00007ff9`feea5ace ntdll!RtlDispatchException+0x33f 0b 000000ba`92855200 00007ff9`fed51f29 ntdll!KiUserExceptionDispatch+0x2e 0c 000000ba`92855f70 00007ff9`feea5ace ntdll!RtlLookupFunctionEntry+0x8d 0d 000000ba`928561c0 00007ff9`fed4e02d ntdll!RtlDispatchException+0x33f ... ハイライトされたスタックフレームのブロック(RtlLookupFunctionEntryからKiUserExceptionDispatchまで)が非常に長く繰り返されていました。これは明らかに、ある種の再帰的な例外処理のデッドスパイラルに陥っていることを示しています。例外が発生し、カーネルモードでは処理できないと判断されたため、ユーザーモードに例外が反映され、さらなる処理が行われました(KiUserExceptionDispatch)。どの例外ハンドラを呼び出すかを判断しようとしている最中(RtlLookupFunctionEntry)、例外が発生し、例外ループが再開されました。最終的に、これらの再帰的な例外がスタックを使い果たし、スタックオーバーフロー例外が発生してプロセスが終了しました。 このバグはshell32に割り当てられました。shell32が元の例外の原因であるように見えたからです。スタックの一番下までたどると、次のようになります。 23f 000000ba`9294c620 00007ff9`fed5222f ntdll!RtlLookupFunctionEntry+0x8d 240 000000ba`9294c670 00007ff9`feea5ace ntdll!RtlDispatchException+0x33f 241 000000ba`9294cdc0 00007ff9`fed4e02d ntdll!KiUserExceptionDispatch+0x2e 242 000000ba`9294db20 00007ff9`fed5222f ntdll!RtlLookupFunctionEntry+0x8d 243 000000ba`9294db70 00007ff9`feea5ace ntdll!RtlDispatchException+0x33f 244 000000ba`9294e2c0 00007ff9`fcba0af0 ntdll!KiUserExceptionDispatch+0x2e 245 000000ba`9294f018 00007ff9`fde2ad13 combase!CoTaskMemFree 246 000000ba`9294f020 00007ff9`fc7abc75 shell32!wil::details::string_maker::~string_maker+0x13 247 000000ba`9294f050 00007ff9`fc7ab897 ucrtbase!<lambda_f03950bc5685219e0bcd2087efbe011e>::operator()+0xa5 248 000000ba`9294f0a0 00007ff9`fc7ab84d ucrtbase!__crt_seh_guarded_call<int>::operator()+0x3b 249 000000ba`9294f0d0 00007ff9`fc7d2f0c ucrtbase!execute_onexit_table+0x3d 24a 000000ba`9294f110 00007ff9`fdff4645 ucrtbase!__crt_state_management::wrapped_invoke+0x2c 24b 000000ba`9294f140 00007ff9`fdff476e shell32!dllmain_crt_process_detach+0x45 24c 000000ba`9294f180 00007ff9`fee9f6fe shell32!dllmain_dispatch+0xe6 24d 000000ba`9294f1e0 00007ff9`fed4bcae ntdll!LdrpCallInitRoutineInternal+0x22 24e 000000ba`9294f210 00007ff9`fedcd37f ntdll!LdrpCallInitRoutine+0x10e 24f 000000ba`9294f280 00007ff9`fedcc54e ntdll!LdrShutdownProcess+0x17f 250 000000ba`9294f390 00007ff9`fdcb18ab ntdll!RtlExitUserProcess+0x9e 251 000000ba`9294f3c0 00007ff9`e754882e kernel32!ExitProcessImplementation+0xb 252 000000ba`9294f3f0 00007ff9`e754f344 mscoreei!RuntimeDesc::ShutdownAllActiveRuntimes+0x2fa 253 000000ba`9294f6d0 00007ff9`e66f464b mscoreei!CLRRuntimeHostInternalImpl::ShutdownAllRuntimesThenExit+0x14 254 000000ba`9294f700 00007ff9`e66f44c9 clr!EEPolicy::ExitProcessViaShim+0x8b 255 000000ba`9294f760 00007ff9`e66f441e clr!SafeExitProcess+0x9d 256 000000ba`9294f9e0 00007ff9`e66f3f44 clr!HandleExitProcessHelper+0x3e 257 000000ba`9294fa10 00007ff9`e66f3e24 clr!_CorExeMainInternal+0xf8 258 000000ba`9294faa0 00007ff9`e753d6da clr!CorExeMain+0x14 259 000000ba`9294fae0 00007ff9`e75d785b mscoreei!CorExeMain+0xfa 25a 000000ba`9294fb40 00007ff9`fdc9e8d7 mscoree!CorExeMain_Exported+0xb 25b 000000ba`9294fb70 00007ff9`fedcc40c kernel32!BaseThreadInitThunk+0x17 25c 000000ba`9294fba0 00000000`00000000 ntdll!RtlUserThreadStart+0x2c 繰り返されるブロックは、最初の例外の原因であるcombase!CoTaskMemFreeで停止しています。元の問題が何であったかを確認するために、例外レコードを探すことができます。例外レコードとコンテキストレコードはRtlDispatchExceptionに渡される可能性が高いので、KiUserExceptionDispatchが何を渡すかを見ることができます。 # Child-SP RetAddr Call Site 243 000000ba`9294db70 00007ff9`feea5ace ntdll!RtlDispatchException+0x33f 244 000000ba`9294e2c0 00007ff9`fcba0af0 ntdll!KiUserExceptionDispatch+0x2e 0:000> u ntdll!KiUserExceptionDispatch 00007ff9`feea5ace ntdll!KiUserExceptionDispatch: 00007ff9`feea5aa0 cld 00007ff9`feea5aa1 mov rax,qword ptr [ntdll!Wow64PrepareForException (00007ff9`fef272f0)] 00007ff9`feea5aa8 test rax,rax 00007ff9`feea5aab je ntdll!KiUserExceptionDispatch+0x1c (00007ff9`feea5abc) 00007ff9`feea5aad mov rcx,rsp 00007ff9`feea5ab0 add rcx,4F0h 00007ff9`feea5ab7 mov rdx,rsp 00007ff9`feea5aba call rax 00007ff9`feea5abc mov rcx,rsp 00007ff9`feea5abf add rcx,4F0h 00007ff9`feea5ac6 mov rdx,rsp 00007ff9`feea5ac9 call ntdll!RtlDispatchException (00007ff9`fed51ef0) 00007ff9`feea5ace test al,al RtlDispatchExceptionに渡される2つのパラメータがrsp+4f0hとrspにあることがわかります。EXCEPTION_POINTERSではその順序でポインタが現れるので、例外レコードが最初に来て、その後にコンテキストレコードが来ると推測します。 # Child-SP RetAddr Call Site 244 000000ba`9294e2c0 00007ff9`fcba0af0 ntdll!KiUserExceptionDispatch+0x2e 00007ff9`feea5ace test al,al 0:000> dps 000000ba`9294e2c0+4f0 000000ba`9294e7b0 00000000`c0000005 ← STATUS_ACCESS_VIOLATION 000000ba`9294e7b8 00000000`00000000 000000ba`9294e7c0 00007ff9`fcba0af0 combase!CoTaskMemFree 000000ba`9294e7c8 00000000`00000002 000000ba`9294e7d0 00000000`00000008 うん、例外レコードのようです。例外コードから始まり、その直後に例外が発生したコードアドレスが続きます。 0:000> .exr 000000ba`9294e2c0+4f0 ExceptionAddress: 00007ff9fcba0af0 (combase!CoTaskMemFree) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 0000000000000008 Parameter[1]: 00007ff9fcba0af0 Attempt to execute non-executable address 00007ff9fcba0af0 さて、非実行可能アドレスを実行しようとしたのですが、そのアドレスはcombase!CoTaskMemFreeです。念のため、2番目のパラメータが本当にコンテキストレコードであることを確認してみましょう。 0:000> .cxr 000000ba`9294e2c0 rax=00007ff9fe3a9850 rbx=000001bbebd12388 rcx=000001bbebd63140 rdx=00007ff9fe4e99e0 rsi=000001bbebd12828 rdi=000001bbebd12310 rip=00007ff9fcba0af0 rsp=000000ba9294f018 rbp=0000df1c60b20569 r8=000001bbebd12310 r9=0000df1c60b20569 r10=d94b3944a87271f0 r11=000000000000000b r12=0000000000000001 r13=00007ff9fdff47c0 r14=000000ba9294f128 r15=000001bbebd12310 iopl=0 nv up ei pl nz na pe nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202 combase!CoTaskMemFree: 00007ff9`fcba0af0 sub rsp,28h うん、コンテキストレコードのようです。しかし、待ってください。例外はcombase!CoTaskMemFreeが実行可能ではないと主張しています。まず、デバッガーがこの評価に同意するかどうか見てみましょう。 0:000> !address 00007ff9`fcba0af0 Usage: Image Base Address: 00007ff9`fcb20000 End Address: 00007ff9`fcea6000 Region Size: 00000000`00386000 ( 3.523 MB) State: 00010000 MEM_FREE Protect: 00000001 PAGE_NOACCESS Type: <info not present at the target> Image Path: C:\Windows\System32\combase.dll Module Name: combase Loaded Image Name: combase.dll Mapped Image Name: C:\symbols\combase.dll More info: lmv m combase More info: !lmi combase Mor