《软件调试》读书笔记:第13章 硬错误和蓝屏
會話管理器進程SMSS.exe是系統啟動后的第一個用戶態進程,負責啟動和監護windows子系統進程:CSRSS.exe和登陸管理進程:WinLogon
SMSS.exe從注冊表中查詢子系統exe文件的位置,并且啟動它
CSRSS是windows子系統進程,自NT4以后窗口管理和GDI的主體實現被移出了CSRSS放到了win32k.sys中。
CSRSS監管著所有windows線程和進程,每個進程在創建后都要到這里登記才能運行,退出時也要報告注銷。(維護了Windows子系統層面上的記錄結構)
CSRSS具有桌面管理、終端登錄、控制臺管理、HardError報告等方面的重要作用。
為了適應惡劣環境下的錯誤提示的需要,Windows定義了硬錯誤提示機制。
硬錯誤本意是硬件有關錯誤,后來泛指嚴重的錯誤。
硬錯誤可以在用戶態使用也可以在內核態使用。
硬錯誤的核心處理函數是內核中的ExpRaiseHardError函數。
在我們看這個函數的源碼前,先想一想,發送硬錯誤消息,首先要的是找到發送硬錯誤的端口。
這個端口怎么找?是通過一系列的設置和標志位來判斷的。
如下是具體的程序內容
1 NTSTATUS 2 ExpRaiseHardError ( 3 IN NTSTATUS ErrorStatus, 4 IN ULONG NumberOfParameters, 5 IN ULONG UnicodeStringParameterMask, 6 IN PULONG_PTR Parameters, 7 IN ULONG ValidResponseOptions, 8 OUT PULONG Response 9 ) 10 { 11 PTEB Teb; 12 PETHREAD Thread; 13 PEPROCESS Process; 14 ULONG_PTR MessageBuffer[PORT_TOTAL_MAXIMUM_MESSAGE_LENGTH/sizeof(ULONG_PTR)]; 15 PHARDERROR_MSG m; 16 NTSTATUS Status; 17 HANDLE ErrorPort; 18 KPROCESSOR_MODE PreviousMode; 19 BOOLEAN DoingShutdown; 20 21 PAGED_CODE(); 22 //要發送的消息結構 23 m = (PHARDERROR_MSG)&MessageBuffer[0]; 24 PreviousMode = KeGetPreviousMode(); 25 26 DoingShutdown = FALSE; 27 //如果參數要求關機,就檢查是否有關機權限 28 if (ValidResponseOptions == OptionShutdownSystem) { 29 30 // 31 // Check to see if the caller has the privilege to make this call. 32 // 33 34 if (!SeSinglePrivilegeCheck (SeShutdownPrivilege, PreviousMode)) { 35 return STATUS_PRIVILEGE_NOT_HELD; 36 } 37 38 ExReadyForErrors = FALSE; 39 HardErrorState = SHUTDOWN; 40 DoingShutdown = TRUE; 41 } 42 43 Thread = PsGetCurrentThread(); 44 Process = PsGetCurrentProcess(); 45 46 // 47 // If the default handler is not installed, then 48 // call the fatal hard error handler if the error 49 // status is error 50 // 51 // Let GDI override this since it does not want to crash the machine 52 // when a bad driver was loaded via MmLoadSystemImage. 53 // 54 55 if ((Thread->CrossThreadFlags & PS_CROSS_THREAD_FLAGS_HARD_ERRORS_DISABLED) == 0) { 56 //如果滿足這個標志位說明用戶態HardError系統還沒有準備好,只能在內核態去提示這個HardError了 57 if (NT_ERROR(ErrorStatus) && (HardErrorState == STARTING || DoingShutdown)) { 58 //而所謂的在內核態提示HardError就是執行這個函數了,實質上就是一個KeBugCheckEx,也就是說想著內核態提示HardError只能是通過拋出藍屏 59 ExpSystemErrorHandler ( 60 ErrorStatus, 61 NumberOfParameters, 62 UnicodeStringParameterMask, 63 Parameters, 64 (BOOLEAN)((PreviousMode != KernelMode) ? TRUE : FALSE)); 65 } 66 } 67 68 // 69 // If the process has an error port, then if it wants default 70 // handling, use its port. If it disabled default handling, then 71 // return the error to the caller. If the process does not 72 // have a port, then use the registered default handler. 73 // 74 75 ErrorPort = NULL; 76 //這個就是通過各種標志位來判斷硬錯誤端口是什么了。對于一個進程來說只有異常端口和調試端口兩個東西,并沒有單獨指定硬錯誤端口的結構。 77 if (Process->ExceptionPort) { 78 //異常端口存在時 79 if (Process->DefaultHardErrorProcessing & 1) { 80 //這個標志位存在時,異常端口就是硬錯誤端口 81 ErrorPort = Process->ExceptionPort; 82 } else { 83 84 // 85 // If error processing is disabled, check the error override 86 // status. 87 // 88 89 if (ErrorStatus & HARDERROR_OVERRIDE_ERRORMODE) { 90 //滿足這個條件的話,也是異常端口 91 ErrorPort = Process->ExceptionPort; 92 } 93 } 94 } else { 95 if (Process->DefaultHardErrorProcessing & 1) { 96 ErrorPort = ExpDefaultErrorPort; 97 } else { 98 99 // 100 // If error processing is disabled, check the error override 101 // status. 102 // 103 104 if (ErrorStatus & HARDERROR_OVERRIDE_ERRORMODE) { 105 ErrorPort = ExpDefaultErrorPort; 106 } 107 } 108 } 109 //雖然上面比較的那么熱鬧。。但是ExpDefaultErrorPort和ExeceptionPort的值其實是一樣的 110 //都是CSRSS進程的\Windows\ApiPort端口。這是一個LPC端口對象 111 112 if ((Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HARD_ERRORS_DISABLED) != 0) { 113 ErrorPort = NULL; 114 } 115 //設置了禁止硬錯誤就把ErrorPort清零 116 if ((ErrorPort != NULL) && (!IS_SYSTEM_THREAD(Thread))) { 117 Teb = (PTEB)PsGetCurrentThread()->Tcb.Teb; 118 try { 119 if (Teb->HardErrorMode & RTL_ERRORMODE_FAILCRITICALERRORS) { 120 ErrorPort = NULL; 121 } 122 } except (EXCEPTION_EXECUTE_HANDLER) { 123 ; 124 } 125 } 126 127 if (ErrorPort == NULL) { 128 *Response = (ULONG)ResponseReturnToCaller; 129 return STATUS_SUCCESS; 130 } 131 //自己給自己發異常?出現問題了 132 if (Process == ExpDefaultErrorPortProcess) { 133 if (NT_ERROR(ErrorStatus)) { 134 ExpSystemErrorHandler (ErrorStatus, 135 NumberOfParameters, 136 UnicodeStringParameterMask, 137 Parameters, 138 (BOOLEAN)((PreviousMode != KernelMode) ? TRUE : FALSE)); 139 } 140 *Response = (ULONG)ResponseReturnToCaller; 141 Status = STATUS_SUCCESS; 142 return Status; 143 } 144 145 m->h.u1.Length = HARDERROR_API_MSG_LENGTH; 146 m->h.u2.ZeroInit = LPC_ERROR_EVENT; 147 m->Status = ErrorStatus & ~HARDERROR_OVERRIDE_ERRORMODE; 148 m->ValidResponseOptions = ValidResponseOptions; 149 m->UnicodeStringParameterMask = UnicodeStringParameterMask; 150 m->NumberOfParameters = NumberOfParameters; 151 152 if (Parameters != NULL) { 153 try { 154 RtlCopyMemory (&m->Parameters, 155 Parameters, 156 sizeof(ULONG_PTR)*NumberOfParameters); 157 } except (EXCEPTION_EXECUTE_HANDLER) { 158 } 159 } 160 161 KeQuerySystemTime(&m->ErrorTime); 162 //執行發送函數 163 Status = LpcRequestWaitReplyPortEx (ErrorPort, 164 (PPORT_MESSAGE) m, 165 (PPORT_MESSAGE) m); 166 167 if (NT_SUCCESS(Status)) { 168 switch (m->Response) { 169 //作為一個返回值 170 case ResponseReturnToCaller : 171 case ResponseNotHandled : 172 case ResponseAbort : 173 case ResponseCancel : 174 case ResponseIgnore : 175 case ResponseNo : 176 case ResponseOk : 177 case ResponseRetry : 178 case ResponseYes : 179 case ResponseTryAgain : 180 case ResponseContinue : 181 break; 182 default: 183 m->Response = (ULONG)ResponseReturnToCaller; 184 break; 185 } 186 *Response = m->Response; 187 } 188 189 return Status; 190 }這個函數把硬錯誤信息發送到了CSRSS進程的\Windows\ApiPort端口上去。
接下來就是看CSRSS進程是怎么接受并處理這個硬錯誤消息的。
CSRSS進程中專門啟用了一個線程來監聽并處理\Windows\ApiPort端口的內容
CsrApiRequestThread就是這個專門用來監聽的工作線程
PORT_MESSAGE是發送的LPC端口的數據結構。
CSRSS負責后續的處理工作,并進行用戶層面的彈出提示。
轉載于:https://www.cnblogs.com/Ox9A82/p/5383818.html
總結
以上是生活随笔為你收集整理的《软件调试》读书笔记:第13章 硬错误和蓝屏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hbase本地调试环境搭建
- 下一篇: 两圆相交面积