Windows异常处理流程

合集下载

编写的windows程序,崩溃时产生crashdump文件的办法

编写的windows程序,崩溃时产生crashdump文件的办法

编写的windows程序,崩溃时产⽣crashdump⽂件的办法⼀、引⾔dump⽂件是C++程序发⽣异常时,保存当时程序运⾏状态的⽂件,是调试异常程序重要的⽅法,所以程序崩溃时,除了⽇志⽂件,dump⽂件便成了我们查找错误的最后⼀根救命的稻草。

windows程序产⽣dump⽂件和linux程序产⽣dump⽂件的⽅式不⼀样,linux默认是不让产⽣core dump⽂件,只要在⽤户⾃⼰的~/.bash_profile⽂件中增加ulimit -S -c unlimited > /dev/null 2>&1这样程序崩溃就可以产⽣可调试的core dump⽂件了。

但是windows环境就得写代码才能实现了。

⼆、原理windows程序当遇到异常,没有try-catch或者try-catch也⽆法捕获到的异常时,程序就会⾃动退出,如果这时候没有dump⽂件的话,我们是没有得到任何程序退出的信息。

在windows程序异常退出之前,会预先调⽤⼀个在程序中注册的异常处理回调函数(默认是没有设置),只要我们在这个回调函数中调⽤MiniDumpWriteDump函数就可以产⽣我们想要的dump⽂件。

三、实现1.调⽤SetUnhandledExceptionFilter注册⼀个⾃定义的异常处理回调函数SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);异常处理回调函数的原型LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);2.CreateFile创建dump⽂件,调⽤MiniDumpWriteDump函数往dump⽂件写异常信息[cpp]1. inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)2. {3. HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,4. FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);5.6. if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))7. {8. MINIDUMP_EXCEPTION_INFORMATION mdei;9. mdei.ThreadId = GetCurrentThreadId();10. mdei.ExceptionPointers = pep;11. mdei.ClientPointers = NULL;12.13. MINIDUMP_CALLBACK_INFORMATION mci;14. mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;15. mci.CallbackParam = 0;16.17. ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);18.19. CloseHandle(hFile);20. }21. }CreateMiniDump函数是在异常处理回调函数MyUnhandledExceptionFilter中调⽤的[cpp]1. LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)2. {3. CreateMiniDump(pExceptionInfo, "core.dmp");4.5. return EXCEPTION_EXECUTE_HANDLER;3.将SetUnhandledExceptionFilter失效vs2005中,编译的过程中,编译器会⾃动给你的程序加上⼀句SetUnhandledExceptionFilter(NULL),这就会导致你之前⾃定义的SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);⽆效,就有可能不会产⽣dump⽂件,因此我们必须在⾃定义的SetUnhandledExceptionFilter之后,让之后调⽤的SetUnhandledExceptionFilter ⽆效。

Windows异常处理机制研究

Windows异常处理机制研究

Windows异常处理机制研究摘要:对Windows异常处理机制的原理进行介绍分析,引入Windows 精髓SEH,并详细介绍了SEH原理,对如何更好地利用SEH服务于代码的编写,并且利用SEH和dump文件进行bug定位进行了研究。

关键词:Windows异常处理机制;SEH;dump文件;bug定位0 引言异常处理是一种允许两个独立开发的程序组件在程序执行期间遇到不正常情况下进行相互通信的机制。

包括3步:产生、抛出、处理。

异常广义上可以分为软件异常(software exception)、硬件异常(hardware exception)。

硬件异常也叫CPU异常,比如,程序员不会去存取一个无效的内存地址或用0来除一个数值,不过,这样的错误还是常常会发生的。

C P U负责捕捉无效内存访问和用0除一个数值这种错误,并相应引发一个异常作为对这些错误的反应。

操作系统和应用程序也可以引发相应的异常,即软件异常。

作为时下最流行的系统,Windows SEH在异常的处理上给我们带了非常多的惊喜。

它在程序的稳定和健壮方面发挥着举重轻重的作用。

本文将从代码编写、bug定位方面介绍SEH。

首先对SEH、dump文件进行介绍。

1 SEH和dump文件1.1 SEH在C语言的开发过程中,常常会对一个指针进行无休止的检测,对内存的分配是否成功进行繁琐的检测和处理,对C语言测试程序员来说,这是一个十分头疼的事情。

检测机制这么多就是为了同一个目标,即程序的安全性。

但这是一把双刃剑,安全性得到了保证,代码就会显得十分冗余,对阅读方面会造成极大的影响。

指针是C语言的精髓,试想如果一个工程里面通篇都是对不同类型指针安全性进行检测,代码会是怎样一种情况。

SEH的引入就很好地解决了这个难题。

同时,你是否也在为bug定位苦恼。

很多时候,C++的异常处理机制可以很好地跳过异常代码,但是这又同样引入一个问题,虽程序运行没有问题,但是异常终归是异常,必须解决,普通的C++异常无法定位。

第5章程序调试与异常处理

第5章程序调试与异常处理

程序运行期间产生的不可预料的错误 称为异常,它干扰正常的程序流程。存 在许多可能导致异常发生的情形,例如, 内存申请失败,浮点运算的溢出,文件 I/O的各种异常,以及打印异常等等。
在SysUtils单元中定义的RTL异常类和在 Controls单元中定义的VCL异常类,都由 Exception类派生而来,在Exception类中定义 了进行异常处理的基本属性和方法。这些异 常类的定义,一方面归纳总结了Delphi应用 程序可能出现的异常,另一方面对异常进行 了内置的保护。
1. 单步执行
单步执行就是一次执行一行语句,当程 序遇到断点暂停后,可以选择这种方式 跟踪程序的执行。通过选择执行【Run】 →【Step Over】菜单项,或按下F8键 实现程序单步执行。
2. 跟踪执行
跟踪执行和单步执行类似,只是当执行到含有过程或 函数调用的行后,执行点将进入过程或函数内部。 跟踪执行程序的方法是选择执行【Run】→【Trace Into】菜单项,或按下F7键。 3. 执行到光标所在处 如果希望程序在没有设置断点的行上暂停,可以把光 标 停 在 这 行 上 , 选 择 执 行 【Run】→【Run to Cursor】菜单项,或按下F4键,程序就会直接执行 到光标所在行上,然后暂停,等待用户作进一步操 作。
在已设断点的行上重复以上所述设置断点的
操作,则取消该行的断点设置。
断点必须设置在可执行的代码行上,如果把
断点设在注释、空行、变量声明等非执行行 上,调试器将认为该断点无效。
2. 设置断点属性
选 择 执 行 【View】→【Debug Windows】→ 【Breakpoints】菜单项,或按下Ctrl+Alt+B 组合键,将打开断点列表窗口,窗口中包含 了所有断点信息。

DHCP服务器迁移时出错或异常过程处理方法

DHCP服务器迁移时出错或异常过程处理方法

DHCP服务器迁移时出错或异常过程处理方法Windows 2000 DHCP Windows 2003 DHCP服务器迁移到windows 2008 出错或异常过程处理方法不管是在Windows 2000 Serve上用Dhcpexim.exe导出DHCP 数据库,把它迁移到windows server2003 或迁移到windwos server 2008.当你用netsh dhcp server export DHCP数据库文件时: 您会收到错误消息。

也就在使用Netsh.exe移动DHCP数据库时,您会收到错误消息例如:出现错误提示:导入类别“Microsoft Windows 2000 选项”时出错。

此类别和现存的类别“Microsoft Windows 2000 选项”冲突导入类别"默认BOOTP 的类别" 时出错导入类"默认BOOTP"时出现错误。

此类冲突,与现有类"BOOTP 类默认值"这是由于不同版本之间的DHCP的类别或类别的描述不同造成的。

解决的方法是删除原机器上的类别和类别描述,并且导入新机器上的windows 2008 DHCP server 的类别和类别描述.处理:分别导出2000,2003,2008的dhcp类别和类别描述在2000下运行netsh dhcp server dump > c:\dhcp2000.txt在2003下运行netsh dhcp server dump > c:\dhcp2003.txt在2008下运行netsh dhcp server dump > c:\dhcp2008.txt我的2000机器上:#========================================= # DHCP 配置#=========================================pushd dhcp#========================================= =====================# 服务器192.168.111.117 的配置信息#========================================= =====================# ===================================== # Add Classes# ===================================== Dhcp Server 192.168.111.117 Add Class "Microsoft Windows 2000选项" "Microsoft 的Windows 2000 客户的特定供应商选项" 4d53465420352e30 1 bDhcp Server 192.168.111.117 Add Class "Microsoft Windows 98选项" "Windows 98 客户的Microsoft 供应商专用的选项" 4d534654203938 1 bDhcp Server 192.168.111.117 Add Class "Microsoft 选项" "Microsoft Windows 98 和Windows 2000 适用的客户指定的选项" 4d534654 1 bDhcp Server 192.168.111.117 Add Class "默认BOOTP 的类别""BOOTP 客户的用户类别" 424f4f54502e4d6963726f736f6674 0 b Dhcp Server 192.168.111.117 Add Class "默认路由和远程访问类别" "用户类别的常用和远程访问客户" 525241532e4d6963726f736f6674 0 b# ===================================== # Add Classes 结束# =====================================我的2008机器上:#========================================= =====================# 服务器192.168.111.46 的配置信息#========================================= =====================# ===================================== # 添加类# ===================================== Dhcp Server 192.168.111.46 Add Class "默认路由和远程访问类" "远程访问客户端的用户类" 525241532e4d6963726f736f6674 0 b Dhcp Server 192.168.111.46 Add Class "默认的网络访问保护级别" "受限访问客户端的默认特殊用户类" 4d5346542051756172616e74696e65 0 b Dhcp Server 192.168.111.46 Add Class "默认BOOTP 类""BOOTP 客户端的用户类" 424f4f54502e4d6963726f736f6674 0 bDhcp Server 192.168.111.46 Add Class "Microsoft Windows 2000 选项" "针对Windows 2000 及更高版本客户端的Microsoft 供应商特定选项" 4d53465420352e30 1 bDhcp Server 192.168.111.46 Add Class "Microsoft Windows 98 选项" "Windows 98 客户端的Microsoft 供应商特定选项" 4d534654203938 1 bDhcp Server 192.168.111.46 Add Class "Microsoft 选项" "适用于所有Windows 客户端的Microsoft 供应商特定选项" 4d534654 1 b# ===================================== # Add Classes 结束# =====================================得到这些数据后,我们接下来就是编写一个.bat文件把它放到旧的dhcp server 上去运行(我的旧的dhcp IP:192.168.111.117).完成后导出数据,再把这数据.bat 内容:# ===================================== # Delete 旧机器2000 dhcp or 2003 dhcp Classes# ===================================== netsh Dhcp Server 192.168.111.117 Delete Class "Microsoft Wind ows 2000 选项" "Microsoft 的Windows 2000 客户的特定供应商选项" 4d53465420352e30 1 bnetsh Dhcp Server 192.168.111.117 Delete Class "Microsoft Windows 98 选项" "Windows 98 客户的Microsoft 供应商专用的选项" 4d534654203938 1 bnetsh Dhcp Server 192.168.111.117 Delete Class "Microsoft 选项" "Microsoft Windows 98 和Windows 2000 适用的客户指定的选项" 4d534654 1 bnetsh Dhcp Server 192.168.111.117 Delete Class "默认BOOTP 的类别""BOOTP 客户的用户类别" 424f4f54502e4d6963726f736f6674 0 bnetsh Dhcp Server 192.168.111.117 Delete Class "默认路由和远程访问类别" "用户类别的常用和远程访问客户" 525241532e4d6963726f736f6674 0 b# ===================================== # Delete Classes 结束# ===================================== # ===================================== # 把新机(2008)上的类添加旧机器2000 dhcp or 2003 dhcp# ===================================== netsh Dhcp Server 192.168.111.117 Add Class "默认路由和远程访问类" "远程访问客户端的用户类" 525241532e4d6963726f736f6674 0 b netsh Dhcp Server 192.168.111.117 Add Class "默认的网络访问保护级别" "受限访问客户端的默认特殊用户类" 4d5346542051756172616e74696e65 0 bnetsh Dhcp Server 192.168.111.117 Add Class "默认BOOTP 类""BOOTP 客户端的用户类" 424f4f54502e4d6963726f736f6674 0 bnetsh Dhcp Server 192.168.111.117 Add Class "Microsoft Windows 2000 选项" "针对Windows 2000 及更高版本客户端的Microsoft 供应商特定选项" 4d53465420352e30 1 bnetsh Dhcp Server 192.168.111.117 Add Class "Microsoft Windows 98 选项" "Windows 98 客户端的Microsoft 供应商特定选项" 4d534654203938 1 bnetsh Dhcp Server 192.168.111.117 Add Class "Microsoft 选项" "适用于所有Windows 客户端的Microsoft 供应商特定选项" 4d534654 1 b# ===================================== # Add Classes 结束# ===================================== 保存成addclass.bat 并在旧2000 dhcp上执行.按下面步骤操作.windows 2000/2003 DHCP服务器迁移到windows 2008a.windows 2000系统DHCP迁移到windows 2008如何去实施?b.windows 2003系统DHCP迁移到windows 2008如何去实施?回答:此过程分为导出源DHCP服务器数据库和导入到2008目标服务器两个阶段。

操作系统触发异常el3异常处理流程

操作系统触发异常el3异常处理流程

操作系统触发异常el3异常处理流程操作系统触发异常EL3异常处理流程随着计算机技术的不断发展,操作系统作为计算机系统的核心,扮演着至关重要的角色。

在操作系统中,异常处理是一项非常重要的任务。

当操作系统遇到异常情况时,需要通过异常处理程序来处理。

本文将介绍操作系统触发异常EL3异常处理流程。

一、什么是异常?异常是指在程序执行过程中发生的一些意外情况,例如:硬件故障、非法指令、内存溢出等。

当操作系统检测到异常情况时,会立即停止当前进程,并转入异常处理程序。

二、EL3异常处理流程在操作系统中,EL3是指处于最高特权级别的处理器模式。

当发生严重的异常情况时,操作系统会将处理器模式切换到EL3模式,以确保异常处理程序能够优先执行。

EL3异常处理流程主要包括以下几个步骤:1.异常触发当操作系统检测到某些异常情况时,例如:系统调用、中断请求等,会立即触发异常。

2.中断向量表操作系统将中断号映射到中断向量表中,以确定相应的异常处理程序地址。

中断向量表是一张特殊的表格,其中包含了每种中断类型对应的中断处理程序的地址。

3.异常处理程序操作系统根据中断号从中断向量表中获取相应的异常处理程序地址,并跳转到该地址执行。

异常处理程序是一段预先定义好的代码,用于处理各种异常情况。

在执行异常处理程序时,操作系统会将处理器模式切换到EL3模式,以确保异常处理程序能够优先执行。

4.异常处理异常处理程序会根据异常类型进行相应的处理。

例如:对于系统调用异常,异常处理程序会执行相应的系统调用处理程序,以完成用户进程对内核的请求。

在完成异常处理后,操作系统会将处理器模式切换回原本的模式,并恢复现场,以继续执行原本的进程。

三、EL3异常处理流程的优点EL3异常处理流程具有以下优点:1.优先级高:在发生严重异常情况时,操作系统会将处理器模式切换到EL3模式,以确保异常处理程序能够优先执行。

2.稳定性高:EL3异常处理程序是一段预先定义好的代码,具有较高的稳定性。

04异常的处理流程

04异常的处理流程

04异常的处理流程【太多事情要做了,这部分难度对我来说⼜很⼤,先写⼀下⼤体框架,到时候具体函数逆向分析过程给写出来】问题:1. 被调试器如何表明是否处理了异常?2. 异常处理器是什么?3. 如果异常到最后都没有被处理,那应该怎么办?1. 调试器是否处理异常的标志 调试器使⽤ WaitForDebugEvent 接收调试事件之后要使⽤ ContinueDebugEvent 来继续执⾏被调试程序。

⽽ContinueDebugEvent最后⼀个参数是标志位,如果是 DBG_EXCEPTION_NOT_HANDLE 表⽰当前系统没有处理异常,⽽如果是 DBG_CONTINUE,则表⽰处理异常完成。

因此,操作系统就可以根据这个标志位来决定⾛哪⾥ 注意:如果并没有处理异常,⽽程序继续执⾏,则⼜会触碰该异常,然后继续执⾏。

2. VEH / SEH - 异常处理器 这个我们介绍过,就是异常处理器,⼀个全局⼀个局部,这个之前介绍过就不⽐多说了。

3. 异常处理最后⼀道防线 UnhandledExceptionFilter 在Windows操作系统下,每个线程都包含如下代码。

__try{}__except(UnhandledExceptionFilter(GetExceptionInformation()){//终⽌线程//终⽌进程} UnhandledExceptionFilter中没有任何处理异常的代码,它所做的就是如果调试器⽆法处理,就终⽌进程或县城。

会⾸先调⽤ GetExceptionInformation() 判断是否存在调试器,则传给调试器去处理并等待调试结果。

如果调试成功,代码继续执⾏,否则其会终⽌进程与线程,弹出程序出错。

Windows CMD命令的错误处理与异常情况解决技巧

Windows CMD命令的错误处理与异常情况解决技巧

Windows CMD命令的错误处理与异常情况解决技巧在日常的计算机使用中,我们经常会使用到Windows命令提示符(CMD)来执行各种操作。

然而,由于各种原因,有时候我们会遇到一些错误和异常情况。

本文将分享一些Windows CMD命令的错误处理与异常情况解决技巧,帮助您更好地应对这些问题。

一、错误处理技巧1. 错误代码的解读在CMD中执行命令时,有时会出现一些错误代码。

这些错误代码可以帮助我们定位问题所在。

例如,当我们执行一个不存在的命令时,CMD会返回“不是内部或外部命令,也不是可运行的程序或批处理文件”的错误信息。

这提示我们命令不存在或者路径设置有误。

2. 重定向错误输出有时候,我们需要将错误信息输出到一个文件中以便后续分析。

可以使用">"符号将错误输出重定向到一个文本文件中。

例如,执行命令"dir c:\temp > output.txt 2>&1"会将目录"c:\temp"的内容输出到output.txt文件中,同时将错误信息也重定向到该文件中。

3. 使用错误处理命令CMD提供了一些错误处理命令,可以帮助我们处理错误情况。

例如,使用"IF ERRORLEVEL"命令可以根据错误代码进行条件判断。

这样,我们就可以根据不同的错误代码执行不同的操作,从而更好地处理错误。

二、异常情况解决技巧1. 文件路径包含空格在CMD中执行命令时,如果文件路径中包含空格,会导致命令无法正确执行。

为了解决这个问题,可以使用双引号将文件路径括起来。

例如,执行命令"cd"C:\Program Files""可以正确切换到"C:\Program Files"目录。

2. 文件名包含特殊字符有时候,文件名中可能包含一些特殊字符,如冒号、问号等。

这些特殊字符可能会导致命令无法正确执行。

Windows CMD命令中的异常处理与故障排除方法

Windows CMD命令中的异常处理与故障排除方法

Windows CMD命令中的异常处理与故障排除方法在日常使用Windows操作系统时,经常会遇到一些CMD命令执行异常或者出现故障的情况。

这些问题可能会导致我们无法正常完成任务,因此了解异常处理和故障排除方法是非常重要的。

本文将介绍一些常见的Windows CMD命令异常处理与故障排除方法,帮助读者更好地应对这些问题。

1. 命令执行失败在使用CMD命令时,有时候我们会遇到命令执行失败的情况。

这可能是由于命令输入错误、权限不足、文件路径错误等原因导致的。

首先,我们应该检查命令的拼写和语法,确保输入正确。

如果命令需要管理员权限才能执行,我们可以尝试以管理员身份运行CMD窗口,右键点击CMD图标,选择“以管理员身份运行”。

如果命令涉及到文件路径,我们需要确认路径是否正确,可以使用dir命令查看当前目录下的文件列表,以确保文件存在。

2. 命令无法找到有时候,我们可能会遇到CMD命令无法找到的情况。

这通常是由于命令不存在或者命令所在的路径没有被添加到系统环境变量中导致的。

我们可以通过以下几种方法解决这个问题:首先,我们可以尝试使用绝对路径运行命令,例如"C:\Windows\System32\ipconfig.exe"。

其次,我们可以检查系统环境变量中是否添加了命令所在路径,可以通过在CMD窗口中输入echo %PATH%命令查看环境变量的值。

如果命令所在的路径没有被添加到环境变量中,我们可以手动添加,具体步骤是:右键点击“计算机”图标,选择“属性”->“高级系统设置”->“环境变量”,在系统变量中找到“Path”,点击“编辑”,然后在弹出的窗口中添加命令所在的路径。

3. 命令执行超时有时候,我们可能会遇到CMD命令执行超时的情况。

这通常是由于命令执行时间过长或者命令执行过程中出现了死循环导致的。

为了解决这个问题,我们可以尝试使用以下方法:首先,我们可以尝试优化命令,减少执行时间。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Windows异常处理流程作者:SoBeIt出处:/articles/200412/761.html日期:2005-01-06先来说说异常和中断的区别。

中断可在任何时候发生,与CPU正在执行什么指令无关,中断主要由I/O设备、处理器时钟或定时器等硬件引发,可以被允许或取消。

而异常是由于CPU执行了某些指令引起的,可以包括存储器存取违规、除0或者特定调试指令等,内核也将系统服务视为异常。

中断和异常更底层的区别是当广义上的中断(包括异常和硬件中断)发生时如果没有设置在服务寄存器(用命令号0xb向8259-1中断控制器0x20端口读出在服务寄存器1,用0xb向8259-2中断控制器的0xa0端口读出在服务寄存器2)相关的在服务位(每个在服务寄存器有8位,共对应IRQ 0-15)则为CPU的异常,否则为硬件中断。

下面是WINDOWS2000根据INTEL x86处理器的定义,将IDT中的前几项注册为对应的异常处理程序(不同的操作系统对此的实现标准是不一样的,这里给出的和其它一些资料不一样是因为这是windows的具体实现):中断号名字原因0x0 除法错误1、DIV和IDIV指令除02、除法结果溢出0x1 调试陷阱1、EFLAG的TF位置位2、执行到调试寄存器(DR0-DR4)设置的断点3、执行INT 1指令0x2 NMI中断将CPU的NMI输入引脚置位(该异常为硬件发生非屏蔽中断而保留)0x3 断点执行INT 3指令0x4 整数溢出执行INTO指令且OF位置位0x5 BOUND边界检查错误BOUND指令比较的值在给定范围外0x6 无效操作码指令无法识别0x7 协处理器不可用1、CR0的EM位置位时执行任何协处理器指令2、协处理器工作时执行了环境切换0x8 双重异常处理异常时发生另一个异常0x9 协处理器段超限浮点指令引用内存超过段尾0xA 无效任务段任务段包含的描述符无效(windows不使用TSS进行环境切换,所以发生该异常说明有其它问题)0xB 段不存在被引用的段被换出内存0xC 堆栈错误1、被引用内存超出堆栈段限制2、加载入SS寄存器的描述符的present位置00xD 一般保护性错误所有其它异常处理例程无法处理的异常0xE 页面错误1、访问的地址未被换入内存2、访问操作违反页保护规则0x10 协处理器出错CR0的EM位置位时执行W AIT或ESCape指令0x11 对齐检查错误对齐检查开启时(EFLAG对齐位置位)访问未对齐数据其它异常还包括获取系统启动时间服务int 0x2a、用户回调int 0x2b、系统服务int 0x2e、调试服务int 0x2d等系统用来实现自己功能的部分,都是通过异常的机制,触发方式就是执行相应的int指令。

这里给出几个异常处理中重要的结构:陷阱帧TrapFrame结构(后面提到的异常帧ExceptionFrame结构其实也是一个KTRAP_FRAME结构):typedef struct _KTRAP_FRAME {ULONG DbgEbp;ULONG DbgEip;ULONG DbgArgMark;ULONG DbgArgPointer;ULONG TempSegCs;ULONG TempEsp;ULONG Dr0;ULONG Dr1;ULONG Dr2;ULONG Dr3;ULONG Dr6;ULONG Dr7;ULONG SegGs;ULONG SegEs;ULONG SegDs;ULONG Edx;ULONG Ecx;ULONG Eax;ULONG PreviousPreviousMode;PEXCEPTION_REGISTRATION_RECORD ExceptionList;ULONG SegFs;ULONG Edi;ULONG Esi;ULONG Ebx;ULONG Ebp;ULONG ErrCode;ULONG Eip;ULONG SegCs;ULONG EFlags;ULONG HardwareEsp;ULONG HardwareSegSs;ULONG V86Es;ULONG V86Ds;ULONG V86Fs;ULONG V86Gs;} KTRAP_FRAME;环境Context结构:typedef struct _CONTEXT {ULONG ContextFlags;ULONG Dr0;ULONG Dr1;ULONG Dr2;ULONG Dr3;ULONG Dr6;ULONG Dr7;FLOATING_SA VE_AREA FloatSave;ULONG SegGs;ULONG SegFs;ULONG SegEs;ULONG SegDs;ULONG Edi;ULONG Esi;ULONG Ebx;ULONG Edx;ULONG Ecx;ULONG Eax;ULONG Ebp;ULONG Eip;ULONG SegCs;ULONG EFlags;ULONG Esp;ULONG SegSs;UCHAR ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];} CONTEXT;异常记录ExceptionRecord结构:typedef struct _EXCEPTION_RECORD {NTSTATUS ExceptionCode;ULONG ExceptionFlags;struct _EXCEPTION_RECORD *ExceptionRecord;PVOID ExceptionAddress;ULONG NumberParameters;ULONG_PTRExceptionInformatio[EXCEPTION_MAXIMUM_PARAMETERS];} EXCEPTION_RECORD;当发生异常后,CPU记录当前各寄存器状态并在内核堆栈中建立陷阱帧TrapFrame,然后将控制交给对应异常的陷阱处理程序。

当陷阱处理程序能处理异常时,比如缺页时通过调页程序MmAccessFault将页换入物理内存后通过iret返回发生异常的地方。

但大多数无法处理异常,这时先是调用CommonDispatchException在内核堆栈中建立异常记录ExceptionRecord和异常帧ExceptionFrame。

ExceptionRecord很重要,它记录了异常代码、异常地址以及一些其它附加的参数。

然后调用KiDispatchException进行异常的分派。

这个函数是WINDOWS下异常处理的核心函数,负责异常的分派处理。

KiDispatchException的处理流程(每当异常被某个例程处理时处理的例程将返回TRUE 到上一个例程,未处理则返回FALSE。

当任何一个例程处理了异常返回TRUE时,则KiDispatchException正常返回):在进行用户态内核态的异常的分派前,先判断异常是否来自用户模式,是的话将Context.ContextFlags(这时候Context结构还刚初始化完,还未赋初值) or上CONEXT_FLOATING_POINT,意味着对来自用户模式的异常总是尝试分派浮点状态,这样可以允许异常处理程序或调试器检查和修改协处理器的状态。

然后从陷阱帧中取出寄存器值填入Context结构,并判断是否是断点异常(int 0x3和int 0x2d),如果是的话先将Context.Eip 减一使它指向int 0x3指令(无论是由int 0x3还是由int 0x2d引起的异常,因为前面的陷阱处理程序里已经改变过TrapFrame里面的Eip了)。

然后判断异常是发生于内核模式还是用户模式,根据不同模式而采取不同处理过程。

如果异常发生于内核模式,会给予内核调试器第一次机会和第二次机会处理异常。

当异常被处理后就将设置好陷阱帧并返回到陷阱处理程序,在那里iret返回发生异常的地方继续执行。

内核模式异常处理流程为:(第一次机会)判断KiDebugRoutine是否为空,不为空就将Context、陷阱帧、异常记录、异常帧、发生异常的模式等压入栈并将控制交给KiDebugRoutine。

|||若KiDebugRoutine为空(正常的系统这里不为空。

正常启动的系统KiDebugRoutine为KdpStub,在Boot.ini里加上/DEBUG启动的系统的KiDebugRoutine为KdpTrap。

如果这里为空的话会因为处理不了DbgPrint这类int 0x2d产生的异常而导致系统崩溃)或者KiDebugRoutine未处理异常,则将Context结构和异常记录ExceptionRecord压栈并调用内核模式的RtlDispatchException在内核堆栈中查找基于帧的异常处理例程。

|||RtlDispatchException调用RtlpGetRegistrationHead从fs:[0](0xffdff000)处获取当前线程异常处理链表指针,并调用RtlpGetStackLimits从0xffdff004和0xffdff008取出当前线程堆栈底和顶。

然后开始由异常处理链表指针遍历链表查找异常处理例程(若在XP和2003下先处理VEH再处理SEH),其实这就是SEH,只是和用户态有一点不同是既没有顶层异常处理例程(TOP LEVEL SEH)也没有默认异常处理例程。

然后对每个当前异常处理链表指针检查判断堆栈是否有效(是否超出了堆栈范围或者未对齐)及堆栈是否是DPC堆栈。

若0xffdff80c 处DpcRoutineActive为TRUE且堆栈顶和底在0xffdff81c处取出的DpcStack到DpcStack-0x3000(一个内核堆栈大小),若是则更新堆栈顶和底为DpcStack和DpcStack-0x3000并继续处理,否则将异常记录结构里的异常标志ExceptionRecord.ExceptionFlags设置EXCEPTION_STACK_INV ALID表示为无效堆栈并返回FALSE。

||||调用异常处理链表上的异常处理例程之前会在异常处理例程链表上插入一个新的节点,对应的异常处理例程是用来处理嵌套异常,也就是在处理异常时发生另一个异常。

处理后RtlDispatchException判断异常处理例程的返回值:若为ExceptionContinueExecution,若异常标志ExceptionRecord.ExceptionFlags未设置EXCEPTION_NONCONTINUABLE不可恢复执行,则返回TRUE到上一层,否则在做了一些工作后调用RtlRaiseException进入到KiDispatchException的第二次机会处理部分。

相关文档
最新文档