代码
#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.看看异常处理的内容吧!