文章目录

  • 内容回顾:
  • 总结:
  • 程序代码
  • 实现截图
  • 具体流程

内容回顾:

当用户异常产生后,内核函数KiDispatchException并不是像处理内核异常那样在0环直接处理,而是修正3环EIP为KiUSerExceptionDispatcher函数后就结束了。
这样,当线程再次回到3环时,将会从KiUserExceptionDispatcher函数开始执行。

KiUserExceptionDispatcher会调用RtlDispatchException函数来查找并调用异常处理函数,查找的顺序:

  1. 先查全局链表:VEH
  2. 再查句柄链表:SEH


它是与线程有关的,存储在当前线程的堆栈中。

3环的FS寄存器指向TEB


下图中两个call,第一个是VEH,第二个是SEH

然后进入后查看第一批代码:

首先取出fs+8,和fs+4位置的参数

当前堆栈的界面和起始位置,利用这两个值,进行如下代码检测:

看看堆栈是否属于当前线程(也就是说异常处理函数必须位于当前线程堆栈)

继续看,fs指向Teb,fs:0指向SEH:

真正开始调用异常处理的函数如下(也就是说所写异常处理函数必须符合调用约定,不能随便写):

由内核发起调用的函数都一样,都是必须符合调用约定,写成规范形式。

总结:

  1. fs:[0]指向的是SEH链表的第一个成员
  2. SEH的异常处理函数必须在当前线程的堆栈中
  3. 只有在VEH中的处理函数不存在或者不处理才会到SEH链表中查找

程序代码

#include<Windows.h>
#include <iostream>
//0环异常处理时讲过这个结构体
/*
typedef struct _EXCEPTION_REGISTRATION_RECORD {struct _EXCEPTION_REGISTRATION_RECORD* next;PEXCEPTION_ROUTINE Handler;
};
*/
struct MyException {struct MyException* prev;DWORD handle;
};EXCEPTION_DISPOSITION _cdecl MyException_handler(struct _EXCEPTION_RECORD* ExceptionRecord,//ExceptionRecord存储异常信息,什么类型,异常产生位置void* EstablishFrame,//MyException结构体地址(指向堆栈中的结构体)struct _CONTEXT* ContextRecord,//Context结构体,存储异常发生时的各种寄存器值,堆栈位置等void* DispatcherContext
) {::MessageBoxA(NULL, "SEH异常处理函数执行了", "SEH异常", MB_OK);if (ExceptionRecord->ExceptionCode == 0xC0000094) {ContextRecord->Eip = ContextRecord->Eip + 2;// ContextRecord->Ecx=1;return ExceptionContinueExecution;}return ExceptionContinueSearch;
}int main()
{DWORD temp;//插入异常处理函数,必须在当前线程的堆栈中;MyException myException;//(只能在堆栈中创建,不能定义为全局变量)__asm {mov eax,fs:[0]mov temp,eaxlea ecx,myExceptionmov fs:[0],ecx}myException.prev = (MyException*)temp;myException.handle = (DWORD)&MyException_handler;//创造异常__asm{xor edx,edxxor ecx,ecxmov eax,0x10idiv ecx //EDX:EAX除以ECX}//摘掉异常处理函数__asm{mov eax,tempmov fs:[0],eax}printf("函数正常执行了");
}

实现截图

具体流程

 idiv ecx //EDX:EAX除以ECX

产生异常:

CPU指令检测到异常(例:除0)------>查IDT表,执行中断处理函数--------->CommonDispatchException

然后异常分发:KiDispatchException

  1. 把Trap_frame(当前线程3环进入0环时,那些寄存区环境,也就是eip运行地方那些值)备份到context里(为返回3环做准备)(也就是把3环代码eip保存,不能破坏原来的执行流程
  2. 第二步:判断先前模式,0是内核调用,1是用户调用,用户层异常呢,紧接着就是跳转
  3. 把KeUserExceptionDispatcher里面的值覆盖到Eip
  4. 回到三环的KiUserExceptionDispatcher会调用RtlDispatchException函数来查找并调用异常处理函数,查找的顺序:先查全局链表:VEH; 再查句柄链表:SEH
  5. 找到解决之后呢,调用ZwContine再次进入0环,
    主要作用就是恢复_TRAP_FRAME(也就是第一步中的EIP恢复原来执行流程)然后通过_KiServiceExit返回到3环。

在跳转CommonDispatchException之前,还传了两个参数

 if (ExceptionRecord->ExceptionCode == 0xC0000094) {ContextRecord->Eip = ContextRecord->Eip + 2;// ContextRecord->Ecx=1;return ExceptionContinueExecution;}

记住,这里的返回并非直接回到下面这行代码:

  printf("函数正常执行了");

SEH(结构化异常处理)相关推荐

  1. 异常处理第三讲,SEH(结构化异常处理),异常展开问题

    异常处理第三讲,SEH(结构化异常处理),异常展开问题 作者:IBinary 出处:http://www.cnblogs.com/iBinary/ 版权所有,欢迎保留原文链接进行转载:) 不知道昨天有 ...

  2. Win32 结构化异常处理(SEH)探秘【下篇】

    图十三 UnHandledExceptionFilter 函数的伪代码 UnhandledExceptionFilter( STRUCT _EXCEPTION_POINTERS *pException ...

  3. 深入解析结构化异常处理(SEH) - by Matt Pietrek

    目录 1.浅析SEH 2.移向更深处 3.编译器层面的SEH 4.扩展的异常处理帧 5.ShowSEHFrames程序 6.展开 7.未处理异常 8.进入地狱 9.结论 ​尽管以前写过一篇SEH相关的 ...

  4. Windows系统程序设计之结构化异常处理

    标 题: [原创]Windows系统程序设计之结构化异常处理 作 者: 北极星2003 时 间: 2006-09-20,20:21:28 链 接: http://bbs.pediy.com/showt ...

  5. windows核心编程学习笔记(八)结构化异常处理(Structured Exception Handling)

    首先要要知道,结构化异常处理(SEH)和C++提供的异常处理不相同. 一.Termination HandlersTermination Handlers使用很简单.在想使用SEH处理的地方使用 __ ...

  6. 深入探索Win32结构化异常处理

    原文:http://blog.csdn.net/diamont/article/details/4259590 Matt Pietrek 著 董岩 译 在Win32操作系统提供的所有功能中,使用最广泛 ...

  7. Windows异常世界历险记(五)——VC6中结构化异常处理机制的反汇编分析(下)

    在本系列的上一篇文章Windows异常世界历险记(四)--VC6中结构化异常处理机制的反汇编分析(中)中,给出了针对VC6的异常处理机制进行逆向后得到的伪码.在本文中,我们仍然以之前写的小程序为例,通 ...

  8. SEH结构体异常处理

    异常的主要结构体信息 一般当程序发生异常时,用户代码停止执行,并将CPU的控制权转交给操作系统,操作系统接到控制权后,将当前线程的寄存器环境保存到结构体CONTEXT中,然后查找针对此异常的处理函数 ...

  9. 什么是VB.NET的结构化异常处理

    深谈VB.NET结构化异常处理执行标准 对于VB.NET语言来说,在实际编程中有一个非常重要的操作值得我们去注意,那就关于异常方面的处理.今天我们就可以通过VB.NET结构化异常处理的相关介绍,来仔细 ...

  10. Windows内存管理(3)--检查内存可用性,结构化异常处理 和 ASSERT

    1.      检查内存可用性 在驱动程序开发中,对内存的操作要格外小心.如果某段内存是只读的,而驱动程序试图去写操作,会导致系统的崩溃. DDK提供了两个函数,帮助程序员在不知道某段内存是否可读写的 ...

最新文章

  1. 使用VS.NET2003编写存储过程
  2. 贺州学院计算机协会,2019年广西高等教育学会数学教学专业委员会年会暨学术交流会在贺州学院召开...
  3. 如何查询linux服务器的网卡,Linux服务器如何查看有没有无线网卡
  4. 华为P50系列确定29日发布:但遗憾的是...
  5. Python代码优化之in关键字
  6. 表分析oracle的作用,Oracle中分析表的作用
  7. java forkjoinpool_Java并发——Fork/Join框架与ForkJoinPool
  8. MyBatis SQL注入隐患及防范
  9. c语言科学计数法输出1_e10,北航13年机试--十进制数字的科学计数法表示的C语言实现...
  10. JavaScript字符编码
  11. 北京地铁和广州地铁之感想
  12. 软件工程导论---软件测试(集成测试、单元测试、验收测试、系统测试)
  13. 【MongoDB】使用$lookup做多表关联处理
  14. 英语语法笔记Day7——并列主从句
  15. xv6-lab2-syscall
  16. 伊拉克COR证书电子电器
  17. 转载:从软件工程师到IT猎头续:告诉你如何写简历
  18. Sia(Siacoin/SC/云储币)去中心化存储平台网址汇总
  19. colorkey唇釉是否安全_colorkey唇釉成分安全吗
  20. 古月居ros第十讲遇到的问题

热门文章

  1. 成功解决Eclipse打开py等文件出现乱码
  2. 2.1 name_scope 简单入门(一)
  3. Linux常用命令 积累
  4. 静态方法和实例化方法的区别 -转载
  5. Python学习路程day20
  6. Divide and conquer:K Best(POJ 3111)
  7. C# 3.0实现类本身的方法扩展
  8. C#几种访问修饰符理解
  9. ESP32 OTA 接口简略说明
  10. 语义分析的一些方法(中篇)