反调试——Windows异常-SEH

反调试——Windows异常-SEH

反调试——Windows异常-SEH

概念:

SEH:Structured Exception Handling

SEH是Windows默认的异常处理机制

如何使用

在代码中使用

__try
​
​
__except()//结构类型的语句

__except()小括号里面填写表达式,表达式为真的时候执行里面的内容

__try里面包含的是可能触发异常的语句,except里面包含的是出现了异常后执行的操作。

__except()括号中表达式的取值范围:
1:处理异常
0:不处理异常交给下一个异常节点去处理
-1:继续执行也就是继续EIP处理执行,但是这里又有异常,所以这里就会一直卡在这里

 

例子:

int main()
{
 __try
 {
  cout<<"hello,world"<<endl;
 }
 __except(1)
 {
  cout<<"异常"<<endl;
 }
 return 0;
}

异常的作业

1便于查找错误

2可以用在反调试里面

异常处理机制

当我们在非调试状态下运行一个程序,程序如果触发了异常,会先判断是否有异常处理器,如果存在则跳转到异常处理函数去执行,如果不存在则退出程序

如果程序处于被调试状态,触发异常时,操作系统会先把异常抛给调试进程,也就是让调试器来处理异常。可以看到的现象就是触发了异常后,程序会暂停下来,也就是断下来,也就是断点的原理。当异常抛给调试器后,调试器可以选择:

1修改触发异常的代码继续执行(程序会停在触发异常的代码处,导致异常的代码无法执行)

2忽略异常交给SEH执行

也就是说Windows发生异常后的处理顺序为:1、调试器处理。2、SEH处理 3、崩溃

剖析SEH

SEH结构:

typedef struct _EXCEPTION_REGISTRATION_RECORD {
   struct _EXCEPTION_REGISTRATION_RECORD *Next;
   PEXCEPTION_ROUTINE Handler;//异常处理器,异常处理函数
} EXCEPTION_REGISTRATION_RECORD;

SEH在程序中实际上是以链表形式存在,每一个next都指向下一个SEH,这个链表也叫SEH链

 

每次添加一个异常就会添加该异常到异常链的头结点的位置

观察SEH是如何生成和使用的

生成两个程序观察,两个程序的区别就是一个有异常SEH,一个没有

//有异常的程序代码
#include<Windows.h>
#include<iostream>
int main()
{
 __try
 {
  char* str = NULL;
  str[0] = 'a';
 }
 __except(1)
 {
  printf("触发异常了\n");
 }
 printf("Sna1lGo\n");
 return 0;
}

 

//没有异常的程序代码
#include<Windows.h>
#include<iostream>
int main()
{
 char* str = NULL;
 str[0] = 'a';
 printf("Sna1lGo\n");
 return 0;
}

分别生成后,都用od打开调试比对

 

然后都进入main函数

 

重点查看SEH的代码:

 

这四条指令就是SEH的关键代码,这一系列操作相当于创建了一个异常的结构体,然后添加到异常链的表头里面。

分析为什么是这样:

首先,大概画一个堆栈图:

 

先存进来了一个0x01293609,然后调用了fs:[0]这个东西,这个东西有点眼熟之前的TEP-PEB查找核心模块的时候有用过,但是这里,可以将fs:[0]直接理解为SEH链的表头。

这里取出来fs:[0]给eax后又把eax入栈,然后将fs:[0]赋值为esp

 

 

可以理解为在栈中创建了一个SEH变量,然后第一个字段存放了函数地址也就是0x01293690,next字段指向了fs:[0]也就是SEH链的第一个节点,然后再把fs:[0]的值修改为该节点的首地址,也就是让fs:[0]指向新的节点。(可能你的代码有点不一样,但是稍微分析下,对于异常处理这里也是一样的)

下面进入异常处理函数的地址查看(这里是0x01293690)

 

 

然后再运行会暂停下来,因为出现了异常,异常优先给调试器处理,但是调试器也是可以选择处理异常的:

在od的选项中选择调试选项,再选择异常:

 

 

就可以设置要捕获的异常类型了,选择忽略掉一些异常后再遇到就不会中断下来了。

也可以选择插件的StrongOD:

 

在取消掉Skip Some Exceptions之后,OD就会捕获所有异常了

SEH链存放的位置

 

经过上面的分析可以知道了,SEH存放的位置在fs:[0]这里

操作系统如何使用SEH

创建异常后,操作系统会自动把异常添加到头结点,然后把头指针指向新的异常节点

 

总结:

Windows中有一个机制叫异常处理机制,当出现异常的时候操作系统会先把异常抛给调试器并停止在该指令位置,如果没有调试器就会抛给SEH来处理,SEH实现的原理是内部是一个SEH链表包含了一系列异常处理函数,当有异常类添加进来的时候操作系统会把异常添加到SEH链表里面,然后当异常出现的时候遍历异常类看看有没有对应的异常处理,如果该异常没有异常处理则直接程序崩溃。

分享到 :
相关推荐