栈溢出笔记1.11 SafeSEH

在上节写示例的过程中,我把要用到的POP+POP+RET指令写在了自己的一个DLL中。POP+POP+RET指令是很常见的指令,一般函数的末尾都是这种形式,因此,系统DLL中应该是有该指令的,比如ntdll.dll中就有:
这里写图片描述
图73

我们把上节示例中的地址改成这个地址试试,没有弹出MessageBox,说明Shellcode失效了,在调试器中看看:
这里写图片描述
图74

提示说无法处理异常,说明改了地址后的异常处理函数没有被运行。下面我们继续用我自己的DLL,但是重新编译它,这次在编译时加上“/SAFESEH”选项:
栈溢出笔记1.11 SafeSEH_第1张图片
图75

再来尝试一下(注意,重新编译后,指令地址发生变化),还是同样的提示。用Immunity Debugger的mona插件查看以下加载的模块:
栈溢出笔记1.11 SafeSEH_第2张图片
图76

只有exe不是SafeSEH,其它DLL都是,包括ntdll.dll。这就是本节的内容了。

为了防止基于SEH的栈溢出,Windows改进了SEH,称为SafeSEH。从前面我们至少看到一点,启用SafeSEH编译的模块,我们的Shellcode是无法利用的,系统并不会调用我们伪造的这个“异常处理函数”。

事实上,启用SafeSEH之后,模块中使用的异常处理函数都要提前注册,注册的地方就在加载配置目录(Load Config Directory)。前面我们接触过导出表,导入表,这个加载配置目录也类似,属于16中数据目录中的一种。这样的话,发生异常之后,调用异常处理函数前,系统会对异常处理函数地址进行检验,如果没有注册,说明这个异常处理函数有问题,就直接忽略该异常处理函数。就如我们前面所看到的,我们伪造的异常处理函数被忽略,后面的又被我们所覆盖,因此异常无法被处理。

怎么办呢?第一个办法如我前面所做的,如果程序中有模块没有启用SafeSEH,我们还是可以利用它来加载Shellcode。第二个办法就是SafeSEH有个例外,就是如果异常处理函数位于已加载模块地址范围之外,则异常处理函数依旧会被调用。这样机会就来了,即使程序中所有模块都启用了SafeSEH,或者虽然没有启用,但无法找到合适的指令块做跳板。我们还可以尝试其它不属于该进程的模块。

具体的做法在这篇文章中:https://www.corelan.be/index.php/2009/09/21/exploit-writing-tutorial-part-6-bypassing-stack-cookies-safeseh-hw-dep-and-aslr/。
按他的做,很简单,这里就不重复了。

NLS,全称National Language Support,即本地语言支持。这个语言支持不只是文字,还有键盘,时间日期格式等,那么.nls后缀的文件就是相关的资源文件。这些资源文件使用的方式为内存映射,即读取其内存空间相当于读文件。进程结构PEB中有相应的成员:
这里写图片描述
图77

这些成员指针在进程初始化的时候指向资源文件映射之后相应的地址。

需要注意的是,虽然我们在unicode.nls找到了需要的“指令”,但unicode.nls是数据,只不过是其中的数据正好和指令操作码相同。这与我们把Shellcode放在栈上执行时相同的。

你可能感兴趣的:(栈溢出,Windows编程)