第23章 SEH结构化异常处理(2)

23.2 编译器层面对系统SEH机制的封装

23.2.1 扩展的EXCEPTION_REGISTRATION级相关结构:VC_EXCEPTION_REGISTRATION

(1)VC_EXCEPTION_REGISTRATION结构

 struct VC_EXCEPTION_REGISTRATION
{
     VC_EXCEPTION_REGISTRATION* prev;    //前一个结构体的指针
     FARPROC                    handler; //永远指向_exception_handler4回调函数
     scopetable_entry*          scopetable;//指向scpoetable数组的指针
     int                        _index; //有的书上也叫tryLevel。scopetable项的当前项
     DWORD                      _ebp;   //当前ebp值,用于访问各成员
}

(2)scopetable_entry结构体

struct scopetable_entry
{
     DWORD     prev_entryindex;//指向前一个scopetable_entry在scopetable中的索引
     FARPROC   lpfnFilter; //对应于__except块后小括号内的过滤函数;__finally时为NULL
     FARPROC   lpfnHandler;//__exception或__finally后花括号{}内的代码地址。
}

(3)VC异常帧堆栈布局及VC默认的异常处理

23.2.2 数据结构组织

(1)每个函数注册一个VC_EXCEPTION_REGISTRATION结构(也叫异常帧,如图中的有5个Frame,即有5个函数调用)。为这个函数内的所有__try块建立一个scopetable表,其中每个__try块对应于scopetable中的一项。(用scopetable_entry结构体来表示这个__try项,结构里分别用lpfnFilter和lpfnHandler来表示__except/__finally的过滤函数和处理函数,其中_finally没有过滤函数,只有异常处理函数)。

(2)若有__try块嵌套,则在scopetable_entry结构里的prev_entryindex或指明,多层嵌套形成单向链表。

(3)对于VC的异常处理,其每个异常帧的回调处理函数都统一设为_except_handler4。每进入一个try块里,编译器会将VC_EXCEPTION_REGISTRATION中tryLevel赋值为相应的值。一旦该try块异常发生,系统会先从VC_EXCEPTION_REGISTRATION的handler域中找到_exception_handler4函数(C运行时库函数),然后根据当前tryLevel的值找到scopetable表中这个__try块相应的过滤函数和处理函数对异常进行相应的处理。

23.2.3 _exception_handler4函数的执行流程

(1)异常发生时,根据index找到scopetable项,并调用lfpnFilter。如果过滤函数lpfnFilter返回EXCEPTION_EXECUTE_HANDLER,则执行全局展开之后调用lpfnHandler函数。如果过滤函数lpfnFilter返回EXCEPTION_CONTINUE_EXECUTION,则_except_handler4简单地返回EXCEPTION_CONTINUE_EXECUTION,交由系统恢复线程的执行

(2)如果lpfnFilter返回EXCEPTION_CONTINUE_SEARCH时,此时_except_handler4查看previndex是否是0xFFFFFFFE,若是则_except_handler4返回ExceptionContinueSearch让系统继续遍历外层SEH链或由系统直接处理。否则_except_handler4根据previndex找到相应的过滤函数,根据其返回值重复上面的动作。直到异常被处理或previndex为0xFFFFFFFE为止。

23.2.4 小结:异常处理流程及全局展开

【VcSEH程序】演示多层嵌套try块的调用

/************************************************************************
Module :ExceptFrameInfo.h
Notices:Copyright(c) Microsoft System Journal,February 1997,Matt Pietrek
MSVC 2005之后的编译器开启/GS选项仍可能会回滚到SEH3。不过,CRT的代码总是使用SEH4。
************************************************************************/
#pragma  once

#include <windows.h>
#include <stdio.h>

//-------------------------------------------------------------------
// 本程序仅适用于Visual C++,它使用的数据结构是特定于Visual C++的
//-------------------------------------------------------------------
#ifndef _MSC_VER
#error Visual C++ Required (Visual C++ specific information is displayed)
#endif

/////////////////////////////////结构定义////////////////////////////////
//操作系统定义的基本异常帧

struct EXCEPTION_REGISTRATION
{
    EXCEPTION_REGISTRATION* prev;
    FARPROC     handler;
};

//VC++扩展异常帧指向的数据结构
struct scopetable_entry
{
    DWORD previousTryLevel;
    FARPROC  lpfnFilter;  //过滤函数
    FARPROC  lpfnHandler; //异常处理程序实体的地址
};

//VC++使用的扩展异常帧
struct VC_EXCEPTION_REGISTRATION :EXCEPTION_REGISTRATION
{
    scopetable_entry* scopetable;
    int  trylevel;
    int _ebp;
};

//////////////////////////////////////////////////////////////////////////
//原型声明
//__except_handler3是Visual C++运行时库函数,我们想打印出它的地址,但是它的原型
//并没有出现在任何头文件中,所以需要自己声明它。
extern "C" DWORD __security_cookie;
extern "C" int _except_handler4(PEXCEPTION_RECORD,
                                EXCEPTION_REGISTRATION*,
                                PCONTEXT,
                                PEXCEPTION_RECORD);

//////////////////////////////////////////////////////////////////////////
//显示一个异常帧及其相应的scopetable的信息
void ShowSEHFrame(VC_EXCEPTION_REGISTRATION* pVCExcReg){
    BOOL bVcExceptionHandler4 = pVCExcReg->handler == (FARPROC)_except_handler4; //VC的_except_handler4函数
    if (bVcExceptionHandler4){ //VC的_except_handler4函数
        printf("Frame:%08X Handler:%08X prev:%08X Scopetable:%08X\n",
               pVCExcReg, pVCExcReg->handler, pVCExcReg->prev, (DWORD)pVCExcReg->scopetable^__security_cookie);
    } else{
        printf("Frame:%08X Handler:%08X prev:%08X\n",
               pVCExcReg, pVCExcReg->handler, pVCExcReg->prev);
    }

    DWORD  iAddr = (DWORD)pVCExcReg->scopetable ^ __security_cookie;
    //iAddr = 0x77090928;//在我的系统中,这个值为offset ntdll!ResCSegmentValidateHeader+0x118e (77090928)

    //Scopetable前16个字节几SecurityCookie相关的字段,后面才是scopetable_entry项
    scopetable_entry* pScopeTableEntry = (scopetable_entry*)(iAddr + 16);

    for (int i = 0; i <= pVCExcReg->trylevel; i++){

        if (bVcExceptionHandler4){ //VC的_except_handler4函数

            printf("    scopetable[%u] PreTryLevel:%08X filter:%08X __except:%08X\n",
                   i, pScopeTableEntry->previousTryLevel,
                   pScopeTableEntry->lpfnFilter,
                   pScopeTableEntry->lpfnHandler);
        }

        pScopeTableEntry++;
    }
    printf("\n");
}

//////////////////////////////////////////////////////////////////////////
//遍历异常帧的链表,按顺序显示它们的信息
void WalkSEHFrames(void){
    VC_EXCEPTION_REGISTRATION* pVCExcReg;

    //打印出_except_handler4函数的位置
    printf("_except_handler4 is at address:%08X\n", _except_handler4);
    printf("\n");

    //从FS:[0]处获取指向链表头的指针
    __asm mov eax, FS:[0]
        __asm mov[pVCExcReg], EAX

    //遍历异常帧的链表。0xFFFFFFFF标志着链表的结尾
    while (0xFFFFFFFF != (unsigned)pVCExcReg){
        ShowSEHFrame(pVCExcReg);
        pVCExcReg = (VC_EXCEPTION_REGISTRATION*)(pVCExcReg->prev);
    }
}

//VcSEH.cpp

#include <windows.h>
#include <stdio.h>
#include "ExceptionFrameInfo.h"

void test(void){
    int i = 0;
    //A块
    __try{//第1层
        __try{ //第2层
            __try{ //第3层
                __try{ //第4层
                     i++;
                }__finally {//第4层
                }
            }__except (EXCEPTION_CONTINUE_SEARCH){//第3层
                //这里不会被执行
            }
        }__except (EXCEPTION_CONTINUE_SEARCH){//第2层
            //这里不会被执行
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER){ //第1层
        //该try块及内层发生异常时,这里被执行
    }

    //B块
    __try{
        WalkSEHFrames();
    }__except (EXCEPTION_CONTINUE_SEARCH){
    }
}

int main(){
    __try{
        test();
    }__except (EXCEPTION_EXECUTE_HANDLER){

    }
    return 0;
}

【参考文献】

深入解析结构化异常处理(SEH)

http://www.cppblog.com/weiym/archive/2015/02/27/209884.html

http://blog.csdn.net/bad_sheep/article/details/5803649

http://blog.csdn.net/yuzl32/article/details/5383542

http://www.mouseos.com/windows/index.html

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

http://bbs.pediy.com/showthread.php?threadid=32222

《软件加密技术内幕》,看雪学院

时间: 2024-10-12 01:27:08

第23章 SEH结构化异常处理(2)的相关文章

第23章 SEH结构化异常处理(1)

23.1 基础知识 23.1.1 Windows下的软件异常 (1)中断和异常 ①中断是由外部硬件设备或异步事件产生的 ②异常是由内部事件产生的,可分为故障.陷阱和终止三类. (2)两种异常处理机制:SEH和VEH(WindowsXP以上新引进) (3)结构化异常处理(SEH)是Windows操作系统提供的强大异常处理功能.而Visual C++中的__try{} __finally{}和__try{} __except{}结构本质上是对Windows提供的SEH的封装. 23.1.2 SEH的

第24章 SEH结构化异常处理—异常处理及软件异常

24.1  程序的结构 (1)try/except框架 __try{ //被保护的代码块 …… } __except(except fileter/*异常过滤程序*/){ //异常处理程序 } (2)说明 ①当__try块中的代码发生异常时,__except()中的过滤程序就被调用. ②过滤程序可以是一个简单的表达式或一个函数(返回值应为EXCEPTION_CONTINUE_SEARCH.EXCEPT_CONTINUE_EXECUTE或EXCEPT_EXECUTE_HANDLER之一) ③过滤表

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

25.1 UnhandledExceptionFilter函数详解 25.1.1 BaseProcessStart伪代码(Kernel32内部) void BaseProcessStart(PVOID lpfnEntryPoint) //参数为线程函数的入口地址 { DWORD retValue; DWORD currentESP; DWORD exceptionCode; currentESP = ESP; //lpfnEntryPoint被try/except封装着,这是系统安装的默认的异常

Windows内核读书笔记——SEH结构化异常处理

SEH是对windows系统中的异常分发和处理机制的总称,其实现分布在很多不同的模块中. SEH提供了终结处理和异常处理两种功能. 终结处理保证终结处理块中的程序一定会被执行 1 __try 2 { 3 //要保护的代码 4 } 5 __finally 6 { 7 //终结处理块 8 } 退出保护块的方式:正常结束和非正常结束两种 1.正常结束 正常执行并顺序进入终结处理块称为正常结束 2.非正常结束 因为发生异常或是因为return.goto.break.continue等流程控制语句而离开被

关于SEH(结构化异常处理)的一些知识

梳理老罗win32汇编关于SEH一章的知识. 异常处理方式有两种: 筛选器异常处理和结构化异常处理,筛选器是全局性的,无法为一个线程或一个子程序单独设置一个异常处理回调函数,而结构化异常处理(Structured Exception Handing)SEH提供了每个线程之间独立的异常处理方法. 以下以两个例子来学习SEH 例子1:不含栈展开操作的异常处理(栈展开会在例子二中介绍) .386 .model flat,stdcall option casemap:none ;>>>>&

解析结构化异常处理(SEH)(第二部分)

书接上一篇:http://www.cnblogs.com/ONDragon/p/6855174.html 虽然这个异常回调机制很好,但它并不是一个完美的解决方案.对于稍微复杂一些的应用程序来说,仅用一个 函数就能处理程序中任何地方都可能发生的异常是相当困难的.一个更实用的方案应该是有多个异常处理例程,每个例程针对程序中的一部分.实际上,操作系统提 供的正是这个功能. 还 记得系统用来查找异常回调函数的EXCEPTION_REGISTRATION结构吗?这个结构的第一个成员,称为prev,前面我们

深入研究 Win32 结构化异常处理(作者博客有许多SEH的研究文章)

摘要 就像人们常说的那样,Win32 结构化异常处理(SEH)是一个操作系统提供的服务.你能找到的所有关于 SEH 的文档讲的都是针对某个特定编译器的.建立在操作系统层之上的封装库.我将从 SEH 的最基本概念讲起. Matt Pietrek 著董岩 译Victor 转载自 Xfocus 并整理 在所有 Win32 操作系统提供的机制中,使用最广泛的未公开的机制恐怕就要数结构化异常处理(structured exception handling,SEH)了.一提到结构化异常处理,可能就会令人想起

结构化异常处理(通过设置CONTEXT结构实现反跟踪)

结构化异常处理是Windows操作系统处理程序错误或异常的技术.在一个应用程序发生错误时,Windows挂起程序,并交由调试器处理,当调试器不能处理时,则调用程序的线程相关的SEH异常处理函数. 异常处理函数可以有一个或多个,采用链表的结构将他们链接起来.当前的处理函数如果不处理,并且有多个处理函数时,可以交由链起来的其它异常处理过程进行处理. 如果程序线程的异常处理函数均选择不处理,如果处于被调试状态,操作系统挂起程序通知调试器. 这时有两种可能: (1)如果程序未处于被调试状态或者调试器仍然

深入研究 Win32 结构化异常处理(好多相关文章)

摘要 就像人们常说的那样,Win32 结构化异常处理(SEH)是一个操作系统提供的服务.你能找到的所有关于 SEH 的文档讲的都是针对某个特定编译器的.建立在操作系统层之上的封装库.我将从 SEH 的最基本概念讲起. Matt Pietrek 著董岩 译Victor 转载自 Xfocus 并整理 在所有 Win32 操作系统提供的机制中,使用最广泛的未公开的机制恐怕就要数结构化异常处理(structured exception handling,SEH)了.一提到结构化异常处理,可能就会令人想起