@author: dlive

SEH是Windows的异常处理机制,在程序源代码中使用__try,__catch,__finally关键字来具体实现。

但SEH与C++的try, catch异常处理不同,从时间上看,与C++的try, catch相比,微软先创建了SEH机制,然后才将它搭载到VC++中。

SEH大量应用于压缩器,保护器,恶意程序用来反调试

0x01 OS的异常处理方法

正常运行时的异常处理方法

若进程代码中有具体的异常处理代码,则能顺利处理相关异常,否则OS会启动默认的异常处理机制,终止进程运行

调试运行时的异常处理方法

被调试进程内部发生异常,OS会首先把异常交给调试器处理,若调试器不处理则异常交给被调试者处理,若仍不处理,最后由OS默认的异常处理机制处理。

(OD中使用shift+F7/F8/F9【step into/over/run】可以将当前异常抛还给被调试者)

0x02 常见异常

1.EXECPTION_ACCESS_VIOLATION (C0000005)

试图访问不存在或不具有访问权限的内存区域时,发生非法访异常

2.EXECPTION_BREAKPOINT(80000003)

调试器就是利用该异常实现断点功能的

3.EXCEPTION_ILLEGAL_INSTRUCTION(C000001D)

CPU遇到无法解析的指令时引发该异常。比如“0FFF“指令在x86 CPU中未定义,CPU遇到该指令将引发此异常。

4.EXCEPTION_INT_DIVIDE_BY_ZERO(C0000094)

除法中分母为0引发的异常

5.EXCEPTION_SINGLE_STEP(80000004)

CPU进入单步模式后,每执行一条指令就会引发EXCEPTION_SINGLE_STEP异常,暂停运行。

将EFLAGS寄存器的TF(Trap Flag, 陷阱标志位)位设置为1后,CPU就会进入单步工作模式。

0x03 SEH

SEH以链的形式存在,第一个异常处理器若未处理相关异常,它会被传递到下一个异常处理器,直到得到处理。

从技术层面上看,SEH是由_EXCEPTION_REGISTRATION_RECORD结构体组成的链表

typedef struct _EXCEPTION_REGISTRATION_RECORD
{
PEXCEPTION_REGISTRATION_RECORD Next;
PEXCEPTION_DISPOSITION Handler;
} EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD;

Next是指向下一个结构体的指针,Handler是异常处理函数的地址。若Next = FFFFFFFF,则表示它是最后一个节点。

异常处理函数声明如下

EXCEPTION_DISPOSITION _except_handler
(
EXCEPTION_RECORD *pRecord,
EXCEPTION_REGISTRATION_RECORD *pFrame,
CONTEXT *pContext,
PVOID pValue
);

返回值EXCEPTION_DISPOSITION为枚举类型,ExceptionContinueExecution(0)表示继续执行异常代码,ExceptionContinueSearch(1)表示运行下一个异常处理函数

函数的第一个参数为EXCEPTION_RECORD结构体指针

typedef _EXCEPTION_RECORD{
DWORD ExceptionCode; //异常类型
...
PVOID ExceptionAddress;// 异常发生的地址
}EXCEPTION_RECORD, *PEXCEPTION_RECORD;

函数的第三个参数为线程的上下文CONTEXT结构体,这个结构体在“调试钩取”部分介绍过。每个线程内部都拥有1个CONTEXT结构体。

在异常处理函数中将参数传递过来的CONTEXT.Eip设置为其他地址,然后返回异常处理函数。这样,之前暂停的线程会执行新设置的EIP处的代码(反调试中经常采用这一技术)

TEB.NtTib.ExceptionList(FS:0)存储着SEH链的地址,可以通过FS:[0]获得SEH地址。

0x04 调试SEH

使用OD运行seh.exe,找到用户自定义代码

这里使用一种新的方法定位用户代码,F9运行seh.exe弹出对话框,在OD中点击暂停(F12)

此时程序运行在MessageBox的代码区域,即在user32.dll的内存空间中运行。

使用alt+F9(mac为option+F9)快捷键,该快捷键功能为使程序继续运行直到用户代码空间。

这样EIP便回到用户代码空间中MessageBoxA调用结束的位置,这样就找到了用户代码。

1.查看SEH链

在OD数据窗口ctrl+G跟踪dword ptr fs:[0]

dword ptr fs:[0] == 0012FF78

将数据窗口调节为如下模式,可以看到OD生成对SEH的注释信息,0012FF78指向SEH链头结点

查看第一个SEH处理函数

该函数为VC++生成PE文件时默认添加到其启动函数的

接着查看SEH链中下一个启动函数

该SEH结点为SEH链中最后一个节点(Next=FFFFFFFF)SEH处理函数为ntdll.dll中定义的系统函数,这是OS的默认异常处理器,创建进程时OS会自动产生默认的SEH

2.添加SEH

图中前三行汇编代码即为SEH的安装代码,具体可参考图中注释,本质就是一个链表插入节点的操作

可以看到OD在栈上也会生成SEH的注释,ESP指向的为新SEH结构体中的Next成员变量,ESP+4指向的为SEH处理函数的地址

tips: OD自带查看SEH链功能

菜单中选择查看->SEH链

查看选项提供的功能还是很有用的

3.查看SEH异常处理函数参数

在所有SEH异常处理函数开头下断点,当发生异常时程序将在0040105A处断下

ESP+4指向EXCEPTION_RECORD结构体,结构体的第一个成员变量DWORD ExceptionCode的值为c0000005即EXCEPTION_ACCESS_VIOLATION异常

发生异常的地址PVOID ExceptionAddress为00401019

ESP+8指向EXCEPTION_REGISTRATION_RECORD结构体,其值为0012FF78,它是SEH的起始地址

ESP+C为第三个参数,它指向CONTEXT结构体,该结构体中存储着线程上下文信息,CONTEXT.Eip(Address of CONTEXT + 0xB8)为发生异常的代码地址值为00401019

ESP+10为第四个参数,它供系统使用,可忽略

4.调试异常处理函数代码

前面的内容明白了之后看这段代码还是非常简单的,注释部分详细描述了该代码的功能(这是一种常见的反调试方法)

代码最后return 0表示ExceptionContuineExecution表示异常得到处理,相关线程可以继续执行

00401023和00401039分别是如下两段代码

这里有几个需要重视的地址:

FS:[30] -> PEB的地址

PEB + 0x02 -> PEB.BeingDebugged的地址

CONTEXT + 0xB8 -> CONTEXT.Eip的地址

运行到ret指令后,异常处理函数结束,控制权返回到ntdll.dll模块的代码区域,它属于系统区域,ALT+F9(MAC为OPTION+F9),运行到用户代码区域可以看到运行至00401023处

好吧,alt+f9不行,好像是因为多线程的原因,ntdll.dll代码空间中调用了ZwContinue恢复线程运行(跟进ZwContinue发现最后使用了系统调用),所以需要手动在00401023处下断点才能断下

5.删除SEH

执行完MessageBox之后执行如上0040104D处代码

执行fs:[0] = Next,之后清理栈空间(add esp,4),最后ret

tips2: OD调试选项之异常

勾选上忽略异常之后,被调试者若发生如上异常,调试器会直接将这些异常交给被调试者的异常处理程序处理,无需使用Shift+F7/F8/F9进行手动忽略

SEH的更多相关文章

  1. Kingsoft Office Writer 2012 8.1.0.3385 - (.wps) Buffer Overflow Exploit (SEH)

    #!/usr/bin/python # Exploit Title: Kingsoft Office Writer v2012 8.1.0.3385 .wps Buffer Overflow Expl ...

  2. 第25章 SEH结构化异常处理_未处理异常及向量化异常

    25.1 UnhandledExceptionFilter函数详解 25.1.1 BaseProcessStart伪代码(Kernel32内部) void BaseProcessStart(PVOID ...

  3. 第24章 SEH结构化异常处理_异常处理及软件异常

    24.1  程序的结构 (1)try/except框架 __try{ //被保护的代码块 …… } __except(except fileter/*异常过滤程序*/){ //异常处理程序 } (2) ...

  4. 第23章 SEH结构化异常处理(3)_终止处理程序

    23.3 终止处理程序 23.3.1 程序的结构 (1)框架 __try{ //被保护的代码块 …… } __finally{ //终止处理 } (2)__try/__finally的特点 ①fina ...

  5. 第23章 SEH结构化异常处理(2)_编译器对系统SEH机制的封装

    23.2 编译器层面对系统SEH机制的封装 23.2.1 扩展的EXCEPTION_REGISTRATION级相关结构:VC_EXCEPTION_REGISTRATION (1)VC_EXCEPTIO ...

  6. 第23章 SEH结构化异常处理(1)_系统SEH机制

    23.1 基础知识 23.1.1 Windows下的软件异常 (1)中断和异常 ①中断是由外部硬件设备或异步事件产生的 ②异常是由内部事件产生的,可分为故障.陷阱和终止三类. (2)两种异常处理机制: ...

  7. KTHREAD 线程调度 SDT TEB SEH shellcode中DLL模块机制动态获取 《寒江独钓》内核学习笔记(5)

    目录 . 相关阅读材料 . <加密与解密3> . [经典文章翻译]A_Crash_Course_on_the_Depths_of_Win32_Structured_Exception_Ha ...

  8. Windows SEH学习 x86

    windows 提供的异常处理机制实际上只是一个简单的框架.我们通常所用的异常处理(比如 C++ 的 throw.try.catch)都是编译器在系统提供的异常处理机制上进行加工了的增强版本.这里先抛 ...

  9. 使用了非标准扩展:“xxx”使用 SEH,并且“xxx”有析构函数

    如果一个函数内使用了异常处理机制, VC 编译器在编译该函数时,它会给此函数插入一些“代码和信息”(代码指的是当该函数中出现异常时的回调函数,而信息主要是指与异常出现相关的一些必要的链表),因此每份函 ...

  10. 构造SEH来实现跳转-转载

    下面的代码出自CSDN Delphi版的一高人(kiboisme 蓝色光芒) procedure ExceptProc{ExceptionRecord,SEH,Context,DispatcherCo ...

随机推荐

  1. Vm-Ubuntu下配置Qt开发环境

    在昨天的Ubuntu换降下,安装Qt发现编译的时候是缺少opengl的 奈何找了好多方式都无法安装opengl 今天看到另一位大神写的,才发下自己找的还是有问题 大神帖子网址:http://blog. ...

  2. LeetCode 81——搜索旋转排序数组 II

    1. 题目 2. 解答 2.1. 方法一 基于 LeetCode 33--搜索旋转排序数组 中的方法二. 当 nums[mid] = nums[right] 时,比如 [1, 1, 2, 1, 1], ...

  3. term "JavaScript"

    在Web浏览器上下文中理解的总称“JavaScript”包含几个非常不同的元素. 其中一个是核心语言(ECMAScript),另一个是Web API的集合,包括DOM(文档对象模型) JavaScri ...

  4. BZOJ 4011 HNOI2015 落忆枫音 DAG上的dp(实际上重点在于分析)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4011 题意概述:给出一张N点的DAG(从1可以到达所有的点),点1的入度为0.现在加一条原 ...

  5. C++STL——list

    一.相关定义 list 链表,分配的内存不连续 可以高效地进行插入/删除元素 不可随机访问,访问速度慢 特征 只能通过迭代器来访问list中的元素 在头和尾都可以插入元素 二.list [前提条件] ...

  6. ui-grid下拉过滤

    { field: 'TDK', displayName: 'TDK缺失与否', cellTemplate: `<div class="ui-grid-cell-contents&quo ...

  7. 【bzoj2325】[ZJOI2011]道馆之战 树链剖分+线段树区间合并

    题目描述 给定一棵树,每个节点有上下两个格子,每个格子的状态为能走或不能走.m次操作,每次修改一个节点的状态,或询问:把一条路径上的所有格子拼起来形成一个宽度为2的长方形,从起点端两个格子的任意一个开 ...

  8. 【bzoj4070】[Apio2015]雅加达的摩天楼 set+堆优化Dijkstra

    题目描述 印尼首都雅加达市有 N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 0 到 N−1.除了这 N 座摩天楼外,雅加达市没有其他摩天楼. 有 M 只叫做 “doge” 的神秘生物 ...

  9. sql in()批量操作

    //批量修改 update 表A   set A.name='n'  where   A.id    in(字符串); //批量删除 delete  from    表名称 where  列名称   ...

  10. 2017南开ACM校赛(网络赛) 民间题解

    orz 首先说一下这个只是民间题解,可能会有很多错误 程序还没有评测,所以可能存在问题 C题比赛的时候没想到..后来发现是个模板题,所以没有代码 希望这份题解能对读者有所启发吧... A题 直接倒序枚 ...