博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《软件调试》读书笔记:第13章 硬错误和蓝屏
阅读量:5082 次
发布时间:2019-06-13

本文共 7292 字,大约阅读时间需要 24 分钟。

会话管理器进程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 override101             // 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

你可能感兴趣的文章
【传道】中国首部淘宝卖家演讲公开课:农业本该如此
查看>>
jQuery应用 代码片段
查看>>
MVC+Servlet+mysql+jsp读取数据库信息
查看>>
黑马程序员——2 注释
查看>>
用OGRE1.74搭建游戏框架(三)--加入人物控制和场景
查看>>
转化课-计算机基础及上网过程
查看>>
android dialog使用自定义布局 设置窗体大小位置
查看>>
ionic2+ 基础
查看>>
互联网模式下我们更加应该“专注”
查看>>
myeclipse集成jdk、tomcat8、maven、svn
查看>>
查询消除重复行
查看>>
Win 10 文件浏览器无法打开
查看>>
HDU 1212 Big Number(C++ 大数取模)(java 大数类运用)
查看>>
-bash: xx: command not found 在有yum源情况下处理
查看>>
[leetcode]Minimum Path Sum
查看>>
内存管理 浅析 内存管理/内存优化技巧
查看>>
hiho1079 线段树区间改动离散化
查看>>
【BZOJ 5222】[Lydsy2017省队十连测]怪题
查看>>
第二次作业
查看>>
【input】 失去焦点时 显示默认值 focus blur ★★★★★
查看>>