/SAFESEH
vs2019需要打开此选项才可以正常进行异常处理
https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers?redirectedfrom=MSDN&view=msvc-170
https://docs.microsoft.com/en-us/windows/win32/dxtecharts/best-security-practices-in-game-development
回调函数
// SEH handler#if defined(_M_IX86) && !defined(_CHPE_X86_ARM64_EH_)struct _EXCEPTION_RECORD;struct _CONTEXT;EXCEPTION_DISPOSITION __cdecl _except_handler(_In_ struct _EXCEPTION_RECORD* _ExceptionRecord,_In_ void* _EstablisherFrame,_Inout_ struct _CONTEXT* _ContextRecord,_Inout_ void* _DispatcherContext);#elif defined _M_X64 || defined _M_ARM || defined _M_ARM64 || defined _CHPE_X86_ARM64_EH_#ifndef _M_CEE_PUREstruct _EXCEPTION_RECORD;struct _CONTEXT;struct _DISPATCHER_CONTEXT;_VCRTIMP EXCEPTION_DISPOSITION __cdecl __C_specific_handler(_In_ struct _EXCEPTION_RECORD* ExceptionRecord,_In_ void* EstablisherFrame,_Inout_ struct _CONTEXT* ContextRecord,_Inout_ struct _DISPATCHER_CONTEXT* DispatcherContext);#endif#endif
可以在vs2019include\excpt.h此头文件下找到。此处分为x86和x64。
第一个参数**_EXCEPTION_RECORD**结构体内容为
typedef struct _EXCEPTION_RECORD {DWORD ExceptionCode; // 异常代码DWORD ExceptionFlags;struct _EXCEPTION_RECORD *ExceptionRecord;PVOID ExceptionAddress;DWORD NumberParameters;ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];} EXCEPTION_RECORD;
可以在winnt.h文件中搜索到错误代码
更详细在Windows NT DDK的NTSTATUS.H中。
调试也可以看到
第二个参数**EstablisherFrame**
文档原文
The address of the base of the fixed stack allocation for this function.
一个指向Establisher帧结构的指针。
第三个参数 **_CONTEXT**结构
typedef struct DECLSPEC_NOINITALL _CONTEXT {//// The flags values within this flag control the contents of// a CONTEXT record.//// If the context record is used as an input parameter, then// for each portion of the context record controlled by a flag// whose value is set, it is assumed that that portion of the// context record contains valid context. If the context record// is being used to modify a threads context, then only that// portion of the threads context will be modified.//// If the context record is used as an IN OUT parameter to capture// the context of a thread, then only those portions of the thread's// context corresponding to set flags will be returned.//// The context record is never used as an OUT only parameter.//DWORD ContextFlags;//// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT// included in CONTEXT_FULL.//DWORD Dr0;DWORD Dr1;DWORD Dr2;DWORD Dr3;DWORD Dr6;DWORD Dr7;//// This section is specified/returned if the// ContextFlags word contians the flag CONTEXT_FLOATING_POINT.//FLOATING_SAVE_AREA FloatSave;//// This section is specified/returned if the// ContextFlags word contians the flag CONTEXT_SEGMENTS.//DWORD SegGs;DWORD SegFs;DWORD SegEs;DWORD SegDs;//// This section is specified/returned if the// ContextFlags word contians the flag CONTEXT_INTEGER.//DWORD Edi;DWORD Esi;DWORD Ebx;DWORD Edx;DWORD Ecx;DWORD Eax;//// This section is specified/returned if the// ContextFlags word contians the flag CONTEXT_CONTROL.//DWORD Ebp;DWORD Eip;DWORD SegCs; // MUST BE SANITIZEDDWORD EFlags; // MUST BE SANITIZEDDWORD Esp;DWORD SegSs;//// This section is specified/returned if the ContextFlags word// contains the flag CONTEXT_EXTENDED_REGISTERS.// The format and contexts are processor specific//BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];} CONTEXT;
此结构存放异常发生时,寄存器中的值。
第四个参数**DispatcherContext**
文档原文
Points to the exception context at the time the exception was raised (in the exception handler case) or the current “unwind” context (in the termination handler case).
文档只搜到一个定义。(寄)
_EXCEPTION_DISPOSITION 结构
此结构指明异常发生时调用的callback函数的位置
typedef struct _EXCEPTION_REGISTRATION{struct _EXCEPTION_REGISTRATION* prev;PEXCEPTION_HANDLER handler;} EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION;typedef EXCEPTION_REGISTRATION EXCEPTION_REGISTRATION_RECORD;typedef PEXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION_RECORD;
此结构位于fs:[00000000h]处。
形成
单个异常
//==================================================// MYSEH - Matt Pietrek 1997// Microsoft Systems Journal, January 1997// FILE: MYSEH.CPP// 用命令行CL MYSEH.CPP编译//==================================================#define _CRT_SECURE_NO_WARNINGS#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;// 指明是我们让流程转到我们的异常处理程序的printf("Hello from an exception handler\n");// 改变CONTEXT结构中EAX的值,以便它指向可以成功进写操作的位置ContextRecord->Eax = (DWORD)&scratch;// 告诉操作系统重新执行出错的指令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结构}printf("Hei Hei!\n");__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弹出堆栈}printf("MO MO!\n");return 0;}
多个异常
参考链接
https://bytepointer.com/resources/pietrek_crash_course_depths_of_win32_seh.htm
https://docs.microsoft.com/en-us/archive/msdn-magazine/2001/september/under-the-hood-new-vectored-exception-handling-in-windows-xp
http://www.openrce.org/articles/full_view/21
