首页
社区
课程
招聘
[原创]windows-SEH详解
发表于: 2019-2-22 20:06 25419

[原创]windows-SEH详解

2019-2-22 20:06
25419
       SEH是window操作系统默认的异常处理机制,逆向分析中,SEH除了基本的异常处理功能外,还大量用于反调试程序(这里SEH时保存在栈中的,漏洞利用的时候会用到)

1.SEH
    SEH是windows操作系统异常处理机制,在程序源代码中使用__try,__except,__finally关键字来具体实现。

2.OS异常处理的办法
     2.1正常运行时候的异常处理方法
     进程运行过程中若发生异常,OS会委托进程进行处理。若进程代码中存在具体的异常处理(如SEH异常处理器)代码,则能够顺利处理相关异常,程序继续运行,但如果进程内部没有具体实现SEH,那么相关异常就无法处理,OS就会启动默认的异常处理机制,终止进程运行
     2.2 调试运行时的异常处理方法
     被调试的进程内部发生异常,OS会首先把异常抛给调试进程处理。调器拥有被调试者的所有权限。被调试者内部发生的异常都由调试器处理。调试过程中的所有异常都先由调试器管理。被调试者发生异常时,调试器会停止运行,必须采取相应的措施来处理异常,完成后续的调试。遇到异常的时候的处理方法如下。
      1)直接修改异常:代码、寄存器、内存
      2)将异常泡杯被调试程序,使用od的shift+f7/f8/f9直接将异常抛还给被调试者
      3)OS默认异常处理机制

3.异常
     操作系统中常见的异常
EXCEPTION_ACCESS_VIOLATION 	0xC0000005 	程序企图读写一个不可访问的地址时引发的异常。例如企图读取0地址处的内存。
EXCEPTION_ARRAY_BOUNDS_EXCEEDED 	0xC000008C 	数组访问越界时引发的异常。
EXCEPTION_BREAKPOINT 	                        0x80000003 	触发断点时引发的异常。
EXCEPTION_DATATYPE_MISALIGNMENT 	0x80000002 	程序读取一个未经对齐的数据时引发的异常。
EXCEPTION_FLT_DENORMAL_OPERAND 	0xC000008D 	如果浮点数操作的操作数是非正常的,则引发该异常。所谓非正常,即它的值太小以至于不能用标准格式表示出来。
EXCEPTION_FLT_DIVIDE_BY_ZERO         	        0xC000008E 	浮点数除法的除数是0时引发该异常。
EXCEPTION_FLT_INEXACT_RESULT 	        0xC000008F 	浮点数操作的结果不能精确表示成小数时引发该异常。
EXCEPTION_FLT_INVALID_OPERATION 	        0xC0000090 	该异常表示不包括在这个表内的其它浮点数异常。
EXCEPTION_FLT_OVERFLOW 	                        0xC0000091 	浮点数的指数超过所能表示的最大值时引发该异常。
EXCEPTION_FLT_STACK_CHECK 	                0xC0000092 	进行浮点数运算时栈发生溢出或下溢时引发该异常。
EXCEPTION_FLT_UNDERFLOW 	                0xC0000093 	浮点数的指数小于所能表示的最小值时引发该异常。
EXCEPTION_ILLEGAL_INSTRUCTION 	        0xC000001D 	程序企图执行一个无效的指令时引发该异常。
EXCEPTION_IN_PAGE_ERROR             	        0xC0000006 	程序要访问的内存页不在物理内存中时引发的异常。
EXCEPTION_INT_DIVIDE_BY_ZERO 	                0xC0000094 	整数除法的除数是0时引发该异常。
EXCEPTION_INT_OVERFLOW 	                        0xC0000095 	整数操作的结果溢出时引发该异常。
EXCEPTION_INVALID_DISPOSITION         	        0xC0000026 	异常处理器返回一个无效的处理的时引发该异常。
EXCEPTION_NONCONTINUABLE_EXCEPTION 	0xC0000025 	发生一个不可继续执行的异常时,如果程序继续执行,则会引发该异常。
EXCEPTION_PRIV_INSTRUCTION 	                0xC0000096 	程序企图执行一条当前CPU模式不允许的指令时引发该异常。
EXCEPTION_SINGLE_STEP 	                        0x80000004 	标志寄存器的TF位为1时,每执行一条指令就会引发该异常。主要用于单步调试。
EXCEPTION_STACK_OVERFLOW 	                0xC00000FD 	栈溢出时引发该异常。
       调试的时候经常触发5中最具代表性的异常
       3.1  EXCEPTION_ACCESS_VIOLATION     0xC0000005    
       程序企图读写一个不可访问的地址时引发的异常(不存在,或者不具有访问权限)。例如企图读取0地址处的内存。
       3.2EXCEPTION_BREAKPOINT  0x80000003  
EXCEPTION_ACCESS_VIOLATION 	0xC0000005 	程序企图读写一个不可访问的地址时引发的异常。例如企图读取0地址处的内存。
EXCEPTION_ARRAY_BOUNDS_EXCEEDED 	0xC000008C 	数组访问越界时引发的异常。
EXCEPTION_BREAKPOINT 	                        0x80000003 	触发断点时引发的异常。
EXCEPTION_DATATYPE_MISALIGNMENT 	0x80000002 	程序读取一个未经对齐的数据时引发的异常。
EXCEPTION_FLT_DENORMAL_OPERAND 	0xC000008D 	如果浮点数操作的操作数是非正常的,则引发该异常。所谓非正常,即它的值太小以至于不能用标准格式表示出来。
EXCEPTION_FLT_DIVIDE_BY_ZERO         	        0xC000008E 	浮点数除法的除数是0时引发该异常。
EXCEPTION_FLT_INEXACT_RESULT 	        0xC000008F 	浮点数操作的结果不能精确表示成小数时引发该异常。
EXCEPTION_FLT_INVALID_OPERATION 	        0xC0000090 	该异常表示不包括在这个表内的其它浮点数异常。
EXCEPTION_FLT_OVERFLOW 	                        0xC0000091 	浮点数的指数超过所能表示的最大值时引发该异常。
EXCEPTION_FLT_STACK_CHECK 	                0xC0000092 	进行浮点数运算时栈发生溢出或下溢时引发该异常。
EXCEPTION_FLT_UNDERFLOW 	                0xC0000093 	浮点数的指数小于所能表示的最小值时引发该异常。
EXCEPTION_ILLEGAL_INSTRUCTION 	        0xC000001D 	程序企图执行一个无效的指令时引发该异常。
EXCEPTION_IN_PAGE_ERROR             	        0xC0000006 	程序要访问的内存页不在物理内存中时引发的异常。
EXCEPTION_INT_DIVIDE_BY_ZERO 	                0xC0000094 	整数除法的除数是0时引发该异常。
EXCEPTION_INT_OVERFLOW 	                        0xC0000095 	整数操作的结果溢出时引发该异常。
EXCEPTION_INVALID_DISPOSITION         	        0xC0000026 	异常处理器返回一个无效的处理的时引发该异常。
EXCEPTION_NONCONTINUABLE_EXCEPTION 	0xC0000025 	发生一个不可继续执行的异常时,如果程序继续执行,则会引发该异常。
EXCEPTION_PRIV_INSTRUCTION 	                0xC0000096 	程序企图执行一条当前CPU模式不允许的指令时引发该异常。
EXCEPTION_SINGLE_STEP 	                        0x80000004 	标志寄存器的TF位为1时,每执行一条指令就会引发该异常。主要用于单步调试。
EXCEPTION_STACK_OVERFLOW 	                0xC00000FD 	栈溢出时引发该异常。
       调试的时候经常触发5中最具代表性的异常
       3.1  EXCEPTION_ACCESS_VIOLATION     0xC0000005    
       程序企图读写一个不可访问的地址时引发的异常(不存在,或者不具有访问权限)。例如企图读取0地址处的内存。
       触发断点时引发的异常。在运行的代码中设置断点以后,cpu尝试执行该处的指令时将触发队形的EXCEPTION_BREAKPOINT异常
      INT3,设置断点对应的汇编指令为INT3,对应的机器指令为0xCC.灵活运用这个原理可以为程序运行带来很大的便利。比如使用hex editor打开PE文件,修改EP地址对应的文件偏移处的第一个字节为0xCC,然后运行该PE文件就会发生EXCEPTION_BREAKPOINT异常,经过OS的默认异常处理后会终止程序运行,若在操作系统的注册表中将默认调试器设置为OllyDbg,那么发生以上异常时OS会自动运行ollydbg调试器,附加发生异常的进程。
      3.3EXCEPTION_ILLEGAL_INSTRUCTION  0xC000001D    
      程序企图执行一个无效的指令时引发该异常。
      3.4EXCEPTION_INT_DIVIDE_BY_ZERO   0xC0000094   
      整数除法的除数是0时引发该异常。
      3.5EXCEPTION_SINGLE_STEP   0x80000004    
      标志寄存器的TF位为1时,每执行一条指令就会引发该异常。主要用于单步调试。

4.SEH详细说明
      4.1SEH链
      SEH以链的形式存在。第一个异常处理中未处理相关异常,它就会被传递到下一个异常处理器,直到得到处理。SEH是由_EXCEPTION_REGISTRATION_RECORD结构体组成的链表
ntdll!_EXCEPTION_REGISTRATION_RECORD
   +0x000 Next             : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : Ptr32 _EXCEPTION_DISPOSITION 
}
      Next成员指向下一个_EXCEPTION_REGISTRATION_RECORD结构体指针,handler成员是异常处理函数(异常处理器)。若Next成员的值为FFFFFFFF,则表示它是链表最后一个结点
               
        发生异常的时候会按照(A)->(B)->(C)的顺序依次传递,直到由异常处理器处理
     4.2异常处理函数定义
EXCEPTION_DISPOSITION __cdecl _except_handler (
  EXCEPTION_RECORD      *pRecord,
  EXCEPTION_REGISTRATION_RECORD *pFrame,
  CONTEXT        *pContext,
  PVOID          pValue
);
       由系统调用,是一个回调函数,第一个参数是一个指向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;
      异常处理函数的第三个参数是指向CONTEXT结构体的指针,CONTEXT结构体的定义如下,   CONTEXT结构体用来备份CPU的值。 
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;              // MUST BE SANITIZED
    DWORD   EFlags;             // MUST BE SANITIZED
    DWORD   Esp;
    DWORD   SegSs;
    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];

} CONTEXT;
       异常发生的时候,执行异常代码的线程就会发生中断,转而运行SEH,此时OS会把线程 CONTEXT结构体的指针传递给异常处理函数的相应参数。里面有个eip成员,在异常处理函数中将参数传递过来的CONTEXT.eip设置为其他地址,然后返回处理函数。这样之前暂停的线程会执行新的EIP地址处的代码(反调试中经常使用这个技术)  
        4.3  TEB.NtTib.ExceptionList
        通过TEB结构体的NtTib成员可以很容易的访问进程的SEH链,TEB。
                          NtTib.ExceptionList=FS:[0]
ntdll!_EXCEPTION_REGISTRATION_RECORD
   +0x000 Next             : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : Ptr32 _EXCEPTION_DISPOSITION 
}
      Next成员指向下一个_EXCEPTION_REGISTRATION_RECORD结构体指针,handler成员是异常处理函数(异常处理器)。若Next成员的值为FFFFFFFF,则表示它是链表最后一个结点

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-2-22 21:10 被wwzzww编辑 ,原因: 补充内容
收藏
免费 9
支持
分享
打赏 + 6.00雪花
打赏次数 2 雪花 + 6.00
 
赞赏  Editor   +1.00 2019/02/25 精品文章~
赞赏  kanxue   +5.00 2019/02/23 感谢分享~
最新回复 (11)
雪    币: 1641
活跃值: (3601)
能力值: (RANK:15 )
在线值:
发帖
回帖
粉丝
2
顶一下
2019-2-22 20:41
0
雪    币: 26245
活跃值: (63297)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
3
支持一下,感谢楼主分享!
2019-2-25 09:49
0
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
支持支持,讲得很详细!
2019-5-17 17:42
0
雪    币: 1176
活跃值: (1264)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
5
自己编写的try except 异常处理是由什么注册管理的 ?
2019-5-17 19:38
0
雪    币: 7285
活跃值: (780)
能力值: ( LV9,RANK:270 )
在线值:
发帖
回帖
粉丝
6
Tennn 自己编写的try except 异常处理是由什么注册管理的 ?
try...catch是编译器对__try ... __except的一个包装,该包装仅处理C++异常类型,在windows下,仍然是通过SEH机制实现。
2019-5-25 13:39
0
雪    币: 1176
活跃值: (1264)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
7
我没问try catch是不是回错了……
2019-5-27 07:46
0
雪    币: 432
活跃值: (141)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
你好,请问为什么使用OD调试时候,对于中文系统nseh = "\xeb\x06\x90\x90" 装入内存时候\xeb\x06会变成一个字节\3F,从而不能出发漏洞 
2019-11-20 14:26
0
雪    币: 14
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
感谢作者分享 最近刚学到着 了解~
2019-12-22 09:47
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
学习到了
2019-12-24 17:14
0
雪    币: 367
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
你好,vs2017编译的时候提示warning C4733: 内联 asm 分配到“FS:0”: 处理程序未注册为安全处理程序
如何解决?用网上的办法在命令行加入/SAFESEH:NO不起作用
2020-2-2 20:41
0
雪    币: 185
活跃值: (292)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
很棒
2020-5-2 16:34
0
游客
登录 | 注册 方可回帖
返回
//