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.异常
操作系统中常见的异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
调试的时候经常触发5中最具代表性的异常
3.1 EXCEPTION_ACCESS_VIOLATION 0xC0000005
程序企图读写一个不可访问的地址时引发的异常(不存在,或者不具有访问权限)。例如企图读取0地址处的内存。
3.2EXCEPTION_BREAKPOINT 0x80000003
触发断点时引发的异常。在运行的代码中设置断点以后,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结构体组成的链表
1 2 3 4 |
|
Next成员指向下一个_EXCEPTION_REGISTRATION_RECORD结构体指针,handler成员是异常处理函数(异常处理器)。若Next成员的值为FFFFFFFF,则表示它是链表最后一个结点
发生异常的时候会按照(A)->(B)->(C)的顺序依次传递,直到由异常处理器处理
4.2异常处理函数定义
1 2 3 4 5 6 |
|
由系统调用,是一个回调函数,第一个参数是一个指向EXCEPTION_RECORD结构体的指针
1 2 3 4 5 6 7 8 |
|
异常处理函数的第三个参数是指向CONTEXT结构体的指针,CONTEXT结构体的定义如下, CONTEXT结构体用来备份CPU的值。
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 |
|
异常发生的时候,执行异常代码的线程就会发生中断,转而运行SEH,此时OS会把线程 CONTEXT结构体的指针传递给异常处理函数的相应参数。里面有个eip成员,在异常处理函数中将参数传递过来的CONTEXT.eip设置为其他地址,然后返回处理函数。这样之前暂停的线程会执行新的EIP地址处的代码(反调试中经常使用这个技术)
4.3 TEB.NtTib.ExceptionList
通过TEB结构体的NtTib成员可以很容易的访问进程的SEH链,TEB。
NtTib.ExceptionList=FS:[0]
4.4 SEH安装/删除方法
汇编中安装使用
1 2 3 |
|
汇编中的删除SEH代码
1 2 |
|
od中有查看SEH链的功能
5 od中的SEH
程序在正常运行与调试运行的时候有不同的分支代码,借助SEH实现的反调试及时很多,这为代码的调试带来了很多不便,使调试更加困难。OD提供了很多调试选项,调试中发生异常的时候,调试器不会暂停,会自动将异常派送给被调试者。od中选择options-debugging options-.exception选项卡:灵活使用od的excettion选项,可以在不暂停调试器的前提下自动规避使用SEH的反调试“花招”,从而继续调试。