在前一篇<Oday安全 12.3.1Ret2Libc实战之利用ZwSetInformationProcess>一节注记(上) 的末尾部分,我们遇到访问无效内存的异常,本篇将讨论如何解决这个异常并关闭DEP保护。我们已经知道引起异常的原因是向无效地址[ebp-4](0x9090908C)写入数据。要解决这个异常可能有2种思路:1.让[ebp-4]指向可读写的地址;2.修改函数LdrpCheckNxCompatibility的实现,当然,这种方法不是本篇讨论的内容,是否具有可行性也没有验证过,所以,还是来讨论方式1。

出错时,ebp指向0x90909090,esp指向0x12ff80,当然esp指向的内存地址是可读写的,如果将esp的值赋给ebp,然后再执行mov ss:[ebp-4],esi就不会出错了。这样修改ebp最直白的方式应该是mov ebp,esp;ret;不知道是进程空间里搜不到这样的指令流还是别的原因,(想想也是mov ebp,esp一般都出现在函数入口出用于形成栈帧,才形成栈帧就执行retn感觉在浪费时间...)作者用的是一种替代方法:

push esp
pop ebp
retn

这个是个很神奇的指令序列: 1.经过push esp;pop ebp的确达到了修改ebp寄存器的目的;2在关闭DEP保护函数 LdrpCheckNxCompatibility的返回部分有这么一段指令流:

ntdll!LdrpCheckNXCompatibility+0x5c:
7c93cd6d 5e              pop     esi
7c93cd6e c9              leave     ;leave指令等效于mov esp,ebp pop ebp
7c93cd6f c20400          ret     4 ;

一般在函数的入口处会有一个Entry指令用于建立函数的栈帧,并在退出函数时调用leave恢复函数调用前的栈。由于,我们是以不正常的方式跳过Entry指令并进入LdrpCheckNxCompatibility函数,当离开LdrpCheckNxCompatibility前,执行leave指令可能会导致用错误的ebp寄存器的值恢复esp,最终影响整个溢出过程中的堆栈布局。为了消除leave指令带来的影响,我们需要手工建立栈帧。这就有了上面的指令流----在进入LdrpCheckNxCompatibility函数之前执行push esp;pop ebp序列,相当于执行了一次Entry指令,这样关闭DEP后esp能保持进入前的原样,就不会破坏堆栈布局;3.在2的基础上,由于esp寄存器的值具有进出函数前后的一致性,因此不管在LdrpCheckNxCompatibility函数怎么操作堆栈,最终退出该函数时,esp还指向shellcode,这样的好处是便于定位(虽然shellcode的内容可能在关闭DEP的过程中被频繁的出入栈操作冲刷掉了)。我猜想作者是鉴于这样思路,所以选择使用这段指令流。

现在要做的就是寻找这样的指令流,这简单,使用OD的OllyFindAddr插件就能实现这个功能:我挑选0x77ecdc68处的指令流。

编译后再次加载调试,可以看到ebp和esp的值一致,当执行完ret指令进入关闭DEP保护的流程时esp==0x12FF88:

下图为调整ebp准备进入LdrpCheckNxCompatibility函数:

下图为进入LdrpCheckNxCompatibility函数:

再来验证一下执行mov [ebp-4],esi指令时是否会引发异常,嗯,谢天谢地,终于让我饶过了这个是非之地:

大家还记得前一篇我整理的关闭DEP保护的代码流吗?最重要的是要饶过代码流中标识3.处。当执行完上面mov ss:[ebp-4],esi指令不就后,就会执行到标识3处:

3.
7c93cd2f 837dfc00        cmp     dword ptr [ebp-4],0                ;[ebp-4]中的值来源于1.中地址0x7c93cd26和0x7c93cd28的push/pop语句
7c93cd33 0f85f89a0100    jne     ntdll!LdrpCheckNXCompatibility+0x4d (7c956831) ;跳到4处执行  

由于此时[ebp-4]的值为2,因此将跳转到LdrpCheckNxCompatibility函数关闭DEP保护的代码流标识4处执行:

图为执行cmp ss:[ebp-4],00指令时寄存器和内存值,此时[ebp-4]==0x02,并将跳转到0x7c956831处运行:

0x7c956831处的几条指令翻译成c语言其实就是ZwSetInformationProcess(-1,0x22,&[ebp-4],04);这条语句看似风平浪静,其实暗流涌动,请大家注意执行call ZwSetInformationProcess前后堆栈的变化:

call之前的截图:

call之后的截图:

大家仔细观察从0x12FF78-0x12FF88这片栈内存值的变化。原本这片内存中存放的是精心构造的shellcode,很不幸,由于调用ZwSetInformationProcess函数shellcode的内容被覆盖的面目全非。这影响不大,最多shellcode执行不了了,但是当LdrpCheckNxCompatibility函数即将结束,执行leave;ret时,程序将返回到一个不可控的地址。让我们来手动模拟一下这个过程:

首先是执行leave指令,等效于mov esp,ebp;pop ebp;执行过后esp=0x12FF84,ebp=0x12FF7c;

紧接着准备执行retn指令,eip去[esp]中取返回地址,看看[esp]中存放了什么:[esp]=[0x12ff84]=0x04,shit,eip将返回到0x04去执行,想想都害怕。

下图为执行leave指令后寄存器/堆栈的状态:

下图为执行retn后Od的状态,指令窗口都黑线了,eip指向0x04,遇到这样的结果真倒霉:

前面已经说过直接导致这个结果的原因是堆栈中的shellcode被覆盖,再深层次的挖掘一下,是因为栈顶esp的值离这关键部分的shellcode(关闭DEP保护的shellcode)太近。解决方法是在进入LdrpCheckNxCompatibility函数前先抬高esp的值,让它离这部分的shellcode远一点。书中提到的方法是在进程空间中寻找retN(N==0x28)指令。但是,od的OllyFindAddr插件没有直接提供这样的功能,它只能寻找pop+retN这类指令。作者建议是Number of pop对话框中填0,Number of ret 填0x28,这么建议是有讲究的:

1.以Number of pop=1;Number of retN=0x28为例,ollyFindAddr找到的调整esp的指令流多数长这样:

如果选取pop ebp+retn 28指令流会引起新的bug----调用ZwSetInformationProcess时传入的第三个参数是[ebp-4]的地址:

ntdll!LdrpCheckNXCompatibility+0x4d:
7c956831 6a04            push    4
7c956833 8d45fc          lea     eax,[ebp-4]  <---取[ebp-4]的地址
7c956836 50              push    eax          <---地址入栈
7c956837 6a22            push    22h
7c956839 6aff            push    0FFFFFFFFh
7c95683b e84074fdff      call    ntdll!ZwSetInformationProcess (7c92dc80)
7c956840 e92865feff      jmp     ntdll!LdrpCheckNXCompatibility+0x5c (7c93cd6d)

一旦执行了pop ebp,势必影响lea eax, [ebp-4]得结果,所以作者提到抬高esp的过程中不能修改ebp;

2.既然不能修改ebp的地址,即不能执行pop ebp这样的指令,那我选择pop eax;retN这类指令流总可以吧。的确是可以,不过pop eax会影响esp的值,不方便计算shellcode的布局。鉴于上述两点原因,作者在对话框中填入了Number of pop=0;Number of RetN=28。

重新生成shellcode,将找到用于调整esp指针的retN地址插入到push esp;pop ebp;retn 0x4的地址之后,两者之间必选相隔4B而不是紧挨着,这是为什么?大家来看一下此时堆栈分布情况:esp指向0x12FF80,执行完retn 0x4之后,除了ret本身会让esp=esp+4 后面的 0x04又会让esp=esp+4.最终的效果就是修改esp为0x12FF88。CPU执行完retn 0x04之后,将执行retn 0x28,返回地址从栈顶esp寄存器中取出,原本我们指望esp取出的返回地址是0x7c974a19(就是进入关闭DEP保护的流程)。事与愿违的事发生了,esp将从栈顶取出的值为0x90909090,CPU返回到这个地址执行又会异常。所以我们先要在地址0x12FF84处预留4B的空档,然后在堆栈0x12FF88处存放值0x7C93CD24,好在执行retn 0x28时返回到LdrpCheckNxCompatibility函数中

编译od加载,让我们把程序停在执行retn 28之前,看下此时堆栈的分布:

此时esp寄存器值为0x12FF80,执行retn 04后eip将指向0x7c974a19(存放指令retn 0x28----用于抬高esp的值),同时esp被修改为0x12FF88:

再次执行retn 0x28指令,esp将被修改为0x12FF88+0x04+0x28=0x12FFb4;eip进入LdrpCheckNxCompatibility函数,进行关闭DEP的流程:

等到关闭DEP流程结束执行leave指令时,esp寄存器会恢复到之前修改EBP寄存器的值时的状态。下一次执行retn 4时Eip会从栈顶0x12FF84取返回地址,还记得这指向前面修改ebp值和抬高esp值时留下的空档?忘了可以回过去看看前面的段落。

一般而言,这个空档会用进程空间中jmp esp指令的地址填补,使得关闭DEP后,shellcode进入堆栈继续执行。注意LdrpCheckNxCompatibility函数末尾的retn 4指令使得esp指向0x12FF8c,因此shellcode最终会从此处开始执行:

下图是我搜索到的jmp esp的地址,将这个地址填补前面提到的空档。

当jmp esp执行后,eip从堆栈中取指令运行,Ret2LibC成功。

最后贴上我的代码:

#include <windows.h>/* shellcode内容注释
\x52\xe2\x92\x7c->mov al,0x01;ret;
\x85\x8b\x1d\x5d->push esp;pop ebp;retn 04;
\x19\x4a\x97\x7c->retn 0x28
\x13\x98\xd1\x7d->jmp esp
\x24\xcd\x93\x7c->关闭DEP
*/char shellcode[] = {"\x90\x90\x90\x90\x90\x90\x90\x90"\"\x52\xe2\x92\x7c"\"\x85\x8b\x1d\x5d"\"\x19\x4a\x97\x7c"\"\x13\x98\xd1\x7d"\"\x24\xcd\x93\x7c"\"\x90\x90\x90\x90"};int test()
{char arry[4] = {0};strcpy(arry,shellcode);return 0;
}int main()
{HMODULE hMod = LoadLibrary("shell32.dll");test();
}

Oday安全 12.3.1Ret2Libc实战之利用ZwSetInformationProcess一节注记(下)相关推荐

  1. Oday安全 12.3.1Ret2Libc实战之利用ZwSetInformationProcess一节注记(上)

    0day安全这书越到后面越难,哎...先记录一下看书过程中的注记,便于后面理解. 书中以绕过ntdll!LdrpCheckNXCompatibility:ntdll!LdrpCheckNXCompat ...

  2. Oday安全 12.3.1Ret2Libc实战之利用ZwSetInformationProcess一节补充

    本文补充记录我在试验关闭DEP过程遇到的问题和解决方法. 1.首先要说一下用OllyFindAddr插件寻找目标指令时可能会遇到的问题.诚然这个插件是个好东西,能迅速列出需要的指令流的地址,但并不是所 ...

  3. Oday安全 11.5利用未启用SafeSEH模块绕过SafeSEH一节注记

    Oday安全一书的内容越往后越深奥,不得不做些注记备忘. 1.书P297 插图11.5.6写道__except函数地址根据EBP-4的值得出.这是目前为止,书中写的最含糊的地方,需要展开讨论一下.参考 ...

  4. ArcGIS中利用DEM数据生成地形图既视感的等高线;利用掩膜进行等高线注记;DEM的可视化表达总结

    文章目录 前言 一.效果图展示 二.地形(DEM)可视化表达 1.一维可视化 2.二维可视化 3.三维可视化 二.ArcGIS中利用DEM数据制作等高线 1.DEM数据下载 2.镶嵌 3.提取出需要的 ...

  5. Oday安全 11.6利用加载模块之外的地址绕过SafeSEH一节注记---jmp [ebp+N] (上)

    看到这一章我又抓狂了:作者提及从进程空间类型为Map的映射文件中寻找如下指令地址: call/jmp dword ptr[esp+0x8] call/jmp dword ptr[esp+0x14] c ...

  6. Oday安全 11.6利用加载模块之外的地址绕过SafeSEH一节注记---jmp [ebp+N] (下)

    接上回,还剩几条跳转的指令还没分析到,这些指令将在本篇中完成. 先来看看call/jmp [ebp-0x4]这条指令.这是在当前函数_except_handler4栈的局部变量,因此需要查看反汇编代码 ...

  7. NLP实战:利用Python理解、分析和生成文本 | 赠书

    导读:本文内容参考自<自然语言处理实战:利用Python理解.分析和生成文本>一书,由Hobson Lane等人所著. 本书是介绍自然语言处理(NLP)和深度学习的实战书.NLP已成为深度 ...

  8. mysql shell可视化_shell编程系列24--shell操作数据库实战之利用shell脚本将文本数据导入到mysql中...

    shell编程系列24--shell操作数据库实战之利用shell脚本将文本数据导入到mysql中 利用shell脚本将文本数据导入到mysql中 需求1:处理文本中的数据,将文本中的数据插入到mys ...

  9. Vue.js学习笔记—shop-bus:实战:利用计算属性、指令等知识开发购物车

    参考<Vue,js>实战(梁灏编著) shop-bus:实战:利用计算属性.指令等知识开发购物车 git代码地址 index.html <!DOCTYPE html> < ...

最新文章

  1. aes离线解密工具_CrazyCrypt2.1勒索病毒已有一键解密工具
  2. 重构增长:如何从价值创造出发,打造企业的成长思维
  3. java导出jar带第三方库_在.jar文件中导出java库
  4. 电气技术应用和计算机应用,电气技术应用专业介绍-1.ppt
  5. linux root密码激活,Linux - root初始密码设置
  6. Mysql复习(基础概念+基础操作)
  7. Unity C#中TryGetValue与属性
  8. linux下keytool生成证书_keytool命令 – 密钥和证书管理工具
  9. 在java中调用mockjs生成模拟数据
  10. python登录判断用户名和密码_第一个python程序-判断登陆用户名和密码是否正确...
  11. 刘强东的高调,给京东带来了流量,也给京东带来了灾难
  12. AddressBook获取用户信息
  13. pandas多列合并成一列
  14. 【Redis基础和应用】(四)HyperLogLog BloomFilter
  15. ubuntu 16.04 编译android 7.1,jack报错
  16. android camera 对焦大小,Android camera2对焦设置
  17. 多普达830玩友玩祖玛的时候要小心啊
  18. 工业蒸汽量预测-特征工程
  19. 预训练模型-代码补全(一):CodeGeeX(清华大学)
  20. Java对txt文件、二进制文件的基本读写

热门文章

  1. ChatGPT可以改变哪些行业?
  2. 张飞开关电源二_sdchguyi_新浪博客
  3. x86_64是什么意思
  4. 【23】SCI易中期刊推荐——神经网络科学及机器人学(中科院3区)
  5. 三国志战略版:天作之合,登庸令群魏延+沮授,官渡之战
  6. HTML5新特性之标签使用:header、nav、aside、main、footer......
  7. c语言地址数组,C语言多维数组的地址
  8. 机器学习的数学基础:向量篇
  9. 嵌入式课设-基于GPS模块的校园定位程序
  10. 压缩机振动探头本特利330904-06-14-05-02-00