从csrss弹出的ASSERT对话框谈起
?
昨天遇到一件怪事,在進行遠程線程注入的時候從csrss進程中竟然彈出了vc的ASSERT對話框。根據對話框提示信息找到了斷言的位置在mfc的auxdata.cpp的第95行代碼:
void AUX_DATA::UpdateSysMetrics()
{
?// System metrics
?cxIcon = GetSystemMetrics(SM_CXICON);
?cyIcon = GetSystemMetrics(SM_CYICON);
?// System metrics which depend on subsystem version
?afxData.cxVScroll = GetSystemMetrics(SM_CXVSCROLL) + CX_BORDER;
?afxData.cyHScroll = GetSystemMetrics(SM_CYHSCROLL) + CY_BORDER;
?// Device metrics for screen
?HDC hDCScreen = GetDC(NULL);
?ASSERT(hDCScreen != NULL);?<------------------就是這個斷言
?cxPixelsPerInch = GetDeviceCaps(hDCScreen, LOGPIXELSX);
?cyPixelsPerInch = GetDeviceCaps(hDCScreen, LOGPIXELSY);
?ReleaseDC(NULL, hDCScreen);
}
具體的環境就是win xp進行多用戶登陸:首先登陸一個windows帳號user1, session id = 0, 對csrss進程成功進行了遠程線程注入。接著在保持user1登陸的情況下切換用戶登陸到user2,進去之后同樣的對新的session(session id = 1)的csrss進程進行遠程線程注入,沒什么問題。但是切回到user1后發現界面上有一個斷言對話框,顯示了上面代碼位置的斷言失敗。查看這個對話框所在的進程確實是session 0的csrss進程。因為是一個穩定的重現的問題,使用windbg遠程附加到session 0的csrss進程,查看彈出對話框的線程調用棧如下:
?ChildEBP RetAddr?
??????? 0071f8d8 77d193f5 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
??????? 0071f910 77d2688a USER32!NtUserWaitMessage+0xc
??????? 0071f938 77d3b7c5 USER32!InternalDialogBox+0xd0 (FPO: [6,1,4])
??????? 0071fbf8 77d3b12b USER32!SoftModalMessageBox+0x938 (FPO: [1,165,4])
??????? 0071fd48 77d65fdf USER32!MessageBoxWorker+0x2ba (FPO: [1,78,4])
??????? 0071fda0 764f9b1b USER32!MessageBoxTimeoutW+0x7a (FPO: [6,19,0])
??????? 0071fe7c 764f9d5b winsrv!HardErrorHandler+0x2e8 (FPO: [0,44,4])
??????? 0071fe9c 764fb0f1 winsrv!ProcessHardErrorRequest+0x9b (FPO: [1,3,4])
??????? 0071febc 764fb173 winsrv!UserHardErrorEx+0x234 (FPO: [3,2,4])
??????? 0071fed0 75aa47a0 winsrv!UserHardError+0x12 (FPO: [2,0,0])
??????? 0071fff4 00000000 CSRSRV!CsrApiRequestThread+0x18a (FPO: [Non-Fpo])
這里很奇怪,斷言的調用鏈里面應該會出現__crtMessageBoxA,除非是符號不對,但是調用棧里面所有的返回地址都有符號。
難道是調用棧不完整,于是結合匯編代碼對調用棧進行核實---沒問題。一個偶然的原因在ReactOS上面看了一下CsrApiRequestThread函數的源代碼才意識到這個對話框是通過LPC端口投遞過來的消息顯示。winsrv!UserHardError是最后一個出錯處理回調例程。
用戶態調試查不出這個LPC是哪里投遞過來的,轉而使用內核態調試。
根據從運程線程注入的結果,對session 1的csrss進程進行的遠程線程一直沒有收到注入成功的回復,很自然想到看一下session 1的csrss進程的情況。
kd> !process 81a81468?
PROCESS 81a81468? SessionId: 1? Cid: 0238??? Peb: 7ffd5000? ParentCid: 0240
??? DirBase: 084003e0? ObjectTable: e178ca80? HandleCount: 128.
??? Image: csrss.exe
??? VadRoot 81711920 Vads 100 Clone 0 Private 702. Modified 2674. Locked 0.
??? DeviceMap e10000b8
??? Token???????????????????????????? e1474138
??? ElapsedTime?????????????????????? 00:01:01.984
??? UserTime????????????????????????? 00:00:01.500
??? KernelTime??????????????????????? 00:00:01.921
??? QuotaPoolUsage[PagedPool]???????? 123956
??? QuotaPoolUsage[NonPagedPool]????? 4160
??? Working Set Sizes (now,min,max)? (125, 50, 345) (500KB, 200KB, 1380KB)
??? PeakWorkingSetSize??????????????? 2818
??? VirtualSize?????????????????????? 59 Mb
??? PeakVirtualSize?????????????????? 76 Mb
??? PageFaultCount??????????????????? 3524
??? MemoryPriority??????????????????? BACKGROUND
??? BasePriority????????????????????? 13
??? CommitCharge????????????????????? 874
??????? /略去一些無關線程信息
??????? THREAD 8170eda8? Cid 0238.096c? Teb: 7ffd3000 Win32Thread: e24c1ba0 WAIT: (WrLpcReply) UserMode Non-Alertable
??????????? 8170ef9c? Semaphore Limit 0x1
??????? Waiting for reply to LPC MessageId 0000209e:
??????? Current LPC port e1353840
??????? Not impersonating
??????? DeviceMap???????????????? e10000b8
??????? Owning Process??????????? 81a81468?????? Image:???????? csrss.exe
??????? Wait Start TickCount????? 13207????????? Ticks: 2483 (0:00:00:38.796)
??????? Context Switch Count????? 17???????????????? LargeStack
??????? UserTime????????????????? 00:00:00.140
??????? KernelTime??????????????? 00:00:00.015
??????? Win32 Start Address 0x7ff90000
??????? Start Address KERNEL32!BaseThreadStartThunk (0x7c810856)
??????? Stack Init f72f1000 Current f72f0a94 Base f72f1000 Limit f72ee000 Call 0
??????? Priority 13 BasePriority 13 PriorityDecrement 0 DecrementCount 0
??????? ChildEBP RetAddr?
??????? f72f0aac 8050117a nt!KiSwapContext+0x2e (FPO: [Uses EBP] [0,0,4])
??????? f72f0ab8 804fa9be nt!KiSwapThread+0x46 (FPO: [0,0,0])
??????? f72f0ae0 805989d5 nt!KeWaitForSingleObject+0x1c2 (FPO: [Non-Fpo])
??????? f72f0b18 80598b21 nt!LpcpRequestWaitReplyPort+0x43d (FPO: [Non-Fpo])
??????? f72f0b30 8060a467 nt!LpcRequestWaitReplyPortEx+0x21 (FPO: [Non-Fpo])
??????? f72f0cd4 8060a8c5 nt!ExpRaiseHardError+0x1bd (FPO: [Non-Fpo])
??????? f72f0d44 8053d808 nt!NtRaiseHardError+0x16b (FPO: [Non-Fpo])
??????? f72f0d44 7c92eb94 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f72f0d64)
??????? 0350b348 7c92e273 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
??????? 0350b34c 77d65d43 ntdll!NtRaiseHardError+0xc (FPO: [6,0,0])
??????? 0350b3a8 77d48ffe USER32!ServiceMessageBox+0x145 (FPO: [Non-Fpo])
??????? 0350b504 77d65fdf USER32!MessageBoxWorker+0x13e (FPO: [Non-Fpo])
??????? 0350b55c 77d66084 USER32!MessageBoxTimeoutW+0x7a (FPO: [Non-Fpo])
??????? 0350b590 77d50598 USER32!MessageBoxTimeoutA+0x9c (FPO: [Non-Fpo])
??????? 0350b5b0 77d50550 USER32!MessageBoxExA+0x1b (FPO: [Non-Fpo])
??????? 0350b5cc 1020c2aa USER32!MessageBoxA+0x45 (FPO: [Non-Fpo])
??????? 0350b604 1020cd3e MSVCR71D!__crtMessageBoxA+0x16a (FPO: [Non-Fpo]) (CONV: cdecl) [f:/vs70builds/3077/vc/crtbld/crt/src/crtmbox.c @ 119]
??????? 0350c75c 1020ca2a MSVCR71D!CrtMessageWindow+0x2be (FPO: [Non-Fpo]) (CONV: cdecl) [f:/vs70builds/3077/vc/crtbld/crt/src/dbgrpt.c @ 617]
??????? 0350f7d8 03666b3f MSVCR71D!_CrtDbgReport+0x41a (FPO: [Non-Fpo]) (CONV: cdecl) [f:/vs70builds/3077/vc/crtbld/crt/src/dbgrpt.c @ 516]
??????? 0350f818 0361bad2 MFC71UD!AfxAssertFailedLine+0x2f (FPO: [Non-Fpo]) (CONV: stdcall) [f:/vs70builds/3077/vc/mfcatl/ship/atlmfc/src/mfc/afxasert.cpp @
28]
??????? 0350f830 0368cc9e MFC71UD!AUX_DATA::UpdateSysMetrics+0x62 (FPO: [Non-Fpo]) (CONV: thiscall) [f:/vs70builds/3077
/vc/mfcatl/ship/atlmfc/src/mfc/auxdata.cpp @ 95]
??????? 0350f840 0368cd5d MFC71UD!AUX_DATA::AUX_DATA+0x2e (FPO: [Non-Fpo]) (CONV: thiscall) [f:/vs70builds/3077/vc/mfcatl/ship/atlmfc/src/mfc/auxdata.cpp @
35]
??????? 0350f848 10201d48 MFC71UD!$E5+0xd (FPO: [Non-Fpo]) (CONV: cdecl) [f:/vs70builds/3077/vc/mfcatl/ship/atlmfc/src/mfc/auxdata.cpp @ 22]
??????? 0350f850 035da943 MSVCR71D!_initterm+0x18 (FPO: [Non-Fpo]) (CONV: cdecl) [f:/vs70builds/3077/vc/crtbld/crt/src/crt0dat.c @ 600]
??????? 0350f860 035daa5a MFC71UD!_CRT_INIT+0xa3 (FPO: [Non-Fpo]) (CONV: stdcall) [f:/vs70builds/3077/vc/crtbld/crt/src/crtdll.c @ 184]
??????? 0350f8ac 7c9211a7 MFC71UD!_DllMainCRTStartup+0x9a (FPO: [Non-Fpo]) (CONV: stdcall) [f:/vs70builds/3077/vc/crtbld/crt/src/crtdll.c @ 266]
??????? 0350f8cc 7c93cbab ntdll!LdrpCallInitRoutine+0x14
??????? 0350f9d4 7c936178 ntdll!LdrpRunInitializeRoutines+0x344 (FPO: [Non-Fpo])
??????? 0350fc80 7c9362da ntdll!LdrpLoadDll+0x3e5 (FPO: [Non-Fpo])
??????? 0350ff28 7c801bb9 ntdll!LdrLoadDll+0x230 (FPO: [Non-Fpo])
??????? 0350ff90 7c80ace4 KERNEL32!LoadLibraryExW+0x18e (FPO: [Non-Fpo])
??????? 0350ffa4 7ff90010 KERNEL32!LoadLibraryW+0x11 (FPO: [Non-Fpo])
WARNING: Frame IP not in any known module. Following frames may be wrong.
??????? 0350ffb4 7c80b50b 0x7ff90010
??????? 0350ffec 00000000 KERNEL32!BaseThreadStart+0x37 (FPO: [Non-Fpo])
看到這一個線程的信息之后,原因終于找到了,是在對session 1的csrss進行注入之后,加載dll,初始化mfc動態鏈接庫的時候導致斷言失敗,對話框通過LPC的方式重定向到session 0的csrss進程去顯示了。到這里還是有很多疑問,主要是兩個問題:
1.為什么auxdata.cpp第94行HDC hDCScreen = GetDC(NULL);獲取屏幕DC的時候會得到NULL句柄。
2.為什么在對session 0的csrss進程注入的時候沒有出現這個問題。
寫了如下的測試dll:
#include "stdafx.h"
#include <crtdbg.h>
#define ASSERT(expr, msg) /
?do { if (!(expr) && /
?(1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, msg))) /
?_CrtDbgBreak(); } while (0)
BOOL APIENTRY DllMain( HANDLE hModule,
?????????????????????? DWORD? ul_reason_for_call,
?????????????????????? LPVOID lpReserved
????? )
{
?if (DLL_PROCESS_ATTACH == ul_reason_for_call){
??_asm int 3????;這里的斷點,是為了跟蹤調試GetDC
??ASSERT(NULL != GetDC(0), NULL);
?}
??? return TRUE;
}
同時寫一個簡單的注入程序將上面的dll注入到csrss進程中。內核調試在int 3斷點中斷,nop掉int 3指令。單步跟蹤GetDC(注意跟蹤的時候對)同時結合windows nt的源代碼,發現之所以返回NULL,是因為csrss進程沒有關聯桌面,獲取不到屏幕DC(具體參考nt源代碼)。
同時發現session 0確實也拿不到屏幕DC,繼續跟蹤斷言消息框顯示流程。發現__crtMessageBoxA函數(VC有源代碼)在uType參數加上了MB_SERVICE_NOTIFICATION標志,導致MessageBoxWorker函數(win2k源代碼)最終調用ServiceMessageBox,而不是SoftModalMessageBox。
kd> !process 8150b5c0?
PROCESS 8150b5c0? SessionId: 1? Cid: 0dc0??? Peb: 7ffdd000? ParentCid: 023c
??? DirBase: 02b403e0? ObjectTable: e11a0e48? HandleCount: 136.
??? Image: csrss.exe
??? VadRoot 816ca8d0 Vads 86 Clone 0 Private 199. Modified 2530. Locked 0.
??? DeviceMap e1000110
??? Token???????????????????????????? e1157930
??? ElapsedTime?????????????????????? 01:41:39.406
??? UserTime????????????????????????? 00:00:02.906
??? KernelTime??????????????????????? 00:00:04.250
??? QuotaPoolUsage[PagedPool]???????? 127108
??? QuotaPoolUsage[NonPagedPool]????? 3600
??? Working Set Sizes (now,min,max)? (96, 50, 345) (384KB, 200KB, 1380KB)
??? PeakWorkingSetSize??????????????? 2097
??? VirtualSize?????????????????????? 59 Mb
??? PeakVirtualSize?????????????????? 64 Mb
??? PageFaultCount??????????????????? 4342
??? MemoryPriority??????????????????? BACKGROUND
??? BasePriority????????????????????? 13
??? CommitCharge????????????????????? 304
??????? //略去無關線程
??????? THREAD 8141c278? Cid 0dc0.01b0? Teb: 7ffd3000 Win32Thread: e1dd6938 WAIT: (WrLpcReply) UserMode Non-Alertable
??????????? 8141c46c? Semaphore Limit 0x1
??????? Waiting for reply to LPC MessageId 00003e93:
??????? Current LPC port e13cb988
??????? Not impersonating
??????? DeviceMap???????????????? e1000110
??????? Owning Process??????????? 0?????? Image:???????? <Unknown>
??????? Attached Process????????? 8150b5c0?????? Image:???????? csrss.exe
??????? Wait Start TickCount????? 23986????????? Ticks: 4438 (0:00:01:09.343)
??????? Context Switch Count????? 17???????????????? LargeStack
??????? UserTime????????????????? 00:00:00.093
??????? KernelTime??????????????? 00:00:00.031
??????? Win32 Start Address 0x02b60000
??????? Start Address KERNEL32!BaseThreadStartThunk (0x7c810669)
??????? Stack Init f72f6000 Current f72f5a94 Base f72f6000 Limit f72f3000 Call 0
??????? Priority 13 BasePriority 13 PriorityDecrement 0 DecrementCount 0
??????? Kernel stack not resident.
??????? ChildEBP RetAddr?
??????? f72f5aac 80501366 nt!KiSwapContext+0x2e (FPO: [Uses EBP] [0,0,4])
??????? f72f5ab8 804fabd0 nt!KiSwapThread+0x46 (FPO: [0,0,0])
??????? f72f5ae0 80598d01 nt!KeWaitForSingleObject+0x1c2 (FPO: [5,5,4])
??????? f72f5b18 80598e4d nt!LpcpRequestWaitReplyPort+0x43d (FPO: [4,4,0])
??????? f72f5b30 8060a799 nt!LpcRequestWaitReplyPortEx+0x21 (FPO: [3,0,0])
??????? f72f5cd4 8060abf7 nt!ExpRaiseHardError+0x1bd (FPO: [Non-Fpo])
??????? f72f5d44 8053da48 nt!NtRaiseHardError+0x16b (FPO: [Non-Fpo])
??????? f72f5d44 7c92eb94 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f72f5d64)
??????? 02c6b2d8 7c92e273 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
??????? 02c6b2dc 77d65d43 ntdll!NtRaiseHardError+0xc (FPO: [6,0,0])
??????? 02c6b338 77d48ffe USER32!ServiceMessageBox+0x145 (FPO: [4,13,0])
??????? 02c6b494 77d65fdf USER32!MessageBoxWorker+0x13e (FPO: [1,78,4])
??????? 02c6b4ec 77d66084 USER32!MessageBoxTimeoutW+0x7a (FPO: [6,19,0])
??????? 02c6b520 77d50598 USER32!MessageBoxTimeoutA+0x9c (FPO: [6,2,4])
??????? 02c6b540 77d50550 USER32!MessageBoxExA+0x1b (FPO: [5,0,0])
??????? 02c6b55c 1001811a USER32!MessageBoxA+0x45 (FPO: [4,0,0])
??????? 02c6b594 10012c5e ApiHook!__crtMessageBoxA+0x16a (FPO: [Non-Fpo]) (CONV: cdecl) [f:/vs70builds/3077/vc/crtbld/crt/src/crtmbox.c @ 119]
??????? 02c6c6ec 1001283a ApiHook!CrtMessageWindow+0x2be (FPO: [Non-Fpo]) (CONV: cdecl) [f:/vs70builds/3077/vc/crtbld/crt/src/dbgrpt.c @ 617]
??????? 02c6f768 10011fa3 ApiHook!_CrtDbgReport+0x41a (FPO: [Non-Fpo]) (CONV: cdecl) [f:/vs70builds/3077/vc/crtbld/crt/src/dbgrpt.c @ 516]
??????? 02c6f850 1001320b ApiHook!DllMain+0x53 (FPO: [Non-Fpo]) (CONV: stdcall) [e:/lzz/vc proj/apihook/apihook.cpp @ 20]
??????? 02c6f898 7c9211a7 ApiHook!_DllMainCRTStartup+0xbb (FPO: [Non-Fpo]) (CONV: stdcall) [f:/vs70builds/3077/vc/crtbld/crt/src/dllcrt0.c @ 297]
??????? 02c6f8b8 7c93cbab ntdll!LdrpCallInitRoutine+0x14
??????? 02c6f9c0 7c936178 ntdll!LdrpRunInitializeRoutines+0x344 (FPO: [Non-Fpo])
??????? 02c6fc6c 7c9362da ntdll!LdrpLoadDll+0x3e5 (FPO: [Non-Fpo])
??????? 02c6ff14 7c801bb9 ntdll!LdrLoadDll+0x230 (FPO: [Non-Fpo])
??????? 02c6ff7c 7c801d6e KERNEL32!LoadLibraryExW+0x18e (FPO: [Non-Fpo])
??????? 02c6ff90 7c801da4 KERNEL32!LoadLibraryExA+0x1f (FPO: [3,0,0])
??????? 02c6ffac 02b6000a KERNEL32!LoadLibraryA+0x94 (FPO: [1,0,0])
WARNING: Frame IP not in any known module. Following frames may be wrong.
??????? 02c6ffec 00000000 0x2b6000a
內核函數ExpRaiseHardError根據當前進程的ExceptionPort發送這個消息框調用。這時候剛好csrss的ExceptionPort為NULL,系統使用默認的ExpDefaultErrorPort,但csrss(session 0)是默認的ExpDefaultErrorPortProcess, 操作系統對這個進程的消息不進行LPC投遞,直接返回. 這就是為什么第一個csrss被注入沒有彈出斷言消息框的原因。這之后的第二個csrss進程的ExceptionPort也是NULL,LPC被發送到了ExpDefaultErrorPort,第一個csrss對該消息進行了處理顯示了斷言消息框。
進一步發現系統中只有system,smss,csrss進程沒有ExceptionPort,其它的進程都有ExceptionPort。這個Port的名字就是"ApiPort",每一個session都有一個這樣的Port,csrss進程負責監聽,而沒有ExceptionPort的進程則通過ExpDefaultErrorPort發送,默認由session 0的csrss進程處理。
總結
以上是生活随笔為你收集整理的从csrss弹出的ASSERT对话框谈起的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Excel快速删除一列中的空行
- 下一篇: 宝塔Linux面板使用