反调试——Windows异常-SEH
反调试——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的更多相关文章
- Windows反调试技术(下)
OD的DBGHELP模块 检测DBGHELP模块,此模块是用来加载调试符号的,所以一般加载此模块的进程的进程就是调试器.绕过方法也很简单,将DBGHELP.DLL改名. #include <Wi ...
- Windows 下常见的反调试方法
稍稍总结一下在Crack或Rervese中比较常见的一些反调试方法,实现起来也比较简单,之后有写的Demo源码参考,没有太大的难度. ①最简单也是最基础的,Windows提供的API接口:IsDebu ...
- Windows反调试技术(上)
写在前面 在逆向工程中为了防止破解者调试软件,通常都会在软件中采用一些反调试技术来防破解.下面就是一些在逆向工程中常见的反调试技巧与示例. BeingDebuged 利用调试器加载程序时调试器会通过C ...
- Windows 32位-调试与反调试
1.加载调试符号链接文件并放入d:/symbols目录下. 0:000> .sympath srv*d:\symbols*http://msdl.microsoft.com/download/s ...
- Windows 反调试技术——OpenProcess 权限过滤 - ObRegisterCallback
转载: https://blog.xpnsec.com/anti-debug-openprocess/ 看雪翻译:https://bbs.pediy.com/thread-223857.htm 本周我 ...
- windows的SEH异常处理以及顶层异常处理
前言 windows的SEH结构化异常处理是基于线程的,传统的SEH结构化异常会基于堆栈形成一条包含异常回调函数地址的链(SEH链).而fs:[0](TEB的第一个字段)指向这条链的链头,当有异常发生 ...
- 反调试技术常用API,用来对付检测od和自动退出程序
在调试一些病毒程序的时候,可能会碰到一些反调试技术,也就是说,被调试的程序可以检测到自己是否被调试器附加了,如果探知自己正在被调试,肯定是有人试图反汇编啦之类的方法破解自己.为了了解如何破解反调试技术 ...
- WinDbg调试流程的学习及对TP反调试的探索
基础知识推荐阅读<软件调试>的第十八章 内核调试引擎 我在里直接总结一下内核调试引擎的几个关键标志位,也是TP进行反调试检测的关键位. KdPitchDebugger : Boolean ...
- 基于TLS的反调试技术
TLS(Thread Local Storage 线程局部存储) 一个进程中的每个线程在访问同一个线程局部存储时,访问到的都是独立的绑定于该线程的数据块.在PEB(进程环境块)中TLS存储槽共64个( ...
随机推荐
- 第39天学习打卡(多线程 Thread Runnable 初始并发问题 Callable )
多线程详解 01线程简介 Process与Thread 程序:是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念. 进程则是执行程序的一次执行过程,它是一个动态的概念.是系统资源分配的 ...
- java基础知识 + 常见面试题
准备校招面试之Java篇 一. Java SE 部分 1.1 Java基础 1. 请你解释Object若不重写hashCode()的话,hashCode()如何计算出来的? Object 的 hash ...
- 小程序基于Token登录 示意图
- salesforce零基础学习(一百零一)如何了解你的代码得运行上下文
本篇参考:https://developer.salesforce.com/docs/atlas.en-us.228.0.apexcode.meta/apexcode/apex_enum_System ...
- 关于PHP的表单数组提交显示
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title></title> 5 <meta chars ...
- 面试被吊打系列 - Redis原理
小张兴冲冲去面试,结果被面试官吊打! 小张: 面试官,你好.我是来参加面试的. 面试官: 你好,小张.我看了你的简历,熟练掌握Redis,那么我就随便问你几个Redis相关的问题吧.首先我的问题是,R ...
- FreeBSD 开发已经迁移至 git
FreeBSD 开发已经迁移至 git 全部预计于 2021 年 3 月完成迁移. https://git.freebsd.org/src.git 或者 https://cgit.freebsd.or ...
- 翻译:《实用的Python编程》05_01_Dicts_revisited
目录 | 上一节 (4.4 异常) | 下一节 (5.2 封装) 5.1 再谈字典 Python 对象系统主要基于字典实现.本节将对此进行讨论. 字典 字典是命名值(named values)的集合. ...
- Java 树结构实际应用 一(堆排序2秒排完800w数据)
堆排序 1 堆排序基本介绍 1) 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复 杂度均为 O(nlogn),它也是不稳定排序. 2) 堆是具有以下性 ...
- Elasticsearch 结构化搜索、keyword、Term查询
前言 Elasticsearch 中的结构化搜索,即面向数值.日期.时间.布尔等类型数据的搜索,这些数据类型格式精确,通常使用基于词项的term精确匹配或者prefix前缀匹配.本文还将新版本的&qu ...