快速业务通道

Win32结构化异常处理(SEH)探秘(上)

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-29
,回想一下结构化异常处理是以线程为基础,并作用在每个线程上,明白这一点是有助于理解的。也就是说,每个线程具备其自己的异常处理回调函数。在我1996年5月的专栏文章中,我描述了一个关键的 Win32 数据结构——线程信息块(即 TEB 和 TIB)。该数据结构的某些域在 Windows NT、Windows 95、Win32s 和 OS/2 平台上是一样的。TIB 中的第一个 DWORD 是指向线程 EXCEPTION_REGISTRATION 结构的指针。在 Intel Win32 平台上,FS 寄存器总是指向当前的 TIB。因此,在 FS:[0]位置,你能找到 EXCEPTION_REGISTRATION 结构的指针。

现在我们知道了,当异常发生时,系统检查出错线程的 TIB 并获取 EXCEPTION_REGISTRATION 结构的指针。这个结构中就有一个 _except_handler 回调函数的指针。这些信息足以让操作系统知道在哪里以及如何调用 _except_handler 函数,如图二所示:

Win32结构化异常处理(SEH)探秘(上)

图二 _except_handler 函数

通过前面的描述,我写了一个小程序来对操作系统层的结构化异常进行示范。程序代码如下:

 //==================================================
  // MYSEH - Matt Pietrek 1997
  // Microsoft Systems Journal, January 1997
  // FILE: MYSEH.CPp
  // To compile: CL MYSEH.CPp
  //==================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>

DWORD scratch;

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

// Indicate that we made it to our exception handler
   printf( "Hello from an exception handler\n" );

// Change EAX in the context record so that it points to someplace
   // where we can successfully write
   ContextRecord->Eax = (DWORD)&scratch;

// Tell the OS to restart the faulting instruction
   return ExceptionContinueExecution;
}

int main()
{
   DWORD handler = (DWORD)_except_handler;
   __asm
   {
     // 创建 EXCEPTION_REGISTRATION 结构:
     push handler
// handler函数的地址
     push FS:[0] 
// 前一个handler函数的地址
     mov FS:[0],ESp
// 装入新的EXECEPTION_REGISTRATION结构
   }
   __asm
   {
     mov eax,0
// EAX清零
     mov [eax], 1
// 写EAX指向的内存从而故意引发一个错误
   }
   printf( "After writing!\n" );
   __asm
   {
     // 移去我们的 EXECEPTION_REGISTRATION 结构记录
     mov eax,[ESP]  
// 获取前一个结构
     mov FS:[0], EAX 
// 装入前一个结构
     add esp, 8
// 将 EXECEPTION_REGISTRATION 弹出堆栈
   }
   return 0;
}

代码中只有两个函数,main 函数使用了三部分内联汇编块 ASM。第一个 ASM 块通过两个 PUSH 指令(即:“PUSH handler”和“PUSH FS:[0]”)在堆栈上建立一个 EXCEPTION_REGISTRATION 结构。PUSH FS:[0] 保存以前 FS:[0] 的值,它是结构的一部分,但目前这个值对我们不重要。重要的是在堆栈上有一个 8-byte 的 EXCEPTION_REGISTRATION 结构。紧接着的指令(MOV FS:[0],ESP)是让线程信息块中的第一个 DWORD 指到新的 EXCEPTION_REGISTRATION 指令。

如果你想知道为

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号