首页 深入解析windows操作系统之崩溃转储分析

深入解析windows操作系统之崩溃转储分析

举报
开通vip

深入解析windows操作系统之崩溃转储分析深入解析windows操作系统 深入解析windows操作系统 第14章 崩溃转储分析 几乎每一位Windows用户都听说过臭名昭著的“蓝屏死机(blue screen of death)”,有的甚至还亲身经历过。这一不祥的术语是指当Microsoft Windows崩溃或停止执行(由于灾难性的错误或者内部条件阻止系统继续运行下去)时所显示的蓝色屏幕。 在本章中,我们将讨论那些引起Windows崩溃的基本问题,讲述一下在蓝屏上显示的信息,同时还将解释各种用于创建崩溃转储(crash dump)的配置选项。这里的崩溃...

深入解析windows操作系统之崩溃转储分析
深入解析windows操作系统 深入解析windows操作系统 第14章 崩溃转储分析 几乎每一位Windows用户都听说过臭名昭著的“蓝屏死机(blue screen of death)”,有的甚至还亲身经历过。这一不祥的术语是指当Microsoft Windows崩溃或停止执行(由于灾难性的错误或者内部条件阻止系统继续运行下去)时所显示的蓝色屏幕。 在本章中,我们将讨论那些引起Windows崩溃的基本问题,讲述一下在蓝屏上显示的信息,同时还将解释各种用于创建崩溃转储(crash dump)的配置选项。这里的崩溃转储是指在系统崩溃时刻的系统内存的纪录,它可以帮助你找出是哪个组件导致了这次系统崩溃。安排这一部分 内容 财务内部控制制度的内容财务内部控制制度的内容人员招聘与配置的内容项目成本控制的内容消防安全演练内容 的意图并不是提供有关如何分析一次Windows系统崩溃的详细诊断信息。本章还将向你展示如何分析一个崩溃转储来识别出一个错误的驱动程序或者组件。为执行基本的崩溃转储分析而需要做的工作是非常少的,只需要几分钟就够了。即使每5个或10个崩溃转储中只有一个通过崩溃转储分析能探查到有问题的驱动程序,这种分析仍然是值得去做的:一次成功的分析可以避免将来的数据丢失、系统宕机和应用失败。 14.1  Windows为什么会崩溃 Windows崩溃(停止执行并显示蓝屏)有以下一些原因。 n  运行在内核模式下的设备驱动程序或者操作系统函数引发了一个未被处理的异常,比如内存访问违例(由于企图写一个只读页面或者企图读一个当前未被映射[因而不是一个有效内存位置]的地址而引起)。 n  调用一个内核支持例程,导致一次重新调度,比如当中断请求级别(IRQL)为DPC/Dispatch级别或更高级别时等待一个处于无信号状态的分发器对象(关于IRQL的细节,请参见第3章)。 n  在DPC/Dispatch级别或更高的IRQL级别时,在“由页面文件或内存映射文件中的数据来支撑的内存”上发生了一个页面错误(这将要求内存管理器必须等待一个I/O操作发生,但正如上面刚刚所说的,在DPC/Dispatch级别或更高级别上不能够进行等待,因为那将要求一次重新调度)。 n  一个设备驱动程序或操作系统函数显式地使系统崩溃(通过调用系统函数KeBugCheckEx)。因为它检测到一个内部条件表明了数据遭受破坏,或者表明了其他的情形:在不冒险破坏数据的情况下系统无法继续执行。 n  发生硬件错误,比如机器检查(machine check)或者不可屏蔽中断(NMI)。 对于Windows XP用户提交给Microsoft OCA(Microsoft Online Crash Analysis,在线崩溃分析,本章后面将会介绍)Web站点的崩溃转储,Microsoft的分析表明了崩溃原因的分类如图14.1所示(这里显示的数据是2004年4月份生成的)。 图14.1  提交给OCA的崩溃的原因分类 当一个内核模式设备驱动程序或者子系统引发一个非法的异常时,Windows面临着困难的抉择。此时,它检测到了在操作系统中,有能力访问任何硬件设备和任何有效内存的系统代码部分做了一些不应该做的事情。 但是,为什么这意味着Windows必须崩溃呢?难道它就不能够忽略该异常,让设备驱动程序或者子系统继续往下执行,就好像什么也没有发生过吗?该错误能被隔离出来的可能性是存在的,并且该组件将来能够通过某种方式被恢复过来的可能性也是存在的。但是,更有可能的是,被检测到的异常来源于更深层的问题——比如,由于内存的常规破坏(general corruption),或者由于硬件设备不能正常工作。允许系统继续运行下去将可能导致更多的异常,而且,存储在磁盘或其他外设中的数据可能也会遭受破坏,这样招致的风险太高了。 14.2  蓝屏 不管系统崩溃的原因是什么,真正执行崩溃的函数是KeBugCheckEx(Windows DDK中有文档)。该函数接受一个停止代码(stop code,有时候也称为错误检查码[bug check code]),以及四个根据停止代码来解释的参数。KeBugCheckEx屏蔽了该系统的所有处理器上的所有中断以后,将显示器切换到低分辨率的VGA图形模式(Windows支持的所有视频卡都实现了这种模式)下,绘制一个蓝色背景,然后显示此停止代码,后面紧跟一些文本来建议用户应该怎么办。最后,KeBugCheckEx调用任何已注册的设备驱动程序错误检查回调函数(通过调用KeRegisterBugCheckCallback函数来注册的回调函数),从而让驱动程序有机会停止它们的设备(有可能系统数据结构已经被破坏得太严重,以至于蓝屏都显示不出来)。图14.2显示了Windows XP蓝屏的一个例子。 注     Windows XP Service Pack 1和更高的版本,以及Windows Server 2003引入了KeRegisterBugCheckReasonCallback函数,以允许设备驱动程序在一个崩溃转储的后面附加一些数据,或者将崩溃转储的信息写到其他的设备中。 图14.2  蓝屏的例子 KeBugCheckEx在蓝屏顶部的附近显示了停止代码的文本表示,在Windows 2000蓝屏的顶部,也显示了停止代码数值以及四个参数,但是,在Windows XP和Windows 2003蓝屏上,这些数值被显示在蓝屏底部。 第一行列出了传递给KeBugCheckEx的停止代码和四个参数。屏幕顶部附近的文本提供了该停止代码数值标识符的文本表示。根据图14.2中的例子,停止代码0x000000D1是一个DRIVER_IRQL_NOT_LESS_OR_EQUAL崩溃。当其中一个参数包含了操作系统或设备驱动程序代码的地址时(如同图14.2中显示的那样),Windows显示出该地址所处的模块的基地址、日期戳,以及该设备驱动程序的文件名。仅仅这些信息就有可能帮助你查明错误的组件。 虽然总共有一百多个不同的停止代码,但是,绝大多数代码很少在产品系统上发生(尽管也有)。相反地,少数常见的停止代码表达了大多数的Windows系统崩溃实例。而且,四个附加参数的含义也取决于停止代码(并不是所有的停止代码都有扩展的参数信息)。然而,查看停止代码和参数(如果适用的话)的含义至少有可能帮助你诊断出当前正在经受失败的组件(或者引发系统崩溃的硬件设备)。 你可以在Windows调试工具箱(Windows Debugging Tools)帮助文件的“Bug Checks (Blue Screens)”一节中找到关于停止代码的信息(有关Windows调试工具箱的信息,请参见第1章)。你也可以在Microsoft的在线Knowledge Base(http://support.microsoft.com)中查找某一个停止代码和可疑的硬件或应用程序的名称。你可能会找到有关如何规避此问题、如何更新软件的信息,或者找到关于修正此问题的服务补丁包(service pack)的信息。Windows DDK中的Bugcodes.h包含了150个左右停止代码的一个完整列表,并且给出了有关某些停止代码的原因的额外信息。 通常你是在安装了一个新的软件产品或者硬件设备以后才开始看到蓝屏的。如果你刚刚添加了一个驱动程序,再重新引导,然后在系统初始化过程的早期看到了一个蓝屏,那么,你可以重新启动机器,在出现提示时按下F8键,然后选择“Last Known Good Configuration(最后已知的好配置)”。选择了最后已知的好配置选项,可以让Windows将注册表的设备驱动程序注册键(HKLM\SYSTEM\CurrentControlSet\Services)从最近一次成功引导的配置(在你安装该驱动程序以前)中恢复一份拷贝。从最后已知好配置的角度来看,一次成功的引导是指,所有的服务和驱动程序都已经完成了加载,并且至少有一次登录已经成功了(第5章更加详细地讲述了最后已知的好配置)。 如果你仍然看到蓝屏,那么,一种显而易见的办法是,卸掉在你第一次看到蓝屏之前刚刚加入的那些组件。如果从你上次加入新组件以来已经过了一段时间,或者你差不多同时加入了好多东西,那么,你需要将任何一个参数中引用到的设备驱动程序的名称 记录 混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载 下来。如果你识别出这些名称中有的名称跟你刚刚加入的组件有关联(比如,如果你安装了一个新的SCSI驱动器,你正好看到了Scsiport.sys),那么,你可能已经找到了罪魁祸首。 许多设备驱动程序有隐藏的名称,但是有一种办法可以让你找到哪个应用程序或者硬件设备是跟一个名称相关联的,那就是,通过在注册表的HKLM\SYSTEM\CurrentControlSet\Services键下面搜索该设备驱动程序的名称,你可以找到与该设备驱动程序相关联的服务的名称。注册表的这一分支正是Windows保存当前系统中每个设备驱动程序注册信息的地方。如果你搜索到了一个匹配,则寻找名为DisplayName和Description的值。有些驱动程序通过填充这些值来描述设备驱动程序的用途。例如,你可能会在DisplayName值中找到字符串“Virus Scanner”,这表明你已经运行了反病毒软件。你可以在计算机管理(Computer Management)工具(从Start菜单中,选择Programs/Administrative Tools/Computer Management)中显示驱动程序的列表。在Computer Management中,展开System Tools,System Information和Software Environment,然后选择Drivers即可。 然而,停止代码和四个关联的参数有时候还不足以诊断一次系统崩溃。例如,你可能需要检查内核模式的调用栈,才能查明触发此次崩溃的驱动程序或者系统组件。而且,因为Windows系统上的默认行为是在系统崩溃时自动重新引导的,因此,你可能没有时间记录下在蓝屏上显示的信息。所以,Windows在默认情况下,要试图将有关系统崩溃的信息记录到磁盘上,以便于事后进行分析。这也将我们带入到下一个话题:崩溃转储文件。 14.3  崩溃转储文件 在默认情况下,所有的Windows系统都被设置为:当系统崩溃时,系统总是试图记录下有关当前系统的状态的信息。你可以通过用户界面看到这些设置,做法是,打开控制面板中的System工具,然后在System Properties对话框中,点击Advanced标签,然后点击Startup And Recovery按钮。Windows XP Professional系统的默认设置如图14.3所示。 图14.3  崩溃转储设置 对于一次系统崩溃,以下三种层次的信息可以被记录下来。 n  完全内存转储  完全内存转储包含了在崩溃时刻所有的物理内存。这种转储类型要求页面文件至少是物理内存的大小再加上1MB(用于记录头信息)。因为在大内存的系统上,它要求一个非常大的页面文件,所以,这种类型的转储文件是最少见的设置。Windows NT 4只支持这种类型的崩溃转储文件。这也是Windows Server系统的默认设置。 n  内核内存转储  内核内存转储只包含了在崩溃时刻位于物理内存中的内核模式读/写页面。这种转储类型并不包含属于用户进程的页面。然而,因为只有内核模式的代码才可以直接导致Windows崩溃,所以,用户进程页面通常对于崩溃调试来说是不必要的。而且,所有与崩溃转储分析有关的数据结构,包括当前运行进程的列表、当前线程的栈,以及已加载驱动程序的列表,都被保存在非换页的内存中,它们也被记录在内核内存转储中。没有很好的办法来预测内核内存转储的大小,因为它的大小取决于该机器上操作系统和所有活动驱动程序已经分配的内核模式内存的数量。 n  小内存转储  小内存转储(在Windows Professional上,这是默认设置)也称为小转储(minidump)或分类优先转储(triage dump),它的大小为64KB(在64位系统上为128KB)。它包含了停止代码和参数、已加载的设备驱动程序的列表、描述当前进程和线程的数据结构(称为EPROCESS和ETHREAD,见第6章的描述),以及引起此次崩溃的线程的内核栈。 虽然完全内存转储是其他选项的超集,但是,它的缺点是,其大小达到了一个系统上所有物理内存的总量,因而变得很不实用。大的服务器系统有几GB物理内存的情形并不罕见,这样会导致崩溃转储文件太大,以致无法上载到FTP服务器上,或者被刻到CD上。因为在绝大多数的崩溃分析过程中,用户模式的代码和数据并没有被使用到(因为系统崩溃是由于内核内存中存在问题而引起的,并且,系统数据结构驻留在内核内存中),所以,在完全内存转储中保存的许多数据与分析并不相关,因而它们纯粹浪费了转储文件的空间。最后一个缺点是,引导卷(\Windows目录所在的卷)上的页面文件的大小必须至少等于该系统中物理内存的数量再加上1MB。由于在一般情况下,所要求的页面文件的大小与实际物理内存的数量成反比例,因此,这一需求可能强迫页面文件变得不必要的大。你应该考虑小内存转储和内核内存转储这两种选项所提供的好处。 小转储的一个好处是它的尺寸非常小,这使得它非常便于交换,比如通过电子邮件来交换。而且,每一次崩溃都会在\Windows\Minidump目录中生成一个文件,该文件有一个惟一的文件名,是由字符串“Mini”加上日期和一个序列号(比如Mini082604-01.dmp)构成的。小转储的一个缺点是,为了对它们进行分析,你在分析时必须使用与生成该转储的系统上用到的相同映像文件(最起码,Ntoskrnl.exe必须是相符的版本,以便进行最基本的分析)。如果你想在一个不同于生成某个转储的系统上分析该转储,那么这可能是一个问题。然而,Microsoft的符号服务器包含了Windows XP系统及以后版本的映像(和符号),所以,你可以在调试器中设置映像路径,使它指向符号服务器,于是,调试器就会自动 下载 课程表模板下载资产负债表下载英语单词下载学习机资料下载励志文章下载 所需要的映像(当然,Microsoft的映像服务器并不包含你所安装的第三方驱动程序的映像)。 一个更重要的缺点是,由于在转储文件中只保存了很有限的数据,这可能会使得有效的分析难以进行。另外,即使你配置一个系统,并让它生成内核崩溃转储或完全崩溃转储,你也可以获得小转储的好处,你只需用Windbg来打开一个大的崩溃转储,然后用“.dump /m”命令提取出一个小转储。注意,在Windows XP和Windows Server 2003上,小转储是自动创建的,即使系统被设置为完全转储或内核转储。 注     你可以在Livekd中,利用.dump命令生成当前活动系统的一个内存映像,因而你无需停止系统就可以离线地分析该系统。若一个系统虽然出现了一个问题但仍然在提供服务,而且你想在不打断该服务的情况下诊断此问题,那么,此时这种方法非常有用。结果得到的崩溃映像并不是完全一致的,因为不同内存区域的内容反映的是不同时间点上的情形,但是它可能包含了对于分析非常有用的信息。 内核内存转储 方案 气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载 提供了一种更切合实际的中间选择。因为它包含了所有的属于内核模式的物理内存,所以,它与完全内存转储具有同样层次的可分析数据,但是它省略了通常不相关的用户模式数据和代码,因此,它可以比完全内存转储小得多。举例来说,在一个具有256MB RAM的Windows XP系统上,一个内核内存转储的大小为34MB;在另一个具有1.5GB RAM的Windows XP系统上,一个内核内存转储达到了72MB。 当你配置内核内存转储的时候,系统检查页面文件是否足够大(见表14.1),但是,这些只是估计的大小值,因为没有办法可以预测一个内核内存转储的大小。之所以无法预测一个内核内存转储的大小,是因为它的大小取决于在崩溃时刻该机器的操作系统和所有活动驱动程序正在使用的内核模式内存的数量。 表14.1  针对内核转储的默认最小页面文件大小 系统内存的大小 针对内核转储的最小页面文件大小 < 128 MB 50 MB < 4 GB 200 MB < 8 GB 400 MB >= 8 GB 800 MB 因此,在崩溃发生时,因为页面文件太小而无法容纳一个内核转储,这是有可能的。如果你想要看一看自己系统上一个内核转储的大小,那么,你可以手工强制来一次崩溃,做法是,配置相应的选项以便你可以从控制台发起一次手工系统崩溃,或者使用本章后面将要讲述的Notmyfault工具(本章后面讲述了这两种方法)。当你重新引导时,你可以进行检查,以确保一个内核转储已经生成了,而且,你也可以检查它的大小以估算出你的引导卷页面文件应该设置为多大。为保险起见,在32位系统上,你可以选择2GB加1MB大小的页面文件,因为2GB是所有可用内核模式地址空间的最大值。 最后,即使系统成功地在崩溃时刻将崩溃转储记录到页面文件中了,它还必须有足够的空闲磁盘空间来提取此转储文件。如果没有足够的磁盘空间,那么,崩溃转储就丢失了,因为在页面文件中用于保存崩溃转储的空间被释放了,随着系统开始使用此页面文件,这部分空间也将被覆盖掉。如果你在引导卷上没有足够的空间来保存memory.dmp文件,那么,你可以通过如图14.3中显示的对话框来选择任何其他本地硬盘上的某一个位置。 崩溃转储的生成 当系统引导时,它读取注册表值HKLM\System\CurrentControlSet\Control\CrashControl,以检查当前配置的崩溃转储选项。如果已经配置了一个转储,那么,它把用来写引导卷的磁盘小端口驱动程序在内存中做一份拷贝,并且赋予它一个与小端口相同的名称,前面加上“dump_”作为前缀。对于在写崩溃转储过程中涉及的组件,系统也计算它们的校验和,并且保存起来。这样的组件包括刚刚被拷贝的磁盘小端口驱动程序、执行崩溃转储写操作的I/O管理器函数,以及引导卷的页面文件在磁盘上的映射表。当KeBugCheckEx执行时,它再次计算这些组件的校验和,并且将新得到的校验和与引导时得到的校验和进行比较。如果两者不相符,那么它不再写崩溃转储文件,因为这样做可能会失败,或者破坏磁盘。如果两个校验和相匹配,那么,KeBugCheckEx直接将转储信息写到由页面文件占据的磁盘扇区中,从而绕过了文件系统驱动程序(它可能已被破坏,甚至正是它导致了系统崩溃)。 当SMSS在引导过程中启用换页机制时,系统检查引导卷的页面文件,看是否存在一个崩溃转储,并且将页面文件中被崩溃转储所占据的那部分保护起来。这使得在引导的早期阶段,引导卷页面文件的部分或全部是不可用的,从而可能会导致发出通知以显示“系统当前的虚拟内存过低”。当然,这一条件只是暂时的。后来,仍然在引导过程中,Winlogon通过调用未文档化的NtQuerySystemInformation API来确定该页面文件中是否存在一个崩溃转储,如果存在崩溃转储,则激发Savedump进程(\Windows\System32\Savedump.exe),以便从该页面文件中提取出此崩溃转储,并且将它拷贝到最终的位置上。这些步骤如图14.4所示。 图14.4  崩溃转储文件的生成 14.4  Windows错误 报告 软件系统测试报告下载sgs报告如何下载关于路面塌陷情况报告535n,sgs报告怎么下载竣工报告下载 正如在第3章中所提到的,Windows XP和Windows Server 2003包含了一个称为Windows错误报告的设施,它可以自动帮助将进程和系统崩溃提交给Microsoft(或者一个内部错误报告服务器)进行分析。这一特性是默认打开的,但是通过改变Savedump的行为,它是可以被修改的;Savedump采取额外的步骤来确定该系统是否已被配置为“在崩溃之后重新引导起来时将崩溃转储发送给Microsoft(或者一个私有服务器,在本章后面的‘在线崩溃分析’一节中有进一步的解释)进行分析”。图14.5显示了错误报告配置对话框,你可以通过控制面板的System小程序的Advanced标签页访问此对话框。此对话框允许你配置系统的错误报告设置,这些设置信息被保存在注册表的HKLM\Software\Microsoft\PCHealth\ErrorReporting下面。 图14.5  错误报告配置对话框 在崩溃之后系统重新引导起来时,Savedump检查ErrorReporting键下的几个值,包括Showui、DoReport和IncludeKernelFaults。如果所有这三个值都是true,则Savedump使用下面的步骤,以便做好准备“向Microsoft OCA(Online Crash Analysis)站点(或者一个内部错误报告服务器,如果已经这样配置的话)发送一个崩溃转储报告”。 1.   如果它生成的转储类型不是一个小转储,那么,它从转储文件中提取出一个小转储,并且将其保存在\Windows\Minidumps的默认位置处。 2.   它将小转储文件的名称写到HKLM\Software\Microsoft\PCHealth\ErrorReporting\ KernelFaults中。 3.   它在HKLM\Software\Microsoft\Windows\CurrentVersion\Run中加入一条命令以执行Dumprep (\Windows\System32\Dumprep.exe),所以,在第一个用户登录到该系统的过程中,Dumpreg将被执行 14.5  在线崩溃分析 如上所述,Savedump配置了要启动Dumprep工具,作为这一配置的结果,当Dumprep工具执行时,它也要检查那三个被Savedump参考过的注册表值,看一看该系统是否已被配置为“当系统从一次崩溃中重新引导起来时,向Microsoft发送一个错误报告”。如果是,则Dumprep生成一个XML格式的文件,其中包含了有关该系统的基本描述信息,包括操作系统的版本、机器上已安装的驱动程序的列表,以及在崩溃时刻系统中已加载的即插即用驱动程序的列表。然后,它出示一个如图14.6所示的对话框,询问用户是否愿意给Microsoft发送一个错误报告。如果用户选择了发送错误报告,则除非被组策略所改变,否则Dumprep将此XML文件和小转储发送至http://Watson.Microsoft.Com,此Web服务器又将数据转发给一个服务器场(server farm)以进行自动化分析。下一节将介绍此分析过程。管理员可以通过组策略来配置他们所管辖的系统,使这些系统将错误报告发送至一个内部的错误报告网络共享体,以便事后利用Microsoft Corporate Error Reporting(CER)工具箱进行处理。此工具箱只有符合条件的Microsoft Software Assurance(Microsoft软件保障)客户才可以使用(有关更多的信息,请参见http://www.microsoft.com/resources/satech/cer)。 图14.6  崩溃转储错误报告对话框 服务器场的自动化分析过程所使用的分析引擎,也正是当你在Microsoft内核调试器中加载一个崩溃转储文件时(稍后介绍)内核调试器所使用的同一个分析引擎。此分析过程会得出一个桶ID(bucket ID),这是一个用于标识某个特定崩溃类型的特征值。服务器场使用此桶ID来查询一个数据库,以确定是否有一个解决方案适用于此次崩溃;而且,它给Dumprep送回一个指向OCA Web站点(http://oca.microsoft.com)的URL。Dumprep启动Internet浏览器,打开OCA Web站点上包含初步的崩溃分析结果的页面。如果有一个解决方案可供使用的话,则该页面指示用户到哪儿获得一个热补丁(hotfix)、服务补丁包(service pack)或者第三方驱动程序的更新版本;否则,用户可以接受这样的选项:通过电子邮件来跟踪该崩溃分析的进展。 对于未连接至Internet的站点,或者不想把崩溃转储自动发送至Microsoft的站点,它们可以使用组策略来配置为:错误数据被存储在一个内部的错误报告网络共享体上,以便事后利用前面提到的Microsoft CER工具箱进行处理。 14.6  基本的崩溃转储分析 如果OCA未能提供一个解决方案,或者你不能将崩溃信息提交给OCA(譬如,如果你有一个由Windows 2000生成的崩溃转储文件,这种文件不支持OCA),那么,一种可供选择的做法是,你自己来分析这些崩溃转储。正如前面所提到的,当你在Windbg和Kd中加载一个崩溃转储文件时,它们执行的分析引擎与OCA使用的分析引擎是相同的;有时候,基本的分析也能够查明问题所在。所以,你可能会很幸运,通过自动的分析就能够解开一次崩溃转储之谜。但如果你没有那么幸运,那么,也有一些直接的技术可以让你试着解决系统崩溃的问题。 这一节解释如何执行基本的崩溃分析步骤,在这一节之后将介绍一些诊断技巧,让你利用驱动程序检验器(Driver Verifier,在第7章中介绍)来捕捉有错误的驱动程序(当它们破坏系统的时候),因而通过崩溃转储分析能查出这些驱动程序。 Notmyfault 你可以使用来自www.sysinternals.com/windowsinternals的Notmyfault工具来产生这里所描述的崩溃。Notmyfault是由一个名为Notmyfault.exe的可执行文件和一个名为Myfault.sys的驱动程序组成的。当你运行Notmyfault可执行程序时,它加载该驱动程序,并且显示一个如图14.7所示的对话框,该对话框允许你以各种方式来崩溃系统,或者让驱动程序泄漏换页内存池。这里提供的崩溃类型代表了Microsoft产品支持服务组(Microsoft Product Support Services)看到的最常见的系统崩溃。在对话框中选择一个选项,并点击Do Bug按钮,这将使得此可执行程序通过使用DeviceIoControl Windows API,来告诉驱动程序应该触发哪种类型的错误。注意,你应该在一个测试系统上,或者在一个虚拟机中执行Notmyfault崩溃,因为毕竟还是有一点小小的风险:Notmyfault破坏的内存将被写到磁盘上,从而导致文件或磁盘被破坏。 图14.7  Notmyfault 注     Notmyfault可执行文件的名称(“不是我的错”)和驱动程序的名称(“我的错”)也正是突出了“用户模式不可能直接导致系统崩溃”这一事实。Notmyfault可执行文件只有通过“加载一个驱动程序,以便帮它在内核模式下执行一个非法操作”才能引发系统崩溃。 基本的崩溃转储分析 最直接的Notmyfault崩溃是通过选择High IRQL Fault (Kernelmode)选项并点击Do Bug按钮而引起的崩溃。这使得驱动程序从换页池中申请一个页面,再释放该页面,并且将IRQL提升到DPC/Dispatch级别以上,然后访问刚刚被释放的页面(有关IRQL的更多信息,请参见第3章)。如果这样做还不会引起系统崩溃,则进程仍然往下执行,它越过该页面的尾部继续读内存,直至由于访问无效页面而引起系统崩溃。结果是,该驱动程序执行了以下几个非法操作。 1.   它引用了不再属于它的内存。 2.   它在DPC/Dispatch级别或更高级别上引用了换页内存池,这是非法的,因为当处理器的IRQL是DPC/Dispatch级别或更高级别时,页面错误是不允许的。 3.   当它越过了它所申请的内存的尾部时,它试图引用一段可能无效的内存。 第一次页面引用可能不会引发系统崩溃,其原因是,如果驱动程序释放的页面仍然在系统工作集中,那么它不会产生一个页面错误(有关系统工作集的信息,请参见第7章)。 当你将一个由该错误产生的崩溃转储加载到Kd中时,它的分析将显示类似如下的信息: Microsoft (R) Windows Debugger  Version 6.3.0011.2 Copyright (c) Microsoft Corporation. All rights reserved.     Loading Dump File [c:\windows\memory.dmp] Kernel Summary Dump File: Only kernel address space is available   Symbol search path is: srv*c:\symbols*http://msdl.microsoft.com/download/symbols   Executable search path is: Windows 2000 Kernel Version 2195 UP Free x86 compatible Product: LanManNt, suite: Enterprise TerminalServer Kernel base = 0x80400000 PsLoadedModuleList = 0x8046a4c0 Debug session time: Mon Apr 05 18:28:44 2004 System Uptime: 0 days 0:09:20.105 Loading Kernel Symbols ................................................................................ ............... Loading unloaded module list No unloaded module list present Loading User Symbols .......... ******************************************************************************* *                                                                             * *                        Bugcheck Analysis                                    * *                                                                             * *******************************************************************************   Use !analyze -v to get detailed debugging information.   BugCheck D1, {bead1800, 1c, 0, ec1fb357}   *** ERROR: Module load completed but symbols could not be loaded for myfault.sys   *** WARNING: Unable to verify checksum for NotMyfault.exe *** ERROR: Module load completed but symbols could not be loaded for NotMyfault.exe Probably caused by : myfault.sys ( myfault+357 )   Followup: MachineOwner ---------   kd> 注意到的第一件事情是,Kd报告错误:它不能加载Myfault.sys和Notmyfault.exe的符号。这些错误是意料之中的,因为它们的符号文件不在符号文件路径(它被配置为指向Microsoft的符号服务器)上。对于不随操作系统一起发行的第三方驱动程序和可执行程序,你也会看到类似的错误。 分析文本本身非常简洁,仅仅显示了数值化的停止代码和错误检查参数,后面跟着“probably caused by”行,显示了分析引擎对于有错误驱动程序的最佳猜测。在这个例子中,它切中要害,直接指出了Myfault.sys,所以,无需再进行手工分析了。 “Followup”行通常并没有用,这是专门给Microsoft内部使用的,调试器在“Debugging Tools for Windows(Windows调试工具箱)”安装目录的Triage目录下的Triage.ini文件中查找该模块的名称。此文件的Microsoft内部版本列出了负责处理“在某一个特定驱动程序中发生的崩溃”的开发人员或开发组,因而调试器在适当的时候将他们的名字显示在Followup这一行中。 详细的分析 尽管Notmyfault崩溃的基本分析已经标识出了有错误的驱动程序,但你总是应该让调试器执行一次详细的分析,做法很简单,输入下面的命令: !analyze –v 在详细分析和默认分析之间的第一个显然的区别是有关停止代码及其参数的描述。当在上述的崩溃转储上执行详细分析命令时,输出如下: DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1) An attempt was made to access a pageable (or completely invalid) address at an interrupt request level (IRQL) that is too high.  This is usually caused by drivers using improper addresses. If kernel debugger is available get stack backtrace. Arguments: Arg1: bead1800, memory referenced Arg2: 0000001c, IRQL Arg3: 00000000, value 0 = read operation, 1 = write operation Arg4: ec1fb357, address which referenced memory 这可以让你省下打开帮助文件来查找同样这些信息的麻烦,有时候,这些文本描述给出了有关诊断步骤的建议,在下一节有关高级崩溃转储分析的介绍中你将会看到一个例子。 在一个详细分析中,其他可能有用的信息是,崩溃时刻在发生崩溃的处理器上正在执行的线程的栈痕迹。以下是前面的转储中的栈痕迹信息: STACK_TEXT:   WARNING: Stack unwind information not available. Following frames may be wrong. b7e6dc34 804ac5de ff7c4040 beb4bf68 ff80a9c8 myfault+0x357 b7e6dd00 804a8f1e 00000070 00000000 00000000 nt!IopXxxControlFile+0x5e4 b7e6dd34 80461691 00000070 00000000 00000000 nt!NtDeviceIoControlFile+0x28 b7e6dd34 77f96be2 00000070 00000000 00000000 nt!KiSystemService+0xc4 0012f4a0 77e84c9b 00000070 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xb 0012f504 004017c3 00000070 83360018 00000000 KERNEL32!DeviceIoControl+0x100 000200ac 00000000 00000000 00000000 00000000 NotMyfault+0x17c3 上面的栈痕迹显示了Notmyfault可执行映像(如栈的底部所示)调用了Kernel32.dll中的DeviceIoControl函数,而DeviceIoControl又依次调用了Ntdll.dll中的ZwDeviceIoControlFile,如此等等,直至最后,在Myfault映像中有一条指令执行之后系统发生崩溃。像这样的栈痕迹可能非常有用,因为有时候,崩溃的发生是由于一个驱动程序给另一个驱动程序传递了格式不正确的、已被破坏的、或者非法的参数信息。接受此无效数据的驱动程序可能引发了崩溃,从而在基本分析中被蒙冤,但是,栈痕迹指明了另一个驱动程序也被牵连进来。在以上的例子中,除了Myfault以外,没有其他的驱动程序被列示出来(模块“nt”是Ntoskrnl)。 如果在一次分析中被选中的驱动程序对你来说并不熟悉,那么,使用lm(列出模块)命令可以查看该驱动程序的版本信息。加上k(内核模块)和v(verbose,详细)选项,以及m选项,后面再跟上该驱动程序的名称和一个通配符,如下所示: kd> lm kv m myfault* start    end        module name f224d000 f224dbe0   myfault      (deferred)                  Image path: \??\C:\WINNT\system32\drivers\myfault.sys     Timestamp: Thu Apr 29 14:53:12 2004 (40915D28)  Checksum: 00010090     ImageSize : 00000BE0     File version:     2.0.0.0     Product version:  2.0.0.0     File flags:       0 (Mask 3F)     File OS:          40004 NT Win32     File type:        3.7 Driver     File date:        00000000.00000000     Translations:     0409.04b0     CompanyName:      Sysinternals     ProductName:      Sysinternals Myfault     InternalName:     myfault.sys     OriginalFilename: myfault.sys     ProductVersion:   2.0     FileVersion:      2.0     FileDescription:  Crash Test Driver     LegalCopyright:   Copyright (C) M. Russinovich 2002-2004 除了通过描述信息来识别出一个驱动程序的用途以外,你还可以使用该文件和产品的版本号来确定所安装的版本是否是最新的可使用版本(例如,你可以检查厂商的Web站点来做到这一点)。如果版本信息没有出现的话(因为在崩溃时刻这些信息可能被换出物理内存了),那么,你可以在发生崩溃的系统上,在Explorer(文件管理器)中检查该驱动程序映像文件的属性。 14.7  使用崩溃诊断工具 在上一节中通过Notmyfault的“High IRQL Fault (Kernelmode)”选项生成的崩溃转储,并没有对调试器的自动化分析带来多大的挑战。不幸的是,大多数崩溃并不是这么容易,而且通常不可能进行调试。按照系统性能退化的程度,有几个严重程度逐渐增加的级别可能使一个系统本来生成不可分析的崩溃转储,变为生成可被分析的崩溃转储。如果在你配置了一个级别并且重新引导以后,所生成的崩溃转储并没有表露出崩溃的原因,则试一试下一个级别。 1.   如果你正在怀疑有一个或者多个驱动程序可能是崩溃的源头,因为它们是最近才被引入到系统中的,或者它们最近刚刚被更新过,或者崩溃的场景暗示着它们可能是罪魁祸首,那么,对这些驱动程序使用驱动程序检验器(Driver Verifier)进行检验,除了低资源模拟选项以外,检查所有其他的选项。 2.   对于系统中未签名的所有驱动程序,启用第1级别中的检验选项。或者,如果你正在运行Windows 2000,而在Windows 2000上,驱动程序检验器并不区分签名的和未签名的驱动程序,那么,你可以针对所有的非Microsoft的驱动程序,启用第1级别中的检验选项。 3.   对于系统中的所有驱动程序,启用第1级别中的检验选项。为了维持合理的性能,你可能想要将驱动程序分成组,这样,每次重新引导时,只针对一个组启用驱动程序检验器。 显然,在你花时间和精力来调整系统配置和分析崩溃转储以前,首先应该确保你的系统中的内核和驱动程序都是最新的版本,你可以通过Windows Update以及第三方驱动程序支持站点的服务来做到这一点。 如果因为驱动程序检验器检测到了一个驱动程序错误并且使系统崩溃,从而导致你的系统变得不可引导,那么,请在安全模式下启动起来(在这种模式下是禁止检验的),运行驱动程序检验器,并删除检验设置。注 下面的小节解释了驱动程序检验器如何能够使不可能调试的崩溃变成你可以解决的崩溃。你也应该参考调试工具箱(Debugging Tools)的帮助文件,其中有一些关于高级调试技术的指导。 缓冲区溢出和特殊内存池 到目前为止,在Windows上,最常见的崩溃源头是内存池被破坏。内存池破坏通常发生于一个驱动程序遭受了一个缓冲区上溢或缓冲区下溢错误的时候,也就是说,这样的错误改写了该驱动程序从换页内存池或非换业内存池中申请的缓冲区的开始之前或结束之后的数据。执行体的池跟踪(pool tracking)数据结构驻留在池缓冲区的两端,它们把内存池的缓冲区相互隔开。因此,这些错误会破坏池跟踪数据结构,或者破坏其他驱动程序的缓冲区,或者对两者皆造成破坏。由于内存池破坏而引起的崩溃本质上是不可能调试的,因为系统崩溃发生于破坏的数据被引用之时,而并非发生于数据被破坏之时。 注     为了帮助捕获这些难以捕获的内存破坏,Windows XP (Service Pack 2)及以后的版本总是执行池内存块的尾部检查。因此,缓冲区溢出可能会立刻引发一个BAD_POOL_HEADER崩溃。 你只需运行Notmyfault并选择“Buffer Overflow”错误,就可以产生一个内存池破坏类型的崩溃。这一选项使得Myfault申请一个缓冲区,然后改写该缓冲区之后的40字节。从你点击Do Bug按钮到发生崩溃,两者之间可能会有一段明显的延迟,甚至在崩溃发生之前你可能要运行或操作某些应用程序以便池内存被使用到,这也更加突出了从内存破坏到系统稳定受到影响之间的距离。对这样的崩溃转储的分析,几乎总是报告Ntoskrnl或另一个驱动程序是可能的出错原因,这也说明了详细分析以及它对停止代码的描述是非常有用的: DRIVER_CORRUPTED_EXPOOL (c5) An attempt was made to access a pageable (or completely invalid) address at an interrupt request level (IRQL) that is too high.  This is caused by drivers that have corrupted the system pool.  Run the driver verifier against any new (or suspect) drivers, and if that doesn’t turn up the culprit, then use gflags to enable special pool. Arguments: Arg1: 4f4f4f53, memory referenced Arg2: 00000002, IRQL Arg3: 00000001, value 0 = read operation, 1 = write operation Arg4: 80467139, address which referenced memory 在描述文本中给出的建议是,针对任何新的或可疑的驱动程序运行驱动程序检验器,或者使用GFlags来启用特殊内存池特性。两者完成的事情是一样的:让系统在内存破坏发生的时候就检测到它,并且通过一种专门的方式使系统崩溃,从而允许自动分析过程能够直接指出是哪个驱动程序导致内存破坏。 如果驱动程序检验器的特殊内存池选项被启用,那么,被检验的驱动程序对于略小于一个页面大小的缓冲区申请,都使用特殊的内存池,而不使用换页的或非换页的内存池。从特殊内存池中分配的缓冲区被夹在两个无效页面之间,在默认情况下跟页面的顶端对齐。特殊内存池的例程也会用一些随机模式来填充所分配页面中未被使用的部分。图14.8显示了一个特殊内存池的缓冲区分配。 图14.8  特殊内存池的缓冲区分配 对于小于一个页面大小的缓冲区的溢出,系统在溢出发生的时候就会检测到,因为它们导致在缓冲区之后的无效页面发生了页面错误(page fault)。图14.8中的特征签名被用于在驱动程序释放一个缓冲区时捕捉缓冲区下溢的情形,因为在分配该缓冲区时放在这里的模式的完整性可能已经被破坏了。 为了看清楚如何使用特殊内存池来引发一个可让分析引擎很容易诊断的崩溃,请运行驱动程序检验器管理器。在Windows 2000系统上,转到Setting标签页,在页面底部,允许你在指定额外驱动程序的编辑框中输入myfault.sys,并选择特殊内存池复选框,应用(apply)这些变化,退出驱动程序检验器管理器,并重新引导。在Windows XP和Windows Server 2003上,在向导的第一个页面上选择“Create Custom Settings (For Code Developers)”选项,在第二个页面上选择“Select Individual Settings From A Full List”,然后选中“Special Pool”。在接下来的页面上选择“Select Drivers From A List”选项,然后在列出驱动程序的页面上,按下按钮以便加入尚未加载的驱动程序,并且在File Find对话框中输入“myfault.sys”(你在File Find对话框中不必找到myfault.sys,只需输入其名称即可)。然后,选中myfault.sys驱动程序,退出向导,并重新引导系统。 当你运行Notmyfault,并引发一个缓冲区溢出时,系统将立即崩溃,对崩溃转储的分析报告如下: Probably caused by : myfault.sys ( myfault+3f1 ) 详细分析描述的停止代码如下: DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION (d6) N bytes of memory was allocated and more than N bytes are being referenced. This cannot be protected by try-except. When possible, the guilty driver’s name (Unicode string) is printed on the bugcheck screen and saved in KiBugCheckDriver. Arguments: Arg1: beb50000, memory referenced Arg2: 00000001, value 0 = read operation, 1 = write operation Arg3: ec3473f1, if non-zero, the address which referenced memory. Arg4:
本文档为【深入解析windows操作系统之崩溃转储分析】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_530219
暂无简介~
格式:doc
大小:213KB
软件:Word
页数:31
分类:工学
上传时间:2010-11-02
浏览量:47