网上关于栈溢出后用jmp esp执行shellcode的文章有很多,感觉分析的都没有戳到点,所以想结合自己调试的经历写下自己的想法。
正常情况下,函数栈分布图如下:
---->栈内存由低向高方向----->
|------------栈变量----------|----ebp----|------返回地址------|函数形参|
发生溢出后,以上栈空间的内容被覆盖,可能从上面的布局变成这样:
---->栈内存由低向高方向----->
|------------x90x90x90x90x90|x90x90x90..|shellcode缓存区的地址|x90x90.|
即,返回地址被改为一段缓存区的地址。当函数执行结束,从栈中取返回地址准备执行时,取到的是shellcode的地址,最终跳进shellcode执行。这段shellcode的地址一般被硬编码为某个地址,这个地址可以存在于程序空间的任何地方,只要有执行权限。
就像写代码时用绝对路径读取配置文件的内容,偶尔会出错一样,为了解决这种错误,可能会用相对程序运行时的路径去获取配置文件的内容。硬编码shellcode的地址也会出错,于是先人提出一种相对定位shellcode地址的方法,这就是jmp esp。
这用到了栈指针esp的一个特性:当函数执行ret指令后,Eip寄存器发生了跳转,但Esp还指向函数形参在栈中的地址。如示意图:
ret返回前 esp的位置:
---->栈内存由低向高方向----->
|------------栈变量----------|----ebp----|------返回地址------|函数形参|
^
|
esp指向这个位置
ret返回后 esp的位置
---->栈内存由低向高方向----->
|------------栈变量----------|----ebp----|------返回地址------|函数形参|
^
|
esp指向这个位置