从csrss弹出的ASSERT对话框谈起
?
昨天遇到一件怪事,在進(jìn)行遠(yuǎn)程線程注入的時候從csrss進(jìn)程中竟然彈出了vc的ASSERT對話框。根據(jù)對話框提示信息找到了斷言的位置在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);
}
具體的環(huán)境就是win xp進(jìn)行多用戶登陸:首先登陸一個windows帳號user1, session id = 0, 對csrss進(jìn)程成功進(jìn)行了遠(yuǎn)程線程注入。接著在保持user1登陸的情況下切換用戶登陸到user2,進(jìn)去之后同樣的對新的session(session id = 1)的csrss進(jìn)程進(jìn)行遠(yuǎn)程線程注入,沒什么問題。但是切回到user1后發(fā)現(xiàn)界面上有一個斷言對話框,顯示了上面代碼位置的斷言失敗。查看這個對話框所在的進(jìn)程確實(shí)是session 0的csrss進(jìn)程。因?yàn)槭且粋€穩(wěn)定的重現(xiàn)的問題,使用windbg遠(yuǎn)程附加到session 0的csrss進(jìn)程,查看彈出對話框的線程調(diào)用棧如下:
?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])
這里很奇怪,斷言的調(diào)用鏈里面應(yīng)該會出現(xiàn)__crtMessageBoxA,除非是符號不對,但是調(diào)用棧里面所有的返回地址都有符號。
難道是調(diào)用棧不完整,于是結(jié)合匯編代碼對調(diào)用棧進(jìn)行核實(shí)---沒問題。一個偶然的原因在ReactOS上面看了一下CsrApiRequestThread函數(shù)的源代碼才意識到這個對話框是通過LPC端口投遞過來的消息顯示。winsrv!UserHardError是最后一個出錯處理回調(diào)例程。
用戶態(tài)調(diào)試查不出這個LPC是哪里投遞過來的,轉(zhuǎn)而使用內(nèi)核態(tài)調(diào)試。
根據(jù)從運(yùn)程線程注入的結(jié)果,對session 1的csrss進(jìn)程進(jìn)行的遠(yuǎn)程線程一直沒有收到注入成功的回復(fù),很自然想到看一下session 1的csrss進(jìn)程的情況。
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
??????? /略去一些無關(guān)線程信息
??????? 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進(jìn)行注入之后,加載dll,初始化mfc動態(tài)鏈接庫的時候?qū)е聰嘌允?#xff0c;對話框通過LPC的方式重定向到session 0的csrss進(jìn)程去顯示了。到這里還是有很多疑問,主要是兩個問題:
1.為什么auxdata.cpp第94行HDC hDCScreen = GetDC(NULL);獲取屏幕DC的時候會得到NULL句柄。
2.為什么在對session 0的csrss進(jìn)程注入的時候沒有出現(xiàn)這個問題。
寫了如下的測試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????;這里的斷點(diǎn),是為了跟蹤調(diào)試GetDC
??ASSERT(NULL != GetDC(0), NULL);
?}
??? return TRUE;
}
同時寫一個簡單的注入程序?qū)⑸厦娴膁ll注入到csrss進(jìn)程中。內(nèi)核調(diào)試在int 3斷點(diǎn)中斷,nop掉int 3指令。單步跟蹤GetDC(注意跟蹤的時候?qū)?同時結(jié)合windows nt的源代碼,發(fā)現(xiàn)之所以返回NULL,是因?yàn)閏srss進(jìn)程沒有關(guān)聯(lián)桌面,獲取不到屏幕DC(具體參考nt源代碼)。
同時發(fā)現(xiàn)session 0確實(shí)也拿不到屏幕DC,繼續(xù)跟蹤斷言消息框顯示流程。發(fā)現(xiàn)__crtMessageBoxA函數(shù)(VC有源代碼)在uType參數(shù)加上了MB_SERVICE_NOTIFICATION標(biāo)志,導(dǎo)致MessageBoxWorker函數(shù)(win2k源代碼)最終調(diào)用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
??????? //略去無關(guān)線程
??????? 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
內(nèi)核函數(shù)ExpRaiseHardError根據(jù)當(dāng)前進(jìn)程的ExceptionPort發(fā)送這個消息框調(diào)用。這時候剛好csrss的ExceptionPort為NULL,系統(tǒng)使用默認(rèn)的ExpDefaultErrorPort,但csrss(session 0)是默認(rèn)的ExpDefaultErrorPortProcess, 操作系統(tǒng)對這個進(jìn)程的消息不進(jìn)行LPC投遞,直接返回. 這就是為什么第一個csrss被注入沒有彈出斷言消息框的原因。這之后的第二個csrss進(jìn)程的ExceptionPort也是NULL,LPC被發(fā)送到了ExpDefaultErrorPort,第一個csrss對該消息進(jìn)行了處理顯示了斷言消息框。
進(jìn)一步發(fā)現(xiàn)系統(tǒng)中只有system,smss,csrss進(jìn)程沒有ExceptionPort,其它的進(jìn)程都有ExceptionPort。這個Port的名字就是"ApiPort",每一個session都有一個這樣的Port,csrss進(jìn)程負(fù)責(zé)監(jiān)聽,而沒有ExceptionPort的進(jìn)程則通過ExpDefaultErrorPort發(fā)送,默認(rèn)由session 0的csrss進(jìn)程處理。
總結(jié)
以上是生活随笔為你收集整理的从csrss弹出的ASSERT对话框谈起的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Excel快速删除一列中的空行
- 下一篇: 宝塔Linux面板使用