SEH异常处理

SEH是应用最为广泛,却没有被微软公开技术之一,所有不同windows版本,SEH可能有所不同。

SEH链表位置:fs:[0]->线程信息块TIB,TIB.ExceptionList->SEH链表

一)有关SEH链表结构:

1)线程信息块TIB结构

kd> dt _NT_TIB
nt!_NT_TIB
   +0x000 ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD            ;SEH链表头
   +0x004 StackBase        : Ptr32 Void
   +0x008 StackLimit       : Ptr32 Void
   +0x00c SubSystemTib     : Ptr32 Void
   +0x010 FiberData        : Ptr32 Void
   +0x010 Version          : Uint4B
   +0x014 ArbitraryUserPointer : Ptr32 Void
   +0x018 Self             : Ptr32 _NT_TIB

2)链表节点

_EXCEPTION_REGISTRATION struc

    prev           dd ?                   ;下一个_EXCEPTION_REGISTRATION结构

    handler       dd ?                   ;异常处理函数地址

_EXCEPTION_REGISTRATION ends

3)异常处理函数约定

_Exception_Handler proc C _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext

  ret

_Exception_Handler endp

3.1)异常处理函数为系统回调,调用方式不是stdcall而是C方式调用。

3.2)参数说明

参数类型分别为:(一般只用前3个参数)

struct _EXCEPTION_RECORD * pExceptionRecord,

struct EXCEPTION_REGISTRATION * pRegistrationFrame,

struct _CONTEXT *pContextRecord,

void * pDispatcherContext

第一个参数

kd> dt _EXCEPTION_RECORD
nt!_EXCEPTION_RECORD
   +0x000 ExceptionCode    : Int4B                                    ;异常代码
   +0x004 ExceptionFlags   : Uint4B                                    ;异常标志
   +0x008 ExceptionRecord  : Ptr32 _EXCEPTION_RECORD
   +0x00c ExceptionAddress : Ptr32 Void                             ;产生异常的地址
   +0x010 NumberParameters : Uint4B
   +0x014 ExceptionInformation : [15] Uint4B

 第二参数

为新插入到SEH链表的新节点,利用此参数,既可恢复ebp、esp寄存器,也可通过堆栈传递数据。如:

线程代码为:

_Test  proc

;********************************************************************
; 在堆栈中构造一个 EXCEPTION_REGISTRATION 结构
;********************************************************************
  assume fs:nothing
  push ebp
  push offset _SafePlace
  push offset _Handler
  push fs:[0]
  mov fs:[0],esp
;********************************************************************
; 会引发异常的指令
;********************************************************************
  pushad
  xor ebp,ebp
  xor eax,eax
  mov dword ptr [eax],0
  popad  ;这一句将无法被执行
_SafePlace:
  invoke MessageBox,NULL,addr szSafe,addr szCaption,MB_OK
;********************************************************************
; 恢复原来的 SEH 链
;********************************************************************
  pop fs:[0]
  add esp,0ch
  ret

_Test  endp

异常处理函数为:

_Handler proc C _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext
  local @szBuffer[256]:byte

  pushad
  mov esi,_lpExceptionRecord
  mov edi,_lpContext
  assume esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT
  invoke wsprintf,addr @szBuffer,addr szMsg,\
   [edi].regEip,[esi].ExceptionCode,[esi].ExceptionFlags
  invoke MessageBox,NULL,addr @szBuffer,NULL,MB_OK
;********************************************************************
; 将 EIP 指向安全的位置并恢复堆栈
;********************************************************************
  mov eax,_lpSEH
  push [eax + 8]
  pop [edi].regEip
  push [eax + 0ch]
  pop [edi].regEbp
  push eax
  pop [edi].regEsp
  assume esi:nothing,edi:nothing
  popad
  mov eax,ExceptionContinueExecution
  ret

_Handler endp

 第三个参数,cpu寄存器状态值

kd> dt _CONTEXT
nt!_CONTEXT
   +0x000 ContextFlags     : Uint4B
   +0x004 Dr0              : Uint4B
   +0x008 Dr1              : Uint4B
   +0x00c Dr2              : Uint4B
   +0x010 Dr3              : Uint4B
   +0x014 Dr6              : Uint4B
   +0x018 Dr7              : Uint4B
   +0x01c FloatSave        : _FLOATING_SAVE_AREA
   +0x08c SegGs            : Uint4B
   +0x090 SegFs            : Uint4B
   +0x094 SegEs            : Uint4B
   +0x098 SegDs            : Uint4B
   +0x09c Edi              : Uint4B
   +0x0a0 Esi              : Uint4B
   +0x0a4 Ebx              : Uint4B
   +0x0a8 Edx              : Uint4B
   +0x0ac Ecx              : Uint4B
   +0x0b0 Eax              : Uint4B
   +0x0b4 Ebp              : Uint4B
   +0x0b8 Eip              : Uint4B
   +0x0bc SegCs            : Uint4B
   +0x0c0 EFlags           : Uint4B
   +0x0c4 Esp              : Uint4B
   +0x0c8 SegSs            : Uint4B
   +0x0cc ExtendedRegisters : [512] UChar

 3.3)返回值

EXCEPTION_CONTINUE_SEARCH表示本异常处理函数不处理,系统将沿着链表查找下一个异常处理函数。

ExceptionContinueExecution表示返回到_lpContext.Eip指定的安全位置继续运行程序。

二)SEH链表图解

 

三)SEH调试

OD调试方法:在异常处理函数下断,当执行到异常指令的时候,根据状态栏提示按F9,就可以调试到达异常处理函数断点处。

原文地址:https://www.cnblogs.com/guanlaiy/p/2469297.html