windows 结构化异常处理机制
操作系统的错误处理与异常处理技巧
操作系统的错误处理与异常处理技巧在计算机领域中,操作系统是一种关键的软件,负责管理和控制计算机硬件和软件资源,使各种应用程序能够高效地运行。
然而,由于各种原因,操作系统在运行过程中可能会遇到各种错误和异常情况。
为了保证系统的稳定性和可靠性,操作系统必须具备相应的错误处理和异常处理技巧。
本文将介绍一些常见的操作系统错误处理与异常处理技巧。
一、错误处理技巧错误处理是指操作系统如何识别、报告和解决发生的错误。
操作系统应该具备以下的错误处理技巧:1. 错误检测和诊断:操作系统需要能够及时检测到各种错误,包括硬件故障、软件错误和用户操作错误等。
一旦发现错误,操作系统应该能够准确诊断出错误的类型和原因,并报告给用户或管理员。
2. 错误恢复:当发生错误时,操作系统应该能够及时采取措施进行错误恢复,以避免系统崩溃或数据丢失。
常见的错误恢复技巧包括重新启动受影响的进程或服务、关闭异常的应用程序、回滚错误的操作等。
3. 错误日志记录:操作系统应该能够将发生的错误记录到错误日志中,以便管理员和开发人员能够及时获取错误信息并进行相应的处理。
错误日志应该包含错误类型、错误代码、错误发生的时间和地点等重要信息。
二、异常处理技巧异常处理是指操作系统如何应对各种异常情况,如访问非法内存、除零错误等。
操作系统应该具备以下的异常处理技巧:1. 异常检测和响应:操作系统需要能够及时检测到各种异常情况,并进行相应的响应。
例如,当访问非法内存时,操作系统应该能够及时检测到并终止受影响的进程,避免对系统造成更大的损害。
2. 异常处理机制:操作系统应该具备一套完善的异常处理机制,以便能够处理各种异常情况。
常见的异常处理技巧包括触发异常处理程序、中断正在执行的进程、保存现场信息等。
3. 异常恢复:当发生异常时,操作系统应该能够及时采取措施进行异常恢复,以避免系统崩溃或数据丢失。
异常恢复的技巧包括重新启动受影响的进程、回滚异常操作等。
三、错误处理与异常处理的实例为了更好地理解错误处理与异常处理技巧,以下是一些实例:1. 内存错误处理:当应用程序发生内存访问错误时,操作系统可以通过检测到异常并终止受影响的进程,避免对系统造成更大的影响。
基于Windows的C++异常处理机制研究
D o gl n , N igxa , U H n —a g WA G Q n —in wU H o i a
(n tueo f ma o n ier g If m t n E gn eigU i ri , h n z o 5 0 2 C ia I s tt f no t nE g ei , o ai n ie r nv s y Z e g h u4 0 0 , h ) i I r i n n n r o n e t n
中图分 类号 :P 2 . T 367
文献标 识 码 : A
文章编 号 :6 1— 6 3 2 1 ) 3— 3 9— 6 17 07 (00 0 0 3 0
Re e r h o ++ Ex e i n Ha dl s d o i o sa c n C c pto n i Ba e n W nd ws Ope a i n S s e ng r to y t m
基 于 Widw n o s的 +异 常处 理 机 制 研 究 C+
杜 红 亮 ,王 清 贤 ,吴 灏
( 息工程大学 信息工程学 院 , 南 郑州 400 ) 信 河 50 2
摘 要 : 先从 系统层 面和 编译 层 面分析 了 Wi o s C++异 常处 理 的基 本 原 理 , 出 了基 于 首 n w 和 d 指 Widw n o s的 C+ +异 常处 理机 制在 使用 过 程 中可 能 出现 的逻 辑错误 , 以及 Widw 运 行 时库 中 no s
K e o d e c p in;e c p in h n ln y w r s: x e to x e to a d i g; S EH ; c d e u i o e s c rt y;a d tn u ii g
异常处理机制
异常处理机制异常处理是指在程序执行过程中发生错误或异常时,如何保证程序能够继续运行而不中断的一种机制。
异常处理机制是现代编程语言和操作系统的核心特性之一,它可以帮助开发人员及时发现并处理程序中的错误,保证程序的稳定性和可靠性。
异常处理机制的基本原理是将代码分为两个部分:正常代码和异常处理代码。
正常代码是程序的主要逻辑部分,用于执行预期的操作;而异常处理代码则是用于捕获和处理异常的代码段。
当程序执行过程中出现异常时,异常处理代码会被触发执行,并根据不同的异常类型进行相应的处理。
1.异常类型定义:异常类型是指在程序执行过程中可能会出现的错误或异常情况。
不同的编程语言和操作系统提供了一系列的异常类型,用于表示不同的错误或异常情况。
开发人员可以根据需要自定义异常类型来表示特定的错误或异常。
2.异常抛出:当程序执行过程中发生错误或异常情况时,会通过抛出异常的方式将错误信息传递给上层调用者。
异常抛出会中断当前的执行流程,并将错误信息传递给上层调用者。
异常抛出的过程通常由编程语言或操作系统自动完成,开发人员只需要在适当的地方使用关键字或函数来抛出异常即可。
3. 异常捕获:异常捕获是指在程序执行过程中,通过捕获异常的方式来处理错误或异常情况。
异常捕获可以在代码中的任意位置进行,通常通过使用try-catch语句块来实现。
try语句块用于执行可能引发异常的代码,catch语句块用于捕获异常并进行处理。
4.异常处理:异常处理是指在捕获异常后,对异常进行处理的一系列操作。
异常处理的方式可以有很多种,包括打印错误信息、记录日志、重试操作等。
开发人员可以根据具体的业务需求和异常类型来选择适当的异常处理方式。
1.提高程序的可靠性和稳定性:异常处理可以帮助开发人员及时发现并处理错误,避免程序崩溃或异常退出。
通过合理地捕获和处理异常,可以确保程序能够继续运行而不中断,提高程序的可靠性和稳定性。
2.简化调试和错误定位:异常处理可以将错误信息准确地传递给上层调用者,有助于开发人员快速定位和解决问题。
safeseh 原理
safeseh 原理
Safeseh(Safe Structured Exception Handling,安全结构化异常处理)是一种在Windows操作系统中防止漏洞利用的技术。
它的原理是通过在异常处理链中引入额外的保护机制,来防止异常处理过程中发生缓冲区溢出等漏洞攻击。
Safeseh的基本原理如下:
1. Windows操作系统在处理异常时会按照一定的顺序查找可处理该异常的异常处理程序(异常处理链)。
2. Safeseh通过修改程序的异常处理链,将一个额外的异常处理程序添加到链表的开头。
3. 该额外的异常处理程序会检测异常处理链本身的有效性,以及是否存在被攻击者恶意篡改的异常处理程序。
4. 如果检测到异常处理链被恶意篡改,Safeseh会终止程序的执行,防止漏洞利用继续进行。
Safeseh的引入可以增加程序的安全性,防止一些常见的漏洞攻击,比如通过缓冲区溢出来修改异常处理链。
然而,Safeseh并不能完全消除所有的漏洞,因此仍然需要其他的安全措施来维护系统的安全。
异常处理结构
异常处理结构
异常处理结构是一种程序设计结构,用于在程序运行过程中捕捉和处理异常情况。
异常处理结构通常包括以下几个部分:
1. try块:在try块中编写可能引发异常的代码。
如果在try块中引发了异常,那么该块后面的代码将不再执行,而是转到异常处理块。
2. except块:在except块中编写处理异常的代码。
当try块中的代码引发异常时,异常会被传递到except块中,然后在该块中进行处理。
一个try块可以对应多个except块,用于处理不同类型的异常。
3. finally块:在finally块中编写不管是否发生异常都需要执行的代码。
finally块中的代码会在try块和except块执行完毕后执行,并且无论是否发生异常都会执行。
4. raise语句:在代码中使用raise语句可以手动引发异常。
可以使用raise语句来主动触发异常,然后在except块中捕获并处理该异常。
异常处理结构能够有效地处理程序运行过程中可能出现的异常情况,提高程序的健壮性和稳定性。
通过合理使用异常处理结构,可以在程序出现异常时及时处理和恢复,以保证程序的正常运行。
操作系统的中断处理与异常处理机制
操作系统的中断处理与异常处理机制在计算机系统中,操作系统是一个管理和协调系统资源的软件,中断处理和异常处理是操作系统的核心功能之一。
中断处理和异常处理机制使得操作系统能够及时响应硬件设备或软件程序的请求,并采取相应的措施进行处理,保证系统的稳定性和可靠性。
本文将详细介绍操作系统的中断处理与异常处理机制。
一、中断处理机制中断是指在计算机系统运行过程中,某个硬件设备或者软件程序发出的一种请求,通过打断正常的程序执行流程,通知操作系统去处理该请求。
中断可以分为硬件中断和软件中断两类。
1. 硬件中断硬件中断是由硬件设备发生的一种中断事件,比如外设设备的输入输出操作,时钟中断等。
当硬件设备发生中断事件后,会向处理器发送一个中断信号,处理器暂停当前的执行任务,保存当前的上下文信息,并转入中断处理程序来处理中断事件。
中断处理程序会根据中断类型来执行相应的操作,比如读取输入设备的数据,将数据写入输出设备等。
处理完中断事件后,处理器会恢复之前被中断的任务继续执行。
2. 软件中断软件中断是由软件程序主动触发的一种中断事件,也称为系统调用。
软件中断通常由用户态程序调用系统库函数来完成,通过系统调用指令将自己的执行权限转交给操作系统,由操作系统代为执行相应的操作。
常见的软件中断包括文件读写操作、进程创建与销毁等系统调用。
中断处理机制的优点在于能够及时响应外部设备和软件程序的请求,提高了系统的实时性和处理能力。
同时,使用中断处理机制可以实现很多复杂的功能,比如多任务处理、设备驱动程序等。
二、异常处理机制异常是指在程序执行过程中出现的一种非正常情况,例如非法指令、除数为零等。
异常处理机制能够捕捉这些异常事件并进行相应的处理。
异常处理机制主要分为硬件异常和软件异常两类。
1. 硬件异常硬件异常指的是由硬件设备产生的异常事件,如页错误、越界访问等。
当硬件设备检测到异常事件后,会向处理器发送一个异常信号,处理器会中断当前任务的执行,并把当前的上下文信息保存起来,然后转入异常处理程序去处理异常事件。
系统异常处理机制
系统异常处理机制
摘要:
1.系统异常处理机制的概念和重要性
2.系统异常的分类
3.常见的系统异常处理方法
4.我国在系统异常处理方面的实践与挑战
5.结论与展望
正文:
系统异常处理机制是指在计算机系统运行过程中,对出现的异常情况进行识别、记录、处理和恢复的一系列技术手段和策略。
这一机制在保障系统稳定运行、提高系统可用性和安全性等方面具有至关重要的作用。
系统异常可以分为两大类:软异常和硬异常。
软异常是由于程序逻辑错误、数据不合法等因素导致的异常,通常可以通过修改程序或数据来解决。
硬异常则是由于硬件故障、网络故障等外部原因导致的异常,这类异常往往需要通过系统监控和备份等手段来尽量避免或减轻影响。
针对不同类型的系统异常,有多种处理方法。
对于软异常,可以通过代码审查、测试和日志记录等手段来发现和修复问题。
对于硬异常,可以采用冗余设计、负载均衡、数据备份和恢复等技术来提高系统的容错能力和可用性。
此外,还有许多专门针对系统异常处理的软件工具和框架,如调试器、异常处理库等,可以帮助开发者更方便地处理各种异常情况。
我国在系统异常处理方面取得了显著的成就,但仍然面临一些挑战。
首
先,随着互联网技术的飞速发展,系统规模和复杂度不断上升,对系统异常处理技术提出了更高的要求。
其次,我国在某些关键技术上与国际先进水平仍有一定差距,需要加大研发投入和人才培养力度。
最后,针对不同领域的系统异常处理,缺乏统一的规范和标准,导致实践中存在一定程度的混乱和低效。
总之,系统异常处理机制是计算机系统设计和运行中不可或缺的一环。
Windows异常处理流程
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指令。
she结构化异常的基本概念以及异常处理的基本过程
she结构化异常的基本概念以及异常处理的基本过程结构化异常(Structured Exception)是一种在计算机程序编程中用于处理异常情况的机制。
异常是在程序运行过程中出现的错误或意外情况,可能导致程序中断或产生不可预料的结果。
为了更好地管理和处理异常情况,程序员可以使用结构化异常来捕获和处理这些异常。
在程序中,结构化异常通常由以下几个要素组成:1.触发异常的事件:触发异常的事件可能是由于用户操作、环境变化或程序错误等引起的。
这样的事件会导致程序执行流程意外中断或出错,称为异常事件。
2.异常处理器:异常处理器是为了处理异常事件而编写的特定代码块。
在异常事件发生后,异常处理器会捕获并处理这些异常,例如显示错误信息、记录日志、再尝试或回滚操作等。
3.异常类型:异常类型通常由程序开发者定义,用于区分不同的异常事件。
常见的异常类型包括系统错误、输入/输出错误、空指针错误、算术错误等。
每种异常类型都有特定的处理方式和异常处理器。
基本的异常处理过程如下:1.异常抛出:当程序中发生异常事件时,程序会抛出相应的异常对象。
异常对象会携带异常事件的信息,包括异常类型、错误代码、错误消息等。
2.异常捕获:在程序中,可以使用异常处理器来捕获被抛出的异常。
异常处理器通常位于可能发生异常的代码块中,并根据异常类型进行匹配,找到与之对应的异常处理器。
3.异常处理:一旦异常被捕获,相应的异常处理器会开始执行处理逻辑。
处理逻辑可以包括输出错误信息、回滚操作、重新尝试等,具体取决于程序设计者的需求。
4.异常传递:如果在当前代码块中没有合适的异常处理器,异常会被传递给调用该代码块的上一层,继续寻找适合的异常处理器。
这个过程持续进行,直到异常被捕获或者传递到最顶层,程序终止。
结构化异常的基本概念和异常处理的基本过程为程序员提供了一种机制来统一管理和处理异常情况。
它使得程序能够更加健壮和可靠,减少错误对程序执行流程的干扰,提高程序的可维护性和用户体验。
脱壳基础知识入门
脱壳基础知识入门现在加解密发展己形成2个分支了,一个就是传统的算法,另一个就是加密壳。
越来越多的软件采用了密码学相关算法,现在要做出一个软件注册机己不象前几年那么容易,这就要求解密者必须要有一定的数学功底和密码学知识,而这些在短时间内是不容易掌握的。
除了密码学的应用,越来越多的软件加壳了,因此要求解密者必须掌握一些脱壳技术,这就使得壳成了解密必须迈过的一个门槛。
壳发展到今天,强度越来越高了,将许多人挡在门外,使得大家望壳兴叹。
另外,论坛现在两极分化比较严重,高手讨论的脱壳技术新手看不懂,很多人想学脱壳,但看到壳这么难,只好放弃了,造成新手与高手间一个断档,为了鼓励更多新人加入脱壳的行列,很有必要将壳有关知识总结一下。
主页提供的教学确实有点过时了,己到非更新不可了。
相对于密码学算法,脱壳并不难,只要肯花时间,短期内还是比较容易取得成绩的。
第一课 PE格式要想学脱壳,第一步就得掌握PE格式,PE是Portable Executable File Format(可移植的执行体)简写,它是目前Windows平台上的主流可执行文件格式。
Microsoft Visual C++提供的WINNT.H里有PE数据结构的完整定义。
推荐文档:ah007翻译的“PE文件格式”1.9版qduwg翻译的PE文件格式Iczelion's 的PE文件格式PE结构各字段偏移参考学习PE格式的方法是自己先准备一个十六进制工具,如HexWorkshop,WinHex,用这些工具打开一个EXE文件对照着学。
强烈推荐你用Stud_PE v.2.2.0.5这款工具辅助学习PE格式。
PE格式学习的重点是在输入表(Import Table)这块。
Stud_PE工具界面:PE结构图:第二课 SEH技术结构化异常处理(Structured Exception Handling,SEH)是Windows操作系统处理程序错误或异常的技术。
SEH是Windows操作系统的一种系统机制,与特定的程序设计语言无关。
数据结构中的异常处理与容错机制
数据结构中的异常处理与容错机制在数据结构中,异常处理和容错机制是非常重要的概念。
异常处理是指在程序运行时发生错误或异常情况时,如何进行适当的处理,以确保程序的稳定性和可靠性。
容错机制是指在面对错误和异常情况时,如何保证程序能够继续正常运行或者如何进行相应的补救措施。
1. 异常处理的基本概念和原则异常处理是一种对程序异常情况进行捕获和处理的机制。
在处理异常时,我们可以使用一些预先定义好的异常类来表示不同的异常情况,并在程序中使用try-catch语句来捕获和处理这些异常。
异常处理的基本原则包括:1.1 异常的分类和层次在数据结构中,异常可以分为不同的类型,如输入错误、内存溢出、空指针引用等。
这些异常一般都继承自异常类的层次结构,形成了一个异常类的分类体系。
1.2 异常处理的机制在程序中,使用try-catch语句块来捕获和处理异常。
try块用于执行可能会引发异常的代码,catch块用于捕获并处理异常。
当异常发生时,程序会从try块跳转到catch块,并执行相应的异常处理代码。
1.3 异常处理的优先级在捕获和处理异常时,异常类的继承关系决定了异常处理的优先级。
如果在catch块中定义了多个异常的处理方式,Java会先匹配最具体的异常类型,然后逐级向上匹配,直到找到合适的处理代码为止。
2. 常见的异常处理策略在数据结构中,我们通常会使用以下几种常见的异常处理策略来提高程序的稳定性和可靠性。
2.1 异常信息的记录与输出当程序发生异常时,及时记录异常信息并输出是非常重要的。
我们可以使用日志记录工具,如Log4j或日志类库来记录异常信息,并在控制台或日志文件中输出这些信息。
这样可以帮助我们更好地了解异常产生的原因,以便更好地进行处理和修复。
2.2 异常的传播与追踪在程序中,异常不仅可以在本地进行处理,还可以将异常传递给调用者进行处理。
通过异常的传播和追踪,可以更好地定位异常发生的位置和原因,并根据需要进行相应的处理措施。
脱壳基础知识入门
脱壳基础知识入门现在加解密发展己形成2个分支了,一个就是传统的算法,另一个就是加密壳。
越来越多的软件采用了密码学相关算法,现在要做出一个软件注册机己不象前几年那么容易,这就要求解密者必须要有一定的数学功底和密码学知识,而这些在短时间内是不容易掌握的。
除了密码学的应用,越来越多的软件加壳了,因此要求解密者必须掌握一些脱壳技术,这就使得壳成了解密必须迈过的一个门槛。
壳发展到今天,强度越来越高了,将许多人挡在门外,使得大家望壳兴叹。
另外,论坛现在两极分化比较严重,高手讨论的脱壳技术新手看不懂,很多人想学脱壳,但看到壳这么难,只好放弃了,造成新手与高手间一个断档,为了鼓励更多新人加入脱壳的行列,很有必要将壳有关知识总结一下。
主页提供的教学确实有点过时了,己到非更新不可了。
相对于密码学算法,脱壳并不难,只要肯花时间,短期内还是比较容易取得成绩的。
第一课PE格式要想学脱壳,第一步就得掌握PE格式,PE是Portable Executable File Format(可移植的执行体)简写,它是目前Windows平台上的主流可执行文件格式。
Microsoft Visual C++提供的WINNT.H里有PE数据结构的完整定义。
推荐文档:ah007翻译的“PE文件格式”1.9版qduwg翻译的PE文件格式Iczelion's的PE文件格式PE结构各字段偏移参考学习PE格式的方法是自己先准备一个十六进制工具,如HexWorkshop,WinHex,用这些工具打开一个EXE文件对照着学。
强烈推荐你用Stud_PE v.2.2.0.5这款工具辅助学习PE格式。
PE格式学习的重点是在输入表(Import Table)这块。
Stud_PE工具界面:PE结构图:第二课SEH技术结构化异常处理(Structured Exception Handling,SEH)是Windows操作系统处理程序错误或异常的技术。
SEH是Windows操作系统的一种系统机制,与特定的程序设计语言无关。
SEH结构化异常处理
异常处理程序未安装异常
总结词
异常处理程序未安装异常发生在程序试图使用未安装的异常处理程序时。
详细描述
例如,当程序试图使用一个未注册的异常处理函数来处理异常时,就会触发异常处理程 序未安装异常。
03
SEH异常处理过程
异常捕获
异常捕获
在程序运行过程中,当发生异常时,系统会 触发异常捕获机制,将异常信息记录下来, 并传递给异常处理程序。
访问违规异常
总结词
当程序试图访问一个不允许访问的内存区域时,会发生访问违规异常。
详细描述
例如,当程序试图读取一个只写的内存区域,或者写入一个只读的内存区域时,就会触发访问违规异 常。
整数异常
总结词
整数异常通常发生在整数运算过程中, 当结果超出了整数类型的表示范围时。
VS
详细描述
例如,当两个非常大的整数相加,结果超 过了整数类型的最大值时,就会触发整数 异常。
程序稳定性增强
异常处理机制完善
SEH结构化异常处理提供了完善的异常处理 机制,能够有效地捕获和处理运行时错误, 避免程序崩溃或不可预测的行为。
资源释放和清理
在SEH结构化异常处理中,finally块可以确 保在异常发生后正确释放资源并进行清理工
作,有助于提高程序的稳定性和可靠性。
05
SEH结构化异常处理的注意
02
异常处理程序的调用应尽可能靠近异常发生的源头, 以提高异常处理的效率和准确性。
03
在调用异常处理程序时,应提供足够的上下文信息, 以便更好地理解和处理异常。
异常处理程序的返回值
异常处理程序应根据需要返回适当的值,以便在异常发生后能够正确地恢复程序的 执行。
如果异常处理程序需要返回错误码或状态信息,应确保返回值的含义清晰明确,避 免歧义和误解。
SEH+in+ASM研究
SEH in ASM研究第一部分基础篇PART I 简单接触一、SEH背景知识SEH("Structured Exception Handling"),即结构化异常处理.是(windows)操作系统提供给程序设计者的强有力的处理程序错误或异常的武器.在VISUAL C++中你或许已经熟悉了_try{} _finally{} 和_try{} _except {} 结构,这些并不是编译程序本身所固有的,本质上只不过是对windows内在提供的结构化异常处理的包装,不用这些高级语言编译器所提供的包装,照样可以利用系统提供的强大seh处理功能,在后面你将可以看到,用系统本身提供seh结构和规则以及ASM语言,我们将对SEH的机制以及实现进行一番(深入?)探究.使用windows的人对microsoft设计的非法操作对话框一定不会陌生,尤其是在9X下.这表示发生了一个错误,如果是应用程序的错误,那么windows可能要关闭应用程序,如果是系统错误,你很可能不得不reset以重新启动计算机.从程序编写的角度来看,这种异常产生的原因很多,诸如堆栈溢出,非法指令,对windows保护内存的读写权限不够等等.幸运的是windows通过she机制给了应用程序一个机会来修补错误,事实上windows内部也广泛采用seh来除错.让我们先来看看如果一个应用程序发生错误后windows是怎么处理的.程序发生异常时系统的处理顺序(most by Jeremy Gordon):1.因为有很多种异常,系统首先判断异常是否应发送给目标程序的异常处理例程,如果决定应该发送,并且目标程序正处于被调试状态,则系统挂起程序并向调试器发送EXCEPTION_DEBUG_EVENT消息.剩下的事情就由调试器全权负责.如果系统级调试器存在,对于int 1,int 3这样的异常在faults on时一般是会选择处理的,因而如果你的异常处理程序由他们来进入,则不会得到执行,呵呵,这不是正好可以用来探测调试器的存在吗?2.如果你的程序没有被调试或者调试器未能处理异常(/错误),系统就会继续查找你是否安装了线程相关的异常处理例程,如果你安装了线程相关的异常处理例程,系统就把异常发送给你程序的线程相关的seh处理例程,交由其处理.3.每个线程相关的异常处理例程可以处理或者不处理这个异常,如果他不处理并且安装了多个线程相关的异常处理例程,可交由链起来的其他例程处理.4.如果这些例程均选择不处理异常,如果程序处于被调试状态,操作系统仍会再次挂起程序通知debugger.5.如果程序未处于被调试状态或者debugger没有能够处理,并且你调用SetUnhandledExceptionFilter安装了final型异常处理例程的话,系统转向对它的调用.6.如果你没有安装最后异常处理例程或者他没有处理这个异常,系统会调用默认的系统处理程序,通常显示一个对话框, 你可以选择关闭或者最后将其附加到调试器上的调试按钮.如果没有调试器能被附加于其上或者调试器也处理不了,系统就调用ExitProcess终结程序.7.不过在终结之前,系统仍然对发生异常的线程异常处理句柄来一次展开,这是线程异常处理例程最后清理的机会.以上大致描述了异常/错误发生时系统的逻辑处理顺序,如果你看了一头雾水的话,别着急,化点时间慢慢理解或者进入下一部分实例操作.作几个例子后你也许就会慢慢理解了.你要有一个最基本的观念就是She只不过是系统在终结你应用程序之前给你的一个最后处理错误的机会,从程序设计的角度来说就是给你自己设计的一个回调函数执行的机会.二.初步实战演习:你在自己程序里可以设计两种异常处理例程,一种是通过SetUnhandledExceptionFilter API设置的,姑且称之为final型的,他是进程相关的,也就是说在线程相关的异常处理部分不能处理的异常才会到达final处理例程.另外一种是线程相关的,他一般用来监视处理进程中某个线程的异常情况.他比较灵活,可选择监视线程中的某一小段代码.姑且称之为thread型的.下面看看如何设计一个最简单的异常处理程序.挂接异常处理例程:I. final型的异常处理对于final型的,在你的异常未能得到调试器以及线程相关处理例程处理操作系统在即将关闭程序之前会回调的例程,这个例程是进程相关的而不是线程相关的,因此无论是哪个线程发生异常未能被处理,都会调用这个例程.见下面的例子1:;==========================================; ex. 1,by Hume,2001 演示final型异常处理;==========================================.586p.model flat, stdcalloption casemap :none ; case sensitiveinclude c:\hd\hd.h ;头部包含文件include c:\hd\mac.h ;常用宏,自己维护一个吧;;--------------.dataszCap db "By Hume[AfO],2001...",0szMsgOK db "OK,the exceptoin was handled by final handler!",0szMsgERR1 db "It would never Get here!",0.code_start:push offset Final_Handlercall SetUnhandledExceptionFilter;调用SetUnhandledExceptionFilter来安装final SEH;原型很简单SetUnhandledExceptionFilter proto;pTopLevelExceptionFilter:DWORDxor ecx,ecxmov eax,200cdqdiv ecx ;除0错误;以下永远不会被执行invoke MessageBox,0,addr szMsgERR1,addr szCap,30h+1000hinvoke ExitProcess,0 ;30h=MB_ICONEXCLAMA TION;1000h=MB_SYSTEMMODAL;-----------------------------------------Final_Handler:invoke MessageBox,0,addr szMsgOK,addr szCap,30hmov eax,EXCEPTION_EXECUTE_HANDLER;==1 这时不出现非法操作的讨厌对话框;mov eax,EXCEPTION_CONTINUE_SEARCH;==0 出现,这时是调用系统默认的异常;处理过程,程序被终结了;mov eax,EXCEPTION_CONTINUE_EXECUTION;==-1 不断出现对话框,你将陷入死循环,可;别怪我ret 4end _start简单来解释几句,windows根据你的异常处理程序的返回值来决定如何进一步处理EXCEPTION_EXECUTE_HANDLER equ 1 表示我已经处理了异常,可以优雅地结束了EXCEPTION_CONTINUE_SEARCH equ 0 表示我不处理,其他人来吧,于是windows调用默认的处理程序,显示一个除错对话框,并结束EXCEPTION_CONTINUE_EXECUTION equ -1 表示错误已经被修复,请从异常发生处继续执行你可以试着让程序返回0和-1然后编译程序,就会理解我所有苍白无力的语言...II.线程相关的异常处理.通常每个线程初始化准备好运行时fs指向一个TIB结构(THREAD INFORMA TION BLOCK),这个结构的第一个元素fs:[0]指向一个_EXCEPTION_REGISTRA TION结构,具体结构见下,后面_EXCEPTION_REGISTRATION为了简化,用ERR来代替这个结构...不要说没见过啊... fs:[0]->_EXCEPTION_REGISTRATION strucprev dd ? ;前一个_EXCEPTION_REGISTRATION结构handler dd ? ;异常处理例程入口....呵呵,现在明白该怎么作了吧_EXCEPTION_REGISTRATION ends我们可以建立一个ERR结构然后将fs:[0]换成指向他的指针,当然最常用的是堆栈,如果你非要用静态内存区也可以,把handler域换成你的程序入口,就可以在发生异常时调用你的代码了,好马上实践一下,见例子2;===========================================; ex. 2,by Hume,2001 线程相关的异常处理;===========================================.386.model flat, stdcalloption casemap :none ; case sensitiveinclude hd.h;;============================.dataszCap db "By Hume[AfO],2001...",0szMsgOK db "It's now in the Per_Thread handler!",0szMsgERR1 db "It would never Get here!",0.code_start:ASSUME FS:NOTHING ;否则Masm编译报错push offset perThread_Handlerpush fs:[0]mov fs:[0],esp ;建立SEH的基本ERR结构,如果;不明白,就仔细研究一下前面所述xor ecx,ecxmov eax,200cdqdiv ecx;以下永远不会被执行invoke MessageBox,0,addr szMsgERR1,addr szCap,10h+1000hpop fs:[0] ;清除seh链表add esp,4invoke ExitProcess,0;============================perThread_Handler:invoke MessageBox,NULL,addr szMsgOK,addr szCap, 40h+1000hmov eax,1 ;ExceptionContinueSearch,不处理,由其他例程或系统处理;mov eax,0 ;ExceptionContinueExecution,表示已经修复CONTEXT,可;从异常发生处继续执行ret ;这里如果返回0,你会陷入死循环,不断跳出对话框....end _start嘿嘿,这个简单吧,我们由于没有足够的资料,暂时还不能修复ecx的值使之从异常发生处继续执行,只是简单显示一个MSG,然后让系统处理,自然跳出讨厌的对话框了....注意化5分钟研究和final返回值的含义不同...windows也是根据返回值来决定下一步的动作的.好像到此为止,我们并没有从异常处理中得到任何好处,除了在异常发生后可以执行一点我们微不足道的代码,事实上SEH可以修复这些异常或者干我们想干的任何事情然后从希望的地方继续执行,嘿嘿,很爽吧,可惜我们没有足够的信息,那里找到我们所需要的信息?PART II 继续深入三、传递给异常处理例程的参数I、传递给final型的参数,只有一个即指向EXCEPTION_POINTERS结构的指针, EXCEPTION_POINTERS定义如下:EXCEPTION_POINTERS STRUCTpExceptionRecord DWORD ?ContextRecord DWORD ?EXCEPTION_POINTERS ENDS执行时堆栈结构如下:esp -> ptEXCEPTION_POINTERS然后执行call _Final_Handler注意堆栈中的参数是指向EXCEPTION_POINTERS 的指针,而不是指向pExceptionRecord的指针以下是EXCEPTION_POINTERS两个成员的详细结构EXCEPTION_RECORD STRUCTExceptionCode DWORD ? ;异常码ExceptionFlags DWORD ? ;异常标志PExceptionRecord DWORD ? ;指向另外一个EXCEPTION_RECORD的指针ExceptionAddress DWORD ? ;异常发生的地址NumberParameters DWORD ? ;下面ExceptionInformation所含有的dword数目ExceptionInformation DWORD EXCEPTION_MAXIMUM_PARAMETERS dup(?) EXCEPTION_RECORD ENDS ;EXCEPTION_MAXIMUM_PARAMETERS ==15;================具体参数解释======================================== ExceptionCode 异常类型,SDK里面有很多类型,但你最可能遇到的几种类型如下:C0000005h----读写内存冲突C0000094h----非法除0C00000FDh----堆栈溢出或者说越界80000001h----由Virtual Alloc建立起来的属性页冲突C0000025h----不可持续异常,程序无法恢复执行,异常处理例程不应处理这个异常C0000026h----在异常处理过程中系统使用的代码,如果系统从某个例程莫名奇妙的返回,则出现此代码,例如调用RtlUnwind时没有Exception Record参数时产生的异常填入的就是这个代码80000003h----调试时因代码中int3中断80000004h----处于被单步调试状态注:也可以自己定义异常代码,遵循如下规则:_____________________________________________________________________+位: 31~30 29~28 27~16 15~0_____________________________________________________________________+含义: 严重程度29位功能代码异常代码0==成功0==Mcrosoft MICROSOFT定义用户定义1==通知1==客户2==警告28位3==错误被保留必须为0ExceptionFlags 异常标志0----可修复异常1----不可修复异常2----正在展开,不要试图修复什么,需要的话,释放必要的资源pExceptionRecord 如果程序本身导致异常,指向那个异常结构ExceptionAddress 发生异常的eip地址ExceptionInformation 附加消息,在调用RaiseException可指定或者在异常号为C0000005h即内存异常时(ExceptionCode=C0000005h) 的含义如下,其他情况下一般没有意义第一个dword 0==读冲突1==写冲突第二个dword 读写冲突地址;==========CONTEXT具体结构含义================================ CONTEXT STRUCT ; _ContextFlags DWORD ? ; |--------------- +00iDr0 DWORD ? ; | +04iDr1 DWORD ? ; | +08iDr2 DWORD ? ; >调试寄存器+0CiDr3 DWORD ? ; | +10iDr6 DWORD ? ; | +14iDr7 DWORD ? ; _| +18FloatSave FLOATING_SA VE_AREA <> ;浮点寄存器区+1C~~+88regGs DWORD ? ;--| +8CregFs DWORD ? ; |\段寄存器+90regEs DWORD ? ; |/ +94regDs DWORD ? ;--| +98regEdi DWORD ? ;____________ +9CregEsi DWORD ? ; | 通用+A0regEbx DWORD ? ; | 寄+A4regEdx DWORD ? ; | 存+A8regEcx DWORD ? ; | 器+ACregEax DWORD ? ;_______|___组_ +B0regEbp DWORD ? ;++++++++++++++++ +B4regEip DWORD ? ; |控制+B8regCs DWORD ? ; |寄存+BCregFlag DWORD ? ; |器组+C0regEsp DWORD ? ; | +C4regSs DWORD ? ;+++++++++++++++++ +C8ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)CONTEXT ENDS以上是两个成员的详细结构,下面给出一个final型的例子,这也是本文所讨论的最后一个final 型的例子,以后的例子集中在thread类型上.;--------------------------------------------; Ex3,演示final处理句柄的参数获取,加深前面; 参数传递的介绍理解如果难于理解请先看partIII; 再回来看这个例子;--------------------------------------------.586.model flat, stdcalloption casemap :none ; case sensitiveinclude hd.hinclude mac.h;;--------------.datasztit db "exceptION MeSs,by hume[AfO]",0fmt db "Context eip--> %8X ebx--> %8X ",0dh,0ahdb "Flags Ex.c-> %8x flg--> %8X",0szbuf db 200 dup(0);;-----------------------------------------.CODE_Start:assume fs:nothingpush offset _final_xHandler0call SetUnhandledExceptionFilterxor ebx,ebxmov eax,200cdqdiv ebxinvoke MessageBox,0,ddd("Good,divide overflow was solved!"),addr sztit,40h xor eax,eaxmov [eax],ebxinvoke ExitProcess,0;-----------------------------------------_final_xHandler0:push ebpmov ebp,espmov eax,[ebp+8] ;the pointer to EXCEPTION_POINTERSmov esi,[eax] ;pointer to _EXCEPTION_RECORDmov edi,[eax+4] ;pointer to _CONTEXTtest dword ptr[esi+4],1jnz @_final_cnotdotest dword ptr[esi+4],6jnz @_final_unwind;call dispMsgcmp dword ptr[esi],0c0000094hjnz @_final_cnotdomov dword ptr [edi+0a4h],10call dispMsgmov eax,EXCEPTION_CONTINUE_EXECUTION ;GO ONjmp @f@_final_unwind:invoke MessageBox,0,CTEXT("state:In final unwind..."),addr sztit,0;好像不论处理不处理异常,都不会被调用,right?@_final_cnotdo:mov eax,EXCEPTION_CONTINUE_SEARCHjmp @f@@:mov esp,ebppop ebpret;-----------------------------------------dispMsg proc ;My lame proc to display some messagepushadmov eax,[esi]mov ebx,[esi+4]mov ecx,[edi+0b8h]mov edx,[edi+0a4h]invoke wsprintf,addr szbuf,addr fmt,ecx,edx,eax,ebxinvoke MessageBox,0,addr szbuf,CTEXT("related Mess of context"),0popadretdispMsg endpEND _Start;;------------------------------------------------II、传递给per_thread型异常处理程序的参数,如下:在堆栈中形成如下结构esp -> *EXCEPTION_RECORDesp+4 -> *ERR ;注意这也就是fs:[0]的指向esp -> *CONTEXT record ;point to registersesp -> *Param ;呵呵,没有啥意义然后执行call _Per_Thread_xHandler操作系统调用handler的MASM原型是这样invokexHANDLER,*EXCEPTION_RECORD,*_EXCEPTION_REGISTRA TION,*CONTEXT,*Param 即编译后代码如下:PUSH *Param ;通常不重要,没有什么意义push *CONTEXT record ;上面的结构push *ERR ;the struc abovepush *EXCEPTION_RECORD ;see aboveCALL HANDLERADD ESP,10h下一部分给出thread类型的具体实例.PART III 不是终结我们的目标是分三步走,学会SEH,现在让我们接触最有趣的部分:SEH的应用.seh设计的最初目的就是为了使应用程序运行得更健壮,因此SEH用于除错,避免应用程序和系统的崩溃是最常见的用途.例如:1.比如你的程序里出现了除0错,那你就可以在你的seh处理程序中将除数改为非零值,per_Thread seh返回0(ExceptionContinueExecution)、final返回-1 (EXCEPTION_CONTINUE_EXECUTION),系统就会根据你的意图用改变过的context加载程序在异常处继续执行,由于被除数已经改变为非零值,你的程序就可以正常仿佛什么也没有发生的继续执行了.2.seh还可以处理内存读写异常,如果你分配的堆栈空间不够,产生溢出,这时你就可以处理这个异常,再多分配一些空间,然后结果是你的程序照常运行了,就好像什么也没有发生过,这在提高内存运用效率方面很值得借鉴,虽然会降低一些程序的执行效率.另外,在很多加壳或反跟踪软件中,利用vitualAlloc和VitualProtect制造异常来进入异常程序,或仅仅是用,mov [0],XXX来进入异常程序,要比用int3或者int1或pushfand [esp],100hpopf进入要隐蔽得多,如果可以随机引起这些异常的话,效果会更好...当然应用很多了,感兴趣自己去找.话题似乎有点远了,让我们回到最基础的地方.前面的例子中你可能已经注意到,假如我们改变了Context的内容,(注意啊,context包含了系统运行时各个重要的寄存器),并且返回0(ExceptionContinueExecution-->perThread SEH),或者-1(EXCEPTION_CONTINUE_EXECUTION,final SEH),就表示要系统已现有的context继续执行程序,当然我们的改变被重载了,就像周星驰的月光宝盒改变了历史一样奇妙,程序就会以改变的context内容去执行程序,通过这种手段,我们可以修复程序,使其继续执行.看下面的例子4.读之前,先再罗嗦几句,由于前面介绍了seh例程被调用的时候,系统把相关信息已经压入堆栈,所以我们只要在程序里寻址调用就行了,怎么寻址呢???唉....回顾一下call指令执行的基本知识,一般对于近调用,通过[esp+4]即刻找到*EXCEPTION_RECORD,其余的不用说了吧,如果执行了push ebp;mov ebp,esp的话,就是[ebp+8]指向*EXCEPTION_RECORD,这也是大多数程序用的和我们最常见到的,明白了吗?不明白?我--去--跳--楼.;________________________________________________________________________;|EX.4 By hume,2001,to show the basic simple seh function;|________________________________________________________________________.386.model flat, stdcalloption casemap :none ; case sensitiveinclude hd.h ;//相关的头文件,你自己维护一个吧.dataszCap db "By Hume[AfO],2001...",0szMsgOK db "It's now in the Per_Thread handler!",0szMsg1 db "In normal,It would never Get here!",0fmt db "%s ",0dh,0ah," 除法的商是:%d",0buff db 200 dup(0).code_start:Assume FS:NOTHINGpush offset perThread_Handlerpush fs:[0]mov fs:[0],esp ;//建立SEH的基本ERR结构,如果不;//明白,就仔细研究一下吧xor ecx,ecxmov eax,200cdqdiv ecxWouldBeOmit: ;//正常情况以下永远不会被执行add eax,100 ;//这里不会执行,因为我们改变了eip的值ExecuteHere:div ecx ;//从这里开始执行,从结果可以看到invoke wsprintf,addr buff,addr fmt,addr szMsg1,eaxinvoke MessageBox,NULL,addr buff,addr szCap,40h+1000hpop fs:[0] ;//修复后显示20,因为我们让ecx=10add esp,4invoke ExitProcess,NULLperThread_Handler proc \uses ebx pExcept:DWORD,pFrame:DWORD,pContext:DWORD,pDispatch:DWORDmov eax,pContextAssume eax:ptr CONTEXTmov [eax].regEcx,20 ;//Ecx改变lea ebx, ExecuteHeremov [eax].regEip,ebx ;//从我们想要的地方开始执行,嘿嘿,这就是很多;//反跟踪软件把你引向的黑暗之域mov eax,0 ;//ExceptionContinueExecution,表示已经修复;//CONTEXT,可从异常发生处;//reload并继续执行retperThread_Handler endpend _start;//====================================================哈哈,从这个例子里我门可以真正看到seh结构化处理的威力,他不仅恢复了ecx的内容而且使程序按照你想要的顺序执行了,哈哈,如果你对反跟踪很感兴趣的话,你还可以在例程中加入xor ebx,ebxmov [eax].iDr0,ebxmov [eax].iDr2,ebxmov [eax].iDr3,ebxmov [eax].iDr4,ebx清除断点,跟踪者....嘿嘿,不说你也体验过,当然也可以通过检验drx的值来判断是否被跟踪,更复杂地,你可以设置dr6,和dr7产生一些有趣的结果,我就不罗嗦了.上面的例子理解了吧,因为我用的是MASM提供的优势来简化程序,老Tasm Fans可能会不以为然,你可以试一下下面的代码代替,是TASM,MASM compatibale的perThread_Handler:push ebpmov ebp,espmov eax,[ebp+10h] ;取context的指针mov [eax+0ach],20 ;将ecx=0,可以对照前面的例程和context结构lea ebx, ExecuteHeremov [eax+0b8h],ebx ;eip== offset ExecuteHere,呵呵xor eax,eaxmov esp,ebppop ebpret这是raw asm的,不过masm既然给我们设计了这么多好东西,我们为什么不好好利用呢? 好,到现在为止,基本知识已经结束了,我们应该可理解seh的相关文章和写简单的seh处理程序了,但关于seh还只是刚刚开始,很多内容和应用还没有涉及到,请继续看提高篇.第二部分提高篇PART IV 关于异常处理的嵌套和堆栈展开在实际程序设计过程中,不可能只有一个异常处理例程,这就产生了异常处理程序嵌套的问题,可能很多处理例程分别监视若干子程序并处理其中某种异常,另外一个监视所有子程序可能产生的共性异常,这作起来实际很容易,也方便调试.你只要依次建立异常处理框架就可以了.关于VC++异常处理可以嵌套很多人可能比较熟悉,用起来更容易不过实现比这里也就复杂得多,在VC++中一个程序所有异常只指向一个相同的处理句例程,然后在这个处理例程里再实现对各个子异常处理例程的调用,他的大致方法是建立一个子异常处理例程入口的数组表,然后根据指针来调用子处理例程,过程比较烦琐,原来打算大致写一点,现在发现自己对C/C++了解实在太少,各位有兴趣还是自己参考MSDN Matt Pietrek 1996年写的一篇文章<<A Crash Course on the Depths of Win32? Structured Exception Handling>>,里面有非常详细的说明,对于系统的实现细节也有所讨论,不过相信很多人都没有兴趣.hmmm...:)实际上Kernel的异常处理过程和VC++的很相似.我们的程序中当然也可以采用这种方法,不过一般应用中不必牛刀砍蚂蚁.有异常嵌套就涉及到我们可能以前经常看到并且被一些污七八糟的不负责任的”翻译家”搞得头晕脑涨不知为何的”异常展开”的问题,也许你注意到了如果按照我前面的例子包括final 都不处理异常的话,最后系统在终结程序之前会来一次展开,在试验之后发现,展开不会调用final只是对per_thread例程展开(right?).什么是堆栈展开?为什么要进行堆栈展开?如何进行堆栈展开?我曾经为堆栈展开迷惑过,原因是各种资料的描述很不一致,Matt Pietrek说展开后前面的ERR结构被释放,并且好像seh链上后面的处理例程如果决定处理异常必须对前面的例程来一次展开,很多C/C++讲述异常处理的书也如斯说这使人很迷惑,我们再来看看Jeremy Gordon的描述,堆栈展开是处理异常的例程自愿进行的.呵呵,究竟事实如何?在迷惑好久之后我终于找到了答案:Matt Pietrek讲的没有错,那是VC++以及系统kernel的处理方法,Jeremy Gordon说的也是正确的,那是我门asm Fans的自由!好了,现在来说堆栈展开,堆栈展开这个词似乎会使人有所误解,堆栈怎么展开呢?事实上,堆栈展开是异常处理例程在决定处理某个异常的时候给前面不处理这个异常的处理例程的一个清洗的机会,前面拒绝处理这个异常的例程可以释放必要的句柄对象或者释放堆栈或者干点别的工作...那完全是你的自由,叫stack unwind似乎有点牵强.堆栈展开有一个重要的标志就是EXCEPTION_RECORD.ExceptionFlag为2,表示正在展开,你可以进行相应的处理工作,但实际上经常用的是6这是因为还有一个UNWIND_EXIT equ 4什么的,具体含义未知,不过kernel确实就是检测这个值,因此我们也就检测这个值来判断展开.注意在自己的异常处理例程中,unwind不是自动的,必须你自己自觉地引发,如果所有例程都不处理系统最后的展开是注定的. 当然如果没有必要你也可以选择不展开.win32提供了一个api RtlUnwind来引发展开,如果你想展开一下,就调用这个api吧,少候讲述自己代码如何展开RtlUnwind调用描述如下:PUSH Return value ;返回值,一般不用PUSH pExceptionRecord ;指向EXCEPTION_RECORD的指针PUSH OFFSET CodeLabel ;展开后从哪里执行PUSH LastStackFrame ;展开到哪个处理例程终止返回,通常是处理异常的Err结构CALL RtlUnwind调用这个api之前要注意保护ebx,esi和edi,否则...嘿嘿MASM格式如下:InvokeRtlUnwind,pFrame,OFFSET return_code_Address,pExceptionRecord,Return_value这样在展开的时候,就以pExceptionRecord.flag=2 依次调用前面的异常处理例程,到决定异常的处理例程停止,Jeremy Gordon手动展开代码和我下面的例子有所不同.他描述最后决定处理异常的ERR结构的prev成员为-1,好像我的结果和他的有所差异,因此采用了另外的方法,具体看下面的例子.最后一点要注意在嵌套异常处理程序的时候要注意保存寄存器,否则你经常会得到系统异常代码为C00000027h的异常调用,原因是异常处理中又产生异常,而这个异常又无法解决,只好由操作系统终结你的程序.一下给出一点垃圾代码演示可能有助于理解,注意link的时候要加入/section:.text,RWE 否则例子里面的代码段不能写,SMC功能会产生异常以致整个程序不能进行.注意:2K/XP下非法指令异常的代码不一致,另外用下面的例子在2K下不能工作,具体错误未知.因此只能在9X下演示,为了在2k/Xp下也能运行我加了点代码,有兴趣看看,另外帮我解决一下2K/Xp下SMC的问题?thx!下面例子很烂,不过MASM格式写起来容易一点,也便于理解.看来比较长实际很简单,耐心看下去.;-----------------------------------------;Ex5,演示堆栈展开和异常嵌套处理by Hume,2002;humewen@;;-----------------------------------------.586.model flat, stdcalloption casemap :none ; case sensitiveinclude hd.hinclude mac.h;;--------------per_xHandler1 proto C :DWORD,:DWORD,:DWORD,:DWORDper_xHandler2 proto C :DWORD,:DWORD,:DWORD,:DWORDper_xHandler3 proto C :DWORD,:DWORD,:DWORD,:DWORD;-----------------------------------------.datasztit db "except Mess,by hume[AfO]",0count dd 0,0Expt1_frm dd 0 ;ERR结构指针,用于堆栈展开手动代码Expt2_frm dd 0Expt3_frm dd 0;;-----------------------------------------.CODE_Start:assume fs:nothingpush offset per_xHandler3push fs:[0]mov fs:[0],espmov Expt3_frm,esppush offset per_xHandler2push fs:[0]mov fs:[0],espmov Expt2_frm,esppush offset per_xHandler1push fs:[0]mov fs:[0],espmov Expt1_frm,esp;--------------------------;install xhnadler;-----------------------------------------xor ebx,ebxmov eax,200cdqdiv ebx ;除法错误invoke MessageBox,0,ddd("Good,divide overflow was solved!"),addr sztit,40hsub eax,eaxmov [eax],ebx ;内存写错误succ:invoke MessageBox,0,ddd("Good,memory write violation solved!"),addr sztit,40hdb 0F0h,0Fh,0C7h,0C8h ;什么cmpchg8b指令的非法形式?我从来没有成功过!!;演示程序中使用seh实现SMC技术,加密??...invoke MessageBox,0,ddd("illeagal instruction was solved!"),addr sztit,20h;--------------------------;uninstall xhnadler;-----------------------------------------pop fs:[0]add esp,4pop fs:[0]add esp,4;或者add esp,10hpop fs:[0]add esp,4invoke ExitProcess,0;-----------------------------------------;异常处理句柄1,处理除法异常错误per_xHandler1 PROC C pExcept:DWORD,pFrame:DWORD,pContext:DWORD,pDispatch:DWORDpushadMOV ESI,pExceptASSUME ESI:PTR EXCEPTION_RECORDTEST [ESI].ExceptionFlags,1JNZ @cantdo1TEST [ESI].ExceptionFlags,6JNZ @unwind1CMP [ESI].ExceptionCode,0C0000094hJNZ @cantdo1MOV EDI,pContextASSUME EDI:PTR CONTEXTm2m [edi].regEbx,20 ;将ebx置20,修复除法错误,继续执行popadMOV EAX, ExceptionContinueExecutionRET@unwind1:invoke MessageBox,0,CTEXT("state: unwinding in xhandler1..."),addr sztit,0@cantdo1:popadMOV EAX,ExceptionContinueSearchRETper_xHandler1 ENDP;-----------------------------------------;异常处理句柄2,处理内存写错误,扩展可以有其他的例子如自动扩充堆栈per_xHandler2 PROC C pExcept:DWORD,pFrame:DWORD,pContext:DWORD,pDispatch:DWORDpushadMOV ESI,pExceptASSUME ESI:PTR EXCEPTION_RECORDMOV EDI,pContextASSUME EDI:PTR CONTEXTcall Dispcont ;显示一点lame的消息,自己调试用TEST [ESI].ExceptionFlags,1JNZ @cantdo2TEST [ESI].ExceptionFlags,6JNZ @unwind2CMP [ESI].ExceptionCode,0C0000005hJNZ @cantdo2.data ;ASM的数据定义灵活性,如果需要这是可以的validAddress dd 0.codem2m [EDI].regEax,<offset validAddress> ;置eax为有效地址popadMOV EAX, ExceptionContinueExecutionRET@unwind2:invoke MessageBox,0,CTEXT("hmmm... unwinding in xhandler2..."),addr sztit,40h@cantdo2:popadMOV EAX,ExceptionContinueSearchRETper_xHandler2 ENDP;-----------------------------------------per_xHandler3 PROC C pExcept:DWORD,pFrame:DWORD,pContext:DWORD,pDispatch:DWORDpushadMOV ESI,pExceptASSUME ESI:PTR EXCEPTION_RECORDMOV EDI,pContextASSUME EDI:PTR CONTEXTTEST [ESI].ExceptionFlags,1JNZ @cantdo3TEST [ESI].ExceptionFlags,6JNZ @unwind3;-----------------------------------------push ecxmov ecx,csxor cl,cljecxz win2k_Xpwin9X:pop ecxCMP [ESI].ExceptionCode,0C000001DH ;非法指令异常,与2K/XP下的不一致JNZ @cantdo3jmp ok_herewin2k_Xp:pop ecx ;注意,只有在9X下才可以CMP [ESI].ExceptionCode,0C000001EH ;非法指令异常->2K/XPJNZ @cantdo3 ;sMc不成mov [edi].regEip,offset safereturnpopadmov eax,0retpush ebxpush esipush edicomment $ 调用RtlUnwind展开堆栈lea ebx,unwindbackinvoke RtlUnwind,Expt3_frm,ebx,esi,0$mov dword ptr [esi+4],2 ;置展开标志,准备展开,这里是;手动代码mov ebx,fs:[0]selfun:;mov eax,Expt2_frm ;这里显示了ASM手动展开的灵活性mov eax,Expt3_frmcmp ebx,eax ;按照Jeremy Gordon的好像不大对头;cmp dword ptr [ebx],-1 ;这样好像有问题,只好如上,请教答案jz unwindbackpush ebxpush esi ; 压入Err和Exeption_registration结构call dword ptr[ebx+4]add esp,8mov ebx,[ebx]jmp selfununwindback:invoke MessageBox,0,CTEXT("I am Back!"),addr sztit,40hpop edipop esipop ebx ;一定要保存这三个寄存器!MOV EAX,[EDI].regEipMOV DWORD PTR[EAX],90909090H ;改为nop指令...SMC? 很简单吧;SMC注意连接/section:RWEpopadMOV EAX, ExceptionContinueExecutionRET@unwind3:invoke MessageBox,0,CTEXT("Note... unwinding in xhandler3..."),addr sztit,40h @cantdo3:popadMOV EAX,ExceptionContinueSearchRETper_xHandler3 ENDP;-----------------------------------------;lame routine for debugDispcont procinc countcall dispMsgretDispcont endpdispMsg proclocal szbuf[200]:bytepushadmov eax,dword ptr[esi]mov ebx,dword ptr[esi+4]mov ecx,dword ptr[edi+0b8h]mov edx,dword ptr[edi+0a4h].datafmt db "Context eip--> %8X ebx--> %8X ",0dh,0ahdb "Flags Ex.c-> %8x flg--> %8X",0dh,0ahdb "it's the %d times xhandler was called!",0.codeinvoke wsprintf,addr szbuf,addr fmt,ecx,edx,eax,ebx,countinvoke MessageBox,0,addr szbuf,CTEXT("related Mess of context"),0popadretdispMsg endp;;------------------------------------------------END _Start;------------------下面是我在本文里用到到的宏,我的mac.h比较长,就不贴了-----ddd MACRO Text ;define data in .data sectionlocal name ;This and other can be used as: ddd("My god!").data ;isn't cool?name db Text,0.codeEXITM <addr name>ENDMCTEXT MACRO y:V ARARG ;This is a good macroLOCAL symCONST segmentIFIDNI <y>,<>sym db 0ELSEsym db y,0ENDIFCONST endsEXITM <OFFSET sym>ENDMm2m MACRO M1, M2 ;mov is too boring sometimes!push M2pop M1ENDM;-----------------------------------------BTW:够长了吧,基本内容介绍完毕,更多内容下一部分介绍一点利用Seh的tricks,哪位大侠有什么好的想法或者有什么错误,请不吝指正,毕竟我是菜鸟...PART V 利用SEH进入ring0以及单步自跟踪的实现--SEH的简单应用实在太累了,这将是最后一部分.一、ring0!并不遥远...作为seh的一个有趣的应用是进入ring0,ring0意味着更多的权利,意味着你可以进行一些其他ring3级应用程序不能进行的操作,譬如改自己的代码段(在不修改段属性的前提下),改系统数据(病毒?)等等,在9X下进入ring0的方法很多,在NT下困难的多,SEH只是其中较简单的一种.打开调试器看看系统kernel的工作状态,在9X下cs一般是28h,ds,ss等通常是30h,因此只要我们的cs和ss等在异常处理程序中被赋予上述ring0选择子值,进入ring0就可以实现.可能我们需要执行较复杂的操作,在ring0下一般不能直接调用常用api,当然VxD,WDM等提供的系统服务是另外一种选择. 否则,这在用下述简单方法进入ring0后执行会产生错误,因此,我们在ring0下尽快完成需要完成的任务,然后迅速返回ring3.在ring0下要完成如下任务:1.取CR3的值,返回ring3显示.在ring3下不可以读取cr3的值.你可以打开kernel调试器看看例子程序取到的值是否正确.2.修改代码段后面的jmp ****代码,这在通常情况下只会导致保护错误.而在ring0下是可以的,就像在前面例子中用she实现SMC的效果是一样的,最后显示几个MsgBox,证明我们曾经到达过ring0这个例子是参考owl的那个nasm写的例子用masm改写,并增加ring0下SMC的代码部分以作演示.另外代码中iretd指令并不是简单实现跳转,而是实现从ring0切回ring3的功能,在变换代码特权级的同时,堆栈的也要变换到ring3.可能原例子ljtt前辈的中文注释容易引起初学者的误解.别的不说,我发现进入ring0后修改代码段可以使trw的跟踪崩溃...hmmm,好消息?代码如下: 其中用的一些宏在Ex5中已经贴了,就不再重复.;-----------------------------------------;Ex6,演示利用seh进入ring0! by Hume,2002;humewen@;;-----------------------------------------.586.model flat, stdcalloption casemap :none ; case sensitiveinclude hd.hinclude mac.h;;--------------ring0_xHandler proto C :DWORD,:DWORD,:DWORD,:DWORD.dataszbuf db 100 dup (0)count dd 0;;-----------------------------------------.CODE_Start:assume fs:nothingpush offset ring0_xHandlerpush fs:[0]mov fs:[0],esp;--------------------mov ecx,dstest ecx,100bjz NT_2K_XP ;NT/2K/XP has no LDTpushfdmov eax,esp。
“结构化异常处理相制”在实际开发中的应用
in
a t io n
Ha
n
dlin g Me c h a
n
is
m
);
r e
:
向量 化 异 常 处 理 机 制
Ex
c e
(V e c t o
d
j
e x c e
r
y
p tio n
Ha
n
dl i n g
Me
c
ha
n
is
m
)
。
f 从
pt
(
Ex
c e
p t io n
F ilt e
r
)
{
, 产生 /
“
W in
个缺少 稳定性 和 可 靠性 的
“
(O ) :其 含 义 是 告 诉 操 作 系 统
理 这 个异常
,
,
我不想处
软件产 品是不 可 能在市场 上 获得 成 功
的 可 以 通 过 给程 序 引 入 结 构 化 异 常 处
。
数据类 型 越界
、
由操 作 系统 继 续 查 找 异 常
E X E CUT
或 数组 下 标 越 界
。
件 质 量 的基 础 又 主 要 是 由稳 定 性 和 可 靠
。
用 中会 经 常 遇 到 的 异 常 (而 不 是 全 部 ) : 非 法 内存 访 问 (如 野 指 针 :未 初 始 化 的指 针 或 无 效 地 址 )
、
E X C E P T I O N C O N rr IN U E
—
SE A R CH
XP
开 始新 增 的特 性 )
{
,异 常处 理 代 码 f 当 出现 异 常 后 /
SEH(结构化异常处理)
整理ppt
12
__ try和__ finally关键字用来标出 结束处理程序两段代码的轮廓。在上面
的代码段中,操作系统和编译程序共同 来确保结束处理程序中的__ finally代码 块能够被执行,不管保护体(__try块) 是如何退出的。不论你在保护体中用 return,还是goto,或者是longjump, 结束处理程序(__finally块)都将被调 用。
• 顺序执行到__finally块区域内的代码,这种 情况很简单,容易理解
• goto语句或return语句引发的程序控制流离 开当前__try块作用域时,系统自动完成对 __finally块代码的调用
• 由于在__try块中出现异常时,导致程序控 制流离开当前__try块作用域,这种情况下 也是由系统自动完成对__finally块的调用
整理ppt
10
SEH实际包含两个主要功能:
• 结束处理( termination handling )
• 异常处理( exception handling )
整理ppt
11
结束处理
一个结束处理程序能够确保去调用和执行一个代 码块(结束处理程序,termination handler),而不 管另外一段代码(保护体,guarded body)是如何退 出的。结束处理程序的文法结构(使用微软的Visual C++编译程序)如下:
// 注意,下面return语句直接让函数返
回了 return;
由此可见:
} __finally {
不管在何种情况下,在离 开当前的作用域__finally
puts("__finally块中"); } puts("world");
系统异常处理机制
系统异常处理机制系统异常处理机制是指在软件开发中,为了应对系统运行过程中可能出现的各种异常情况,而设计的一套处理流程和机制。
异常是指在系统运行过程中发生的、不符合预期的事件或错误,这些异常可能是因为错误的用户输入、系统资源不足、网络故障、硬件故障等原因引起的。
异常处理机制的设计可以提高系统的稳定性和可靠性,有效地避免程序崩溃和数据丢失。
下面是一些相关参考内容,供大家参考和学习。
1. 异常处理原则:- 高内聚低耦合原则:将异常的捕获和处理放在尽可能接近产生异常的地方,减少代码的侵入性,降低模块间的耦合度。
- 提供友好的错误提示:向用户提供明确的错误提示信息,让用户能够理解和解决问题。
2. 异常处理流程:- 异常抛出:在需要处理异常的代码块中,通过throw关键字抛出异常对象。
- 异常捕获:在上层代码中使用try-catch语句块来捕获异常。
catch块中的代码会处理异常,并可以抛出新的异常。
- 异常处理:在catch块中,使用合适的日志记录、错误处理、资源释放等方式来处理异常。
3. 异常分类:- 可查异常(Checked Exceptions):在编译期间必须进行处理的异常,比如IOException、SQLException等。
通常需要使用try-catch语句块来捕获和处理这些异常。
- 运行时异常(Runtime Exceptions):不需要在编译期间指定捕获的异常,比如NullPointerException、ArrayIndexOutOfBoundsException等。
通常是由于程序逻辑错误或数据错误引起的,应该避免出现此类异常。
4. 异常处理策略:- 异常日志记录:将异常信息写入日志文件,便于分析和排查问题。
- 异常回滚:当异常发生时,将系统恢复到异常发生之前的状态,避免数据的不一致性。
- 重试机制:对于可恢复的异常,可以进行自动重试操作,直到达到重试次数限制。
- 容错操作:通过提供默认值、忽略错误、降级处理等方式,对错误进行容错,保证系统的可用性。
计算机化系统异常事件管理标准操作流程
计算机化系统异常事件管理标准操作流程1.异常事件发生后,立即通知相关部门负责人。
After the abnormal event occurs, immediately notify the relevant department head.2.负责人接到通知后,立即召集相关人员组成应急处理小组。
After the person in charge receives the notification, immediately convene the relevant personnel to form an emergency response team.3.应急处理小组成员到达现场后,首先进行安全评估和风险分析。
Upon arrival at the site, the emergency response team members first conduct a safety assessment and risk analysis.4.根据评估结果,采取必要的安全措施,确保人员和设备安全。
Based on the assessment results, necessary safety measures are taken to ensure the safety of personnel and equipment.5.同时,对系统进行初步排查,寻找可能的故障点。
At the same time, a preliminary inspection of the system is carried out to identify possible points of failure.6.如果发现明显的故障点,立即按照标准操作程序处理。
If obvious points of failure are found, the standard operating procedures are immediately followed.7.如果需要额外的技术支持或设备,负责人可立即向上级领导提出申请。
嵌套异常的循环
嵌套异常的循环真是个不可思议的巧合。
仅隔⼏天,我就要解决两个与嵌套异常处理程序有关的问题。
具体来说,导致堆栈溢出的嵌套异常的⽆限循环。
这是⼀个⾮常致命的组合。
堆栈溢出对于调试来说是⼀个极其严重的错误;嵌套异常意味着异常处理程序遇到了⼀个异常,这是不可能的;更糟糕的是,堆栈损坏也在幕后发⽣。
请继续阅读以了解诊断嵌套异常的技巧,以及⾸先可能导致这些异常的原因。
案例1:VC异常过滤器中的读取错误客户机有多个转储⽂件供我查看,它们都显⽰了⼀个⾮常疯狂的模式。
应⽤程序中会发⽣异常,这是完全可以预料和处理的异常。
但是,它不会被正常处理,⽽是会导致⽆限的嵌套异常级联,最终导致进程崩溃,出现堆栈溢出。
为了简洁起见,这⾥有⼀个简短的图⽚:0:000> kcn 10000... <repeated hundreds more times>19e9 <Unloaded_Helper.dll>19ea NestedExceptions1!exception_filter19eb NestedExceptions1!trigger_exception19ec MSVCR120D!_EH4_CallFilterFunc19ed MSVCR120D!_except_handler4_common19ee NestedExceptions1!_except_handler419ef ntdll!ExecuteHandler219f0 ntdll!ExecuteHandler19f1 ntdll!KiUserExceptionDispatcher19f2 <Unloaded_Helper.dll>19f3 NestedExceptions1!exception_filter19f4 NestedExceptions1!trigger_exception19f5 MSVCR120D!_EH4_CallFilterFunc19f6 MSVCR120D!_except_handler4_common19f7 NestedExceptions1!_except_handler419f8 ntdll!ExecuteHandler219f9 ntdll!ExecuteHandler19fa ntdll!KiUserExceptionDispatcher19fb <Unloaded_Helper.dll>19fc NestedExceptions1!exception_filter19fd NestedExceptions1!trigger_exception19fe MSVCR120D!_EH4_CallFilterFunc19ff MSVCR120D!_except_handler4_common1a00 NestedExceptions1!_except_handler41a01 ntdll!ExecuteHandler21a02 ntdll!ExecuteHandler1a03 ntdll!KiUserExceptionDispatcher1a04 NestedExceptions1!trigger_exception1a05 NestedExceptions1!main1a06 NestedExceptions1!__tmainCRTStartup1a07 NestedExceptions1!mainCRTStartup1a08 kernel32!BaseThreadInitThunk1a09 ntdll!__RtlUserThreadStart1a0a ntdll!_RtlUserThreadStart在前⾯的调⽤堆栈中,很明显exception_filter试图调⽤卸载的DLL(Helper.DLL)中的函数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Common Errors & Approaches to Error Checking
• Common Errors
– Failure of new to allocate requested memory – Array index out of bounds – Division by zero – Function received invalid parameters
• Software-generated exception
– INT n instruction generates an exception with an exception number (n) as an operand
Interrupts vs Exceptions
– Interrupt (device generated)
• Error handling should be used for
– processing exceptional situations – processing exceptions for components that cannot handle them directly – processing exceptions for widely used components (libraries, classes, functions) that should not process their own exceptions – large projects that require uniform error processing
•
Language level.
• • • Type conversion; illegal values, improper casts. Bounds violations; illegal array indices. Bad references; null pointers.
•
Program level.
–
–
TLB miss, page fault, protection
divide by zero, invalid opcode, misaligned access
Illegal operations
–
Trap
• Return to the next instruction (after the trapping instruction)
• User defined exceptions.
What:
• Interrupts • Exception • Interrupts vs Exception
Interrupts
• Interrupts
– Forced transfer of control to a procedure (handler) due to external events (interrupts) or due to an erroneous condition (exceptions)
– Procedure
• When an interrupt is received or an exception condition detection, the current task is suspended and transfer automatically goes to a handler • After the handler is complete, the interrupted task resumes without loss of continuity, unless recovery is not possible or the interrupt causes the currently running task to be terminated.
• Severe errors or malfunctions • Abort handlers are designed to collect diagnostic information about the processor’s state and then perform a graceful system shutdown • Examples: bit error (parity error), inconsistent or illegal values in system tables
– – – – The try, catch, and throw Statements Unhandled C++ Exceptions When to use exception handle Good Programming Style with C++ Exceptions
• Mechanism • Performance
• Interrupt handling mechanism
– Allows interrupts/exceptions to be handled transparently to the executing process (application programs and operating system)
– Non-maskable interrupt (NMI)
• Cannot be disabled by program • Received on the processor’s NMI# input pin
– Software interrupt
• Generated by INT n instruction – INT instruction can be used to generate an interrupt or an exception by using a vector number as an operand • Viewed as an implicit call to interrupt handler of interrupt vector n • No mechanism for masking interrupts
Exception
– Abort
• Suspend the process at an unpredictable location
– Does not report the precise location of the instruction causing the exception e program
– For a JMP instruction, the next instruction should point to the target of the JMP instruction
• •
Reported immediately following the execution of the trapping instruction Examples: breakpoint, debug, overflow
Agenda
•2013 •2
Where:
Exceptions can occur at many levels:
•
Hardware/operating system level.
• • Arithmetic exceptions; divide by 0, under/overflow. Memory access violations; segfault, stack over/underflow.
• Approaches to Error Checking
– Ignore the possibility – Handle the error where it occurs
•2013 •1
Easy to observe the error handling code
When Exception Handling Should Be Used
– Exceptions
• Processor-detected
– Faults – correctable (restartable); e.g. page fault – Traps – no reexecution needed; e.g. breakpoint – Aborts – severe error; process usually terminated (by signal)
Exception
• Exception Classification (processor-generated)
– Fault
• • • • Return to the faulting instruction Reported during the execution of the faulting instruction Virtual memory faults
• Maskable: device-generated, associated with IRQs (interrupt request lines); may be temporarily disabled (still pending) • Nonmaskable: some critical hardware failures
Exception in windows
How:
• C++ Exception Handling • Structure Exception Handling
•2013 •1
C++ Exception
• Common Errors & Approaches to Error Checking • Use Exception handle
Introduction of Exception Handling in windows