用C实现SEH的例子&如何跟进SEH
代码
#include <windows.h>
#include <stdio.h>
DWORD scratch;
typedef struct _MYCONTEXT {
DWORD ContextFlags;
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
FLOATING_SAVE_AREA FloatSave;
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
DWORD Ebp;
DWORD Eip;
DWORD SegCs; // MUST BE SANITIZED
DWORD EFlags; // MUST BE SANITIZED
DWORD Esp;
DWORD SegSs;
BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} MYCONTEXT;
EXCEPTION_DISPOSITION
__cdecl
_except_handler( struct _EXCEPTION_RECORD *ExceptionRecord,
void * EstablisherFrame,
struct _CONTEXT *ContextRecord,
void * DispatcherContext )
{
printf( "Hello from an exception handler\n" );
MYCONTEXT * mContext;
mContext=(MYCONTEXT *)ContextRecord;
mContext->Eax=(DWORD)&scratch;
//ContextRecord->Eax = (DWORD)&scratch; //这个地方VC 6.0不能正确提示处EAX,所以自己定义了一个context结构MYCONTEXT
return ExceptionContinueExecution;
}
int main()
{
DWORD handler = (DWORD)_except_handler;
__asm
{
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;
}
#include <stdio.h>
DWORD scratch;
typedef struct _MYCONTEXT {
DWORD ContextFlags;
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
FLOATING_SAVE_AREA FloatSave;
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
DWORD Ebp;
DWORD Eip;
DWORD SegCs; // MUST BE SANITIZED
DWORD EFlags; // MUST BE SANITIZED
DWORD Esp;
DWORD SegSs;
BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} MYCONTEXT;
EXCEPTION_DISPOSITION
__cdecl
_except_handler( struct _EXCEPTION_RECORD *ExceptionRecord,
void * EstablisherFrame,
struct _CONTEXT *ContextRecord,
void * DispatcherContext )
{
printf( "Hello from an exception handler\n" );
MYCONTEXT * mContext;
mContext=(MYCONTEXT *)ContextRecord;
mContext->Eax=(DWORD)&scratch;
//ContextRecord->Eax = (DWORD)&scratch; //这个地方VC 6.0不能正确提示处EAX,所以自己定义了一个context结构MYCONTEXT
return ExceptionContinueExecution;
}
int main()
{
DWORD handler = (DWORD)_except_handler;
__asm
{
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;
}
通过对以上SEH例子的分析发现使用OD调试SEH的方法,步骤如下:
1.在OD的调试选项-》异常选单里把忽略的异常全部去掉
2.OD中F9,让程序跑起来,如果有非法访问内存之类异常的话OD会中断
3.在发生异常的那一句设断点,然后在OD的调试选项-》异常选单里忽略所有异常
4.重新载入程序,F9运行到断点处,F8跟进,会进入系统领空,即NT.DLL
5.依次跟进NT.DLL的第1、5、1、1个call,就进入了用户自定义的异常处理了,最后一个call为 call ecx(由于windows版本的不同,这个call的顺序应该不完全一致)
6.看看异常处理的内容吧!