反调试——Windows异常-SEH

概念:

SEH:Structured Exception Handling

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

如何使用

在代码中使用

__try


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

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

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

例子:

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的更多相关文章

  1. Windows反调试技术(下)

    OD的DBGHELP模块 检测DBGHELP模块,此模块是用来加载调试符号的,所以一般加载此模块的进程的进程就是调试器.绕过方法也很简单,将DBGHELP.DLL改名. #include <Wi ...

  2. Windows 下常见的反调试方法

    稍稍总结一下在Crack或Rervese中比较常见的一些反调试方法,实现起来也比较简单,之后有写的Demo源码参考,没有太大的难度. ①最简单也是最基础的,Windows提供的API接口:IsDebu ...

  3. Windows反调试技术(上)

    写在前面 在逆向工程中为了防止破解者调试软件,通常都会在软件中采用一些反调试技术来防破解.下面就是一些在逆向工程中常见的反调试技巧与示例. BeingDebuged 利用调试器加载程序时调试器会通过C ...

  4. Windows 32位-调试与反调试

    1.加载调试符号链接文件并放入d:/symbols目录下. 0:000> .sympath srv*d:\symbols*http://msdl.microsoft.com/download/s ...

  5. Windows 反调试技术——OpenProcess 权限过滤 - ObRegisterCallback

    转载: https://blog.xpnsec.com/anti-debug-openprocess/ 看雪翻译:https://bbs.pediy.com/thread-223857.htm 本周我 ...

  6. windows的SEH异常处理以及顶层异常处理

    前言 windows的SEH结构化异常处理是基于线程的,传统的SEH结构化异常会基于堆栈形成一条包含异常回调函数地址的链(SEH链).而fs:[0](TEB的第一个字段)指向这条链的链头,当有异常发生 ...

  7. 反调试技术常用API,用来对付检测od和自动退出程序

    在调试一些病毒程序的时候,可能会碰到一些反调试技术,也就是说,被调试的程序可以检测到自己是否被调试器附加了,如果探知自己正在被调试,肯定是有人试图反汇编啦之类的方法破解自己.为了了解如何破解反调试技术 ...

  8. WinDbg调试流程的学习及对TP反调试的探索

    基础知识推荐阅读<软件调试>的第十八章 内核调试引擎 我在里直接总结一下内核调试引擎的几个关键标志位,也是TP进行反调试检测的关键位. KdPitchDebugger : Boolean ...

  9. 基于TLS的反调试技术

    TLS(Thread Local Storage 线程局部存储) 一个进程中的每个线程在访问同一个线程局部存储时,访问到的都是独立的绑定于该线程的数据块.在PEB(进程环境块)中TLS存储槽共64个( ...

随机推荐

  1. 后端程序员之路 17、LaTeX公式

    之前的文章写了两个公式:d(x,y)=\sqrt{\sum_{i=1}^{n}(x_i-y_i)^2} H_x=-\sum_{i=1}^{n}p(x_i)\log_{2}{p(x_i)} LaTex ...

  2. 653. 两数之和 IV - 输入 BST + HashSet

    653. 两数之和 IV - 输入 BST 题目描述 题解分析 最简单的方法就是遍历整棵树,找出所有可能的组合,判断是否存在和为 kk 的一对节点.现在在此基础上做一些改进. 如果存在两个元素之和为 ...

  3. OpenGL导出渲染的图像到外部文件中

    需要配置Freeimage库 首先下载好FreeImage 找打dist目录下的x32目录,将.h文件放在包含目录下:将lib文件放在库目录下,将dll放在运行目录下 保存渲染结果到png格式的图像: ...

  4. Ubuntu 18.04下Intel SGX应用程序程序开发——获得OCALL调用的返回值

    本文中,我们介绍在Enclave函数中调用不可信OCALL函数,并获得OCALL函数的返回值. 1. 复制SampleEnclave示例并建立自己的OcallRetSum项目 SampleEnclav ...

  5. 2020年12月-第01阶段-前端基础-认识HTML

    1. HTML 初识 HTML 指的是超文本标记语言 (Hyper Text Markup Language)是用来描述网页的一种语言. HTML 不是一种编程语言,而是一种标记语言 (markup ...

  6. 爬虫必知必会(6)_提升scrapy框架爬取数据的效率之配置篇

    如何提升scrapy爬取数据的效率:只需要将如下五个步骤配置在配置文件中即可 增加并发:默认scrapy开启的并发线程为32个,可以适当进行增加.在settings配置文件中修改CONCURRENT_ ...

  7. Linux系统(Centos7)最新版本Docker简易(yum)安装步骤

    Docker从1.13版本之后采用时间线的方式作为版本号,分为社区版CE和企业版EE. 社区版是免费提供给个人开发者和小型团体使用的,企业版会提供额外的收费服务,比如经过官方测试认证过的基础设施.容器 ...

  8. django 自带的用户系统

    首先,我要说明一下,下面内容不是必须品,如果各位大神喜欢手写也是可以的,你也可以选择自带的功能来缩减你的代码量,提高效率! 第一步 系统配置用户表 首先,在models中创建用户表,导包 from d ...

  9. 小白的第一次sql实战

    去年发的有一篇sql注入忘记粘贴过来了,今天想起了就fuzz过来一下 有id尝试sql注入 找这种sql注入的站用sql检索就行了,但是最好挂代理用谷歌搜索,百度的话搜sql注入的很多被别人打过了,导 ...

  10. 【故障公告】阿里云 RDS SQL Server 数据库实例 CPU 100% 引发全站故障

    非常抱歉,今天 8:48 开始,我们使用的阿里云 RDS SQL Server 数据库实例突然出现 CPU 100%  问题,引发全站故障,由此给您带来麻烦,请您谅解. 发现故障后立即进行主备切换,和 ...