一、缓冲区溢出原理介绍:
缓冲区:stack、heap
1、栈溢出:当前输入的字符的数量大于buf的大小,造成溢出,ret地址被覆盖,造成任意地址跳转
来道题目直接看看:
这里很清晰,一个main函数,调用puts函数和read函数和puts函数,下面简单的例子演示下参数入栈:
单步走:先调用puts函数,先将参数“give me some thing?”压入栈中
执行完puts函数,借助栈中的0x8048489可回到下一条将要执行的指令的地址(return地址),回到了现场,此过程pop出0x8048489(因为调用结束,没有用了)
接着调用read函数,可以看到栈中压入的参数,从右往左0x40,buf,0,执行完read下一条将要执行的指令的地址0x804849c(return地址)入栈(__cdecl 调用约定,从右往左)
这里,我们知道了函数调用参数从左到右入栈的原理,而且知道栈是往低地址增长的,接着我们要往栈中写入东西呢?
从我们的输入可以看到,写入栈中的内容是往高地址写的,这里理解了:
参数入栈:往低地址增长
写栈:往高地址增长
再次调用puts函数,可以看到参数,下一个将要返回的指令地址以及当前栈的ebp
当执行完了puts,回到前面的栈帧:
开始不断地还原回去:
最后pop出ebp,ret那个libc_start_main的位置。
由于写栈往高地址写,那么意味着可以覆盖ret地址,只要写的足够长,这样,当函数返回时就会执行ret,如果我们恶意修改ret地址为任意地址,就可以实现任意地址跳转~这就是最基础的栈溢出的原理。
接着继续分析64位的情况:
64位的参数是放入到rdi、rsi、rdx、rcx、r8、r9,当这6个参数都放不了时才选择放在栈中,优先放入到寄存器中
继续看read函数调用:
这里我们知道了参数的保存,64位的写栈也是一样的,往高地址写:
这里根据我们之前学的,可以覆盖到ret地址,那我们试着覆盖下:
先找后门函数:
接着填充覆盖(0x20+8个字节覆盖ebp)+ function(ret位置)
程序执行完就可以getshell了:
以上就是有关栈溢出的所有知识点介绍,总结下:
首先是参数入栈图:
然后是写栈图:
写入字符串:
这样就可以getshell了~