栈就是这样的,EIP始终指向ESP。我们的目的就是要把DATA以及EBP给占满。但是占满之前需要知道,究竟多少个字节才能够占满。
首先需要了解EBP占四个字节。也就是如果是char buffer[8];的话你需要加4才能够完全的到达EIP区。
来测试一波一个简单的DEMO:
#include "stdio.h"
#include "string.h"
char name[] = "hackershhelloworld";
int main()
{
char buffer[8];
strcpy(buffer,name);
printf("%s\n",buffer);
getchar();
return 0;
}
编译好然后丢到XP中。
重点看第四步:code:0x0000005的意思就是意味着溢出,而Address就是溢出的地址(EIP或者说返回地址);
Address是:72、6f、77、6f
然后将其转换一波十六进制的字符ASCII为字符,也就是r、o、w、o
翻转过来也就是owor(这里需要去了解入栈和出栈的流程,就像一瓶水,把A瓶子里的水倒入B瓶子的时候,水会首先进入B瓶子的瓶底,最后的会到A瓶子的瓶面。这就是入栈,然后出栈的时候也就是相反的,B瓶子的水倒入A瓶子,刚开始第一次倒的水在水面的会首先进入B瓶子的瓶底,最后的会进入瓶面)所以这里的EIP我们拿到的反的,你需要翻转才行。
那么就可以与name数组中的几个字符对应了"hackershhelloworld";
对应的这几个字符就称之为返回地址,也就是eip了。找到可以发现到o的前面总共有12个字符,而EBP占了4个字符,也就是说,前面的八个字符(hackersh)是DATA,后面的4个字符(hell)是EBP;
(这里分享一个疑惑点吧,就是在测试当中发现如果是name[3]的话好像就有点不同了,可以自己测试一波,如果不测试的话,这句话当我没说。)
通常找EIP有可能会很大,比如EIP可能会是在80个字符,或者更多,为了更快更高效的找可以结合例如大小写字母组合起来,小写字母占26,大写26,那么一组大小写下来就是52个字符,如果说是80个的话就很快就可以找到。因为你只需要两组大小写字母就可以了。(PS:找到了记得需要减去4(EBP所占大小)才是DATA哟)
然后找到溢出地址栈了以后,需要找到ESP
那么如何找ESP呢?可以直接通过Olly ICE找。
加载进去以后右键->查找->命令->输入jmp esp
然后得到jmp esp #这里需要说明一下,各个系统的jmp esp可能是不一样的哈。
也可以通过如下代码编译然后获得:
#include<windows.h> #include<stdio.h> #include<stdlib.h> int main() { BYTE *ptr; int position; HINSTANCE handle; BOOL done_flag = FALSE; handle = LoadLibrary("user32.dll"); if(!handle) { printf("load dll error"); exit(0); } ptr = (BYTE*)handle; for(position = 0;!done_flag;position++) { try { //jmp esp 机器码ffe4 if(ptr[position] == 0xFF && ptr[position+1]==0xE4) { int address = (int)ptr + position; printf("opcode found at 0x%x\n",address); } } catch(...) { int address = (int)ptr + position; printf("end of 0x%x\n",address); done_flag = true; } } getchar(); return 0; }