SEH( Structured Exception Handling , 结构化异常处理 )
结构化异常处理(SEH)是Windows操作系统提供的强大异常处理功能。而Visual C++中的__try{}/__finally{}和__try{}/__except{}结构本质上是对Windows提供的SEH的封装
我们知道SEH是基于线程的异常处理,我们利用 __try{}/__except{}来模拟一下SEH的异常处理:
在这里可以看到我们把EAX的值置为空指针,然后向空指针里写入值,引发 STATUS_ACCESS_VIOLATION(内存访问异常) ,然后在异常处理里面把
EAX的值设置为 变量dwTest的地址,然后返回 EXCEPTION_CONTINUE_EXECUTION 表示异常被处理,从异常处继续执行,这里是MSDN
对于异常处理( Exception Handling )返回值的定义:
1
2
3
#define EXCEPTION_EXECUTE_HANDLER 1 //表示异常被处理,从下一条指令开始执行
#define EXCEPTION_CONTINUE_SEARCH 0 //表示异常未被处理,交由下一个SEH
#define EXCEPTION_CONTINUE_EXECUTION -1 //表示异常被处理,从异常处开始执行
对于上面这段定义,很多人给出的注释不同,以上注释是我对他们的实验结果和理解。
平时我们听说过很多异常处理术语:VEH SEH VCH UEF等等,下面我们用实验整理它们先后的处理顺序;
- VEH(向量化异常处理,最顶端的异常处理)
1
2
3
4
PVOID WINAPI AddVectoredExceptionHandler(
_In_ ULONG FirstHandler,
_In_ PVECTORED_EXCEPTION_HANDLER VectoredHandler
);
向进程里注册一个异常捕获函数,参数FirstHandler 决定插入到链表的位置(非0为头部,0为底部),异常处理中最先执行
- VCH(同上,最低端 的异常处理 )
1
2
3
4
PVOID WINAPI AddVectoredContinueHandler(
_In_ ULONG FirstHandler,
_In_ PVECTORED_EXCEPTION_HANDLER VectoredHandler
);
向进程里注册一个异常捕获函数,参数FirstHandler 决定插入到链表的位置(非0为头部, 0为底部 ) ,异常处理中最后执行
- SEH(结构化异常处理,基于线程栈的异常处理)
SEH是基于线程的异常处理,因为SEH链指针是在TEB(线程信息块)的第一个结构体成员(NT_TIB)的头部:fs:[0]
- UEF(TopLevelEH,顶级异常处理)
1
2
3
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
_In_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
);
TopLevelEH 为线程顶级异常处理器,通常可以处理到所有线程消息发生的异常。
这里我们可以发现以上异常处理回调函数参数大都为 EXCEPTION_POINTERS 结构体,我们查询下它的结构:
1
2
3
4
typedef struct _EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS,
*``PEXCEPTION_POINTERS;
EXCEPTION_RECORD:
1
2
3
4
5
6
7
8
typedef struct _EXCEPTION_RECORD {
DWORD ExceptionCode;
/``/``异常码,以STATUS_或EXCEPTION_开头,可自定义。(sehdef.inc)
DWORD ExceptionFlags;
/``/``异常标志。``0``可修复;``1``不可修复;``2``正在展开,不要试图修复
struct _EXCEPTION_RECORD
*``ExceptionRecord;
/``/``指向嵌套的异常结构,通常是异常中又引发异常
PVOID ExceptionAddress;
/``/``异常发生的地址
DWORD NumberParameters;
/``/``下面ExceptionInformation所含有的dword数目
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
/``/``附加消息,如读或写冲突
} EXCEPTION_RECORD;
CONTEXT:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
typedef struct _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 SANITIZED
DWORD EFlags;
/``/
MUST BE SANITIZED
DWORD 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;
CONTEXT结构体大家应该都懂!
下面我们简单的写一个Demo,试验一下他们的处理顺序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/``/
SEHTest.cpp : 定义控制台应用程序的入口点。
/``/
#include "stdafx.h"
/``/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
/``/
LONG
__stdcall VEHandler(
EXCEPTION_POINTERS
*``ExceptionInfo
)
{
printf(``"VEHandler\n"``);
return
EXCEPTION_CONTINUE_SEARCH;
}
LONG
__stdcall VCHandler(
EXCEPTION_POINTERS
*``ExceptionInfo
)
{
printf(``"VCHandler\n"``);
ExceptionInfo``-``>ContextRecord``-``>Eip``+``+``;
return
EXCEPTION_CONTINUE_EXECUTION;
}
/``/
LONG
NTAPI TopLevelExcepFilter(EXCEPTION_POINTERS
*``pExcepInfo)
{
printf(``"TopLevelEHandler\n"``);
return
EXCEPTION_CONTINUE_EXECUTION;
}
/``/
LONG
NTAPI SEHander(EXCEPTION_POINTERS
*``ExceptionInfo){
/``/``异常处理
printf(``"SEHandler\n"``);
return
EXCEPTION_CONTINUE_SEARCH;
}
int
_tmain(``int
argc, _TCHAR``*
argv[])
{
AddVectoredExceptionHandler(``0``,VEHandler);
AddVectoredContinueHandler(``0``,VCHandler);
SetUnhandledExceptionFilter(&TopLevelExcepFilter);
__try
{
__asm
int
3
}
__except (SEHander(GetExceptionInformation()))
{
}
system(``"Pause"``);
return
0``;
}
我们分别注册了VEH、VCH、 TopLevalEH 、SEH,我们看下结果:
他们处理异常的优先级为:
为什么调试器在第一个呢?因为我们发现在VS里面调试直接接管了异常。(/手动滑稽)
我们上一章发现SEH链表位于结构体 NT_TIB 的第一个结构体成员,而结构体 NT_TIB 也位于TEB的第一个结构体成员,一句话而言SEH链表
指针位于寄存器 FS : [ 0 ] 的位置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
ntdll!_TEB
+``0x000
NtTib : _NT_TIB
/``/``SEH链表头指针
+``0x01c
EnvironmentPointer : Ptr32 Void
+``0x020
ClientId : _CLIENT_ID
+``0x028
ActiveRpcHandle : Ptr32 Void
+``0x02c
ThreadLocalStoragePointer : Ptr32 Void
+``0x030
ProcessEnvironmentBlock : Ptr32 _PEB
+``0x034
LastErrorValue : Uint4B
+``0x038
CountOfOwnedCriticalSections : Uint4B
+``0x03c
CsrClientThread : Ptr32 Void
+``0x040
Win32ThreadInfo : Ptr32 Void
+``0x044
User32Reserved : [``26``] Uint4B
+``0x0ac
UserReserved : [``5``] Uint4B
+``0x0c0
WOW32Reserved : Ptr32 Void
+``0x0c4
CurrentLocale : Uint4B
+``0x0c8
FpSoftwareStatusRegister : Uint4B
+``0x0cc
SystemReserved1 : [``54``] Ptr32 Void
+``0x1a4
ExceptionCode : Int4B
+``0x1a8
ActivationContextStack : _ACTIVATION_CONTEXT_STACK
+``0x1bc
SpareBytes1 : [``24``] UChar
+``0x1d4
GdiTebBatch : _GDI_TEB_BATCH
+``0x6b4
RealClientId : _CLIENT_ID
+``0x6bc
GdiCachedProcessHandle : Ptr32 Void
+``0x6c0
GdiClientPID : Uint4B
+``0x6c4
GdiClientTID : Uint4B
+``0x6c8
GdiThreadLocalInfo : Ptr32 Void
+``0x6cc
Win32ClientInfo : [``62``] Uint4B
+``0x7c4
glDispatchTable : [``233``] Ptr32 Void
+``0xb68
glReserved1 : [``29``] Uint4B
+``0xbdc
glReserved2 : Ptr32 Void
+``0xbe0
glSectionInfo : Ptr32 Void
+``0xbe4
glSection : Ptr32 Void
+``0xbe8
glTable : Ptr32 Void
+``0xbec
glCurrentRC : Ptr32 Void
+``0xbf0
glContext : Ptr32 Void
+``0xbf4
LastStatusValue : Uint4B
+``0xbf8
StaticUnicodeString : _UNICODE_STRING
+``0xc00
StaticUnicodeBuffer : [``261``] Uint2B
+``0xe0c
DeallocationStack : Ptr32 Void
+``0xe10
TlsSlots : [``64``] Ptr32 Void
+``0xf10
TlsLinks : _LIST_ENTRY
+``0xf18
Vdm : Ptr32 Void
+``0xf1c
ReservedForNtRpc : Ptr32 Void
+``0xf20
DbgSsReserved : [``2``] Ptr32 Void
+``0xf28
HardErrorsAreDisabled : Uint4B
+``0xf2c
Instrumentation : [``16``] Ptr32 Void
+``0xf6c
WinSockData : Ptr32 Void
+``0xf70
GdiBatchCount : Uint4B
+``0xf74
InDbgPrint : UChar
+``0xf75
FreeStackOnTermination : UChar
+``0xf76
HasFiberData : UChar
+``0xf77
IdealProcessor : UChar
+``0xf78
Spare3 : Uint4B
+``0xf7c
ReservedForPerf : Ptr32 Void
+``0xf80
ReservedForOle : Ptr32 Void
+``0xf84
WaitingOnLoaderLock : Uint4B
+``0xf88
Wx86Thread : _Wx86ThreadState
+``0xf94
TlsExpansionSlots : Ptr32 Ptr32 Void
+``0xf98
ImpersonationLocale : Uint4B
+``0xf9c
IsImpersonating : Uint4B
+``0xfa0
NlsCache : Ptr32 Void
+``0xfa4
pShimData : Ptr32 Void
+``0xfa8
HeapVirtualAffinity : Uint4B
+``0xfac
CurrentTransactionHandle : Ptr32 Void
+``0xfb0
ActiveFrame : Ptr32 _TEB_ACTIVE_FRAME
+``0xfb4
SafeThunkCall : UChar
+``0xfb5
BooleanSpare : [``3``] UChar
我们直接访问 FS:[0] 即为TIB的结构体地址:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef struct _NT_TIB {
struct _EXCEPTION_REGISTRATION_RECORD
*``ExceptionList;
PVOID StackBase;
PVOID StackLimit;
PVOID SubSystemTib;
#if defined(_MSC_EXTENSIONS)
union {
PVOID FiberData;
DWORD Version;
};
#else
PVOID FiberData;
#endif
PVOID ArbitraryUserPointer;
struct _NT_TIB
*``Self;
} NT_TIB;
typedef NT_TIB
*``PNT_TIB;
如上述代码所示 结构体成员 ExceptionList 即为SEH链的头部指针
So、 fs:[0]即为SEH链的指针,我们接着看对于SEH链的定义:
1
2
3
4
typedef struct _EXCEPTION_REGISTRATION_RECORD {
struct _EXCEPTION_REGISTRATION_RECORD
*``Next``;
PEXCEPTION_ROUTINE Handler;
} EXCEPTION_REGISTRATION_RECORD;
第一个成员 Next 为指向下一个链表的指针,直到遇到 0xFFFFFFFF 结束,而结构体成员 Handler 为SEH的异常处理函数指针,我们接着看它对于
SEH异常处理函数 EXCEPTION_ROUTINE 的定义:
1
2
3
4
5
6
7
8
9
10
11
typedef
_IRQL_requires_same_
_Function_class_(EXCEPTION_ROUTINE)
EXCEPTION_DISPOSITION
NTAPI
EXCEPTION_ROUTINE (
_Inout_ struct _EXCEPTION_RECORD
*``ExceptionRecord,
_In_ PVOID EstablisherFrame,
_Inout_ struct _CONTEXT
*``ContextRecord,
_In_ PVOID DispatcherContext
);
可以看到它对于SEH定义了以 EXCEPTION_DISPOSITION 为返回值的回调函数,我们接着查看它们的定义:
1
2
3
4
5
6
typedef enum _EXCEPTION_DISPOSITION {
ExceptionContinueExecution,
/``/``继续执行异常代码
ExceptionContinueSearch,
/``/``运行下一个异常处理器
ExceptionNestedException,
/``/``在OS内部使用
ExceptionCollidedUnwind
/``/``在OS内部使用
} EXCEPTION_DISPOSITION;
接着我们整理下它的异常处理过程:
从上图可以明白 SEH接收到异常然后处理,处理失败返回 ExceptionContinueSearch(1) 继续运行下一个Handler处理,直到返回
ExceptionContinueSearch(0),若是一直处理不了直到遇到0xFFFFFFFF 把异常交给UEF处理。
通过上述的整理就可以知道,SEH的异常处理的定义为:
1
2
3
4
5
EXCEPTION_DISPOSITION NTAPI _except_handler(
_Inout_ struct _EXCEPTION_RECORD
*``ExceptionRecord,
/``/``指向包含异常信息的EXCEPTION_RECORD结构
_In_ PVOID EstablisherFrame,
/``/``指向该异常相关的EXCEPTION_REGISTRATION结构
_Inout_ struct _CONTEXT
*``ContextRecord,
/``/``指向线程环境CONTEXT结构的指针
_In_ PVOID DispatcherContext)
现在要来谈SEH的注册了,我们的操作为:
1
2
3
push @_except_handler ;异常处理器
push dwod ptr fs:[``0``] ;取出 SEH链表头
mov dwod ptr fs:[``0``],esp ;添加链表
卸载SEH:
1
2
pop dword ptr fs:[``0``] ;还原链表头
add esp,``4
;删除 异常处理器
这些操作很简单,很多前辈们帖子里都有,代码可能不一样,反正是一个意思就行。
这里是MSDN中定义的异常代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/``*``lint
-``save
-``e767
*``/
#define STATUS_WAIT_0 ((DWORD )0x00000000L)
#define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L)
#define STATUS_USER_APC ((DWORD )0x000000C0L)
#define STATUS_TIMEOUT ((DWORD )0x00000102L)
#define STATUS_PENDING ((DWORD )0x00000103L)
#define DBG_EXCEPTION_HANDLED ((DWORD )0x00010001L)
#define DBG_CONTINUE ((DWORD )0x00010002L)
#define STATUS_SEGMENT_NOTIFICATION ((DWORD )0x40000005L)
#define STATUS_FATAL_APP_EXIT ((DWORD )0x40000015L)
#define DBG_TERMINATE_THREAD ((DWORD )0x40010003L)
#define DBG_TERMINATE_PROCESS ((DWORD )0x40010004L)
#define DBG_CONTROL_C ((DWORD )0x40010005L)
#define DBG_PRINTEXCEPTION_C ((DWORD )0x40010006L)
#define DBG_RIPEXCEPTION ((DWORD )0x40010007L)
#define DBG_CONTROL_BREAK ((DWORD )0x40010008L)
#define DBG_COMMAND_EXCEPTION ((DWORD )0x40010009L)
#define STATUS_GUARD_PAGE_VIOLATION ((DWORD )0x80000001L)
#define STATUS_DATATYPE_MISALIGNMENT ((DWORD )0x80000002L)
#define STATUS_BREAKPOINT ((DWORD )0x80000003L)
#define STATUS_SINGLE_STEP ((DWORD )0x80000004L)
#define STATUS_LONGJUMP ((DWORD )0x80000026L)
#define STATUS_UNWIND_CONSOLIDATE ((DWORD )0x80000029L)
#define DBG_EXCEPTION_NOT_HANDLED ((DWORD )0x80010001L)
#define STATUS_ACCESS_VIOLATION ((DWORD )0xC0000005L)
#define STATUS_IN_PAGE_ERROR ((DWORD )0xC0000006L)
#define STATUS_INVALID_HANDLE ((DWORD )0xC0000008L)
#define STATUS_INVALID_PARAMETER ((DWORD )0xC000000DL)
#define STATUS_NO_MEMORY ((DWORD )0xC0000017L)
#define STATUS_ILLEGAL_INSTRUCTION ((DWORD )0xC000001DL)
#define STATUS_NONCONTINUABLE_EXCEPTION ((DWORD )0xC0000025L)
#define STATUS_INVALID_DISPOSITION ((DWORD )0xC0000026L)
#define STATUS_ARRAY_BOUNDS_EXCEEDED ((DWORD )0xC000008CL)
#define STATUS_FLOAT_DENORMAL_OPERAND ((DWORD )0xC000008DL)
#define STATUS_FLOAT_DIVIDE_BY_ZERO ((DWORD )0xC000008EL)
#define STATUS_FLOAT_INEXACT_RESULT ((DWORD )0xC000008FL)
#define STATUS_FLOAT_INVALID_OPERATION ((DWORD )0xC0000090L)
#define STATUS_FLOAT_OVERFLOW ((DWORD )0xC0000091L)
#define STATUS_FLOAT_STACK_CHECK ((DWORD )0xC0000092L)
#define STATUS_FLOAT_UNDERFLOW ((DWORD )0xC0000093L)
#define STATUS_INTEGER_DIVIDE_BY_ZERO ((DWORD )0xC0000094L)
#define STATUS_INTEGER_OVERFLOW ((DWORD )0xC0000095L)
#define STATUS_PRIVILEGED_INSTRUCTION ((DWORD )0xC0000096L)
#define STATUS_STACK_OVERFLOW ((DWORD )0xC00000FDL)
#define STATUS_DLL_NOT_FOUND ((DWORD )0xC0000135L)
#define STATUS_ORDINAL_NOT_FOUND ((DWORD )0xC0000138L)
#define STATUS_ENTRYPOINT_NOT_FOUND ((DWORD )0xC0000139L)
#define STATUS_CONTROL_C_EXIT ((DWORD )0xC000013AL)
#define STATUS_DLL_INIT_FAILED ((DWORD )0xC0000142L)
#define STATUS_FLOAT_MULTIPLE_FAULTS ((DWORD )0xC00002B4L)
#define STATUS_FLOAT_MULTIPLE_TRAPS ((DWORD )0xC00002B5L)
#define STATUS_REG_NAT_CONSUMPTION ((DWORD )0xC00002C9L)
#define STATUS_HEAP_CORRUPTION ((DWORD )0xC0000374L)
#define STATUS_STACK_BUFFER_OVERRUN ((DWORD )0xC0000409L)
#define STATUS_INVALID_CRUNTIME_PARAMETER ((DWORD )0xC0000417L)
#define STATUS_ASSERTION_FAILURE ((DWORD )0xC0000420L)
#if defined(STATUS_SUCCESS) || (_WIN32_WINNT > 0x0500) || (_WIN32_FUSION >= 0x0100)
#define STATUS_SXS_EARLY_DEACTIVATION ((DWORD )0xC015000FL)
#define STATUS_SXS_INVALID_DEACTIVATION ((DWORD )0xC0150010L)
#endif
/``*``lint
-``restore
*``/
下面我们举例几个常用到的异常代码:
STATUS_ACCESS_VIOLATION(0xC0000005)
非法访问异常,试图访问不存在、没有访问权限,或是试图向没有写入权限的地址或是向内核区域写入发生的异常。
STATUS_BREAKPOINT(0x80000003)
断点异常,这个不用提了吧,就是我们常说的INT 3(0xCC)断点
STATUS_ILLEGAL_INSTRUCTION(0xC000001D)
CPU遇到无法解析的指令时发生该异常
STATUS_INTEGER_DIVIDE_BY_ZERO(0xC0000094)
除法中,分母为0时发生的异常
STATUS_SINGLE_STEP
单步调试异常,在EFlag寄存器把TF标志位置1发生的单步调试异常。
除此之外,也有很多平时可以遇到的,我只是举例了几个简单的。
我这里就随便写个Demo了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/``/
SEHList.cpp : 定义控制台应用程序的入口点。
/``/
#include "stdafx.h"
/``/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
DWORD dwTest;
EXCEPTION_DISPOSITION NTAPI ExceptHandler(
_Inout_ struct _EXCEPTION_RECORD
*``ExceptionRecord,
_In_ PVOID EstablisherFrame,
_Inout_ struct _CONTEXT
*``ContextRecord,
_In_ PVOID DispatcherContext){
printf(``"进入异常处理\n"``);
printf(``"异常地址:%X<异常代码:%X>\n"``, ExceptionRecord``-``>ExceptionAddress,
ExceptionRecord``-``>ExceptionCode);
ContextRecord``-``>Eax
=
(DWORD)(&dwTest);
return
ExceptionContinueExecution;
}
int
_tmain(``int
argc, _TCHAR``*
argv[])
{
printf(``"注册SEH\n"``);
__asm{
lea eax, ExceptHandler
push eax
push fs : [``0``]
mov dword ptr fs : [``0``], ESP
}
__asm{
xor eax,eax
mov dword ptr[eax],``1234h
}
printf(``"删除SEH\n"``);
__asm{
pop dword ptr fs : [``0``]
add esp,
4
}
printf(``"dwTest=%X\n"``, dwTest);
getchar();
return
0``;
}
运行结果:
手机扫一扫
移动阅读更方便
你可能感兴趣的文章