从本节開始,我们就要研究一些略微高级点的话题了,如同在1.2节中看到的,Windows中为抵抗栈溢出做了非常多保护性的检查工作,编译的程序默认开启了这些保护。

假设我们不能绕过这些保护。那么我们的Shellcode也就是一个玩具而已,什么都做不了。

我们从SEH(结构化异常处理)開始。

这篇文章讲SEH简洁易懂:http://www.securitysift.com/windows-exploit-development-part-6-seh-exploits/

因此。本文的前面部分就直接对其进行翻译了,后面动手的部分再结合自己的样例进行,由于动手实践还是用自己写的代码好。

(1)什么是结构化异常处理?

Windows下的硬件和软件异常统一採用结构化异常处理(SEH)机制。异常处理结构通常包含在一个try/except或try/catch代码块中。

例如以下:

/*****************************************************************************/
__try {
// 受保护的代码区域
...
}
__except (exception filter) {
// 异常处理代码
...
}
/*****************************************************************************/

含义非常easy,try保护的代码一定会运行。在发生指定的错误/异常之后,就运行except中的代码,进行异常处理。异常处理器(exception filter)就是告诉操作系统对指定的错误/异常运行什么操作。

异常处理器(exception filter)可能由应用程序实现(通过__try/__except结构),或者使用系统自带的。

由于错误的种类非常多(除0。越界等),相应的异常处理器也有非常多。

所有种类的异常处理器,包含应用程序实现和操作系统实现的,都由Windows系统通过一些数据结构和函数进行统一管理。

(2)SEH的主要组成

每一个异常处理器都相应一个EXCEPTION_REGISTRATION_RECORD结构,该结构例如以下:



这些异常处理器的EXCEPTION_REGISTRATION_RECORD结构连接在一起。组成一个SEH链表。

EXCEPTION_REGISTRATION_RECORD结构中的第一个成员Next指向SEH链表中的下一个成员,因此,你能够通过Next来遍历SEH链。

EXCEPTION_REGISTRATION_RECORD结构中的第二个成员Handler为一个异常处理函数的函数指针,该异常处理函数定义例如以下:



函数的第一个參数指向一个_EXCEPTION_RECORD结构。该结构保存了某个异常的相关信息,包含异常码,异常发生的地址。參数的个数等,例如以下:



_except_handler异常处理函数使用该结构中的信息(还有ContextRecord 參数中的寄存器信息)来推断该异常是否能被SEH链中的某个异常处理器处理。EstablisherFrame 參数也非常重要,后面会说到。

_except_handler异常处理函数返回EXCEPTION_DISPOSITION。假设为ExceptionContinueExecution,表示该异常是否已经被成功处理,假设为ExceptionContinueSearch,表示当前异常处理器无法处理该异常,异常移交给SEH链中的下一个异常处理器。

那么,异常处理机制是怎样使用这些结构和函数来进行异常处理的呢?当一个异常发生的时候,操作系统从SEH链头部開始,检查第一个_EXCEPTION_REGISTRATION_RECORD(即异常处理器)的异常处理函数,看它是否能处理该异常(通过ExceptionRecord 和ContextRecord參数)。

假设不能。则移动到下一个_EXCEPTION_REGISTRATION_RECORD。继续检查,直到找到合适的异常处理器。

Windows在SEH链的末尾放置了一个默认的通用异常处理器。保证异常肯定能被处理。

假设使用默认的异常处理器处理,你一般会看到“程序遇到了一个问题。须要关闭…”之类的信息。

每一个线程有它自己的SEH链。操作系统通过TEB中的ExceptionList成员定位SEH链的起始地址。TEB位于FS:[0]。以下为SEH链的一个示意图(图中简化了_EXCEPTION_REGISTRATION_RECORD结构):



图47 Windows SEH链

上图不是SEH机制的所有,可是足够你理解主要的原理。

如今,我们用一个演示样例来看一看SEH机制。

好了,翻译到此为止。可是我后面所写的内容基本也就是原文的内容,仅仅是我换了自己的演示样例。这样便于实际操作。基本上也就相当于翻译。我们找出1.2节中的example_2(具有栈溢出漏洞的那个程序),来看看它的SEH是什么样的。在Immunity Debugger中选择例如以下菜单:



图48 在Immunity Debugger查看SEH链

就可以查看SEH链。我们看一看example_2的SEH链:



图49 example_2的SEH链

SEH的try/except或try/catch代码块实际上是宏定义的一段代码。将我们自己的代码包裹起来,因此,我们能够从当前线程的栈上来找到SEH链,对比上面的地址,找到它:



图50 栈上的SEH链

对比前面讲述的EXCEPTION_REGISTRATION_RECORD结构。Next成员为链中的下一个异常处理器地址。为0xFFFFFFFF表示已经结尾。即最后的一个默认异常处理器。0x7c839ac0为该默认异常处理器的异常处理函数地址。

回看example_2的代码。我们并未定义自己的异常处理块(try/except或try/catch)。因此。程序自带一个默认异常处理器。前面说到,每一个线程都有一个异常处理链,而线程是动态变化的。随着指令流的进行。运行不同的代码块。调用函数等。那么,程序运行起来又是什么样子的呢?

为了回答上面的问题,我们再来看一看。这个程序有输入字符串的操作(gets),因此,我们让程序运行。到达等待输入的时刻。然后再来看SEH链:



图51 暂停于gets时刻的SEH链

好大一串。

当中有系统的,有VS2008的,另一个我们“自己”的,最后才是系统默认的。这些异常都是用来干嘛的?如今,我们把断点设在调用gets函数之后:



图52

在看此时的SEH链:



图53

看来,刚刚我们应该是看错了位置。

我们前面是在gets函数等待输入的时候看的。也就是说停在了gets函数内部,而gets函数由编译器实现,因此。它内部包装有自己的异常处理。这就是图51中为什么我们看到了那么多系统和编译器提供的异常处理函数。看来。SEH链是在动态变化的,进入了包装有异常处理的代码,就会在SEH链中加入异常处理器,退出其代码块之后,又会从SEH链中删除异常处理器。

这就是为什么说SEH链是与线程相应的。

可是,既然我们自己未定义异常处理,这里为什么还多出来一个?这个后面再说。

接下来,我们给example_2的程序包装一个异常处理块,然后再看看SEH链的样子:

/*****************************************************************************/
// example_10: 演示SEH链
#include <Windows.h>
#include <stdio.h> void get_print()
{
char str[11]; __try
{
gets(str);
printf("%s\n", str);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
//
}
} int main()
{
get_print(); return 0;
}
/*****************************************************************************/

最初暂停的点:



图54

最初还是仅仅有一个SEH链。相同在调用gets之后的语句暂停:



图55 example_10的SEH链

和图53对比。SEH链中多了一个节点,由于我们自己加入了一个异常处理块。如今另一个疑问,多出来的那个是什么?依照SEH链的原理,局部的应该位于前面。因此,第一个是我们自定义的。那第二个是哪里来的呢?(注意不要依据地址来和图53比較进行推断,如今已经是一个不同的程序了)它的异常处理函数地址为0x0041104B,明显位于本模块中。我们把断点设置调用 get_print()之前。也就是main函数中,来看:



图56

这个时候。第二个异常处理器就已经出现了,因此,这个异常处理器是main函数的,VC++实现main函数的时候也包装了一个异常处理块。你能够自己去找到是何时设置的。

我们来看看两个异常处理函数的地址,分别为0x411046和0x41104B:



图56



图57

第一个指向MSVCR90D.dll中的_except_handler3,第二个终于指向MSVCR90D.dll中的_except_handler4_common。这是VC++对SEH的实现。并不是使用原生的SEH,要理解这个_except_handler3和_except_handler4_common,你须要这篇文章:https://www.microsoft.com/msj/0197/exception/exception.aspx

这篇经典的文章有中文翻译。

本节先到这里。下一节继续。

栈溢出笔记1.9 认识SEH的更多相关文章

  1. 栈溢出笔记1.3 准备Shellcode

    经过1.1和1.2节的讲述,我们已经知道了怎样更改EIP的值. 程序运行函数之后将跳转到我们设定的位置開始运行,因此,我们须要准备一个自己的程序,接手后面的工作.这是一个什么样的程序?是一个C语言编写 ...

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

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

  3. SEH分析笔记(X64篇)

    SEH分析笔记(X64篇) v1.0.0 boxcounter 历史: v1.0.0, 2011-11-4:最初版本. [不介意转载,但请注明出处 www.boxcounter.com  附件里有本文 ...

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

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

  5. 关于C++异常机制的笔记(SEH, try-catch)

    昨天晚上加班解决了一个问题,是由于无法正确的捕获到异常导致的.刚开始用try-catch,但是没法捕获到异常:后面改成SEH异常才解决.因此今天将这个问题重新梳理了一遍,关于try-catch, SE ...

  6. Windows内核读书笔记——SEH结构化异常处理

    SEH是对windows系统中的异常分发和处理机制的总称,其实现分布在很多不同的模块中. SEH提供了终结处理和异常处理两种功能. 终结处理保证终结处理块中的程序一定会被执行 __try { //要保 ...

  7. linux漏洞分析入门笔记-栈溢出

    ida7.0 ubuntu16.04 lts 0x00:环境配置 使用IDA远程调试Linux程序步骤如下: 1. 在进行远程调试之前需要对Linux平台进行一些准备工作.在IDA的安装目录中的dbg ...

  8. exploit writing tutorial 阅读笔记总结

    近日阅读Corelan Team编写的exploit writing tutorial系列,大致了解了一下原理,记了一些笔记.此系列文章有中文翻译版,在看雪论坛上发表. 英文版地址:https://w ...

  9. C++Windows核心编程读书笔记

    转自:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E6%96%87/71405.shtml "C++Windows核心编程读书笔 ...

随机推荐

  1. C#string转换为Datetime

    DateTime.ParseExact("0710090000", "MMddHHmmss", CultureInfo.CurrentCulture, Date ...

  2. UML学习之初步总结

    UML(Unified Modeling Language)即统一建模语言,是一种开放的方法,用于说明.可视化.构建和编写一个正在开发的.面向对象的.软件密集系统的制品的开放方法.UML展现了一系列最 ...

  3. 15、python学习手册之:python语句、赋值、表达式和打印

    1.语句的另一个特殊规则是用一对括号把语句括起来就可以:括号().方括号[].字典的大括号{}.任何括在这些符号里的程序代码都可横跨好几行. 2.括号是可以包含一切的,因为任何表达式都可以包含在内,只 ...

  4. MyBatis学习总结(13)——Mybatis查询之resultMap和resultType区别

    MyBatis的每一个查询映射的返回类型都是ResultMap,只是当我们提供的返回类型属性是resultType的时候,MyBatis对自动的给我们把对应的值赋给resultType所指定对象的属性 ...

  5. 图灵机器人API,适用于微信、微博、QQ群、智能硬件等

    该API有智能聊天.查天气.查快递.查菜谱.查车票.查航班.查出行.查周边等近500个功能,能够用在微信公众平台.QQ群.手机语音助手.智能硬件等领域\ [1].[代码] [PHP]代码 跳至 [1] ...

  6. Codeforces Round #426 (Div. 1) A.The Meaningless Game (二分+数学)

    题目链接: http://codeforces.com/problemset/problem/833/A 题意: 给你 \(a\) 和 \(b\),两个人初始化为 \(1\).两个人其中一方乘以 \( ...

  7. 为什么我要选择erlang+go进行server架构(2)

    原创文章,转载请注明出处:server非业余研究http://blog.csdn.net/erlib 作者Sunface 为什么我要选择Erlang呢? 一.erlang特别适合中小团队创业: erl ...

  8. 9.6 Binder系统_驱动情景分析_server的多线程实现

    当多个client对server发出请求的时候,如果server忙不过来的时候会创建多线程来处理请求 那么忙不过来由谁来判断? server进程有个binder_proc结构体,其里面有todo链表( ...

  9. VSX(翻译)Moving Code Blocks Among Code Regions using VS 2010 Extensions

    Moving Code Blocks Among Code Regions using VS 2010 Extensions (翻译)使用VS 2010 扩展性将代码块移至Region区域中 Down ...

  10. Spring Boot系列二 Spring @Async异步线程池用法总结

    1. TaskExecutor Spring异步线程池的接口类,其实质是java.util.concurrent.Executor Spring 已经实现的异常线程池: 1. SimpleAsyncT ...