( windows 提供的异常处理机制实际上只是一个简单的框架,一般情况下开发人员都不会直接用到。我们通常所用的异常处理(比如 C++ 的 throw、try、catch)都是编译器在系统提供的异常处理机制上进行加工了的增强版本。这里先抛开增强版的不提,主要叙述原始版本。)

0x01  系统如何找到异常链表

结构化异常处理是以线程为基础的。线程的内核数据结构体现是 _ETHREAD,从它开始进入,通过windbg,找到所关注的异常链表(win7 x86):


查看 _KTHREAD结构(dt _KTHREAD):

查看TEB:

查看TIB:

_NT_TIB 的第一个域成员 ExceptionList 就是异常链表头。

但是系统不是这么一步一步找的,而是借助 FS 寄存器来加速寻找。先来说说系统对 FS 的使用。
在应用层,FS 寄存器“指向”当前执行线程的 _TEB 结构体。在内核层,FS 寄存器“指向”另一个跟 CPU 相关的结构体:_KPCR,来看看它的结构,

与 _TEB 一样,它的第一个域成员也是 _NT_TIB,只不过此时是 nt!_NT_TIB,而在应用层是 ntdll!_NT_TIB,但它们的结构是一样的。

这样,不论在应用层还是在内核层,系统都可以使用 FS:[0] 找到异常链表。

0x02  异常处理相关的结构

(1)_EXCEPTION_REGISTRATION_RECORD

    typedef struct _EXCEPTION_REGISTRATION_RECORD {
struct _EXCEPTION_REGISTRATION_RECORD *Next;
PEXCEPTION_ROUTINE Handler;
} EXCEPTION_REGISTRATION_RECORD;

 EXCEPTION_REGISTRATION_RECORD 结构就是登记信息。数据成员:
  1. EXCEPTION_REGISTRATION_RECORD::Next 域指向下一个 EXCEPTION_REGISTRATION_RECORD,由此构成一个异常登记信息(从字面上说,应该叫做“异常注册记录”更恰当)链表。链表中的最后一个结点会将 Next 置为 EXCEPTION_CHAIN_END,表示链表到此结束。
  2. EXCEPTION_REGISTRATION_RECORD::Handler 指向异常处理函数。

(2)异常的回调函数

EXCEPTION_DISPOSITION
__cdecl _except_handler( struct _EXCEPTION_RECORD *ExceptionRecord,
void * EstablisherFrame,
struct _CONTEXT *ContextRecord,
void * DispatcherContext);

 函数参数:

 1..第一个参数ExceptionRecord,是一个指向EXCEPTION_RECORD结构的指针

 2.第二个参数是一个指向establisher帧结构的指针。这个异常帧结构就是_EXCEPTION_REGISTRATION_RECORD。

 3.第三个参数是一个指向CONTEXT结 构的指针。此结构在WINNT.H中定义,它代表某个特定线程的寄存器值。当用于SEH时,CONTEXT结构表示 异常发生时寄存器的值。顺便说一下,这个CONTEXT结构就是GetThreadContext和SetThreadContext这两个API中使用 的那个CONTEXT结构。

 4.第四个参数是_DispatcherContext,用于存放下一个异常帧,全局展开在执行当前异常帧局部展开中发生嵌套展开时使用。

typedef struct _CONTEXT {  

    //
// The flags values within this flag control the contents of
// a CONTEXT record.
//
// If the context record is used as an input parameter, then
// for each portion of the context record controlled by a flag
// whose value is set, it is assumed that that portion of the
// context record contains valid context. If the context record
// is being used to modify a threads context, then only that
// portion of the threads context will be modified.
//
// If the context record is used as an IN OUT parameter to capture
// the context of a thread, then only those portions of the thread's
// context corresponding to set flags will be returned.
//
// The context record is never used as an OUT only parameter.
// DWORD ContextFlags; //
// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
// included in CONTEXT_FULL.
// DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7; //
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_FLOATING_POINT.
// FLOATING_SAVE_AREA FloatSave; //
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_SEGMENTS.
// DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs; //
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_INTEGER.
// DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax; //
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_CONTROL.
// DWORD Ebp;
DWORD Eip;
DWORD SegCs; // MUST BE SANITIZED
DWORD EFlags; // MUST BE SANITIZED
DWORD Esp;
DWORD SegSs; //
// This section is specified/returned if the ContextFlags word
// contains the flag CONTEXT_EXTENDED_REGISTERS.
// The format and contexts are processor specific
// BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; } CONTEXT; typedef CONTEXT *PCONTEXT;

  

(3)EXCEPTION_RECORD结构

 typedef struct _EXCEPTION_RECORD {
DWORD ExceptionCode; //操作系统提供给异常的一个数,代表异常发生的原因。
DWORD ExceptionFlags;
struct _EXCEPTION_RECORD *ExceptionRecord;
PVOID ExceptionAddress;
DWORD NumberParameters;
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD;

  参数 ExceptionCode 是操作系统分配给异常的号。在 WINNT.H 文件中查找开头为“STATUS_” 的宏就能找到一大堆这样的异常 代号。例如,大家熟知的 STATUS_ACCESS_VIOLATION 的代号就是 0xC0000005。更为完整的异常代号可以 从 Windows NT DDK 中的 NTSTATUS.H 文件里找到。

  EXCEPTION_RECORD 结构体的第四个元素是异常发生处的地 址。其余的 EXCEPTION_RECORD 域目前都可以忽略掉。

0x03  处理过程

当接收到异常后,系统找到当前线程(前面说过异常是线程相关的。系统接收到的异常就是当前正在运行的线程触发的。其实这个说法还不准确,DPC 也会触发异常,而它是线程无关的,这里为了方便理解,当前先只考虑线程)的异常链表,从链表中的第一个结点开始遍历,找到一个 EXCEPTION_REGISTRATION_RECORD 就调用它的 Handler,并把该异常(由第一个类型为 EXCEPTION_RECORD 的参数表示)传递给该 Handler,Handler 处理并返回一个类型为 EXCEPTION_DISPOSITION 的枚举值。该返回值指示系统下一步该做什么:
  ExceptionContinueExecution ——已修正了此异常的故障,重新执行异常产生出代码。
  ExceptionContinueSearch     ——没有处理此异常,请继续搜索其他的解决方案
  ExceptionNestedException 和 ExceptionCollidedUnwind 暂不解释。
  这样系统根据不同的返回值来继续遍历异常链表或者回到触发点继续执行。

(1)内核处理流程

    在windows kernel中,存在一张中断描述符表(IDT, Interupt Descriptor Table). IDT是一张位于内核态物理内存中的线性表,其有256个表项。IDT中的每个表项叫做门描述符(Gate Descriptor)。门描述符的基本作用就是将CPU异常对应的中断号与其对应的异常处理函数KiTrapXX关联起来。

例如,0号中断(即除0错误)对应的处理例程为nt!KiTrap00

    可以在windbg中用!idt -a命令查看。

    

   首先,CPU 执行的指令触发了异常,CPU 改执行 IDT 中 KiTrapXX,KiTrapXX 会调用 KiDispatchException。该函数原型如下:

  VOID
KiDispatchException (
IN PEXCEPTION_RECORD ExceptionRecord,
// 指向 ExceptionRecord的指针
IN PKEXCEPTION_FRAME ExceptionFrame,
// 对于X86 为空
IN PKTRAP_FRAME TrapFrame,
//函数异常记录块指针,由调用者 KiKernelTrapHandler 传递
IN KPROCESSOR_MODE PreviousMode,
// 指示内核态还是用户态
IN BOOLEAN FirstChance
// 是否是第一次尝试
);

  

  

SEH X86的更多相关文章

  1. Windows SEH学习 x86

    windows 提供的异常处理机制实际上只是一个简单的框架.我们通常所用的异常处理(比如 C++ 的 throw.try.catch)都是编译器在系统提供的异常处理机制上进行加工了的增强版本.这里先抛 ...

  2. Kingsoft Office Writer 2012 8.1.0.3385 - (.wps) Buffer Overflow Exploit (SEH)

    #!/usr/bin/python # Exploit Title: Kingsoft Office Writer v2012 8.1.0.3385 .wps Buffer Overflow Expl ...

  3. 第25章 SEH结构化异常处理_未处理异常及向量化异常

    25.1 UnhandledExceptionFilter函数详解 25.1.1 BaseProcessStart伪代码(Kernel32内部) void BaseProcessStart(PVOID ...

  4. 第23章 SEH结构化异常处理(1)_系统SEH机制

    23.1 基础知识 23.1.1 Windows下的软件异常 (1)中断和异常 ①中断是由外部硬件设备或异步事件产生的 ②异常是由内部事件产生的,可分为故障.陷阱和终止三类. (2)两种异常处理机制: ...

  5. KTHREAD 线程调度 SDT TEB SEH shellcode中DLL模块机制动态获取 《寒江独钓》内核学习笔记(5)

    目录 . 相关阅读材料 . <加密与解密3> . [经典文章翻译]A_Crash_Course_on_the_Depths_of_Win32_Structured_Exception_Ha ...

  6. KTHREAD 线程调度 SDT TEB SEH shellcode中DLL模块机制动态

    KTHREAD 线程调度 SDT TEB SEH shellcode中DLL模块机制动态获取 <寒江独钓>内核学习笔记(5)   继续我们的线程相关的数据结构的学习.接下来我们学习 KTH ...

  7. Windows x86 下的 静态代码混淆

    0x00  前言 静态反汇编之王,毫无疑问就是Ida pro,大大降低了反汇编工作的门槛,尤其是出色的“F5插件”Hex-Rays可以将汇编代码还原成类似于C语言的伪代码,大大提高了可读性.但个人觉得 ...

  8. SEH分析笔记(X64篇)

    SEH分析笔记(X64篇) v1.0.0 boxcounter 历史: v1.0.0, 2011-11-4:最初版本. [不介意转载,但请注明出处 www.boxcounter.com  附件里有本文 ...

  9. SEH结构

    首先有几点问题 1.在后文中看到的PE的节中的配置信息表Load configuration是对SEH回调函数的注册,那么Exception Table是加载的什么信息. 2.什么时候走进系统异常,什 ...

随机推荐

  1. count列表中字符出现的次数

    如何count列表中字符出现的次数?可以将其生成一个字典.key是列表中的字符串,value是出现的次数 例如gen = [2, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7, 8, 4, ...

  2. 第四篇——Struts2的引入多个配置文件

    引入多个配置文件 在Struts2配置文件中使用include可引入多个配置文件. 项目实例 1.项目结构 2.pom.xml <project xmlns="http://maven ...

  3. 【Spark-core学习之二】 RDD和算子

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 scala-2.10.4(依赖jdk1.8) spark ...

  4. <转>jmeter(二十三)分布式测试

    本博客转载自:http://www.cnblogs.com/imyalost/category/846346.html 个人感觉不错,对jmeter讲解非常详细,担心以后找不到了,所以转发出来,留着慢 ...

  5. Filter中request对象强转问题

    以下为过滤器doFIlter方法的源代码: public void doFilter(ServletRequest request, ServletResponse response, FilterC ...

  6. Mysql BLOB、BLOB与TEXT区别及性能影响、将BLOB类型转换成VARCHAR类型

    在排查公司项目业务逻辑的时候,见到了陌生的字眼,如下图 顺着关键字BLOB搜索,原来是Mysql存储的一种类型,从很多文章下了解到如下信息 了解 MySQL中,BLOB字段用于存储二进制数据,是一个可 ...

  7. Consul 介绍

    Consul 介绍 Consul是一个分布式.高可用性,在基础设施中发现和配置服务的工具. 主要功能 服务发现 通过DNS或HTTP接口使得消费者发现服务,应用程序可以轻松找到所依赖的服务. 健康检查 ...

  8. ubuntu 16.04 tip

    参考 1. 安装 python3.6 sudo add-apt-repository ppa:jonathonf/python-3.6  sudo apt-get update sudo apt-ge ...

  9. linux --- 5. nginx 初始

    一. 安装nginx 1.安装nginxz之前的依赖包 yum install gcc patch libffi-devel python-devel zlib-devel bzip2-devel o ...

  10. ant_<target>标签含义与使用

    <target>标记目标 目标是一个或多个任务的集合,任务是一段可执行的代码:构建文件中包含一个项目,在项目内部声明了所有目标: <target name = "run&q ...