《软件调试》读书笔记:第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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/573726.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java selenium教程_Selenium3 Java自动化测试完整教程

本课程为一个完整的selenium自动化测试实战课程,采用当前**的版本3。学完后可以独立构建起企业级/项目级的自动化测试,从搭建环境、编写脚本、使用框架组织运行脚本与输出报告、及与持续集成工具Jenkins结合达到构建后即测试或指定晚上运行等方式&#x…

信息安全技术网络安全等级保护定级指南_行业标准 |报业网络安全等级保护定级参考指南V2.0发布,明确保护对象、定级要求...

近期,中国新闻技术工作者联合会正式发布《报业网络安全等级保护定级参考指南V2.0》。该指南由中国新闻技术工作者联合会组织网络安全领域的专家、报业技术专家以及业务专家经过多次调研、学习、探讨后,在原《报业网络安全等级保护定级参考指南V1.0》的基…

nRF51822 硬件复位引脚

nRF51822 有一个硬件复位引脚和Debug 口SWDIO是共用的,名字叫做nReset. 实现硬件复位是怎样子的: 1、这个引脚引出来, 2、给这个引脚低电平, 3、从低电平拉到高电平,即复位。 其实就是给这个引脚一个低电平脉冲。 转载…

java点赞功能实现_JavaWeb中点赞功能的实现及完整实例

实现原理1、功能描述:一个用户对同一文章只能点赞一次,第二次就是取消赞2、建立一个点赞表great,字段有文章ID(aid),点赞用户ID(uid)3、当有用户进行点赞行为时,使用aid和uid搜索点赞表。若有该记录,则表示…

数学作图工具_科研论文作图系列-从PPT到AI (一)

导语:之前的推送中,小编给大家介绍过几款科研作图软件,包括统计分析软件Origin和Prism,图像处理软件ImageJ等等。从本期开始,小编将和大家一起继续学习科研论文作图。重点介绍图像的处理和排版,用到的工具主…

传送图片程序

前言:以C#为程序设计基础,传输大图片,并现实。在过程中,采用套接字,单线程同步机制为例子。需要深化,可以采用异步或者多线程的机制,保障能够顺利执行。具体代码可以到微云下载【链接&#xff1…

java中no1_【Java】-- 网络编程のNo.1

在现有的网络中,网络通讯的方式主要有两种:TCP(传输控制协议)方式UDP(用户数据报协议)方式在网络通讯中,TCP方式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传…

优启通怎么重装系统win10_重装系统失败?小编教你安全给神舟战神GX9 Pro重装win10系统方法...

神舟战神GX9 Pro 上市于2016年1月,虽然现在已经停产,但是还是有不少用户依旧十分喜爱这款笔记本。这款笔记本的性能完全对得起它的售价,很多用户都反馈其比外星人电脑要好。对于爱玩游戏的用户而言,对它17.3英寸的显示屏简直欲罢不…

.NET小细节

1、equals()和运算符的区别 C#中有两种不同的相等:引用相等和值相等。值相等是两个对象包含相同的值;引用相等是两个对象引用的是同一个对象。 “”操作符比较的是两个变量的值是否相等,或两个引用是不是指向同一个内存地址(类似比…

java exception用法_Java基础回顾_Exception异常使用详解

package 内部类异常包装器;public class 异常 {/*** 1.异常:* 有Error和Exception两个基本子类* 2.Error:* Error表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。* 3.Exception:* 表示一种设计或实现问题。也就是说&…

获得代理ippython_Python搭建代理IP池实现获取IP的方法

使用爬虫时,大部分网站都有一定的反爬措施,有些网站会限制每个 IP 的访问速度或访问次数,超出了它的限制你的 IP 就会被封掉。对于访问速度的处理比较简单,只要间隔一段时间爬取一次就行了,避免频繁访问;而…

20135202闫佳歆--week 8 实验:理解进程调度时机跟踪分析进程调度与进程切换的过程--实验及总结...

week 8 实验:理解进程调度时机跟踪分析进程调度与进程切换的过程 1.环境搭建: rm menu -rf git clone https://github.com/megnning/menu.git cd menu ls make rootfs qemu -kernel ../linux-3.18.6/arch/x86/boot/bzImage -initrd ../rootfs.img -s -S …

java jni技术_JNI技术简介

JNI(Java Native Interface)提供一种Java字节码调用C/C的解决方案,JNI描述的是一种技术。NDK(Native Development Kit)Android NDK 是一组允许您将 C 或 C(“原生代码”)嵌入到 Android 应用中的工具,NDK描述的是工具集。 能够在 Android 应用中使用原生…

python 读取mysql大量数据处理_python使用多线程快速把大量mysql数据导入elasticsearch...

使用python多线程,运行时自定义线程数,自动计算每个线程处理的数据量,连接mysql读取数据,处理成需要的字段入到elasticsearch。运行效果图:10个线程 运行会在这里实时刷新,方便查看每个线程处理到的id数&am…

java web redis_java web redis使用(二)

上篇中已经安装好redis,然后下面就说怎么在java web中用客户端来使用regis使用jedis java客户端一:一个简单的示例代码:public static void main(String[] args) {Jedis jedis new Jedis( "147.151.240.234" , 6379 );jedis.set("foo&…

mysql 主从_搭建mysql主从并编写监控主从状态脚本

要求:两台centos7虚拟机分为主和从安装mysqlyum -y install mysql mysql-server关闭防火墙service iptables stopsetenforce 0上面的主从都做。修改主的配置文件vi /etc/my.cnf#添加server-id1log-binmysqlbinrelay-logrelays之后保存退出重启mysql服务service …

Ubuntu Sublime Text 3 搜狗拼音

已知前置条件 本经验目前在Ubuntu14.04环境下&#xff0c;已有搜狗输入法 for Linux和Sublime Text 3的情况下安装成功。 解决方法步骤 保存下面的代码到文件sublime_imfix.c(位于~目录) #include <gtk/gtkimcontext.h> void gtk_im_context_set_client_window (GtkIMCon…

Java核心技术点之动态代理

本篇博文会从代理的概念出发&#xff0c;介绍Java中动态代理技术的使用&#xff0c;并进一步探索它的实现原理。由于个人水平有限&#xff0c;叙述中难免出现不清晰或是不准确的地方&#xff0c;希望大家可以指正&#xff0c;谢谢大家&#xff1a;&#xff09; 一、概述 1. 什么…

pythonwebview自动化测试_GitHub - githubwzg/python-appium: 基于PageObject UI自动化测试框架,支持Android/iOS...

0910 UPDATE新增控件集参数化&#xff0c;相同测试步骤的Android/iOS可共用一份测试用例不同测试步骤的用例还需要单独写0904 UPDATE优化Android log及crsahinfo相关输出路径新增iOS crashreport解析新增内容&#xff1a;适配iOS提取android crash信息优化report(增加自动填充包…

linux中使用lftp上传下载文件

lftp是linux中一款ftp服务器相比windows中的ftp显得要复杂不少了&#xff0c;下面我来总结一下lftp文件上传&#xff0c;文件下载&#xff0c;及文件查找等等相关命令吧。 lftp连接的几种方法&#xff0c;最常用的是lftp namesite&#xff0c;这样可以不用明文输入密码。 1、lf…