SafeSEH原理及绕过技术
设计SafeSEH保护机制的目的,以为了防止那种攻击者通过覆盖堆栈上的异常处理函数句柄,从而控制程序执行流程的攻击。
1、SafeSEH的保护原理
SafeSEH的基本原理很简单,即在调用异常处理函数之前,对要调用的异常处理函数进行一系列的有效性校验,如果发现异常处理函数不可靠(被覆盖了,被篡改了),立即终止异常处理函数的调用。不过SafeSEH需要编译器和系统双重支持,缺少一个则保护能力基本就丧失了。下面从两个方面来阐述怎样来实现SafeSEH。
2、SafeSEH机制的运行机理:
- 首先会检查异常处理链是否在当前程序栈中,如果不在,将停止对异常处理函数的调用。
- 检查异常处理函数指针是否指向当前程序栈,如果是,将停止对异常处理函数的调用。
当前两项检查都通过后,程序调用一个全新的函数RtlIsValidHandler(),来对异常处理函数进行有效性验证
下面看一下RtlIsValidHandler的伪码:
BOOL RtlIsValidHandler(handler)
{
if (handler is in an image)
{
// 在加载模块的进程空间
if (image has the IMAGE_DLLCHARACTERISTICS_NO_SEH flag set)
return FALSE; // 该标志设置,忽略异常处理,直接返回FALSE
if (image has a SafeSEH table) // 是否含有SEH表
if (handler found in the table)
return TRUE; // 异常处理handle在表中,返回TRUE
else
return FALSE; // 异常处理handle不在表中,返回FALSE
if (image is a .NET assembly with the ILonly flag set)
return FALSE; // .NET 返回FALSE
// fall through
}
if (handler is on a non-executable page)
{
// handle在不可执行页上面
if (ExecuteDispatchEnable bit set in the process flags)
return TRUE; // DEP关闭,返回TRUE;否则抛出异常
else
return ACCESS_VIOLATION; // enforce DEP even if we have no hardware NX
}
if (handler is not in an image)
{
// 在加载模块内存之外,并且是可执行页
if (ImageDispatchEnable bit set in the process flags)
return TRUE; // 允许在加载模块内存空间外执行,返回验证成功
else
return FALSE; // don't allow handlers outside of images
}
// everything else is allowed
return TRUE;
}
RtlIsValidHandler()函数对以下3种情况允许异常处理函数执行。
(1) 异常处理函数位于加载模块内存范围外,DEP关闭。
(2) 异常处理函数位于加载模块内存范围内,相应模块未启用SafeSEH(不存在SHE表),同时相应模块不是纯IL。
(3) 异常处理函数位于加载模块内存范围内,相应模块启用SafeSEH,异常处理函数在SHE表中。
3、怎样检测PE文件是否启用SafeSEH
前面介绍过数据目录里面的一个结构(IMAGE_LOAD_CONFIG_DIRECTORY),该结构的成员SEHandlerTable是指向合法SEH处理程序地址列表的指针,成员SEHandlerCount是数目。而IMAGE_LOAD_CONFIG_DIRECTORY这个结构体只有/SAFESEH选项设置了才存在,因此,就可以根据它来判断PE文件是否加了/SAFESEH链接选项。这个结构在PE中的偏移由PE附加头IMAGE_DATA_DIRECTORY 数组的第11项指定。
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
4、绕过方法简介
- 利用堆地址覆盖SEH结构绕过SafeSEH
- 上面讲过,在禁用DEP的进程中,异常分发器允许SEH handler位于除栈空间之外的非映像页面。也就是说我们可以把shellcode放置在堆中,然后通过覆盖SEH跳至堆空间以执行shellcode,这样即可绕过SafeSEH保护。
- 利用没有启用SafeSEH保护的模块绕过SafeSEH
- 在介绍原理时讲过,在国内,目前大部分的PC都是安装的Windows XP,也就是说对于大部分Windows操作系统,其系统模块都没有受到SafeSEH保护,可以选用未开启SafeSEH保护的模块来利用,另外,现在还有很多VC6编译的软件,这些软件本身和自带的dll文件,都是可能没有SafeSEH保护的。这时就可以使用它里面的指令作为跳板来绕过SafeSEH。
- 利用加载模块之外的地址绕过SafeSEH
- 同样是根据SafeSEH的原理可知,对于加载模块之外的地址,SafeSEH同样是不进行有效性检测的(当然假设是DEP是关闭的,或者DEP已经被绕过)。
评论区