windows的异常处理机制SEH

前言: 操作系统或 程序在运行时 难免会遇到各种各样 操作系统或程序在运行时,难免会遇到各种各样的错误,如除0、非法内存访问、文件打开错误、内存不足、读写错误、外设操作失败等。

为了保证系统在遇到错误时不至于崩溃 仍能够 为了保证系统在遇到错误时不至于崩溃,仍能够健壮稳定地继续运行去,Windows会对运行在其中的程序提供一次补救的机会来处理错误,这种机制就是异常处理机制。在这里插入图片描述

OS 的异常处理方法:

1. 正常运行时的异常处理方法

进程运行过程中发生异常,OS会委托进程处理。若进程代码中存在异常处理
代码,则顺利处理相关异常,程序继续运行。若没有SEH,OS启动默认异常处
理机制,终止进程运行。

2. 调试器运行时的异常处理方法

若被调试进程内部发生异常,OS首先把异常抛给调试进程处理;调试器拥有
被调试进程的所有权限,不仅可以运行、终止被调试程序,还拥有被调试进程
的虚拟内存、寄存器的读写权限。当被调试进程发生异常时,调试器会暂停运
行,必须采取相应的措施处理异常,然后再继续调试。

遇到异常时调试器经常采用的几种处理方法:

a) 直接修改异常:代码、寄存器、内存。
b) 将异常抛给被调试程序处理:若被调试程序内部存在SEH能够处理异常,
则由被调试进程自行处理。
c) 若调试器和被调试进程均无法处理当前异常,则OS默认的异常处理机制会
处理,终止被调试进程,同时结束调试。

在这里插入图片描述

OS对异常的定义

在这里插入图片描述
5种具有代表性的异常
‹ 非法访问异常
‹断点异常
‹非法指令异常
‹除零异常
‹单步执行异常

在这里插入图片描述

  • 断点异常
    在运行代码中设置断点后,CPU尝试执行该地址处的指令时,将发生断点异常。调试器就是利用该异常实现断点功能。
    设置断点命令对应的汇编指令是?int 3
    对应的机器指令是?0xCC 这里的断点是软件断点还是硬件断点? 软件断点

在这里插入图片描述

  • 单步执行异常

将标志寄存器的TF(陷阱标志)位设置为1后,CPU会进入单步工作模式。之后每执行一条指令就会引发单步执行异常,暂停运行。

结构化异常处理的基本概念 (Structure Exception Handler)

介绍: SEH是由EXCEPTION_REGISTRATION_RECORD结构体组成的链表,存放在栈中。每个SEH结构包含两个成员:zNext是指向下一个结构体的指针,4字节; zHandler是异常处理函数句柄,4字节。

注意: 若next=FFFFFFFF,表示它是SEH链表的最后一个节点

TEB(线程环境块):

TEB指的是线程环境块,该结构体包含所运行线程的各种信息。TEB结构体的第一个成员为_NT_TIB结构体

TEB 与 SEH的关系:

TEB指向第一个SEH
在这里插入图片描述

TEB结构体的第一个成员_NT_TIB!如下:
在这里插入图片描述

异常处理函数的定义

介绍: 异常处理函数有4个输入参数,分别保存与异常相关的信息;
异常处理函数的返回值为EXCEPTION_DISPOSITION
异常处理函数由系统调用,是一个回调函数,系统调用时会给出4个输入参数

异常处理函数结构:
在这里插入图片描述

1.异常处理函数的第一个参数是指向EXCEPTION_RECORD结构体的指针
在这里插入图片描述2.异常处理函数的第三个参数是指向CONTEXT结构体的指针;

在这里插入图片描述

  • CONTEXT结构体用来备份CPU寄存器的值;

  • 多线程环境下,每个线程内部都有一个CONTEXT结构体,当CPU暂时离开当前线程去运行其他线程时,寄存器的值就会保存在当前线程的CONTEXT结构体;„

  • CPU再次运行该线程时,会将保存在CONTEXT 结构体中的值覆盖 结构体中的值覆盖 CPU寄存器,并从之前暂停的代码处继续执行,确保多线程环境下安全运行各个线程。

异常处 异常处 异常处 函数的返回值:

异常处理函数的返回值:EXCEPTION_DISPOSITION

0:异常处理函数返回后,系统将线程环境设置为_Context结构保存的数据,
并继续执行程序
1:异常处理函数拒绝处理该异常,抛给下一个异常处理函数
2:异常处理函数在执行过程中又发生了新的异常,即嵌套的异常
3:发生了嵌套的展开操作

结构化异常处理总结:

1)S.E.H结构体存放在栈中。
2)当线程初始化时,会自动向栈中安装一个S.E.H,作为线程默认的异常处理。
3)如果程序源代码中使用了__try{}__except{}或者 Assert宏等异常处理机制,编译器将通过向当前函数栈帧中安装 译器将通过向当前函数栈帧中安装 一个SEH S.E.H实现异常处理。
4)栈中一般会同时存在多个S.E.H。
5)栈中的多个S.E.H通过链表指针在栈内由栈顶向栈底串成单向链表,位于链表
最顶端的S.E.H通过 T.E.B(线程环境块)0字节偏移处的指针标识。
6)当异常发生时,操作系统会中断程序,并首先从T.E.B的0字节偏移处取出距离栈顶最近的S.E.H,使用异常处理函数句柄所指向的代码来处理异常。
7)当离“事故现场”最近的异常处理函数运行失败时,将顺着S.E.H链表依次尝
试其他的异常处理函数。
8)如果程序安装的所有异常处理函数都不能处理,系统将采用默认的异常处理函数。通常,这个函数会弹出一个对话框,然后强制关闭程序。

利用S.E.H 来进行攻击:

  • S.E.H就是在系统关闭程序之前,给程序一个执行预先设定的回调函数的机会。那么,这样就会存在一个问题:

    首先,S.E.H存放在栈内,我们学过的栈溢出/缓冲区漏洞可能会派上用场。
    其次,可以精心制造出溢出数据来把S.E.H的异常处理的函数地址替换为
    shellcode的起始地址。
    再次,溢出后,错误的栈帧或堆块数据往往会触发异常。
    最后,当Windows Windows开始处理溢出后的异常时 会调用什么呢? 开始处理溢出后的异常时,会调用什么呢? 就是就是shellcode,它会把shellcode当作异常函数来处理异常。
  • 以上就是利用S.E.H来进行攻击的思路。
    在这里插入图片描述
原创文章 45 获赞 7 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41814777/article/details/102575595