SEH学习

SEH学习以前觉得加技术的QQ群作用只有一个:闲聊,浪费时间现在想找5,6个长期有时间学习逆向的朋友,在一个小群里面,有问题互相讨论(只讨论技术上的问题)为了保持群的活跃,有要求如下群成员要求1懂C语言汇编,基础windows知识2懂得最基本的脱壳激活成功教程知识3乐于助人4群成员之间互相认识,了解各自水平有兴趣加我的QQ315,1028,21(逗号是为了避免

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

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

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

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

一些问题和回答

异常是谁提出的

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

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

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

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

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

其他原因吧,不一一列举

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

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

异常处理工作流程

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

_EXETPTION_DEBUG_INFO结构如下

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结构

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结构

EXCEPTION_REGISTRATION_RECORD
Prev    dd
Handler dd
EXCEPTION_REGISTRATION_RECORD ENDS

链中的前一个EXCEPTION_REGISTRATION_RECORD

当前的Handler

_EXCEPTION_POINTERS
pEXCEPTION_RECORD ExceptionRecord dd
pCONTEXT ContextRecord            dd
_EXCEPTION_POINTERS ENDS

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

EXCEPTION_RECORD
DWORD ExceptionCode
DWORD ExceptionFlags
struct EXCEPTION_RECORD
DVOID ExceptionAddress
DWORD NumberParameters
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]
}EXCEPTION_RECORD ends

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

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

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

发生异常的地址

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

Context结构(寄存器们)

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

只罗列,不多解释

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

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

;******************************************
;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中加载:

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调试下就知道为什么了

assume fs:nothing
push SehHandler
push [fs:0]mov [fs:0],esp

线程SEH使用例子1

;******************************************
;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

;******************************************
;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则表明正在展开堆栈.
展开堆栈是为了让程序在结束之前能够释放资源

堆栈展开例子

;******************************************
;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的封装:

这一部分迟点再更新

未完待续。

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

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/231328.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Wireshark抓包实验[通俗易懂]

    Wireshark抓包实验[通俗易懂]Wireshark抓包实验1.1学习Wireshark工具的基本操作学习捕获选项的设置和使用,如考虑源主机和目的主机,正确设置CaptureFilter;捕获后设置DisplayFilter。1.2PING命令的网络包捕获分析PING命令是基于ICMP协议而工作的,发送4个包,正常返回四个包。以主机210.31.40.41为例,主要实验步骤为:(1)设置“捕获过滤”:在…

  • idea 激活码2021.2.3_最新在线免费激活[通俗易懂]

    (idea 激活码2021.2.3)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.htmlHQE565NV3W-eyJsa…

  • xml格式化 java_Java XML格式化程序

    xml格式化 java_Java XML格式化程序xml格式化javaeXtensiveMarkupLanguage(XML)isoneofthepopularmediumformessagingandcommunicationbetweendifferentapplications.SinceXMLisopensourceandprovidescontroloverdataformatv…

  • php 字符串 替换 最后,如何替换php字符串中最后一个字符

    php 字符串 替换 最后,如何替换php字符串中最后一个字符如何替换php字符串中最后一个字符发布时间:2020-08-1010:36:23来源:亿速云阅读:91作者:Leah这篇文章运用简单易懂的例子给大家介绍如何替换php字符串中最后一个字符,代码非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。php替换字符串最后一个字符的方法:首先使用PHP中的“substr”函数或者“mb_substr”截取字符串至倒数第一位;然后拼接自己想要的数…

  • Unix/Linux fork前传[通俗易懂]

    Unix/Linux fork前传[通俗易懂]本文是《Linuxfork那些隐藏的开销》的前传。fork的由来fork的思想在UNIX出现几年前就出现了,时间大概是1963年,这比UNIX在PDP-7上的第一个版本…

  • Jenkins安装_ansible jenkins

    Jenkins安装_ansible jenkins前言jenkins的环境搭建方法有很多,本篇使用docker快速搭建一个jenkins环境。环境准备:mac/Linuxdockerdocker拉去jenkins镜像先下载jenkins镜

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号