前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SEH学习

SEH学习

作者头像
全栈程序员站长
发布2022-11-15 17:41:48
5820
发布2022-11-15 17:41:48
举报
文章被收录于专栏:全栈程序员必看

因为最近分析的一个壳用到了SEH相关的代码,所以要学习一下

内容转述自《软件加密技术内幕》

一些问题和回答

异常是谁提出的

Intel 提出了中断和异常的概念,中断跟外部硬件设备有关,而异常跟内部事件有关

异常分为故障,陷阱,终止,终止异常为不可恢复异常

为什么要有异常处理机制?

程序会出现错误,如果到处用if(!fun())这样的形式来侦错的话,代码不好维护。

而异常处理机制的使侦错代码和实际代码分离的作用很好的改善了这种情况,当然还有

其他原因吧,不一一列举

哪里用到了异常处理机制?

C++的语法支持异常处理,Windows也支持异常处理,尽管两个不是一样的东西,但是作用 甚至使用的接口名称都非常相似

异常处理工作流程

1 判断异常是何种类型,是否应该发给程序,如果应该发送则将结构_EXETPTION_DEBUG_INFO中的变量dwFirstChance置1并发给调试器,让调试器来处理(也可能会不处理)

_EXETPTION_DEBUG_INFO结构如下

代码语言:javascript
复制
typedef struct _EXCEPTION_DEBUG_INFO
{ 
  EXCEPTION_RECORD ExceptionRecord; 
  DWORD dwFirstChance; 
} EXCEPTION_DEBUG_INFO; 

Jetbrains全家桶1年46,售后保障稳定

2 没有调试器或者调试器不处理这个异常的话系统会找到程序线程中的异常处理程序并交由其处理

3 线程中可以有多个异常处理,如果一个无法处理则让其他来处理

4 如果都无法处理则系统将dwFirstChance置0,再通知调试器(如果有的话),如果没有调试器或者调试器继续不处理,而程序又曾经调用过API SetUnhandledFilter来设置异常处理的过程,系统将会调用这个过程来处理异常(这是进程级别的异常处理过程了)

5 现在如果异常还没被线程/进程相关的异常处理程序解决的话系统就会显示一个框框告诉你程序崩溃了,让你关闭或者调试这个程序

6 在程序终结之前,系统再次调用异常线程中的所有线程(这是释放资源最后的机会)

一些关于SEH的结构

只罗列下,具体的后面再叙述

TEB结构

代码语言:javascript
复制
typedef  struct  _NT_TEB{  //TEB=>Thread Environment Block
000h  NT_TIB        Tib;    
01Ch  PVOID        EnvironmentPointer;
020h  CLIENT_ID      Cid;
028h  PVOID        ActiveRpcInfo;
02Ch  PVOID        ThreadLocalStoragePointer;
030h  PPEB        Peb;    
034h  ULONG        LastErrorValue;
038h  ULONG        CountOfOwnedCriticalSections;
03Ch  PVOID        CsrClientThread;
040h  PVOID        Win32ThreadInfo;
044h  ULONG        Win32ClientInfo[0x1F];
0C0h  PVOID        WOW32Reserved;
0C4h  ULONG        CurrentLocale;
0C8h  ULONG        FpSoftwareStatusRegister;
0CCh  PVOID        SystemReserved1[0x36];
1A4h  PVOID        Spare1;
1A8h  LONG        ExceptionCode;
1ACh  ULONG        SpareBytes1[0x28];
1D4h  PVOID        SystemReserved2[0xA];
1FCh  GDI_TEB_BATCH    GdiTebBatch;
6DCh  ULONG        gdiRgn;
6E0h  ULONG        gdiPen;
6E4h  ULONG        gdiBrush;
6E8h  CLIENT_ID      RealClientId;
6F0h  PVOID        GdiCachedProcessHandle;
6F4h  ULONG        GdiClientPID;
6F8h  ULONG        GdiClientTID;
6FCh  PVOID        GdiThreadLocaleInfo;
700h  PVOID        UserReserved[5];
714h  PVOID        glDispatchTable[0x118];
B74h  ULONG        glReserved1[0x1A];
BDCh  PVOID        glReserved2;
BE0h  PVOID        glSectionInfo;
BE4h  PVOID        glSection;
BE8h  PVOID        glTable;
BECh  PVOID        glCurrentRC;
BF0h  PVOID        glContext;
BF4h  NTSTATUS      LastStatusValue;
BF8h  UNICODE_STRING  StaticUnicodeString;
C00h  WCHAR        StaticUnicodeBuffer[0x105];
E0Ch  PVOID        DeallocationStack;
E10h  PVOID        TlsSlots[0x40];
F10h  LIST_ENTRY      TlsLinks;
F18h  PVOID        Vdm;
F1Ch  PVOID        ReservedForNtRpc;
F20h  PVOID        DbgSsReserved[0x2];
F28h  ULONG        HardErrorDisabled;
F2Ch  PVOID        Instrumentation[0x10];
F6Ch  PVOID        WinSockData;
F70h  ULONG        GdiBatchCount;
F74h  ULONG        Spare2;
F78h  ULONG        Spare3;
F7Ch  ULONG        Spare4;
F80h  PVOID        ReservedForOle;
F84h  ULONG        WaitingOnLoaderLock;
F88h  PVOID        StackCommit;
F8Ch  PVOID        StackCommitMax;
F90h  PVOID        StackReserve;
???h    PVOID        MessageQueue;
}NT_TEB, *PNT_TEB;

TEB永远由[FS:0]指向,其第一项是指向SEH链表的指针

_EXCEPTION_REGISTRATION_RECORD结构

代码语言:javascript
复制
EXCEPTION_REGISTRATION_RECORD
Prev    dd
Handler dd
EXCEPTION_REGISTRATION_RECORD ENDS

链中的前一个EXCEPTION_REGISTRATION_RECORD

当前的Handler

代码语言:javascript
复制
_EXCEPTION_POINTERS
pEXCEPTION_RECORD ExceptionRecord dd
pCONTEXT ContextRecord            dd
_EXCEPTION_POINTERS ENDS

这是给进异常程回调函数的参数

代码语言:javascript
复制
EXCEPTION_RECORD
DWORD ExceptionCode
DWORD ExceptionFlags
struct EXCEPTION_RECORD
DVOID ExceptionAddress
DWORD NumberParameters
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]
}EXCEPTION_RECORD ends

异常代码(内存读写/除0等)

异常标志(可恢复/不可恢复/要终止程序了,请释放资源)

指向嵌套的异常结构(因为在异常里面又发生了异常)

发生异常的地址

附加消息(读冲突/写冲突)

Context结构(寄存器们)

代码语言:javascript
复制
typedef struct _CONTEXT
{
        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;
        DWORD   EFlags;
        DWORD   Esp;
        DWORD   SegSs;
} CONTEXT;

一些关于SEH的API

只罗列,不多解释

代码语言:javascript
复制
UINT SetErrMode(UINT nMode);
//nMode=0, 显示错误对话框
//nMode=NOGPFAULTERRORBOX, 不显示对话框

LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
  _In_  LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
);
//设置进程级别的异常处理过程

void WINAPI RaiseException(
  _In_  DWORD dwExceptionCode,
  _In_  DWORD dwExceptionFlags,
  _In_  DWORD nNumberOfArguments,
  _In_  const ULONG_PTR *lpArguments
);
//引发一个异常,可以自己定义异常代码

BOOL WINAPI GetThreadContext(
  _In_     HANDLE hThread,
  _Inout_  LPCONTEXT lpContext
);
//获取线程环境
BOOL WINAPI SetThreadContext(
  _In_  HANDLE hThread,
  _In_  const CONTEXT *lpContext
);
//设置线程环境
void WINAPI RtlUnwind(
  _In_opt_  PVOID TargetFrame,
  _In_opt_  PVOID TargetIp,
  _In_opt_  PEXCEPTION_RECORD ExceptionRecord,
  _In_      PVOID ReturnValue
);
//进程(顶层)异常处理
//进程(顶层)异常处理用SetUnhandledExceptionFilter来设置,只能有一个,如果设置了几次,以最后一个为准
//回调函数的格式
Handler proc lpExceptionPointer
....
ret
Handler endp
//lpExceptionPointer里存放着异常的信息(就是EXECPTION_POINTERS指针),指向了EXCEPTION_RECORD和CONTEXT
//回调函数的返回值可以有三种
//1 EXECPTION_EXECUTE_HANDLER, 表示程序已经处理过,可以退出了,但是不要显示错误对话框
//2 EXECPTION_CONTINUE_SEARCH, 表示程序无法处理,让系统交给其他代码处理,现在只有系统自己可以处理了,那就给你弹个错误对话框(弹不弹取决于SetErrMode)
//3 EXECPTION_CONTINUE_EXECUTION, 表示程序已经处理好了,回到刚才的异常代码继续执行吧

顶层SEH

下面展示一个小程序,这个程序会因为访问地址违规而出现错误,程序可以忽略这个错误继续运行 安静的退出程序 和弹出一个丑陋的错误框再退出程序

代码语言:javascript
复制
;******************************************
;coded by Hume,2K+
;******************************************
;例子1.演示Final型异常处理及参数获取
;******************************************
include hhd.h                                                ;编译所必需的头文件
.DATA
szTit           db "SEH例子-Final,written by Hume",0
mes000          db "We are in the Exception handler,Kill Prog",0dh,0ah
db "in silence(Y)、noisily(N) or Continue(cancel)?",0
messuc          db "Hello,We manage to return after exception!",0
impossible      db "It's impossible...",0
.DATA?
OldFilter       dd ?
;;-----------------------------------------
.CODE
;Final 型异常处理回调函数
myFinalHandler proc     uses esi edi ebx lpExceptionPointers 
invoke	MessageBox,0,addr mes000,addr szTit,MB_ICONINFORMATION or MB_YESNOCANCEL
.if     eax==IDYES
mov     eax,EXCEPTION_EXECUTE_HANDLER           ;处理完毕,不会显示对话框
.elseif eax==IDNO
orCannotHanle:
mov     eax,EXCEPTION_CONTINUE_SEARCH           ;继续查找,显示对话框
.elseif eax==IDCANCEL                                   ;处理完毕,修改CONTEXT上下文
mov     ebx,[lpExceptionPointers]               ;继续执行程序
ASSUME ebx:ptr EXCEPTION_POINTERS
ASSUME esi:ptr EXCEPTION_RECORD
ASSUME edi:ptr CONTEXT
mov     esi,[ebx].pExceptionRecord
mov     edi,[ebx].ContextRecord
test    [esi].ExceptionFlags,3
jnz     orCannotHanle                           
cmp     [esi].ExceptionCode,STATUS_ACCESS_VIOLATION
jne     orCannotHanle                           ;是内存读写异常吗
mov     [edi].regEip,offset suc_ret             ;改变返回地址
mov     eax,EXCEPTION_CONTINUE_EXECUTION
.endif
ret       
myFinalHandler endp
;程序入口点
_StArT:
invoke	SetErrorMode,0          
invoke	SetUnhandledExceptionFilter,offset myFinalHandler
mov     [OldFilter],eax
xor     eax,eax
mov     [eax],eax               ;向地址0处写数据!产生异常
nop                             ;永不可能执行下面的语句
invoke	MessageBox,0,addr impossible,addr szTit,MB_ICONINFORMATION
nop
suc_ret:                            ;返回后执行到这里
invoke	MessageBox,0,addr messuc,addr szTit,MB_ICONINFORMATION
invoke  ExitProcess,0  
END	_StArT

在OD中加载:

代码语言:javascript
复制
00401065 s>  6A 00            push 0
00401067     E8 4E000000      call <jmp.&KERNEL32.SetErrorMode>
0040106C     68 00104000      push s1.00401000
00401071     E8 4A000000      call <jmp.&KERNEL32.SetUnhandledExceptionFil>
00401076     A3 C0304000      mov dword ptr ds:[4030C0],eax
0040107B     33C0             xor eax,eax
0040107D     8900             mov dword ptr ds:[eax],eax

在最后一句,OD会提示有异常。你可以在OD菜单中的查看-SEH链中找对最前的一个SEH handler地址在反汇编中查看

你也可以在其第一句代码处下断点,然后SHIFT+F9运行程序,程序会断在SEH handler第一句处

线程SEH

注册线程SEH的方法(汇编),进OD调试下就知道为什么了

代码语言:javascript
复制
assume fs:nothing
push SehHandler
push [fs:0]mov [fs:0],esp

线程SEH使用例子1

代码语言:javascript
复制
;******************************************
;coded by Hume,2K+
;******************************************
;例子2.演示Per_Thread型异常处理
;******************************************
include c:\hd\hhd.h
.DATA
szTit   db "SEH例子-Per_Thread,Hume,2k+",0
mesSUC  db "WE SUCEED IN FIX DIV0 ERROR.",0	
.DATA?
hInstance	dd ?
;;-----------------------------------------
.CODE
SehHandler      proc C uses ebx esi edi pExcept,pFrame,pContext,pDispatch
Assume  esi:ptr EXCEPTION_RECORD
Assume  edi:ptr CONTEXT
mov     esi,pExcept
mov     edi,pContext
test    [esi].ExceptionFlags,3
jne     _continue_search
cmp     [esi].ExceptionCode,STATUS_INTEGER_DIVIDE_BY_ZERO         ;是除0错?
jne     _continue_search
mov     [edi].regEcx,10                         ;将被除数改为非0值继续返回执行
;这次可以得到正确结果是10
mov     eax,ExceptionContinueExecution          ;修复完毕,继续执行
ret
_continue_search:
mov     eax,ExceptionContinueSearch             ;其他异常,无法处理,继续遍历seh回调函数列表
ret
SehHandler      endp
_StArT:
assume fs:nothing
push    offset SehHandler
push    fs:[0]
mov     fs:[0],esp                      ;建立EXCEPTION_REGISTRATION_RECORD结构并将
;TIB偏移0改为该结构地址
xor     ecx,ecx                         ;ECX=0
mov     eax,100                         ;EAX=100
xor     edx,edx                         ;EDX=0
div     ecx                             ;产生除0错!
invoke	MessageBox,0,addr mesSUC,addr szTit,0
pop     fs:[0]                          ;恢复原异常回调函数
add     esp,4                           ;平衡堆栈
invoke ExitProcess,0
END	_StArT

线程SEH使用例子2

代码语言:javascript
复制
;******************************************
;coded by Hume,2K+
;******************************************
;例子3.演示Per_Thread型异常处理的嵌套处理
;******************************************
include c:\hd\hhd.h
;~~~~~~~~~~~~~~~~MACROs
;注册回调函数
InstSEHframe    MACRO CallbackFucAddr
push    offset CallbackFucAddr
push    fs:[0]
mov     fs:[0],esp
ENDM
;卸载回调函数
UnInstSEHframe    MACRO
pop     fs:[0]
add     esp,4
ENDM
;用宏简化重复代码,对应于handler中判断部分
SEHhandlerProcessOrNot MACRO ExceptType,Exit2SearchAddr
Assume esi:ptr EXCEPTION_RECORD
Assume edi:ptr CONTEXT
mov     esi,[pExcept]
mov     edi,pContext
test    [esi].ExceptionFlags,7
jnz     Exit2SearchAddr
cmp     [esi].ExceptionCode,ExceptType
jnz     Exit2SearchAddr
;;below should follow the real processing codes
ENDM 
;~~~~~~~~~~~~~~~~~~~~~~~
.DATA
szTit           db "SEH例子-Per_Thread嵌套,Hume,2k+",0
FixDivSuc       db "Fix Div0 Error Suc!",0
FixWriSuc       db "Fix Write Acess Error Suc!",0
FixInt3Suc      db "Fix Int3 BreakPoint Suc!",0
DATABUF         dd 0
;;-----------------------------------------
.CODE
;除0错异常处理函数
Div_handler0    proc  C  uses ebx esi edi pExcept,pFrame,pContext,pDispatch
PUSHAD
SEHhandlerProcessOrNot  STATUS_INTEGER_DIVIDE_BY_ZERO,@ContiSearch      ;是否是整数除0错
mov     [edi].regEcx,10                 ;修正被除数
POPAD
mov     eax,ExceptionContinueExecution  ;返回继续执行       
ret
@ContiSearch:
POPAD
mov     eax,ExceptionContinueSearch         
ret
Div_handler0    endp    
;读写冲突内存异常处理函数
Wri_handler1    proc  C  uses ebx esi edi pExcept,pFrame,pContext,pDispatch
PUSHAD
SEHhandlerProcessOrNot  STATUS_ACCESS_VIOLATION,@ContiSearch      ;是否是读写内存冲突
mov     [edi].regEip,offset safePlace1  ;改变返回后指令的执行地址
;mov     [edi].regEdx,offset DATABUF    ;将写地址转换为有效值
POPAD
mov     eax,ExceptionContinueExecution
ret
@ContiSearch:
POPAD
mov     eax,ExceptionContinueSearch 
ret        
Wri_handler1    endp    
;断点中断异常处理函数
Int3_handler2   proc C   uses ebx esi edi pExcept,pFrame,pContext,pDispatch
PUSHAD
SEHhandlerProcessOrNot  STATUS_BREAKPOINT,@ContiSearch      ;是否是断点
INC     [edi].regEip                            ;调整返回后指令的执行地址,越过断点继续执行  
;注意在9X下INT3异常发生后指令地址为
POPAD
mov     eax,ExceptionContinueExecution
ret
@ContiSearch:
POPAD
mov     eax,ExceptionContinueSearch 
ret       
Int3_handler2   endp    
;mesAddr应含有指向欲显示消息的地址
MsgBox          proc   mesAddr
invoke	MessageBox,0,mesAddr,offset szTit,MB_ICONINFORMATION
ret
MsgBox          endp
;-----------------------------------------
_StArT:
Assume fs:nothing
invoke	SetErrorMode,0
InstSEHframe    Div_handler0 
InstSEHframe    Wri_handler1
InstSEHframe    Int3_handler2
mov     eax,100
cdq                     ;eax=100 edx=0
xor     ecx,ecx         ;ecx=0
div     ecx             ;除0异常!
invoke	MsgBox,offset FixDivSuc       ;如果处理除0错成功
xor     edx,edx
mov     [edx],eax       ;向地址0处写入,发生写异常!
safePlace1:
invoke	MsgBox,offset FixWriSuc       ;如果处理写保护内存成功
int     3
nop
invoke	MsgBox,offset FixInt3Suc      ;如果处理断点int 3成功
invoke	MessageBox,0,CTEXT("Test Illegal INSTR without Handler or Not(Y/N)?"),offset szTit,MB_YESNO
cmp     eax,IDYES
jnz     no_test
db      0Fh,17h      ;为非法指令测试
invoke	MsgBox,CTEXT("here,will Exit")
no_test:
UnInstSEHframe          ;卸载所有的回调函数
UnInstSEHframe
UnInstSEHframe
invoke ExitProcess,0
END	_StArT

——————————————-

堆栈展开 EXCEPTION_RECORD的ExeptionFlags如果等于2,ExceptionCode置为STATUS_UNWIND则表明正在展开堆栈. 展开堆栈是为了让程序在结束之前能够释放资源

堆栈展开例子

代码语言:javascript
复制
;******************************************
;coded by Hume,2K+
;******************************************
;例子4.演示异常处理的堆栈展开
;******************************************
include c:\hd\hhd.h
;~~~~~~~~~~~~~~~~MACROs
;注册回调函数
InstSEHframe    MACRO CallbackFucAddr
push    offset CallbackFucAddr
push    fs:[0]
mov     fs:[0],esp
ENDM
;卸载回调函数
UnInstSEHframe    MACRO
pop     fs:[0]
add     esp,4
ENDM
;用宏简化重复代码,对应于handler中判断部分
SEHhandlerProcessOrNot MACRO ExceptType,Exit2SearchAddr
Assume esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT        
mov     esi,[pExcept]
mov     edi,pContext
test    [esi].ExceptionFlags,1
jnz     Exit2SearchAddr
test    [esi].ExceptionFlags,2
jnz     @_Unwind
cmp     [esi].ExceptionCode,ExceptType
jnz     Exit2SearchAddr
;;below should follow the real processing codes
ENDM 
;~~~~~~~~~~~~~~~~~~~~~~~
.DATA
szTit           db "SEH例子-嵌套及展开,Hume,2k+",0
FixDivSuc       db "Fix Div0 Error Suc!",0
FixWriSuc       db "Fix Write Acess Error Suc!",0
FixInt3Suc      db "Fix Int3 BreakPoint Suc!",0
DATABUF         dd 0
.DATA?
OLDHANDLER      dd ?
;;-----------------------------------------
.CODE
;除0错异常处理函数
;-----------------------------------------
;mesAddr应含有指向欲显示消息的地址
MsgBox          proc   mesAddr
invoke	MessageBox,0,mesAddr,offset szTit,MB_ICONINFORMATION
ret
MsgBox          endp
;-----------------------------------------
Div_handler0    proc  C  pExcept,pFrame,pContext,pDispatch
PUSHAD
SEHhandlerProcessOrNot  STATUS_INTEGER_DIVIDE_BY_ZERO,@ContiSearch      ;是否是整数除0错
mov     [edi].regEcx,10                 ;修正被除数        
POPAD
mov     eax,ExceptionContinueExecution  ;返回继续执行       
ret
@ContiSearch:        
POPAD
mov     eax,ExceptionContinueSearch         
ret
@_Unwind:
invoke	MsgBox,CTEXT("Div Handler unwinds")
jmp     @ContiSearch
Div_handler0    endp    
;读写冲突内存异常处理函数
Wri_handler1    proc  C  pExcept,pFrame,pContext,pDispatch
PUSHAD
SEHhandlerProcessOrNot  STATUS_ACCESS_VIOLATION,@ContiSearch      ;是否是读写内存冲突
mov     [edi].regEip,offset safePlace1  ;改变返回后指令的执行地址
;mov     [edi].regEdx,offset DATABUF    ;将写地址转换为有效值
POPAD
mov     eax,ExceptionContinueExecution
ret
@ContiSearch:
POPAD
mov     eax,ExceptionContinueSearch 
ret        
@_Unwind:
invoke	MsgBox,CTEXT("Write Acess Handler unwinds")
jmp     @ContiSearch
Wri_handler1    endp    
;断点中断异常处理函数
Int3_handler2   proc C   pExcept,pFrame,pContext,pDispatch
PUSHAD
SEHhandlerProcessOrNot  STATUS_BREAKPOINT,@ContiSearch      ;是否是断点
INC     [edi].regEip                            ;调整返回后指令的执行地址,越过断点继续执行  
;注意在9X下INT3异常发生后指令地址为
POPAD
mov     eax,ExceptionContinueExecution
ret
@ContiSearch:
POPAD
mov     eax,ExceptionContinueSearch 
ret    
@_Unwind:
invoke	MsgBox,CTEXT("Int3 Handler unwinds")
jmp     @ContiSearch
Int3_handler2   endp    
SELF_UNWIND     proc C   pExcept,pFrame,pContext,pDispatch
PUSHAD 
SEHhandlerProcessOrNot  STATUS_ILLEGAL_INSTRUCTION,@ContiSearch      ;是否是无效指令测试
invoke	MessageBox,0,CTEXT("Unwind by SELF(Y) or Let SYSTEM do(N)?"),addr szTit,MB_YESNO
cmp     eax,IDYES
jnz     @ContiSearch
mov     [edi].regEip,offset unwind_return
invoke	RtlUnwind,[pFrame],0,[pExcept],0        
POPAD
mov     eax,ExceptionContinueExecution
ret
@ContiSearch:
POPAD
mov     eax,ExceptionContinueSearch 
ret    
@_Unwind:
invoke	MsgBox,CTEXT("The LAST Handler unwinds")
jmp     @ContiSearch
SELF_UNWIND     endp
;-----------------------------------------
_StArT:
Assume fs:nothing
invoke	SetErrorMode,0
mov     [OLDHANDLER],eax
InstSEHframe    SELF_UNWIND
InstSEHframe    Div_handler0 
InstSEHframe    Wri_handler1
InstSEHframe    Int3_handler2
mov     eax,100
cdq                     ;eax=100 edx=0
xor     ecx,ecx         ;ecx=0
div     ecx             ;除0异常!
invoke	MsgBox,offset FixDivSuc       ;如果处理除0错成功
xor     edx,edx
mov     [edx],eax       ;向地址0处写入,发生写异常!
safePlace1:
invoke	MsgBox,offset FixWriSuc       ;如果处理写保护内存成功
nop
invoke	MsgBox,offset FixInt3Suc      ;如果处理断点int 3成功
invoke	MessageBox,0,CTEXT("Test Illegal INSTR with Handler&Unwind ability or Not(Y/N)?"),offset szTit,MB_YESNO
cmp     eax,IDYES
jnz     no_test
db      0Fh,0bh         ;为非法指令测试
nop
nop
unwind_return:                               
invoke	MsgBox,CTEXT("SELF UNWIND SUC NOW EXIT!")
;xor     eax,eax        ;uncomment this to test   
;mov     [eax],eax      ;
no_test:
UnInstSEHframe          ;卸载所有的回调函数
UnInstSEHframe
UnInstSEHframe
UnInstSEHframe
invoke ExitProcess,0
END	_StArT

感觉SEH的作用非常大,对于正面

能处理异常

单步调试自己(虽然没多大意义,因为有Softice,OD了)

还有反跟踪

对于负面

能进入Ring0(在9x下)

栈溢出时能被利用,也可以用来绕过安全机制

剩下的一小部分是VC++对SEH的封装:

这一部分迟点再更新

未完待续。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年10月31日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档